Line data Source code
1 : /* $OpenBSD: amphy.c,v 1.21 2015/03/14 03:38:47 jsg Exp $ */
2 :
3 : /*
4 : * Copyright (c) 1997, 1998, 1999
5 : * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
6 : *
7 : * Redistribution and use in source and binary forms, with or without
8 : * modification, are permitted provided that the following conditions
9 : * are met:
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * 2. Redistributions in binary form must reproduce the above copyright
13 : * notice, this list of conditions and the following disclaimer in the
14 : * documentation and/or other materials provided with the distribution.
15 : * 3. All advertising materials mentioning features or use of this software
16 : * must display the following acknowledgement:
17 : * This product includes software developed by Bill Paul.
18 : * 4. Neither the name of the author nor the names of any co-contributors
19 : * may be used to endorse or promote products derived from this software
20 : * without specific prior written permission.
21 : *
22 : * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 : * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
26 : * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 : * THE POSSIBILITY OF SUCH DAMAGE.
33 : *
34 : * $FreeBSD: src/sys/dev/mii/amphy.c,v 1.3 2000/04/19 14:57:29 phk Exp $
35 : */
36 :
37 : /*
38 : * driver for AMD AM79c873 PHYs
39 : * This driver also works for the Davicom DM9101 PHY, which appears to
40 : * be an AM79c873 workalike.
41 : */
42 :
43 : #include <sys/param.h>
44 : #include <sys/systm.h>
45 : #include <sys/device.h>
46 : #include <sys/socket.h>
47 :
48 : #include <net/if.h>
49 : #include <net/if_var.h>
50 : #include <net/if_media.h>
51 :
52 : #include <dev/mii/mii.h>
53 : #include <dev/mii/miivar.h>
54 : #include <dev/mii/miidevs.h>
55 :
56 : #include <dev/mii/amphyreg.h>
57 :
58 : int amphymatch(struct device *, void *, void *);
59 : void amphyattach(struct device *, struct device *, void *);
60 :
61 : struct cfattach amphy_ca = {
62 : sizeof(struct mii_softc), amphymatch, amphyattach, mii_phy_detach
63 : };
64 :
65 : struct cfdriver amphy_cd = {
66 : NULL, "amphy", DV_DULL
67 : };
68 :
69 : int amphy_service(struct mii_softc *, struct mii_data *, int);
70 : void amphy_status(struct mii_softc *);
71 :
72 : const struct mii_phy_funcs amphy_funcs = {
73 : amphy_service, amphy_status, mii_phy_reset,
74 : };
75 :
76 : static const struct mii_phydesc amphys[] = {
77 : { MII_OUI_xxAMD, MII_MODEL_xxAMD_79C873,
78 : MII_STR_xxAMD_79C873 },
79 : { MII_OUI_xxDAVICOM, MII_MODEL_xxDAVICOM_DM9101,
80 : MII_STR_xxDAVICOM_DM9101 },
81 : { MII_OUI_DAVICOM, MII_MODEL_DAVICOM_DM9102,
82 : MII_STR_DAVICOM_DM9102 },
83 : { MII_OUI_DAVICOM, MII_MODEL_DAVICOM_DM9601,
84 : MII_STR_DAVICOM_DM9601 },
85 : { MII_OUI_xxALTIMA, MII_MODEL_AMD_79C875phy,
86 : MII_STR_AMD_79C875phy },
87 :
88 : { 0, 0,
89 : NULL },
90 : };
91 :
92 : int
93 0 : amphymatch(struct device *parent, void *match, void *aux)
94 : {
95 0 : struct mii_attach_args *ma = aux;
96 :
97 0 : if (mii_phy_match(ma, amphys) != NULL)
98 0 : return (10);
99 :
100 0 : return (0);
101 0 : }
102 :
103 : void
104 0 : amphyattach(struct device *parent, struct device *self, void *aux)
105 : {
106 0 : struct mii_softc *sc = (struct mii_softc *)self;
107 0 : struct mii_attach_args *ma = aux;
108 0 : struct mii_data *mii = ma->mii_data;
109 : const struct mii_phydesc *mpd;
110 :
111 0 : mpd = mii_phy_match(ma, amphys);
112 0 : printf(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
113 :
114 0 : sc->mii_inst = mii->mii_instance;
115 0 : sc->mii_phy = ma->mii_phyno;
116 0 : sc->mii_funcs = &hy_funcs;
117 0 : sc->mii_pdata = mii;
118 0 : sc->mii_flags = ma->mii_flags;
119 :
120 0 : sc->mii_flags |= MIIF_NOISOLATE;
121 :
122 0 : PHY_RESET(sc);
123 :
124 0 : sc->mii_capabilities =
125 0 : PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
126 0 : if (sc->mii_capabilities & BMSR_MEDIAMASK)
127 0 : mii_phy_add_media(sc);
128 0 : }
129 :
130 : int
131 0 : amphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
132 : {
133 0 : struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
134 : int reg;
135 :
136 0 : switch (cmd) {
137 : case MII_POLLSTAT:
138 : /*
139 : * If we're not polling our PHY instance, just return.
140 : */
141 0 : if (IFM_INST(ife->ifm_media) != sc->mii_inst)
142 0 : return (0);
143 : break;
144 :
145 : case MII_MEDIACHG:
146 : /*
147 : * If the media indicates a different PHY instance,
148 : * isolate ourselves.
149 : */
150 0 : if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
151 0 : reg = PHY_READ(sc, MII_BMCR);
152 0 : PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
153 0 : return (0);
154 : }
155 :
156 : /*
157 : * If the interface is not up, don't do anything.
158 : */
159 0 : if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
160 : break;
161 :
162 0 : mii_phy_setmedia(sc);
163 0 : break;
164 :
165 : case MII_TICK:
166 : /*
167 : * If we're not currently selected, just return.
168 : */
169 0 : if (IFM_INST(ife->ifm_media) != sc->mii_inst)
170 0 : return (0);
171 :
172 0 : if (mii_phy_tick(sc) == EJUSTRETURN)
173 0 : return (0);
174 : break;
175 : case MII_DOWN:
176 0 : mii_phy_down(sc);
177 0 : return (0);
178 : }
179 :
180 : /* Update the media status. */
181 0 : mii_phy_status(sc);
182 :
183 : /* Callback if something changed. */
184 0 : mii_phy_update(sc, cmd);
185 0 : return (0);
186 0 : }
187 :
188 : void
189 0 : amphy_status(struct mii_softc *sc)
190 : {
191 0 : struct mii_data *mii = sc->mii_pdata;
192 0 : struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
193 : int bmsr, bmcr, par, anlpar;
194 :
195 0 : mii->mii_media_status = IFM_AVALID;
196 0 : mii->mii_media_active = IFM_ETHER;
197 :
198 0 : bmsr = PHY_READ(sc, MII_BMSR) |
199 0 : PHY_READ(sc, MII_BMSR);
200 0 : if (bmsr & BMSR_LINK)
201 0 : mii->mii_media_status |= IFM_ACTIVE;
202 :
203 0 : bmcr = PHY_READ(sc, MII_BMCR);
204 0 : if (bmcr & BMCR_ISO) {
205 0 : mii->mii_media_active |= IFM_NONE;
206 0 : mii->mii_media_status = 0;
207 0 : return;
208 : }
209 :
210 0 : if (bmcr & BMCR_LOOP)
211 0 : mii->mii_media_active |= IFM_LOOP;
212 :
213 0 : if (bmcr & BMCR_AUTOEN) {
214 : /*
215 : * The PAR status bits are only valid if autonegotiation
216 : * has completed (or it's disabled).
217 : */
218 0 : if ((bmsr & BMSR_ACOMP) == 0) {
219 : /* Erg, still trying, I guess... */
220 0 : mii->mii_media_active |= IFM_NONE;
221 0 : return;
222 : }
223 :
224 0 : if (PHY_READ(sc, MII_ANER) & ANER_LPAN) {
225 0 : anlpar = PHY_READ(sc, MII_ANAR) &
226 0 : PHY_READ(sc, MII_ANLPAR);
227 0 : if (anlpar & ANLPAR_TX_FD)
228 0 : mii->mii_media_active |= IFM_100_TX|IFM_FDX;
229 0 : else if (anlpar & ANLPAR_T4)
230 0 : mii->mii_media_active |= IFM_100_T4|IFM_HDX;
231 0 : else if (anlpar & ANLPAR_TX)
232 0 : mii->mii_media_active |= IFM_100_TX|IFM_HDX;
233 0 : else if (anlpar & ANLPAR_10_FD)
234 0 : mii->mii_media_active |= IFM_10_T|IFM_FDX;
235 0 : else if (anlpar & ANLPAR_10)
236 0 : mii->mii_media_active |= IFM_10_T|IFM_HDX;
237 : else
238 0 : mii->mii_media_active |= IFM_NONE;
239 0 : return;
240 : }
241 :
242 : /*
243 : * Link partner is not capable of autonegotiation.
244 : */
245 0 : par = PHY_READ(sc, MII_AMPHY_DSCSR);
246 0 : if (par & DSCSR_100FDX)
247 0 : mii->mii_media_active |= IFM_100_TX|IFM_FDX;
248 0 : else if (par & DSCSR_100HDX)
249 0 : mii->mii_media_active |= IFM_100_TX|IFM_HDX;
250 0 : else if (par & DSCSR_10FDX)
251 0 : mii->mii_media_active |= IFM_10_T|IFM_FDX;
252 0 : else if (par & DSCSR_10HDX)
253 0 : mii->mii_media_active |= IFM_10_T|IFM_HDX;
254 : } else
255 0 : mii->mii_media_active = ife->ifm_media;
256 0 : }
|