brgphy.c revision 1.31.2.3 1 /* $NetBSD: brgphy.c,v 1.31.2.3 2009/08/18 10:10:19 bouyer Exp $ */
2
3 /*-
4 * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 /*
41 * Copyright (c) 1997 Manuel Bouyer. All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software
52 * must display the following acknowledgement:
53 * This product includes software developed by Manuel Bouyer.
54 * 4. The name of the author may not be used to endorse or promote products
55 * derived from this software without specific prior written permission.
56 *
57 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
58 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
59 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
60 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
61 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
62 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
63 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
64 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
65 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
66 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
67 */
68
69 /*
70 * driver for the Broadcom BCM5400 Gig-E PHY.
71 *
72 * Programming information for this PHY was gleaned from FreeBSD
73 * (they were apparently able to get a datasheet from Broadcom).
74 */
75
76 #include <sys/cdefs.h>
77 __KERNEL_RCSID(0, "$NetBSD: brgphy.c,v 1.31.2.3 2009/08/18 10:10:19 bouyer Exp $");
78
79 #include <sys/param.h>
80 #include <sys/systm.h>
81 #include <sys/kernel.h>
82 #include <sys/device.h>
83 #include <sys/socket.h>
84 #include <sys/errno.h>
85 #include <prop/proplib.h>
86
87 #include <net/if.h>
88 #include <net/if_media.h>
89
90 #include <dev/mii/mii.h>
91 #include <dev/mii/miivar.h>
92 #include <dev/mii/miidevs.h>
93 #include <dev/mii/brgphyreg.h>
94
95 #include <dev/pci/if_bgereg.h>
96 #if 0
97 #include <dev/pci/if_bnxreg.h>
98 #endif
99
100 static int brgphymatch(struct device *, struct cfdata *, void *);
101 static void brgphyattach(struct device *, struct device *, void *);
102
103 struct brgphy_softc {
104 struct mii_softc sc_mii;
105 int sc_isbge;
106 int sc_isbnx;
107 int sc_bge_flags;
108 int sc_bnx_flags;
109 };
110
111 CFATTACH_DECL(brgphy, sizeof(struct brgphy_softc),
112 brgphymatch, brgphyattach, mii_phy_detach, mii_phy_activate);
113
114 static int brgphy_service(struct mii_softc *, struct mii_data *, int);
115 static void brgphy_status(struct mii_softc *);
116 static int brgphy_mii_phy_auto(struct mii_softc *);
117 static void brgphy_loop(struct mii_softc *);
118 static void brgphy_reset(struct mii_softc *);
119 static void brgphy_bcm5401_dspcode(struct mii_softc *);
120 static void brgphy_bcm5411_dspcode(struct mii_softc *);
121 static void brgphy_bcm5421_dspcode(struct mii_softc *);
122 static void brgphy_bcm54k2_dspcode(struct mii_softc *);
123 static void brgphy_adc_bug(struct mii_softc *);
124 static void brgphy_5704_a0_bug(struct mii_softc *);
125 static void brgphy_ber_bug(struct mii_softc *);
126 static void brgphy_crc_bug(struct mii_softc *);
127
128
129 static const struct mii_phy_funcs brgphy_funcs = {
130 brgphy_service, brgphy_status, brgphy_reset,
131 };
132
133 static const struct mii_phydesc brgphys[] = {
134 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5400,
135 MII_STR_BROADCOM_BCM5400 },
136
137 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5401,
138 MII_STR_BROADCOM_BCM5401 },
139
140 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5411,
141 MII_STR_BROADCOM_BCM5411 },
142
143 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5421,
144 MII_STR_BROADCOM_BCM5421 },
145
146 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM54K2,
147 MII_STR_BROADCOM_BCM54K2 },
148
149 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5462,
150 MII_STR_BROADCOM_BCM5462 },
151
152 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5701,
153 MII_STR_BROADCOM_BCM5701 },
154
155 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5703,
156 MII_STR_BROADCOM_BCM5703 },
157
158 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5704,
159 MII_STR_BROADCOM_BCM5704 },
160
161 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5705,
162 MII_STR_BROADCOM_BCM5705 },
163
164 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5714,
165 MII_STR_BROADCOM_BCM5714 },
166
167 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5750,
168 MII_STR_BROADCOM_BCM5750 },
169
170 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5752,
171 MII_STR_BROADCOM_BCM5752 },
172
173 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5780,
174 MII_STR_BROADCOM_BCM5780 },
175
176 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5708C,
177 MII_STR_BROADCOM_BCM5708C },
178
179 { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5722,
180 MII_STR_BROADCOM2_BCM5722 },
181
182 { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5755,
183 MII_STR_BROADCOM2_BCM5755 },
184
185 { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5754,
186 MII_STR_BROADCOM2_BCM5754 },
187
188 { MII_OUI_xxBROADCOM_ALT1, MII_MODEL_xxBROADCOM_ALT1_BCM5906,
189 MII_STR_xxBROADCOM_ALT1_BCM5906 },
190
191 { 0, 0,
192 NULL },
193 };
194
195 static int
196 brgphymatch(struct device *parent, struct cfdata *match, void *aux)
197 {
198 struct mii_attach_args *ma = aux;
199
200 if (mii_phy_match(ma, brgphys) != NULL)
201 return (10);
202
203 return (0);
204 }
205
206 static void
207 brgphyattach(struct device *parent, struct device *self, void *aux)
208 {
209 struct brgphy_softc *bsc = device_private(self);
210 struct mii_softc *sc = &bsc->sc_mii;
211 struct mii_attach_args *ma = aux;
212 struct mii_data *mii = ma->mii_data;
213 const struct mii_phydesc *mpd;
214 prop_dictionary_t dict;
215
216 mpd = mii_phy_match(ma, brgphys);
217 aprint_naive(": Media interface\n");
218 aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
219
220 sc->mii_inst = mii->mii_instance;
221 sc->mii_phy = ma->mii_phyno;
222 sc->mii_mpd_model = MII_MODEL(ma->mii_id2);
223 sc->mii_mpd_rev = MII_REV(ma->mii_id2);
224 sc->mii_pdata = mii;
225 sc->mii_flags = ma->mii_flags;
226 sc->mii_anegticks = MII_ANEGTICKS;
227
228 sc->mii_funcs = &brgphy_funcs;
229
230 PHY_RESET(sc);
231
232 sc->mii_capabilities =
233 PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
234 if (sc->mii_capabilities & BMSR_EXTSTAT)
235 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
236
237 aprint_normal("%s: ", sc->mii_dev.dv_xname);
238 if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
239 (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
240 aprint_error("no media present");
241 else
242 mii_phy_add_media(sc);
243 aprint_normal("\n");
244
245 if (device_is_a(parent, "bge")) {
246 bsc->sc_isbge = 1;
247 dict = device_properties(parent);
248 prop_dictionary_get_uint32(dict, "phyflags",
249 &bsc->sc_bge_flags);
250 } else if (device_is_a(parent, "bnx")) {
251 bsc->sc_isbnx = 1;
252 dict = device_properties(parent);
253 prop_dictionary_get_uint32(dict, "phyflags",
254 &bsc->sc_bnx_flags);
255 }
256 }
257
258 static int
259 brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
260 {
261 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
262 int reg, speed, gig;
263
264 switch (cmd) {
265 case MII_POLLSTAT:
266 /*
267 * If we're not polling our PHY instance, just return.
268 */
269 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
270 return (0);
271 break;
272
273 case MII_MEDIACHG:
274 /*
275 * If the media indicates a different PHY instance,
276 * isolate ourselves.
277 */
278 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
279 reg = PHY_READ(sc, MII_BMCR);
280 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
281 return (0);
282 }
283
284 /*
285 * If the interface is not up, don't do anything.
286 */
287 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
288 break;
289
290 PHY_RESET(sc); /* XXX hardware bug work-around */
291
292 switch (IFM_SUBTYPE(ife->ifm_media)) {
293 case IFM_AUTO:
294 (void) brgphy_mii_phy_auto(sc);
295 break;
296 case IFM_1000_T:
297 speed = BMCR_S1000;
298 goto setit;
299 case IFM_100_TX:
300 speed = BMCR_S100;
301 goto setit;
302 case IFM_10_T:
303 speed = BMCR_S10;
304 setit:
305 brgphy_loop(sc);
306 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
307 speed |= BMCR_FDX;
308 gig = GTCR_ADV_1000TFDX;
309 } else {
310 gig = GTCR_ADV_1000THDX;
311 }
312
313 PHY_WRITE(sc, MII_100T2CR, 0);
314 PHY_WRITE(sc, MII_BMCR, speed);
315 PHY_WRITE(sc, MII_ANAR, ANAR_CSMA);
316
317 if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T)
318 break;
319
320 PHY_WRITE(sc, MII_100T2CR, gig);
321 PHY_WRITE(sc, MII_BMCR,
322 speed|BMCR_AUTOEN|BMCR_STARTNEG);
323
324 if (sc->mii_mpd_model != MII_MODEL_BROADCOM_BCM5701)
325 break;
326
327 if (mii->mii_media.ifm_media & IFM_ETH_MASTER)
328 gig |= GTCR_MAN_MS | GTCR_ADV_MS;
329 PHY_WRITE(sc, MII_100T2CR, gig);
330 break;
331 default:
332 return (EINVAL);
333 }
334 break;
335
336 case MII_TICK:
337 /*
338 * If we're not currently selected, just return.
339 */
340 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
341 return (0);
342
343 if (mii_phy_tick(sc) == EJUSTRETURN)
344 return (0);
345 break;
346
347 case MII_DOWN:
348 mii_phy_down(sc);
349 return (0);
350 }
351
352 /* Update the media status. */
353 mii_phy_status(sc);
354
355 /*
356 * Callback if something changed. Note that we need to poke the DSP on
357 * the Broadcom PHYs if the media changes.
358 */
359 if (sc->mii_media_active != mii->mii_media_active ||
360 sc->mii_media_status != mii->mii_media_status ||
361 cmd == MII_MEDIACHG) {
362 switch (sc->mii_mpd_model) {
363 case MII_MODEL_BROADCOM_BCM5400:
364 brgphy_bcm5401_dspcode(sc);
365 break;
366 case MII_MODEL_BROADCOM_BCM5401:
367 if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3)
368 brgphy_bcm5401_dspcode(sc);
369 break;
370 case MII_MODEL_BROADCOM_BCM5411:
371 brgphy_bcm5411_dspcode(sc);
372 break;
373 }
374 }
375
376 /* Callback if something changed. */
377 mii_phy_update(sc, cmd);
378 return (0);
379 }
380
381 static void
382 brgphy_status(struct mii_softc *sc)
383 {
384 struct mii_data *mii = sc->mii_pdata;
385 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
386 int bmcr, auxsts, gtsr;
387
388 mii->mii_media_status = IFM_AVALID;
389 mii->mii_media_active = IFM_ETHER;
390
391 auxsts = PHY_READ(sc, BRGPHY_MII_AUXSTS);
392
393 if (auxsts & BRGPHY_AUXSTS_LINK)
394 mii->mii_media_status |= IFM_ACTIVE;
395
396 bmcr = PHY_READ(sc, MII_BMCR);
397 if (bmcr & BMCR_ISO) {
398 mii->mii_media_active |= IFM_NONE;
399 mii->mii_media_status = 0;
400 return;
401 }
402
403 if (bmcr & BMCR_LOOP)
404 mii->mii_media_active |= IFM_LOOP;
405
406 if (bmcr & BMCR_AUTOEN) {
407 /*
408 * The media status bits are only valid of autonegotiation
409 * has completed (or it's disabled).
410 */
411 if ((auxsts & BRGPHY_AUXSTS_ACOMP) == 0) {
412 /* Erg, still trying, I guess... */
413 mii->mii_media_active |= IFM_NONE;
414 return;
415 }
416
417 switch (auxsts & BRGPHY_AUXSTS_AN_RES) {
418 case BRGPHY_RES_1000FD:
419 mii->mii_media_active |= IFM_1000_T|IFM_FDX;
420 gtsr = PHY_READ(sc, MII_100T2SR);
421 if (gtsr & GTSR_MS_RES)
422 mii->mii_media_active |= IFM_ETH_MASTER;
423 break;
424
425 case BRGPHY_RES_1000HD:
426 mii->mii_media_active |= IFM_1000_T;
427 gtsr = PHY_READ(sc, MII_100T2SR);
428 if (gtsr & GTSR_MS_RES)
429 mii->mii_media_active |= IFM_ETH_MASTER;
430 break;
431
432 case BRGPHY_RES_100FD:
433 mii->mii_media_active |= IFM_100_TX|IFM_FDX;
434 break;
435
436 case BRGPHY_RES_100T4:
437 mii->mii_media_active |= IFM_100_T4;
438 break;
439
440 case BRGPHY_RES_100HD:
441 mii->mii_media_active |= IFM_100_TX;
442 break;
443
444 case BRGPHY_RES_10FD:
445 mii->mii_media_active |= IFM_10_T|IFM_FDX;
446 break;
447
448 case BRGPHY_RES_10HD:
449 mii->mii_media_active |= IFM_10_T;
450 break;
451
452 default:
453 mii->mii_media_active |= IFM_NONE;
454 mii->mii_media_status = 0;
455 }
456 if (mii->mii_media_active & IFM_FDX)
457 mii->mii_media_active |= mii_phy_flowstatus(sc);
458 } else
459 mii->mii_media_active = ife->ifm_media;
460 }
461
462 int
463 brgphy_mii_phy_auto(struct mii_softc *sc)
464 {
465 int anar, ktcr = 0;
466
467 brgphy_loop(sc);
468 PHY_RESET(sc);
469 ktcr = GTCR_ADV_1000TFDX|GTCR_ADV_1000THDX;
470 if (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5701)
471 ktcr |= GTCR_MAN_MS|GTCR_ADV_MS;
472 PHY_WRITE(sc, MII_100T2CR, ktcr);
473 ktcr = PHY_READ(sc, MII_100T2CR);
474 DELAY(1000);
475 anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA;
476 if (sc->mii_flags & MIIF_DOPAUSE)
477 anar |= ANAR_FC| ANAR_X_PAUSE_ASYM;
478
479 PHY_WRITE(sc, MII_ANAR, anar);
480 DELAY(1000);
481 PHY_WRITE(sc, MII_BMCR,
482 BMCR_AUTOEN | BMCR_STARTNEG);
483 PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00);
484
485 return (EJUSTRETURN);
486 }
487
488 void
489 brgphy_loop(struct mii_softc *sc)
490 {
491 u_int32_t bmsr;
492 int i;
493
494 PHY_WRITE(sc, MII_BMCR, BMCR_LOOP);
495 for (i = 0; i < 15000; i++) {
496 bmsr = PHY_READ(sc, MII_BMSR);
497 if (!(bmsr & BMSR_LINK))
498 break;
499 DELAY(10);
500 }
501 }
502
503 static void
504 brgphy_reset(struct mii_softc *sc)
505 {
506 struct brgphy_softc *bsc = (void *)sc;
507
508 mii_phy_reset(sc);
509
510 switch (sc->mii_mpd_model) {
511 case MII_MODEL_BROADCOM_BCM5400:
512 brgphy_bcm5401_dspcode(sc);
513 break;
514 case MII_MODEL_BROADCOM_BCM5401:
515 if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3)
516 brgphy_bcm5401_dspcode(sc);
517 break;
518 case MII_MODEL_BROADCOM_BCM5411:
519 brgphy_bcm5411_dspcode(sc);
520 break;
521 case MII_MODEL_BROADCOM_BCM5421:
522 brgphy_bcm5421_dspcode(sc);
523 break;
524 case MII_MODEL_BROADCOM_BCM54K2:
525 brgphy_bcm54k2_dspcode(sc);
526 break;
527 }
528
529 /* Handle any bge (NetXtreme/NetLink) workarounds. */
530 if (bsc->sc_isbge != 0) {
531 if (!(sc->mii_flags & MIIF_HAVEFIBER)) {
532
533 if (bsc->sc_bge_flags & BGE_PHY_ADC_BUG)
534 brgphy_adc_bug(sc);
535 if (bsc->sc_bge_flags & BGE_PHY_5704_A0_BUG)
536 brgphy_5704_a0_bug(sc);
537 if (bsc->sc_bge_flags & BGE_PHY_BER_BUG)
538 brgphy_ber_bug(sc);
539 else if (bsc->sc_bge_flags & BGE_PHY_JITTER_BUG) {
540 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0c00);
541 PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG,
542 0x000a);
543
544 if (bsc->sc_bge_flags & BGE_PHY_ADJUST_TRIM) {
545 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT,
546 0x110b);
547 PHY_WRITE(sc, BRGPHY_TEST1,
548 BRGPHY_TEST1_TRIM_EN | 0x4);
549 } else {
550 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT,
551 0x010b);
552 }
553
554 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0400);
555 }
556 if (bsc->sc_bge_flags & BGE_PHY_CRC_BUG)
557 brgphy_crc_bug(sc);
558
559 #if 0
560 /* Set Jumbo frame settings in the PHY. */
561 if (bsc->sc_bge_flags & BGE_JUMBO_CAP)
562 brgphy_jumbo_settings(sc);
563 #endif
564
565 /* Adjust output voltage */
566 if (sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5906)
567 PHY_WRITE(sc, BRGPHY_MII_EPHY_PTEST, 0x12);
568
569 #if 0
570 /* Enable Ethernet@Wirespeed */
571 if (!(bsc->sc_bge_flags & BGE_NO_ETH_WIRE_SPEED))
572 brgphy_eth_wirespeed(sc);
573
574 /* Enable Link LED on Dell boxes */
575 if (bsc->sc_bge_flags & BGE_NO_3LED) {
576 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL,
577 PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL)
578 & ~BRGPHY_PHY_EXTCTL_3_LED);
579 }
580 #endif
581 }
582 #if 0 /* not yet */
583 /* Handle any bnx (NetXtreme II) workarounds. */
584 } else if (sc->sc_isbnx != 0) {
585 bnx_sc = sc->mii_pdata->mii_ifp->if_softc;
586
587 if (sc->mii_mpd_model == MII_MODEL_xxBROADCOM2_BCM5708S) {
588 /* Store autoneg capabilities/results in digital block (Page 0) */
589 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG3_PG2);
590 PHY_WRITE(sc, BRGPHY_5708S_PG2_DIGCTL_3_0,
591 BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE);
592 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0);
593
594 /* Enable fiber mode and autodetection */
595 PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL1,
596 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL1) |
597 BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN |
598 BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE);
599
600 /* Enable parallel detection */
601 PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL2,
602 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL2) |
603 BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN);
604
605 /* Advertise 2.5G support through next page during autoneg */
606 if (bnx_sc->bnx_phy_flags & BNX_PHY_2_5G_CAPABLE_FLAG)
607 PHY_WRITE(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1,
608 PHY_READ(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1) |
609 BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G);
610
611 /* Increase TX signal amplitude */
612 if ((BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_A0) ||
613 (BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_B0) ||
614 (BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_B1)) {
615 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
616 BRGPHY_5708S_TX_MISC_PG5);
617 PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL1,
618 PHY_READ(sc, BRGPHY_5708S_PG5_TXACTL1) &
619 ~BRGPHY_5708S_PG5_TXACTL1_VCM);
620 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
621 BRGPHY_5708S_DIG_PG0);
622 }
623
624 /* Backplanes use special driver/pre-driver/pre-emphasis values. */
625 if ((bnx_sc->bnx_shared_hw_cfg & BNX_SHARED_HW_CFG_PHY_BACKPLANE) &&
626 (bnx_sc->bnx_port_hw_cfg & BNX_PORT_HW_CFG_CFG_TXCTL3_MASK)) {
627 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
628 BRGPHY_5708S_TX_MISC_PG5);
629 PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL3,
630 bnx_sc->bnx_port_hw_cfg &
631 BNX_PORT_HW_CFG_CFG_TXCTL3_MASK);
632 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
633 BRGPHY_5708S_DIG_PG0);
634 }
635 } else {
636 if (!(sc->mii_flags & MIIF_HAVEFIBER)) {
637 brgphy_ber_bug(sc);
638
639 /* Set Jumbo frame settings in the PHY. */
640 brgphy_jumbo_settings(sc);
641
642 /* Enable Ethernet@Wirespeed */
643 brgphy_eth_wirespeed(sc);
644 }
645 }
646 #endif
647 }
648 }
649
650 /* Turn off tap power management on 5401. */
651 static void
652 brgphy_bcm5401_dspcode(struct mii_softc *sc)
653 {
654 static const struct {
655 int reg;
656 uint16_t val;
657 } dspcode[] = {
658 { BRGPHY_MII_AUXCTL, 0x0c20 },
659 { BRGPHY_MII_DSP_ADDR_REG, 0x0012 },
660 { BRGPHY_MII_DSP_RW_PORT, 0x1804 },
661 { BRGPHY_MII_DSP_ADDR_REG, 0x0013 },
662 { BRGPHY_MII_DSP_RW_PORT, 0x1204 },
663 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 },
664 { BRGPHY_MII_DSP_RW_PORT, 0x0132 },
665 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 },
666 { BRGPHY_MII_DSP_RW_PORT, 0x0232 },
667 { BRGPHY_MII_DSP_ADDR_REG, 0x201f },
668 { BRGPHY_MII_DSP_RW_PORT, 0x0a20 },
669 { 0, 0 },
670 };
671 int i;
672
673 for (i = 0; dspcode[i].reg != 0; i++)
674 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
675 delay(40);
676 }
677
678 static void
679 brgphy_bcm5411_dspcode(struct mii_softc *sc)
680 {
681 static const struct {
682 int reg;
683 uint16_t val;
684 } dspcode[] = {
685 { 0x1c, 0x8c23 },
686 { 0x1c, 0x8ca3 },
687 { 0x1c, 0x8c23 },
688 { 0, 0 },
689 };
690 int i;
691
692 for (i = 0; dspcode[i].reg != 0; i++)
693 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
694 }
695
696 void
697 brgphy_bcm5421_dspcode(struct mii_softc *sc)
698 {
699 uint16_t data;
700
701 /* Set Class A mode */
702 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x1007);
703 data = PHY_READ(sc, BRGPHY_MII_AUXCTL);
704 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0400);
705
706 /* Set FFE gamma override to -0.125 */
707 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0007);
708 data = PHY_READ(sc, BRGPHY_MII_AUXCTL);
709 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0800);
710 PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a);
711 data = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT);
712 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, data | 0x0200);
713 }
714
715 void
716 brgphy_bcm54k2_dspcode(struct mii_softc *sc)
717 {
718 static const struct {
719 int reg;
720 uint16_t val;
721 } dspcode[] = {
722 { 4, 0x01e1 },
723 { 9, 0x0300 },
724 { 0, 0 },
725 };
726 int i;
727
728 for (i = 0; dspcode[i].reg != 0; i++)
729 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
730 }
731
732 static void
733 brgphy_adc_bug(struct mii_softc *sc)
734 {
735 static const struct {
736 int reg;
737 uint16_t val;
738 } dspcode[] = {
739 { BRGPHY_MII_AUXCTL, 0x0c00 },
740 { BRGPHY_MII_DSP_ADDR_REG, 0x201f },
741 { BRGPHY_MII_DSP_RW_PORT, 0x2aaa },
742 { BRGPHY_MII_DSP_ADDR_REG, 0x000a },
743 { BRGPHY_MII_DSP_RW_PORT, 0x0323 },
744 { BRGPHY_MII_AUXCTL, 0x0400 },
745 { 0, 0 },
746 };
747 int i;
748
749 for (i = 0; dspcode[i].reg != 0; i++)
750 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
751 }
752
753 static void
754 brgphy_5704_a0_bug(struct mii_softc *sc)
755 {
756 static const struct {
757 int reg;
758 uint16_t val;
759 } dspcode[] = {
760 { 0x1c, 0x8d68 },
761 { 0x1c, 0x8d68 },
762 { 0, 0 },
763 };
764 int i;
765
766 for (i = 0; dspcode[i].reg != 0; i++)
767 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
768 }
769
770 static void
771 brgphy_ber_bug(struct mii_softc *sc)
772 {
773 static const struct {
774 int reg;
775 uint16_t val;
776 } dspcode[] = {
777 { BRGPHY_MII_AUXCTL, 0x0c00 },
778 { BRGPHY_MII_DSP_ADDR_REG, 0x000a },
779 { BRGPHY_MII_DSP_RW_PORT, 0x310b },
780 { BRGPHY_MII_DSP_ADDR_REG, 0x201f },
781 { BRGPHY_MII_DSP_RW_PORT, 0x9506 },
782 { BRGPHY_MII_DSP_ADDR_REG, 0x401f },
783 { BRGPHY_MII_DSP_RW_PORT, 0x14e2 },
784 { BRGPHY_MII_AUXCTL, 0x0400 },
785 { 0, 0 },
786 };
787 int i;
788
789 for (i = 0; dspcode[i].reg != 0; i++)
790 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
791 }
792
793 /* BCM5701 A0/B0 CRC bug workaround */
794 void
795 brgphy_crc_bug(struct mii_softc *sc)
796 {
797 static const struct {
798 int reg;
799 uint16_t val;
800 } dspcode[] = {
801 { BRGPHY_MII_DSP_ADDR_REG, 0x0a75 },
802 { 0x1c, 0x8c68 },
803 { 0x1c, 0x8d68 },
804 { 0x1c, 0x8c68 },
805 { 0, 0 },
806 };
807 int i;
808
809 for (i = 0; dspcode[i].reg != 0; i++)
810 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
811 }
812