Line data Source code
1 : /* $OpenBSD: eephy.c,v 1.56 2015/03/14 03:38:48 jsg 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/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/eephyreg.h>
57 :
58 : int eephy_match(struct device *, void *, void *);
59 : void eephy_attach(struct device *, struct device *, void *);
60 :
61 : struct cfattach eephy_ca = {
62 : sizeof (struct mii_softc), eephy_match, eephy_attach, mii_phy_detach
63 : };
64 :
65 : struct cfdriver eephy_cd = {
66 : NULL, "eephy", DV_DULL
67 : };
68 :
69 : int eephy_service(struct mii_softc *, struct mii_data *, int);
70 : void eephy_status(struct mii_softc *);
71 : void eephy_reset(struct mii_softc *);
72 :
73 : const struct mii_phy_funcs eephy_funcs = {
74 : eephy_service, eephy_status, eephy_reset,
75 : };
76 :
77 : static const struct mii_phydesc eephys[] = {
78 : { MII_OUI_MARVELL, MII_MODEL_MARVELL_E1000_1,
79 : MII_STR_MARVELL_E1000_1 },
80 : { MII_OUI_MARVELL, MII_MODEL_MARVELL_E1000_2,
81 : MII_STR_MARVELL_E1000_2 },
82 : { MII_OUI_MARVELL, MII_MODEL_MARVELL_E1000_3,
83 : MII_STR_MARVELL_E1000_3 },
84 : { MII_OUI_MARVELL, MII_MODEL_MARVELL_E1000_4,
85 : MII_STR_MARVELL_E1000_4 },
86 : { MII_OUI_MARVELL, MII_MODEL_MARVELL_E1000S,
87 : MII_STR_MARVELL_E1000S },
88 : { MII_OUI_MARVELL, MII_MODEL_MARVELL_E1011,
89 : MII_STR_MARVELL_E1011 },
90 : { MII_OUI_MARVELL, MII_MODEL_MARVELL_E1111,
91 : MII_STR_MARVELL_E1111 },
92 : { MII_OUI_MARVELL, MII_MODEL_MARVELL_E1112,
93 : MII_STR_MARVELL_E1112 },
94 : { MII_OUI_MARVELL, MII_MODEL_MARVELL_E1116,
95 : MII_STR_MARVELL_E1116 },
96 : { MII_OUI_MARVELL, MII_MODEL_MARVELL_E1116R,
97 : MII_STR_MARVELL_E1116R },
98 : { MII_OUI_MARVELL, MII_MODEL_MARVELL_E1118,
99 : MII_STR_MARVELL_E1118 },
100 : { MII_OUI_MARVELL, MII_MODEL_MARVELL_E1149,
101 : MII_STR_MARVELL_E1149 },
102 : { MII_OUI_MARVELL, MII_MODEL_MARVELL_E3016,
103 : MII_STR_MARVELL_E3016},
104 : { MII_OUI_MARVELL, MII_MODEL_MARVELL_E3082,
105 : MII_STR_MARVELL_E3082 },
106 : { MII_OUI_MARVELL, MII_MODEL_MARVELL_PHYG65G,
107 : MII_STR_MARVELL_PHYG65G },
108 : { MII_OUI_xxMARVELL, MII_MODEL_xxMARVELL_E1000_5,
109 : MII_STR_xxMARVELL_E1000_5 },
110 : { MII_OUI_xxMARVELL, MII_MODEL_xxMARVELL_E1000_6,
111 : MII_STR_xxMARVELL_E1000_6 },
112 : { MII_OUI_xxMARVELL, MII_MODEL_xxMARVELL_E1000_7,
113 : MII_STR_xxMARVELL_E1000_7 },
114 : { MII_OUI_xxMARVELL, MII_MODEL_xxMARVELL_E1111,
115 : MII_STR_xxMARVELL_E1111 },
116 :
117 : { 0, 0,
118 : NULL },
119 : };
120 :
121 : int
122 0 : eephy_match(struct device *parent, void *match, void *aux)
123 : {
124 0 : struct mii_attach_args *ma = aux;
125 :
126 0 : if (mii_phy_match(ma, eephys) != NULL)
127 0 : return (10);
128 :
129 0 : return (0);
130 0 : }
131 :
132 : void
133 0 : eephy_attach(struct device *parent, struct device *self, void *aux)
134 : {
135 0 : struct mii_softc *sc = (struct mii_softc *)self;
136 0 : struct mii_attach_args *ma = aux;
137 0 : struct mii_data *mii = ma->mii_data;
138 : const struct mii_phydesc *mpd;
139 : int reg, page;
140 :
141 0 : mpd = mii_phy_match(ma, eephys);
142 0 : printf(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
143 :
144 0 : sc->mii_inst = mii->mii_instance;
145 0 : sc->mii_phy = ma->mii_phyno;
146 0 : sc->mii_funcs = &eephy_funcs;
147 0 : sc->mii_model = MII_MODEL(ma->mii_id2);
148 0 : sc->mii_pdata = mii;
149 0 : sc->mii_flags = ma->mii_flags;
150 :
151 : /* XXX No loopback support yet, although the hardware can do it. */
152 0 : sc->mii_flags |= MIIF_NOLOOP;
153 :
154 : /* Make sure page 0 is selected. */
155 0 : PHY_WRITE(sc, E1000_EADR, 0);
156 :
157 : /* Switch to copper-only mode if necessary. */
158 0 : if (sc->mii_model == MII_MODEL_MARVELL_E1111 &&
159 0 : (sc->mii_flags & MIIF_HAVEFIBER) == 0) {
160 : /*
161 : * The onboard 88E1111 PHYs on the Sun X4100 M2 come
162 : * up with fiber/copper auto-selection enabled, even
163 : * though the machine only has copper ports. This
164 : * makes the chip autoselect to 1000baseX, and makes
165 : * it impossible to select any other media. So
166 : * disable fiber/copper autoselection.
167 : */
168 0 : reg = PHY_READ(sc, E1000_ESSR);
169 0 : if ((reg & E1000_ESSR_HWCFG_MODE) == E1000_ESSR_RGMII_COPPER) {
170 0 : reg |= E1000_ESSR_DIS_FC;
171 0 : PHY_WRITE(sc, E1000_ESSR, reg);
172 0 : }
173 : }
174 :
175 : /* Switch to fiber-only mode if necessary. */
176 0 : if (sc->mii_model == MII_MODEL_MARVELL_E1112 &&
177 0 : sc->mii_flags & MIIF_HAVEFIBER) {
178 0 : page = PHY_READ(sc, E1000_EADR);
179 0 : PHY_WRITE(sc, E1000_EADR, 2);
180 0 : reg = PHY_READ(sc, E1000_SCR);
181 0 : reg &= ~E1000_SCR_MODE_MASK;
182 0 : reg |= E1000_SCR_MODE_1000BX;
183 0 : PHY_WRITE(sc, E1000_SCR, reg);
184 0 : PHY_WRITE(sc, E1000_EADR, page);
185 0 : }
186 :
187 0 : PHY_RESET(sc);
188 :
189 0 : sc->mii_capabilities = PHY_READ(sc, E1000_SR) & ma->mii_capmask;
190 0 : if (sc->mii_capabilities & BMSR_EXTSTAT)
191 0 : sc->mii_extcapabilities = PHY_READ(sc, E1000_ESR);
192 :
193 0 : mii_phy_add_media(sc);
194 :
195 0 : }
196 :
197 : void
198 0 : eephy_reset(struct mii_softc *sc)
199 : {
200 : int reg, i;
201 :
202 0 : reg = PHY_READ(sc, E1000_CR);
203 0 : reg |= E1000_CR_RESET;
204 0 : PHY_WRITE(sc, E1000_CR, reg);
205 :
206 0 : for (i = 0; i < 500; i++) {
207 0 : DELAY(1);
208 0 : reg = PHY_READ(sc, E1000_CR);
209 0 : if (!(reg & E1000_CR_RESET))
210 : break;
211 : }
212 :
213 : /*
214 : * Initialize PHY Specific Control Register.
215 : */
216 0 : reg = PHY_READ(sc, E1000_SCR);
217 :
218 : /* Assert CRS on transmit. */
219 0 : reg |= E1000_SCR_ASSERT_CRS_ON_TX;
220 :
221 : /* Enable auto crossover. */
222 0 : switch (sc->mii_model) {
223 : case MII_MODEL_MARVELL_E3016:
224 : case MII_MODEL_MARVELL_E3082:
225 : /* Bits are in a different position. */
226 0 : reg |= (E1000_SCR_AUTO_X_MODE >> 1);
227 0 : break;
228 : default:
229 : /* Automatic crossover causes problems for 1000baseX. */
230 0 : if (sc->mii_flags & MIIF_IS_1000X)
231 0 : reg &= ~E1000_SCR_AUTO_X_MODE;
232 : else
233 0 : reg |= E1000_SCR_AUTO_X_MODE;
234 : }
235 :
236 : /* Disable energy detect; only available on some models. */
237 0 : switch(sc->mii_model) {
238 : case MII_MODEL_MARVELL_E3016:
239 0 : reg &= ~E3000_SCR_EN_DETECT_MASK;
240 0 : break;
241 : case MII_MODEL_MARVELL_E1011:
242 : case MII_MODEL_MARVELL_E1111:
243 : case MII_MODEL_MARVELL_E1112:
244 : case MII_MODEL_MARVELL_PHYG65G:
245 0 : reg &= ~E1000_SCR_EN_DETECT_MASK;
246 0 : break;
247 : }
248 :
249 : /* Enable scrambler if necessary. */
250 0 : if (sc->mii_model == MII_MODEL_MARVELL_E3016)
251 0 : reg &= ~E3000_SCR_SCRAMBLER_DISABLE;
252 :
253 : /*
254 : * Store next page in the Link Partner Next Page register for
255 : * compatibility with 802.3ab.
256 : */
257 0 : if (sc->mii_model == MII_MODEL_MARVELL_E3016)
258 0 : reg |= E3000_SCR_REG8_NEXT_PAGE;
259 :
260 0 : PHY_WRITE(sc, E1000_SCR, reg);
261 :
262 : /* 25 MHz TX_CLK should always work. */
263 0 : reg = PHY_READ(sc, E1000_ESCR);
264 0 : reg |= E1000_ESCR_TX_CLK_25;
265 0 : PHY_WRITE(sc, E1000_ESCR, reg);
266 :
267 : /* Configure LEDs if they were left unconfigured. */
268 0 : if (sc->mii_model == MII_MODEL_MARVELL_E3016 &&
269 0 : PHY_READ(sc, 0x16) == 0) {
270 : reg = (0x0b << 8) | (0x05 << 4) | 0x04; /* XXX */
271 0 : PHY_WRITE(sc, 0x16, reg);
272 0 : }
273 :
274 : /*
275 : * Do a software reset for these settings to take effect.
276 : * Disable autonegotiation, such that all capabilities get
277 : * advertised when it is switched back on.
278 : */
279 0 : reg = PHY_READ(sc, E1000_CR);
280 0 : reg &= ~E1000_CR_AUTO_NEG_ENABLE;
281 0 : PHY_WRITE(sc, E1000_CR, reg | E1000_CR_RESET);
282 0 : }
283 :
284 : int
285 0 : eephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
286 : {
287 0 : struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
288 : int bmcr;
289 :
290 0 : if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0)
291 0 : return (ENXIO);
292 :
293 0 : switch (cmd) {
294 : case MII_POLLSTAT:
295 : /*
296 : * If we're not polling our PHY instance, just return.
297 : */
298 0 : if (IFM_INST(ife->ifm_media) != sc->mii_inst)
299 0 : return (0);
300 : break;
301 :
302 : case MII_MEDIACHG:
303 : /*
304 : * If the media indicates a different PHY instance,
305 : * isolate ourselves.
306 : */
307 0 : if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
308 0 : bmcr = PHY_READ(sc, E1000_CR);
309 0 : PHY_WRITE(sc, E1000_CR, bmcr | E1000_CR_ISOLATE);
310 0 : return (0);
311 : }
312 :
313 : /*
314 : * If the interface is not up, don't do anything.
315 : */
316 0 : if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
317 : break;
318 :
319 0 : mii_phy_setmedia(sc);
320 :
321 : /*
322 : * If autonegitation is not enabled, we need a
323 : * software reset for the settings to take effect.
324 : */
325 0 : if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
326 0 : bmcr = PHY_READ(sc, E1000_CR);
327 0 : PHY_WRITE(sc, E1000_CR, bmcr | E1000_CR_RESET);
328 0 : }
329 : break;
330 :
331 : case MII_TICK:
332 : /*
333 : * If we're not currently selected, just return.
334 : */
335 0 : if (IFM_INST(ife->ifm_media) != sc->mii_inst)
336 0 : return (0);
337 :
338 0 : if (mii_phy_tick(sc) == EJUSTRETURN)
339 0 : return (0);
340 : break;
341 :
342 : case MII_DOWN:
343 0 : mii_phy_down(sc);
344 0 : return (0);
345 : }
346 :
347 : /* Update the media status. */
348 0 : mii_phy_status(sc);
349 :
350 : /* Callback if something changed. */
351 0 : mii_phy_update(sc, cmd);
352 0 : return (0);
353 0 : }
354 :
355 : void
356 0 : eephy_status(struct mii_softc *sc)
357 : {
358 0 : struct mii_data *mii = sc->mii_pdata;
359 : int bmcr, gsr, ssr;
360 :
361 0 : mii->mii_media_status = IFM_AVALID;
362 0 : mii->mii_media_active = IFM_ETHER;
363 :
364 0 : bmcr = PHY_READ(sc, E1000_CR);
365 0 : ssr = PHY_READ(sc, E1000_SSR);
366 :
367 0 : if (ssr & E1000_SSR_LINK)
368 0 : mii->mii_media_status |= IFM_ACTIVE;
369 :
370 0 : if (bmcr & E1000_CR_LOOPBACK)
371 0 : mii->mii_media_active |= IFM_LOOP;
372 :
373 0 : if (!(ssr & E1000_SSR_SPD_DPLX_RESOLVED)) {
374 : /* Erg, still trying, I guess... */
375 0 : mii->mii_media_active |= IFM_NONE;
376 0 : return;
377 : }
378 :
379 0 : if (sc->mii_flags & MIIF_IS_1000X) {
380 0 : mii->mii_media_active |= IFM_1000_SX;
381 0 : } else {
382 0 : if (ssr & E1000_SSR_1000MBS)
383 0 : mii->mii_media_active |= IFM_1000_T;
384 0 : else if (ssr & E1000_SSR_100MBS)
385 0 : mii->mii_media_active |= IFM_100_TX;
386 : else
387 0 : mii->mii_media_active |= IFM_10_T;
388 : }
389 :
390 0 : if (ssr & E1000_SSR_DUPLEX)
391 0 : mii->mii_media_active |= mii_phy_flowstatus(sc) | IFM_FDX;
392 : else
393 0 : mii->mii_media_active |= IFM_HDX;
394 :
395 0 : if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) {
396 0 : gsr = PHY_READ(sc, E1000_1GSR) | PHY_READ(sc, E1000_1GSR);
397 0 : if (gsr & E1000_1GSR_MS_CONFIG_RES)
398 0 : mii->mii_media_active |= IFM_ETH_MASTER;
399 : }
400 0 : }
|