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