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