Annotation of sys/dev/mii/eephy.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: eephy.c,v 1.40 2007/02/11 21:29:24 kettenis Exp $ */
2: /*
3: * Principal Author: Parag Patel
4: * Copyright (c) 2001
5: * 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 unmodified, this list of conditions, and the following
12: * disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: *
17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27: * SUCH DAMAGE.
28: *
29: * Additonal Copyright (c) 2001 by Traakan Software under same licence.
30: * Secondary Author: Matthew Jacob
31: */
32:
33: /*
34: * driver for the Marvell 88E1000 series external 1000/100/10-BT PHY.
35: */
36:
37: /*
38: * Support added for the Marvell 88E1011 (Alaska) 1000/100/10baseTX and
39: * 1000baseSX PHY.
40: * Nathan Binkert <nate@openbsd.org>
41: */
42:
43: #include <sys/param.h>
44: #include <sys/systm.h>
45: #include <sys/kernel.h>
46: #include <sys/device.h>
47: #include <sys/socket.h>
48: #include <sys/proc.h>
49:
50: #include <net/if.h>
51: #include <net/if_media.h>
52:
53: #include <dev/mii/mii.h>
54: #include <dev/mii/miivar.h>
55: #include <dev/mii/miidevs.h>
56:
57: #include <dev/mii/eephyreg.h>
58:
59: int eephy_service(struct mii_softc *, struct mii_data *, int);
60: void eephy_status(struct mii_softc *);
61: int eephymatch(struct device *, void *, void *);
62: void eephyattach(struct device *, struct device *, void *);
63:
64: struct cfattach eephy_ca = {
65: sizeof (struct mii_softc), eephymatch, eephyattach,
66: mii_phy_detach, mii_phy_activate
67: };
68:
69: struct cfdriver eephy_cd = {
70: NULL, "eephy", DV_DULL
71: };
72:
73: int eephy_mii_phy_auto(struct mii_softc *);
74: void eephy_reset(struct mii_softc *);
75:
76: const struct mii_phy_funcs eephy_funcs = {
77: eephy_service, eephy_status, eephy_reset,
78: };
79:
80: static const struct mii_phydesc eephys[] = {
81: { MII_OUI_MARVELL, MII_MODEL_MARVELL_E1000_1,
82: MII_STR_MARVELL_E1000_1 },
83: { MII_OUI_MARVELL, MII_MODEL_MARVELL_E1000_2,
84: MII_STR_MARVELL_E1000_2 },
85: { MII_OUI_MARVELL, MII_MODEL_MARVELL_E1000_3,
86: MII_STR_MARVELL_E1000_3 },
87: { MII_OUI_MARVELL, MII_MODEL_MARVELL_E1000_4,
88: MII_STR_MARVELL_E1000_4 },
89: { MII_OUI_MARVELL, MII_MODEL_MARVELL_E1000S,
90: MII_STR_MARVELL_E1000S },
91: { MII_OUI_MARVELL, MII_MODEL_MARVELL_E1011,
92: MII_STR_MARVELL_E1011 },
93: { MII_OUI_MARVELL, MII_MODEL_MARVELL_E1111,
94: MII_STR_MARVELL_E1111 },
95: { MII_OUI_MARVELL, MII_MODEL_MARVELL_E1112,
96: MII_STR_MARVELL_E1112 },
97: { MII_OUI_MARVELL, MII_MODEL_MARVELL_E1116,
98: MII_STR_MARVELL_E1116 },
99: { MII_OUI_MARVELL, MII_MODEL_MARVELL_E1118,
100: MII_STR_MARVELL_E1118 },
101: { MII_OUI_MARVELL, MII_MODEL_MARVELL_E1149,
102: MII_STR_MARVELL_E1149 },
103: { MII_OUI_MARVELL, MII_MODEL_MARVELL_E3082,
104: MII_STR_MARVELL_E3082 },
105: { MII_OUI_xxMARVELL, MII_MODEL_xxMARVELL_E1000_5,
106: MII_STR_xxMARVELL_E1000_5 },
107: { MII_OUI_xxMARVELL, MII_MODEL_xxMARVELL_E1000_6,
108: MII_STR_xxMARVELL_E1000_6 },
109: { MII_OUI_xxMARVELL, MII_MODEL_xxMARVELL_E1000_7,
110: MII_STR_xxMARVELL_E1000_7 },
111: { MII_OUI_xxMARVELL, MII_MODEL_xxMARVELL_E1111,
112: MII_STR_xxMARVELL_E1111 },
113:
114: { 0, 0,
115: NULL },
116: };
117:
118: int
119: eephymatch(struct device *parent, void *match, void *aux)
120: {
121: struct mii_attach_args *ma = aux;
122:
123: if (mii_phy_match(ma, eephys) != NULL)
124: return (10);
125:
126: return (0);
127: }
128:
129: void
130: eephyattach(struct device *parent, struct device *self, void *aux)
131: {
132: struct mii_softc *sc = (struct mii_softc *)self;
133: struct mii_attach_args *ma = aux;
134: struct mii_data *mii = ma->mii_data;
135: const struct mii_phydesc *mpd;
136: int reg, page;
137:
138: mpd = mii_phy_match(ma, eephys);
139: printf(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
140:
141: sc->mii_inst = mii->mii_instance;
142: sc->mii_phy = ma->mii_phyno;
143: sc->mii_funcs = &eephy_funcs;
144: sc->mii_model = MII_MODEL(ma->mii_id2);
145: sc->mii_pdata = mii;
146: sc->mii_flags = ma->mii_flags;
147:
148: /* XXX No loopback support yet, although the hardware can do it. */
149: sc->mii_flags |= MIIF_NOLOOP;
150:
151: /* Switch to fiber-only mode if necessary. */
152: if (sc->mii_model == MII_MODEL_MARVELL_E1112 &&
153: sc->mii_flags & MIIF_HAVEFIBER) {
154: page = PHY_READ(sc, E1000_EADR);
155: PHY_WRITE(sc, E1000_EADR, 2);
156: reg = PHY_READ(sc, E1000_SCR);
157: reg &= ~E1000_SCR_MODE_MASK;
158: reg |= E1000_SCR_MODE_1000BX;
159: PHY_WRITE(sc, E1000_SCR, reg);
160: PHY_WRITE(sc, E1000_EADR, page);
161:
162: PHY_RESET(sc);
163: }
164:
165: sc->mii_capabilities = PHY_READ(sc, E1000_SR) & ma->mii_capmask;
166: if (sc->mii_capabilities & BMSR_EXTSTAT)
167: sc->mii_extcapabilities = PHY_READ(sc, E1000_ESR);
168:
169: mii_phy_add_media(sc);
170:
171: /*
172: * Initialize PHY Specific Control Register.
173: */
174:
175: reg = PHY_READ(sc, E1000_SCR);
176:
177: /* Assert CRS on transmit. */
178: reg |= E1000_SCR_ASSERT_CRS_ON_TX;
179:
180: /* Enable auto crossover. */
181: switch (sc->mii_model) {
182: case MII_MODEL_MARVELL_E3082:
183: /* Bits are in a different position. */
184: reg |= (E1000_SCR_AUTO_X_MODE >> 1);
185: break;
186: default:
187: /* Automatic crossover causes problems for 1000baseX. */
188: if (sc->mii_flags & MIIF_IS_1000X)
189: reg &= ~E1000_SCR_AUTO_X_MODE;
190: else
191: reg |= E1000_SCR_AUTO_X_MODE;
192: }
193:
194: /* Disable energy detect; only available on some models. */
195: switch(sc->mii_model) {
196: case MII_MODEL_MARVELL_E1011:
197: case MII_MODEL_MARVELL_E1111:
198: case MII_MODEL_MARVELL_E1112:
199: /* Disable energy detect. */
200: reg &= ~E1000_SCR_EN_DETECT_MASK;
201: break;
202: }
203:
204: PHY_WRITE(sc, E1000_SCR, reg);
205:
206: /* 25 MHz TX_CLK should always work. */
207: reg = PHY_READ(sc, E1000_ESCR);
208: reg |= E1000_ESCR_TX_CLK_25;
209: PHY_WRITE(sc, E1000_ESCR, reg);
210:
211: /*
212: * Do a software reset for these settings to take effect.
213: * Disable autonegotiation, such that all capabilities get
214: * advertised when it is switched back on.
215: */
216: reg = PHY_READ(sc, E1000_CR);
217: reg &= ~E1000_CR_AUTO_NEG_ENABLE;
218: PHY_WRITE(sc, E1000_CR, reg | E1000_CR_RESET);
219: }
220:
221: void
222: eephy_reset(struct mii_softc *sc)
223: {
224: int reg, i;
225:
226: reg = PHY_READ(sc, E1000_CR);
227: reg |= E1000_CR_RESET;
228: PHY_WRITE(sc, E1000_CR, reg);
229:
230: for (i = 0; i < 500; i++) {
231: DELAY(1);
232: reg = PHY_READ(sc, E1000_CR);
233: if (!(reg & E1000_CR_RESET))
234: break;
235: }
236: }
237:
238: int
239: eephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
240: {
241: struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
242: int bmcr;
243:
244: if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0)
245: return (ENXIO);
246:
247: switch (cmd) {
248: case MII_POLLSTAT:
249: /*
250: * If we're not polling our PHY instance, just return.
251: */
252: if (IFM_INST(ife->ifm_media) != sc->mii_inst)
253: return (0);
254: break;
255:
256: case MII_MEDIACHG:
257: /*
258: * If the media indicates a different PHY instance,
259: * isolate ourselves.
260: */
261: if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
262: bmcr = PHY_READ(sc, E1000_CR);
263: PHY_WRITE(sc, E1000_CR, bmcr | E1000_CR_ISOLATE);
264: return (0);
265: }
266:
267: /*
268: * If the interface is not up, don't do anything.
269: */
270: if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
271: break;
272:
273: mii_phy_setmedia(sc);
274:
275: /*
276: * If autonegitation is not enabled, we need a
277: * software reset for the settings to take effect.
278: */
279: if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
280: bmcr = PHY_READ(sc, E1000_CR);
281: PHY_WRITE(sc, E1000_CR, bmcr | E1000_CR_RESET);
282: }
283: break;
284:
285: case MII_TICK:
286: /*
287: * If we're not currently selected, just return.
288: */
289: if (IFM_INST(ife->ifm_media) != sc->mii_inst)
290: return (0);
291:
292: if (mii_phy_tick(sc) == EJUSTRETURN)
293: return (0);
294: break;
295:
296: case MII_DOWN:
297: mii_phy_down(sc);
298: return (0);
299: }
300:
301: /* Update the media status. */
302: mii_phy_status(sc);
303:
304: /* Callback if something changed. */
305: mii_phy_update(sc, cmd);
306: return (0);
307: }
308:
309: void
310: eephy_status(struct mii_softc *sc)
311: {
312: struct mii_data *mii = sc->mii_pdata;
313: int bmcr, gsr, ssr;
314:
315: mii->mii_media_status = IFM_AVALID;
316: mii->mii_media_active = IFM_ETHER;
317:
318: bmcr = PHY_READ(sc, E1000_CR);
319: ssr = PHY_READ(sc, E1000_SSR);
320:
321: if (ssr & E1000_SSR_LINK)
322: mii->mii_media_status |= IFM_ACTIVE;
323:
324: if (bmcr & E1000_CR_LOOPBACK)
325: mii->mii_media_active |= IFM_LOOP;
326:
327: if (!(ssr & E1000_SSR_SPD_DPLX_RESOLVED)) {
328: /* Erg, still trying, I guess... */
329: mii->mii_media_active |= IFM_NONE;
330: return;
331: }
332:
333: if (sc->mii_flags & MIIF_IS_1000X) {
334: mii->mii_media_active |= IFM_1000_SX;
335: } else {
336: if (ssr & E1000_SSR_1000MBS)
337: mii->mii_media_active |= IFM_1000_T;
338: else if (ssr & E1000_SSR_100MBS)
339: mii->mii_media_active |= IFM_100_TX;
340: else
341: mii->mii_media_active |= IFM_10_T;
342: }
343:
344: if (ssr & E1000_SSR_DUPLEX)
345: mii->mii_media_active |= mii_phy_flowstatus(sc) | IFM_FDX;
346: else
347: mii->mii_media_active |= IFM_HDX;
348:
349: if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) {
350: gsr = PHY_READ(sc, E1000_1GSR) | PHY_READ(sc, E1000_1GSR);
351: if (gsr & E1000_1GSR_MS_CONFIG_RES)
352: mii->mii_media_active |= IFM_ETH_MASTER;
353: }
354: }
CVSweb