Annotation of sys/dev/mii/bmtphy.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: bmtphy.c,v 1.16 2006/12/27 19:11:08 kettenis Exp $ */
2: /* $NetBSD: bmtphy.c,v 1.17 2005/01/17 13:17:45 scw Exp $ */
3:
4: /*-
5: * Copyright (c) 2001 Theo de Raadt
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: *
16: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26: * SUCH DAMAGE.
27: */
28:
29: /*
30: * Driver for Broadcom BCM5201/BCM5202 "Mini-Theta" PHYs. This also
31: * drives the PHY on the 3Com 3c905C. The 3c905C's PHY is described in
32: * the 3c905C data sheet.
33: */
34:
35: #include <sys/param.h>
36: #include <sys/systm.h>
37: #include <sys/kernel.h>
38: #include <sys/device.h>
39: #include <sys/socket.h>
40: #include <sys/errno.h>
41:
42: #include <net/if.h>
43: #include <net/if_media.h>
44:
45: #include <dev/mii/mii.h>
46: #include <dev/mii/miivar.h>
47: #include <dev/mii/miidevs.h>
48:
49: #include <dev/mii/bmtphyreg.h>
50:
51: int bmtphymatch(struct device *, void *, void *);
52: void bmtphyattach(struct device *, struct device *, void *);
53:
54: struct cfattach bmtphy_ca = {
55: sizeof(struct mii_softc), bmtphymatch, bmtphyattach, mii_phy_detach,
56: mii_phy_activate
57: };
58:
59: struct cfdriver bmtphy_cd = {
60: NULL, "bmtphy", DV_DULL
61: };
62:
63: int bmtphy_service(struct mii_softc *, struct mii_data *, int);
64: void bmtphy_status(struct mii_softc *);
65: void bmtphy_reset(struct mii_softc *);
66:
67: const struct mii_phy_funcs bmtphy_funcs = {
68: bmtphy_service, bmtphy_status, bmtphy_reset,
69: };
70:
71: static const struct mii_phydesc bmtphys[] = {
72: { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_3C905B,
73: MII_STR_BROADCOM_3C905B },
74: { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_3C905C,
75: MII_STR_BROADCOM_3C905C },
76: { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM4401,
77: MII_STR_BROADCOM_BCM4401 },
78: { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5201,
79: MII_STR_BROADCOM_BCM5201 },
80: { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5214,
81: MII_STR_BROADCOM_BCM5214 },
82: { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5220,
83: MII_STR_BROADCOM_BCM5220 },
84: { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5221,
85: MII_STR_BROADCOM_BCM5221 },
86: { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5222,
87: MII_STR_BROADCOM_BCM5222 },
88:
89: { 0, 0,
90: NULL },
91: };
92:
93: int
94: bmtphymatch(struct device *parent, void *match, void *aux)
95: {
96: struct mii_attach_args *ma = aux;
97:
98: if (mii_phy_match(ma, bmtphys) != NULL)
99: return (10);
100:
101: return (0);
102: }
103:
104: void
105: bmtphyattach(struct device *parent, struct device *self, void *aux)
106: {
107: struct mii_softc *sc = (struct mii_softc *)self;
108: struct mii_attach_args *ma = aux;
109: struct mii_data *mii = ma->mii_data;
110: const struct mii_phydesc *mpd;
111:
112: mpd = mii_phy_match(ma, bmtphys);
113: printf(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
114:
115: sc->mii_model = MII_MODEL(ma->mii_id2);
116: sc->mii_inst = mii->mii_instance;
117: sc->mii_phy = ma->mii_phyno;
118: sc->mii_funcs = &bmtphy_funcs;
119: sc->mii_pdata = mii;
120: sc->mii_flags = ma->mii_flags;
121: sc->mii_anegticks = MII_ANEGTICKS;
122:
123: PHY_RESET(sc);
124:
125: /*
126: * XXX Check AUX_STS_FX_MODE to set MIIF_HAVE_FIBER?
127: */
128:
129: sc->mii_capabilities =
130: PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
131: if (sc->mii_capabilities & BMSR_MEDIAMASK)
132: mii_phy_add_media(sc);
133: }
134:
135: int
136: bmtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
137: {
138: struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
139: int reg;
140:
141: if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0)
142: return (ENXIO);
143:
144: switch (cmd) {
145: case MII_POLLSTAT:
146: /*
147: * If we're not polling our PHY instance, just return.
148: */
149: if (IFM_INST(ife->ifm_media) != sc->mii_inst)
150: return (0);
151: break;
152:
153: case MII_MEDIACHG:
154: /*
155: * If the media indicates a different PHY instance,
156: * isolate ourselves.
157: */
158: if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
159: reg = PHY_READ(sc, MII_BMCR);
160: PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
161: return (0);
162: }
163:
164: /*
165: * If the interface is not up, don't do anything.
166: */
167: if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
168: break;
169:
170: mii_phy_setmedia(sc);
171: break;
172:
173: case MII_TICK:
174: /*
175: * If we're not currently selected, just return.
176: */
177: if (IFM_INST(ife->ifm_media) != sc->mii_inst)
178: return (0);
179:
180: if (mii_phy_tick(sc) == EJUSTRETURN)
181: return (0);
182: break;
183:
184: case MII_DOWN:
185: mii_phy_down(sc);
186: return (0);
187: }
188:
189: /* Update the media status. */
190: mii_phy_status(sc);
191:
192: /* Callback if something changed. */
193: mii_phy_update(sc, cmd);
194: return (0);
195: }
196:
197: void
198: bmtphy_status(struct mii_softc *sc)
199: {
200: struct mii_data *mii = sc->mii_pdata;
201: struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
202: int bmsr, bmcr, aux_csr;
203:
204: mii->mii_media_status = IFM_AVALID;
205: mii->mii_media_active = IFM_ETHER;
206:
207: bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
208: if (bmsr & BMSR_LINK)
209: mii->mii_media_status |= IFM_ACTIVE;
210:
211: bmcr = PHY_READ(sc, MII_BMCR);
212: if (bmcr & BMCR_ISO) {
213: mii->mii_media_active |= IFM_NONE;
214: mii->mii_media_status = 0;
215: return;
216: }
217:
218: if (bmcr & BMCR_LOOP)
219: mii->mii_media_active |= IFM_LOOP;
220:
221: if (bmcr & BMCR_AUTOEN) {
222: /*
223: * The later are only valid if autonegotiation
224: * has completed (or it's disabled).
225: */
226: if ((bmsr & BMSR_ACOMP) == 0) {
227: /* Erg, still trying, I guess... */
228: mii->mii_media_active |= IFM_NONE;
229: return;
230: }
231:
232: aux_csr = PHY_READ(sc, MII_BMTPHY_AUX_CSR);
233: if (aux_csr & AUX_CSR_SPEED)
234: mii->mii_media_active |= IFM_100_TX;
235: else
236: mii->mii_media_active |= IFM_10_T;
237:
238: if (aux_csr & AUX_CSR_FDX)
239: mii->mii_media_active |= IFM_FDX;
240: else
241: mii->mii_media_active |= IFM_HDX;
242: } else
243: mii->mii_media_active = ife->ifm_media;
244: }
245:
246: void
247: bmtphy_reset(struct mii_softc *sc)
248: {
249: u_int16_t data;
250:
251: mii_phy_reset(sc);
252:
253: if (sc->mii_model == MII_MODEL_BROADCOM_BCM5221) {
254: /* Enable shadow register mode */
255: data = PHY_READ(sc, 0x1f);
256: PHY_WRITE(sc, 0x1f, data | 0x0080);
257:
258: /* Enable APD (Auto PowerDetect) */
259: data = PHY_READ(sc, MII_BMTPHY_AUX2);
260: PHY_WRITE(sc, MII_BMTPHY_AUX2, data | 0x0020);
261:
262: /* Enable clocks across APD for
263: * Auto-MDIX functionality */
264: data = PHY_READ(sc, MII_BMTPHY_INTR);
265: PHY_WRITE(sc, MII_BMTPHY_INTR, data | 0x0004);
266:
267: /* Disable shadow register mode */
268: data = PHY_READ(sc, 0x1f);
269: PHY_WRITE(sc, 0x1f, data & ~0x0080);
270: }
271: }
CVSweb