brgphy.c revision 1.76.28.2 1 /* $NetBSD: brgphy.c,v 1.76.28.2 2020/04/08 14:08:08 martin 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 and BCM5700 Gig-E PHYs.
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.76.28.2 2020/04/08 14:08:08 martin 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 #include <dev/pci/if_bnxreg.h>
85
86 static int brgphymatch(device_t, cfdata_t, void *);
87 static void brgphyattach(device_t, device_t, void *);
88
89 struct brgphy_softc {
90 struct mii_softc sc_mii;
91 bool sc_isbge;
92 bool sc_isbnx;
93 uint32_t sc_chipid; /* parent's chipid */
94 uint32_t sc_phyflags; /* parent's phyflags */
95 uint32_t sc_shared_hwcfg; /* shared hw config */
96 uint32_t sc_port_hwcfg; /* port specific hw config */
97 };
98
99 CFATTACH_DECL_NEW(brgphy, sizeof(struct brgphy_softc),
100 brgphymatch, brgphyattach, mii_phy_detach, mii_phy_activate);
101
102 static int brgphy_service(struct mii_softc *, struct mii_data *, int);
103 static void brgphy_copper_status(struct mii_softc *);
104 static void brgphy_fiber_status(struct mii_softc *);
105 static void brgphy_5708s_status(struct mii_softc *);
106 static void brgphy_5709s_status(struct mii_softc *);
107 static int brgphy_mii_phy_auto(struct mii_softc *);
108 static void brgphy_loop(struct mii_softc *);
109 static void brgphy_reset(struct mii_softc *);
110 static void brgphy_bcm5401_dspcode(struct mii_softc *);
111 static void brgphy_bcm5411_dspcode(struct mii_softc *);
112 static void brgphy_bcm5421_dspcode(struct mii_softc *);
113 static void brgphy_bcm54k2_dspcode(struct mii_softc *);
114 static void brgphy_adc_bug(struct mii_softc *);
115 static void brgphy_5704_a0_bug(struct mii_softc *);
116 static void brgphy_ber_bug(struct mii_softc *);
117 static void brgphy_crc_bug(struct mii_softc *);
118 static void brgphy_disable_early_dac(struct mii_softc *);
119 static void brgphy_jumbo_settings(struct mii_softc *);
120 static void brgphy_eth_wirespeed(struct mii_softc *);
121
122
123 static const struct mii_phy_funcs brgphy_copper_funcs = {
124 brgphy_service, brgphy_copper_status, brgphy_reset,
125 };
126
127 static const struct mii_phy_funcs brgphy_fiber_funcs = {
128 brgphy_service, brgphy_fiber_status, brgphy_reset,
129 };
130
131 static const struct mii_phy_funcs brgphy_5708s_funcs = {
132 brgphy_service, brgphy_5708s_status, brgphy_reset,
133 };
134
135 static const struct mii_phy_funcs brgphy_5709s_funcs = {
136 brgphy_service, brgphy_5709s_status, brgphy_reset,
137 };
138
139 static const struct mii_phydesc brgphys[] = {
140 MII_PHY_DESC(BROADCOM, BCM5400),
141 MII_PHY_DESC(BROADCOM, BCM5401),
142 MII_PHY_DESC(BROADCOM, BCM5402),
143 MII_PHY_DESC(BROADCOM, BCM5404),
144 MII_PHY_DESC(BROADCOM, BCM5411),
145 MII_PHY_DESC(BROADCOM, BCM5421),
146 MII_PHY_DESC(BROADCOM, BCM5424),
147 MII_PHY_DESC(BROADCOM, BCM5461),
148 MII_PHY_DESC(BROADCOM, BCM5462),
149 MII_PHY_DESC(BROADCOM, BCM5464),
150 MII_PHY_DESC(BROADCOM, BCM5466),
151 MII_PHY_DESC(BROADCOM, BCM54K2),
152 MII_PHY_DESC(BROADCOM, BCM5701),
153 MII_PHY_DESC(BROADCOM, BCM5703),
154 MII_PHY_DESC(BROADCOM, BCM5704),
155 MII_PHY_DESC(BROADCOM, BCM5705),
156 MII_PHY_DESC(BROADCOM, BCM5706),
157 MII_PHY_DESC(BROADCOM, BCM5714),
158 MII_PHY_DESC(BROADCOM, BCM5750),
159 MII_PHY_DESC(BROADCOM, BCM5752),
160 MII_PHY_DESC(BROADCOM, BCM5780),
161 MII_PHY_DESC(BROADCOM, BCM5708C),
162 MII_PHY_DESC(BROADCOM2, BCM5481),
163 MII_PHY_DESC(BROADCOM2, BCM5482),
164 MII_PHY_DESC(BROADCOM2, BCM5708S),
165 MII_PHY_DESC(BROADCOM2, BCM5709C),
166 MII_PHY_DESC(BROADCOM2, BCM5709S),
167 MII_PHY_DESC(BROADCOM2, BCM5709CAX),
168 MII_PHY_DESC(BROADCOM2, BCM5722),
169 MII_PHY_DESC(BROADCOM2, BCM5754),
170 MII_PHY_DESC(BROADCOM2, BCM5755),
171 MII_PHY_DESC(BROADCOM2, BCM5756),
172 MII_PHY_DESC(BROADCOM2, BCM5761),
173 MII_PHY_DESC(BROADCOM2, BCM5784),
174 MII_PHY_DESC(BROADCOM2, BCM5785),
175 MII_PHY_DESC(BROADCOM3, BCM5717C),
176 MII_PHY_DESC(BROADCOM3, BCM5719C),
177 MII_PHY_DESC(BROADCOM3, BCM5720C),
178 MII_PHY_DESC(BROADCOM3, BCM57765),
179 MII_PHY_DESC(BROADCOM3, BCM57780),
180 MII_PHY_DESC(BROADCOM4, BCM54213PE),
181 MII_PHY_DESC(BROADCOM4, BCM5725C),
182 MII_PHY_DESC(xxBROADCOM_ALT1, BCM5906),
183 MII_PHY_END,
184 };
185
186 static int
187 brgphymatch(device_t parent, cfdata_t match, void *aux)
188 {
189 struct mii_attach_args *ma = aux;
190
191 if (mii_phy_match(ma, brgphys) != NULL)
192 return 10;
193
194 return 0;
195 }
196
197 static void
198 brgphyattach(device_t parent, device_t self, void *aux)
199 {
200 struct brgphy_softc *bsc = device_private(self);
201 struct mii_softc *sc = &bsc->sc_mii;
202 struct mii_attach_args *ma = aux;
203 struct mii_data *mii = ma->mii_data;
204 const struct mii_phydesc *mpd;
205 prop_dictionary_t dict;
206
207 mpd = mii_phy_match(ma, brgphys);
208 aprint_naive(": Media interface\n");
209 aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
210
211 sc->mii_dev = self;
212 sc->mii_inst = mii->mii_instance;
213 sc->mii_phy = ma->mii_phyno;
214 sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
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
220 if (device_is_a(parent, "bge"))
221 bsc->sc_isbge = true;
222 else if (device_is_a(parent, "bnx"))
223 bsc->sc_isbnx = true;
224
225 dict = device_properties(parent);
226 if (bsc->sc_isbge || bsc->sc_isbnx) {
227 if (!prop_dictionary_get_uint32(dict, "phyflags",
228 &bsc->sc_phyflags))
229 aprint_error_dev(self, "failed to get phyflags\n");
230 if (!prop_dictionary_get_uint32(dict, "chipid",
231 &bsc->sc_chipid))
232 aprint_error_dev(self, "failed to get chipid\n");
233 }
234
235 if (bsc->sc_isbnx) {
236 /* Currently, only bnx use sc_shared_hwcfg and sc_port_hwcfg */
237 if (!prop_dictionary_get_uint32(dict, "shared_hwcfg",
238 &bsc->sc_shared_hwcfg))
239 aprint_error_dev(self, "failed to get shared_hwcfg\n");
240 if (!prop_dictionary_get_uint32(dict, "port_hwcfg",
241 &bsc->sc_port_hwcfg))
242 aprint_error_dev(self, "failed to get port_hwcfg\n");
243 }
244
245 if (sc->mii_flags & MIIF_HAVEFIBER) {
246 if ((sc->mii_mpd_oui == MII_OUI_BROADCOM2)
247 && sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5708S)
248 sc->mii_funcs = &brgphy_5708s_funcs;
249 else if ((sc->mii_mpd_oui == MII_OUI_BROADCOM2)
250 && (sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5709S)) {
251 if (bsc->sc_isbnx)
252 sc->mii_funcs = &brgphy_5709s_funcs;
253 else {
254 /*
255 * XXX
256 * 5720S and 5709S shares the same PHY id.
257 * Assume 5720S PHY if parent device is bge(4).
258 */
259 sc->mii_funcs = &brgphy_5708s_funcs;
260 }
261 } else
262 sc->mii_funcs = &brgphy_fiber_funcs;
263 } else
264 sc->mii_funcs = &brgphy_copper_funcs;
265
266 mii_lock(mii);
267
268 PHY_RESET(sc);
269
270 PHY_READ(sc, MII_BMSR, &sc->mii_capabilities);
271 sc->mii_capabilities &= ma->mii_capmask;
272 if (sc->mii_capabilities & BMSR_EXTSTAT)
273 PHY_READ(sc, MII_EXTSR, &sc->mii_extcapabilities);
274
275 mii_unlock(mii);
276
277 if (sc->mii_flags & MIIF_HAVEFIBER) {
278 mii_lock(mii);
279 sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP;
280
281 /*
282 * Set the proper bits for capabilities so that the
283 * correct media get selected by mii_phy_add_media()
284 */
285 sc->mii_capabilities |= BMSR_ANEG;
286 sc->mii_capabilities &= ~BMSR_100T4;
287 sc->mii_extcapabilities |= EXTSR_1000XFDX;
288 mii_unlock(mii);
289
290 if (bsc->sc_isbnx) {
291 /*
292 * 2.5Gb support is a software enabled feature
293 * on the BCM5708S and BCM5709S controllers.
294 */
295 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
296 if (bsc->sc_phyflags
297 & BNX_PHY_2_5G_CAPABLE_FLAG) {
298 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_2500_SX,
299 IFM_FDX, sc->mii_inst), 0);
300 aprint_normal_dev(self, "2500baseSX-FDX\n");
301 #undef ADD
302 }
303 }
304 }
305 mii_phy_add_media(sc);
306 }
307
308 static int
309 brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
310 {
311 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
312 uint16_t reg, speed, gig;
313
314 KASSERT(mii_locked(mii));
315
316 switch (cmd) {
317 case MII_POLLSTAT:
318 /* If we're not polling our PHY instance, just return. */
319 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
320 return 0;
321 break;
322
323 case MII_MEDIACHG:
324 /*
325 * If the media indicates a different PHY instance,
326 * isolate ourselves.
327 */
328 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
329 PHY_READ(sc, MII_BMCR, ®);
330 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
331 return 0;
332 }
333
334 /* If the interface is not up, don't do anything. */
335 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
336 break;
337
338 PHY_RESET(sc); /* XXX hardware bug work-around */
339
340 switch (IFM_SUBTYPE(ife->ifm_media)) {
341 case IFM_AUTO:
342 (void) brgphy_mii_phy_auto(sc);
343 break;
344 case IFM_2500_SX:
345 speed = BRGPHY_5708S_BMCR_2500;
346 goto setit;
347 case IFM_1000_SX:
348 case IFM_1000_T:
349 speed = BMCR_S1000;
350 goto setit;
351 case IFM_100_TX:
352 speed = BMCR_S100;
353 goto setit;
354 case IFM_10_T:
355 speed = BMCR_S10;
356 setit:
357 brgphy_loop(sc);
358 if ((ife->ifm_media & IFM_FDX) != 0) {
359 speed |= BMCR_FDX;
360 gig = GTCR_ADV_1000TFDX;
361 } else
362 gig = GTCR_ADV_1000THDX;
363
364 PHY_WRITE(sc, MII_100T2CR, 0);
365 PHY_WRITE(sc, MII_ANAR, ANAR_CSMA);
366 PHY_WRITE(sc, MII_BMCR, speed);
367
368 if ((IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) &&
369 (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_SX) &&
370 (IFM_SUBTYPE(ife->ifm_media) != IFM_2500_SX))
371 break;
372
373 PHY_WRITE(sc, MII_100T2CR, gig);
374 PHY_WRITE(sc, MII_BMCR,
375 speed | BMCR_AUTOEN | BMCR_STARTNEG);
376
377 if ((sc->mii_mpd_oui != MII_OUI_BROADCOM)
378 || (sc->mii_mpd_model != MII_MODEL_BROADCOM_BCM5701))
379 break;
380
381 if (mii->mii_media.ifm_media & IFM_ETH_MASTER)
382 gig |= GTCR_MAN_MS | GTCR_ADV_MS;
383 PHY_WRITE(sc, MII_100T2CR, gig);
384 break;
385 default:
386 return EINVAL;
387 }
388 break;
389
390 case MII_TICK:
391 /* If we're not currently selected, just return. */
392 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
393 return 0;
394
395 /* Is the interface even up? */
396 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
397 return 0;
398
399 /* Only used for autonegotiation. */
400 if ((IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) &&
401 (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T)) {
402 sc->mii_ticks = 0;
403 break;
404 }
405
406 /*
407 * Check for link.
408 * Read the status register twice; BMSR_LINK is latch-low.
409 */
410 PHY_READ(sc, MII_BMSR, ®);
411 PHY_READ(sc, MII_BMSR, ®);
412 if (reg & BMSR_LINK) {
413 sc->mii_ticks = 0;
414 break;
415 }
416
417 /*
418 * mii_ticks == 0 means it's the first tick after changing the
419 * media or the link became down since the last tick
420 * (see above), so break to update the status.
421 */
422 if (sc->mii_ticks++ == 0)
423 break;
424
425 /* Only retry autonegotiation every mii_anegticks seconds. */
426 KASSERT(sc->mii_anegticks != 0);
427 if (sc->mii_ticks <= sc->mii_anegticks)
428 break;
429
430 brgphy_mii_phy_auto(sc);
431 break;
432
433 case MII_DOWN:
434 mii_phy_down(sc);
435 return 0;
436 }
437
438 /* Update the media status. */
439 mii_phy_status(sc);
440
441 /*
442 * Callback if something changed. Note that we need to poke the DSP on
443 * the Broadcom PHYs if the media changes.
444 */
445 if (sc->mii_media_active != mii->mii_media_active ||
446 sc->mii_media_status != mii->mii_media_status ||
447 cmd == MII_MEDIACHG) {
448 switch (sc->mii_mpd_oui) {
449 case MII_OUI_BROADCOM:
450 switch (sc->mii_mpd_model) {
451 case MII_MODEL_BROADCOM_BCM5400:
452 brgphy_bcm5401_dspcode(sc);
453 break;
454 case MII_MODEL_BROADCOM_BCM5401:
455 if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3)
456 brgphy_bcm5401_dspcode(sc);
457 break;
458 case MII_MODEL_BROADCOM_BCM5411:
459 brgphy_bcm5411_dspcode(sc);
460 break;
461 }
462 break;
463 }
464 }
465
466 /* Callback if something changed. */
467 mii_phy_update(sc, cmd);
468 return 0;
469 }
470
471 static void
472 brgphy_copper_status(struct mii_softc *sc)
473 {
474 struct mii_data *mii = sc->mii_pdata;
475 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
476 uint16_t bmcr, bmsr, auxsts, gtsr;
477
478 KASSERT(mii_locked(mii));
479
480 mii->mii_media_status = IFM_AVALID;
481 mii->mii_media_active = IFM_ETHER;
482
483 PHY_READ(sc, MII_BMSR, &bmsr);
484 PHY_READ(sc, MII_BMSR, &bmsr);
485 if (bmsr & BMSR_LINK)
486 mii->mii_media_status |= IFM_ACTIVE;
487
488 PHY_READ(sc, MII_BMCR, &bmcr);
489 if (bmcr & BMCR_ISO) {
490 mii->mii_media_active |= IFM_NONE;
491 mii->mii_media_status = 0;
492 return;
493 }
494
495 if (bmcr & BMCR_LOOP)
496 mii->mii_media_active |= IFM_LOOP;
497
498 if (bmcr & BMCR_AUTOEN) {
499 /*
500 * The media status bits are only valid if autonegotiation
501 * has completed (or it's disabled).
502 */
503 if ((bmsr & BMSR_ACOMP) == 0) {
504 /* Erg, still trying, I guess... */
505 mii->mii_media_active |= IFM_NONE;
506 return;
507 }
508
509 PHY_READ(sc, BRGPHY_MII_AUXSTS, &auxsts);
510
511 switch (auxsts & BRGPHY_AUXSTS_AN_RES) {
512 case BRGPHY_RES_1000FD:
513 mii->mii_media_active |= IFM_1000_T | IFM_FDX;
514 PHY_READ(sc, MII_100T2SR, >sr);
515 if (gtsr & GTSR_MS_RES)
516 mii->mii_media_active |= IFM_ETH_MASTER;
517 break;
518
519 case BRGPHY_RES_1000HD:
520 mii->mii_media_active |= IFM_1000_T | IFM_HDX;
521 PHY_READ(sc, MII_100T2SR, >sr);
522 if (gtsr & GTSR_MS_RES)
523 mii->mii_media_active |= IFM_ETH_MASTER;
524 break;
525
526 case BRGPHY_RES_100FD:
527 mii->mii_media_active |= IFM_100_TX | IFM_FDX;
528 break;
529
530 case BRGPHY_RES_100T4:
531 mii->mii_media_active |= IFM_100_T4 | IFM_HDX;
532 break;
533
534 case BRGPHY_RES_100HD:
535 mii->mii_media_active |= IFM_100_TX | IFM_HDX;
536 break;
537
538 case BRGPHY_RES_10FD:
539 mii->mii_media_active |= IFM_10_T | IFM_FDX;
540 break;
541
542 case BRGPHY_RES_10HD:
543 mii->mii_media_active |= IFM_10_T | IFM_HDX;
544 break;
545
546 default:
547 mii->mii_media_active |= IFM_NONE;
548 mii->mii_media_status = 0;
549 }
550
551 if (mii->mii_media_active & IFM_FDX)
552 mii->mii_media_active |= mii_phy_flowstatus(sc);
553
554 } else
555 mii->mii_media_active = ife->ifm_media;
556 }
557
558 void
559 brgphy_fiber_status(struct mii_softc *sc)
560 {
561 struct mii_data *mii = sc->mii_pdata;
562 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
563 uint16_t bmcr, bmsr, anar, anlpar, result;
564
565 KASSERT(mii_locked(mii));
566
567 mii->mii_media_status = IFM_AVALID;
568 mii->mii_media_active = IFM_ETHER;
569
570 PHY_READ(sc, MII_BMSR, &bmsr);
571 PHY_READ(sc, MII_BMSR, &bmsr);
572 if (bmsr & BMSR_LINK)
573 mii->mii_media_status |= IFM_ACTIVE;
574
575 PHY_READ(sc, MII_BMCR, &bmcr);
576 if (bmcr & BMCR_LOOP)
577 mii->mii_media_active |= IFM_LOOP;
578
579 if (bmcr & BMCR_AUTOEN) {
580 if ((bmsr & BMSR_ACOMP) == 0) {
581 /* Erg, still trying, I guess... */
582 mii->mii_media_active |= IFM_NONE;
583 return;
584 }
585
586 mii->mii_media_active |= IFM_1000_SX;
587
588 PHY_READ(sc, MII_ANAR, &anar);
589 PHY_READ(sc, MII_ANLPAR, &anlpar);
590 result = anar & anlpar;
591
592 if (result & ANAR_X_FD)
593 mii->mii_media_active |= IFM_FDX;
594 else
595 mii->mii_media_active |= IFM_HDX;
596
597 if (mii->mii_media_active & IFM_FDX)
598 mii->mii_media_active |= mii_phy_flowstatus(sc);
599 } else
600 mii->mii_media_active = ife->ifm_media;
601 }
602
603 void
604 brgphy_5708s_status(struct mii_softc *sc)
605 {
606 struct mii_data *mii = sc->mii_pdata;
607 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
608 uint16_t bmcr, bmsr;
609
610 KASSERT(mii_locked(mii));
611
612 mii->mii_media_status = IFM_AVALID;
613 mii->mii_media_active = IFM_ETHER;
614
615 PHY_READ(sc, MII_BMSR, &bmsr);
616 PHY_READ(sc, MII_BMSR, &bmsr);
617 if (bmsr & BMSR_LINK)
618 mii->mii_media_status |= IFM_ACTIVE;
619
620 PHY_READ(sc, MII_BMCR, &bmcr);
621 if (bmcr & BMCR_LOOP)
622 mii->mii_media_active |= IFM_LOOP;
623
624 if (bmcr & BMCR_AUTOEN) {
625 uint16_t xstat;
626
627 if ((bmsr & BMSR_ACOMP) == 0) {
628 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
629 BRGPHY_5708S_DIG_PG0);
630 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_STAT1, &xstat);
631 if ((xstat & BRGPHY_5708S_PG0_1000X_STAT1_LINK) == 0) {
632 /* Erg, still trying, I guess... */
633 mii->mii_media_active |= IFM_NONE;
634 return;
635 }
636 }
637
638 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
639 BRGPHY_5708S_DIG_PG0);
640 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_STAT1, &xstat);
641
642 switch (xstat & BRGPHY_5708S_PG0_1000X_STAT1_SPEED_MASK) {
643 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_10:
644 mii->mii_media_active |= IFM_10_FL;
645 break;
646 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_100:
647 mii->mii_media_active |= IFM_100_FX;
648 break;
649 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_1G:
650 mii->mii_media_active |= IFM_1000_SX;
651 break;
652 case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_25G:
653 mii->mii_media_active |= IFM_2500_SX;
654 break;
655 }
656
657 if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_FDX)
658 mii->mii_media_active |= IFM_FDX;
659 else
660 mii->mii_media_active |= IFM_HDX;
661
662 if (mii->mii_media_active & IFM_FDX) {
663 if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_TX_PAUSE)
664 mii->mii_media_active
665 |= IFM_FLOW | IFM_ETH_TXPAUSE;
666 if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_RX_PAUSE)
667 mii->mii_media_active
668 |= IFM_FLOW | IFM_ETH_RXPAUSE;
669 }
670 } else
671 mii->mii_media_active = ife->ifm_media;
672 }
673
674 static void
675 brgphy_5709s_status(struct mii_softc *sc)
676 {
677 struct mii_data *mii = sc->mii_pdata;
678 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
679 uint16_t bmcr, bmsr, auxsts;
680
681 KASSERT(mii_locked(mii));
682
683 mii->mii_media_status = IFM_AVALID;
684 mii->mii_media_active = IFM_ETHER;
685
686 PHY_READ(sc, MII_BMSR, &bmsr);
687 PHY_READ(sc, MII_BMSR, &bmsr);
688 if (bmsr & BMSR_LINK)
689 mii->mii_media_status |= IFM_ACTIVE;
690
691 PHY_READ(sc, MII_BMCR, &bmcr);
692 if (bmcr & BMCR_ISO) {
693 mii->mii_media_active |= IFM_NONE;
694 mii->mii_media_status = 0;
695 return;
696 }
697
698 if (bmcr & BMCR_LOOP)
699 mii->mii_media_active |= IFM_LOOP;
700
701 if (bmcr & BMCR_AUTOEN) {
702 /*
703 * The media status bits are only valid of autonegotiation
704 * has completed (or it's disabled).
705 */
706 if ((bmsr & BMSR_ACOMP) == 0) {
707 /* Erg, still trying, I guess... */
708 mii->mii_media_active |= IFM_NONE;
709 return;
710 }
711
712 /* 5709S has its own general purpose status registers */
713 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_GP_STATUS);
714 PHY_READ(sc, BRGPHY_GP_STATUS_TOP_ANEG_STATUS, &auxsts);
715
716 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
717 BRGPHY_BLOCK_ADDR_COMBO_IEEE0);
718
719 switch (auxsts & BRGPHY_GP_STATUS_TOP_ANEG_SPEED_MASK) {
720 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_10:
721 mii->mii_media_active |= IFM_10_FL;
722 break;
723 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_100:
724 mii->mii_media_active |= IFM_100_FX;
725 break;
726 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1G:
727 mii->mii_media_active |= IFM_1000_SX;
728 break;
729 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_25G:
730 mii->mii_media_active |= IFM_2500_SX;
731 break;
732 default:
733 mii->mii_media_active |= IFM_NONE;
734 mii->mii_media_status = 0;
735 break;
736 }
737
738 if (auxsts & BRGPHY_GP_STATUS_TOP_ANEG_FDX)
739 mii->mii_media_active |= IFM_FDX;
740 else
741 mii->mii_media_active |= IFM_HDX;
742
743 if (mii->mii_media_active & IFM_FDX)
744 mii->mii_media_active |= mii_phy_flowstatus(sc);
745 } else
746 mii->mii_media_active = ife->ifm_media;
747 }
748
749 static int
750 brgphy_mii_phy_auto(struct mii_softc *sc)
751 {
752 uint16_t anar, ktcr = 0;
753
754 KASSERT(mii_locked(sc->mii_pdata));
755
756 sc->mii_ticks = 0;
757 brgphy_loop(sc);
758 PHY_RESET(sc);
759
760 if (sc->mii_flags & MIIF_HAVEFIBER) {
761 anar = ANAR_X_FD | ANAR_X_HD;
762 if (sc->mii_flags & MIIF_DOPAUSE)
763 anar |= ANAR_X_PAUSE_TOWARDS;
764 } else {
765 anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA;
766 if (sc->mii_flags & MIIF_DOPAUSE)
767 anar |= ANAR_FC | ANAR_PAUSE_ASYM;
768 ktcr = GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
769 if ((sc->mii_mpd_oui == MII_OUI_BROADCOM)
770 && (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5701))
771 ktcr |= GTCR_MAN_MS | GTCR_ADV_MS;
772 PHY_WRITE(sc, MII_100T2CR, ktcr);
773 }
774 PHY_WRITE(sc, MII_ANAR, anar);
775
776 /* Start autonegotiation */
777 PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
778 PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00);
779
780 return EJUSTRETURN;
781 }
782
783 static void
784 brgphy_loop(struct mii_softc *sc)
785 {
786 uint16_t bmsr;
787 int i;
788
789 KASSERT(mii_locked(sc->mii_pdata));
790
791 PHY_WRITE(sc, MII_BMCR, BMCR_LOOP);
792 for (i = 0; i < 15000; i++) {
793 PHY_READ(sc, MII_BMSR, &bmsr);
794 if (!(bmsr & BMSR_LINK))
795 break;
796 DELAY(10);
797 }
798 }
799
800 static void
801 brgphy_reset(struct mii_softc *sc)
802 {
803 struct brgphy_softc *bsc = device_private(sc->mii_dev);
804 uint16_t reg;
805
806 KASSERT(mii_locked(sc->mii_pdata));
807
808 mii_phy_reset(sc);
809 switch (sc->mii_mpd_oui) {
810 case MII_OUI_BROADCOM:
811 switch (sc->mii_mpd_model) {
812 case MII_MODEL_BROADCOM_BCM5400:
813 brgphy_bcm5401_dspcode(sc);
814 break;
815 case MII_MODEL_BROADCOM_BCM5401:
816 if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3)
817 brgphy_bcm5401_dspcode(sc);
818 break;
819 case MII_MODEL_BROADCOM_BCM5411:
820 brgphy_bcm5411_dspcode(sc);
821 break;
822 case MII_MODEL_BROADCOM_BCM5421:
823 brgphy_bcm5421_dspcode(sc);
824 break;
825 case MII_MODEL_BROADCOM_BCM54K2:
826 brgphy_bcm54k2_dspcode(sc);
827 break;
828 }
829 break;
830 case MII_OUI_BROADCOM3:
831 switch (sc->mii_mpd_model) {
832 case MII_MODEL_BROADCOM3_BCM5717C:
833 case MII_MODEL_BROADCOM3_BCM5719C:
834 case MII_MODEL_BROADCOM3_BCM5720C:
835 case MII_MODEL_BROADCOM3_BCM57765:
836 return;
837 }
838 break;
839 default:
840 break;
841 }
842
843 /* Handle any bge (NetXtreme/NetLink) workarounds. */
844 if (bsc->sc_isbge) {
845 if (!(sc->mii_flags & MIIF_HAVEFIBER)) {
846
847 if (bsc->sc_phyflags & BGEPHYF_ADC_BUG)
848 brgphy_adc_bug(sc);
849 if (bsc->sc_phyflags & BGEPHYF_5704_A0_BUG)
850 brgphy_5704_a0_bug(sc);
851 if (bsc->sc_phyflags & BGEPHYF_BER_BUG)
852 brgphy_ber_bug(sc);
853 else if (bsc->sc_phyflags & BGEPHYF_JITTER_BUG) {
854 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0c00);
855 PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a);
856
857 if (bsc->sc_phyflags
858 & BGEPHYF_ADJUST_TRIM) {
859 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT,
860 0x110b);
861 PHY_WRITE(sc, BRGPHY_TEST1,
862 BRGPHY_TEST1_TRIM_EN | 0x4);
863 } else {
864 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT,
865 0x010b);
866 }
867
868 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0400);
869 }
870 if (bsc->sc_phyflags & BGEPHYF_CRC_BUG)
871 brgphy_crc_bug(sc);
872
873 /* Set Jumbo frame settings in the PHY. */
874 if (bsc->sc_phyflags & BGEPHYF_JUMBO_CAPABLE)
875 brgphy_jumbo_settings(sc);
876
877 /* Adjust output voltage */
878 if ((sc->mii_mpd_oui == MII_OUI_BROADCOM2)
879 && (sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5906))
880 PHY_WRITE(sc, BRGPHY_MII_EPHY_PTEST, 0x12);
881
882 /* Enable Ethernet@Wirespeed */
883 if (!(bsc->sc_phyflags & BGEPHYF_NO_WIRESPEED))
884 brgphy_eth_wirespeed(sc);
885
886 #if 0
887 /* Enable Link LED on Dell boxes */
888 if (bsc->sc_phyflags & BGEPHYF_NO_3LED) {
889 PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL, ®);
890 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL,
891 reg & ~BRGPHY_PHY_EXTCTL_3_LED);
892 }
893 #endif
894 }
895 /* Handle any bnx (NetXtreme II) workarounds. */
896 } else if (bsc->sc_isbnx) {
897 uint32_t chip_num = _BNX_CHIP_NUM(bsc->sc_chipid);
898 uint32_t chip_id = _BNX_CHIP_ID(bsc->sc_chipid);
899 uint32_t chip_rev = _BNX_CHIP_REV(bsc->sc_chipid);
900
901 if ((sc->mii_mpd_oui == MII_OUI_BROADCOM2)
902 && sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5708S) {
903 /*
904 * Store autoneg capabilities/results in digital block
905 * (Page 0)
906 */
907 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
908 BRGPHY_5708S_DIG3_PG2);
909 PHY_WRITE(sc, BRGPHY_5708S_PG2_DIGCTL_3_0,
910 BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE);
911 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
912 BRGPHY_5708S_DIG_PG0);
913
914 /* Enable fiber mode and autodetection */
915 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL1, ®);
916 PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL1, reg |
917 BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN |
918 BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE);
919
920 /* Enable parallel detection */
921 PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL2, ®);
922 PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL2,
923 reg | BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN);
924
925 /*
926 * Advertise 2.5G support through next page during
927 * autoneg
928 */
929 if (bsc->sc_phyflags & BNX_PHY_2_5G_CAPABLE_FLAG) {
930 PHY_READ(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1,
931 ®);
932 PHY_WRITE(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1,
933 reg | BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G);
934 }
935
936 /* Increase TX signal amplitude */
937 if ((chip_id == BNX_CHIP_ID_5708_A0) ||
938 (chip_id == BNX_CHIP_ID_5708_B0) ||
939 (chip_id == BNX_CHIP_ID_5708_B1)) {
940 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
941 BRGPHY_5708S_TX_MISC_PG5);
942 PHY_READ(sc, BRGPHY_5708S_PG5_TXACTL1, ®);
943 PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL1,
944 reg & ~BRGPHY_5708S_PG5_TXACTL1_VCM);
945 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
946 BRGPHY_5708S_DIG_PG0);
947 }
948
949 /*
950 * Backplanes use special
951 * driver/pre-driver/pre-emphasis values.
952 */
953 if ((bsc->sc_shared_hwcfg & BNX_SHARED_HW_CFG_PHY_BACKPLANE) &&
954 (bsc->sc_port_hwcfg & BNX_PORT_HW_CFG_CFG_TXCTL3_MASK)) {
955 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
956 BRGPHY_5708S_TX_MISC_PG5);
957 PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL3,
958 bsc->sc_port_hwcfg &
959 BNX_PORT_HW_CFG_CFG_TXCTL3_MASK);
960 PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
961 BRGPHY_5708S_DIG_PG0);
962 }
963 } else if ((sc->mii_mpd_oui == MII_OUI_BROADCOM2)
964 && (sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5709S)) {
965 /* Select the SerDes Digital block of the AN MMD. */
966 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
967 BRGPHY_BLOCK_ADDR_SERDES_DIG);
968
969 PHY_READ(sc, BRGPHY_SERDES_DIG_1000X_CTL1, ®);
970 PHY_WRITE(sc, BRGPHY_SERDES_DIG_1000X_CTL1,
971 (reg & ~BRGPHY_SD_DIG_1000X_CTL1_AUTODET) |
972 BRGPHY_SD_DIG_1000X_CTL1_FIBER);
973
974 if (bsc->sc_phyflags & BNX_PHY_2_5G_CAPABLE_FLAG) {
975 /* Select the Over 1G block of the AN MMD. */
976 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
977 BRGPHY_BLOCK_ADDR_OVER_1G);
978
979 /*
980 * Enable autoneg "Next Page" to advertise
981 * 2.5G support.
982 */
983 PHY_READ(sc, BRGPHY_OVER_1G_UNFORMAT_PG1,
984 ®);
985 PHY_WRITE(sc, BRGPHY_OVER_1G_UNFORMAT_PG1,
986 reg | BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G);
987 }
988
989 /*
990 * Select the Multi-Rate Backplane Ethernet block of
991 * the AN MMD.
992 */
993 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
994 BRGPHY_BLOCK_ADDR_MRBE);
995
996 /* Enable MRBE speed autoneg. */
997 PHY_READ(sc, BRGPHY_MRBE_MSG_PG5_NP, ®);
998 PHY_WRITE(sc, BRGPHY_MRBE_MSG_PG5_NP,
999 reg | BRGPHY_MRBE_MSG_PG5_NP_MBRE |
1000 BRGPHY_MRBE_MSG_PG5_NP_T2);
1001
1002 /* Select the Clause 73 User B0 block of the AN MMD. */
1003 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
1004 BRGPHY_BLOCK_ADDR_CL73_USER_B0);
1005
1006 /* Enable MRBE speed autoneg. */
1007 PHY_WRITE(sc, BRGPHY_CL73_USER_B0_MBRE_CTL1,
1008 BRGPHY_CL73_USER_B0_MBRE_CTL1_NP_AFT_BP |
1009 BRGPHY_CL73_USER_B0_MBRE_CTL1_STA_MGR |
1010 BRGPHY_CL73_USER_B0_MBRE_CTL1_ANEG);
1011
1012 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
1013 BRGPHY_BLOCK_ADDR_COMBO_IEEE0);
1014
1015 } else if (chip_num == BNX_CHIP_NUM_5709) {
1016 if ((chip_rev == BNX_CHIP_REV_Ax) ||
1017 (chip_rev == BNX_CHIP_REV_Bx))
1018 brgphy_disable_early_dac(sc);
1019
1020 /* Set Jumbo frame settings in the PHY. */
1021 brgphy_jumbo_settings(sc);
1022
1023 /* Enable Ethernet@Wirespeed */
1024 brgphy_eth_wirespeed(sc);
1025 } else {
1026 if (!(sc->mii_flags & MIIF_HAVEFIBER)) {
1027 brgphy_ber_bug(sc);
1028
1029 /* Set Jumbo frame settings in the PHY. */
1030 brgphy_jumbo_settings(sc);
1031
1032 /* Enable Ethernet@Wirespeed */
1033 brgphy_eth_wirespeed(sc);
1034 }
1035 }
1036 }
1037 }
1038
1039 /* Turn off tap power management on 5401. */
1040 static void
1041 brgphy_bcm5401_dspcode(struct mii_softc *sc)
1042 {
1043 static const struct {
1044 int reg;
1045 uint16_t val;
1046 } dspcode[] = {
1047 { BRGPHY_MII_AUXCTL, 0x0c20 },
1048 { BRGPHY_MII_DSP_ADDR_REG, 0x0012 },
1049 { BRGPHY_MII_DSP_RW_PORT, 0x1804 },
1050 { BRGPHY_MII_DSP_ADDR_REG, 0x0013 },
1051 { BRGPHY_MII_DSP_RW_PORT, 0x1204 },
1052 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 },
1053 { BRGPHY_MII_DSP_RW_PORT, 0x0132 },
1054 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 },
1055 { BRGPHY_MII_DSP_RW_PORT, 0x0232 },
1056 { BRGPHY_MII_DSP_ADDR_REG, 0x201f },
1057 { BRGPHY_MII_DSP_RW_PORT, 0x0a20 },
1058 { 0, 0 },
1059 };
1060 int i;
1061
1062 for (i = 0; dspcode[i].reg != 0; i++)
1063 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
1064 delay(40);
1065 }
1066
1067 static void
1068 brgphy_bcm5411_dspcode(struct mii_softc *sc)
1069 {
1070 static const struct {
1071 int reg;
1072 uint16_t val;
1073 } dspcode[] = {
1074 { 0x1c, 0x8c23 },
1075 { 0x1c, 0x8ca3 },
1076 { 0x1c, 0x8c23 },
1077 { 0, 0 },
1078 };
1079 int i;
1080
1081 for (i = 0; dspcode[i].reg != 0; i++)
1082 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
1083 }
1084
1085 static void
1086 brgphy_bcm5421_dspcode(struct mii_softc *sc)
1087 {
1088 uint16_t data;
1089
1090 /* Set Class A mode */
1091 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x1007);
1092 PHY_READ(sc, BRGPHY_MII_AUXCTL, &data);
1093 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0400);
1094
1095 /* Set FFE gamma override to -0.125 */
1096 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0007);
1097 PHY_READ(sc, BRGPHY_MII_AUXCTL, &data);
1098 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0800);
1099 PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a);
1100 PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT, &data);
1101 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, data | 0x0200);
1102 }
1103
1104 static void
1105 brgphy_bcm54k2_dspcode(struct mii_softc *sc)
1106 {
1107 static const struct {
1108 int reg;
1109 uint16_t val;
1110 } dspcode[] = {
1111 { 4, 0x01e1 },
1112 { 9, 0x0300 },
1113 { 0, 0 },
1114 };
1115 int i;
1116
1117 for (i = 0; dspcode[i].reg != 0; i++)
1118 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
1119 }
1120
1121 static void
1122 brgphy_adc_bug(struct mii_softc *sc)
1123 {
1124 static const struct {
1125 int reg;
1126 uint16_t val;
1127 } dspcode[] = {
1128 { BRGPHY_MII_AUXCTL, 0x0c00 },
1129 { BRGPHY_MII_DSP_ADDR_REG, 0x201f },
1130 { BRGPHY_MII_DSP_RW_PORT, 0x2aaa },
1131 { BRGPHY_MII_DSP_ADDR_REG, 0x000a },
1132 { BRGPHY_MII_DSP_RW_PORT, 0x0323 },
1133 { BRGPHY_MII_AUXCTL, 0x0400 },
1134 { 0, 0 },
1135 };
1136 int i;
1137
1138 for (i = 0; dspcode[i].reg != 0; i++)
1139 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
1140 }
1141
1142 static void
1143 brgphy_5704_a0_bug(struct mii_softc *sc)
1144 {
1145 static const struct {
1146 int reg;
1147 uint16_t val;
1148 } dspcode[] = {
1149 { 0x1c, 0x8d68 },
1150 { 0x1c, 0x8d68 },
1151 { 0, 0 },
1152 };
1153 int i;
1154
1155 for (i = 0; dspcode[i].reg != 0; i++)
1156 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
1157 }
1158
1159 static void
1160 brgphy_ber_bug(struct mii_softc *sc)
1161 {
1162 static const struct {
1163 int reg;
1164 uint16_t val;
1165 } dspcode[] = {
1166 { BRGPHY_MII_AUXCTL, 0x0c00 },
1167 { BRGPHY_MII_DSP_ADDR_REG, 0x000a },
1168 { BRGPHY_MII_DSP_RW_PORT, 0x310b },
1169 { BRGPHY_MII_DSP_ADDR_REG, 0x201f },
1170 { BRGPHY_MII_DSP_RW_PORT, 0x9506 },
1171 { BRGPHY_MII_DSP_ADDR_REG, 0x401f },
1172 { BRGPHY_MII_DSP_RW_PORT, 0x14e2 },
1173 { BRGPHY_MII_AUXCTL, 0x0400 },
1174 { 0, 0 },
1175 };
1176 int i;
1177
1178 for (i = 0; dspcode[i].reg != 0; i++)
1179 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
1180 }
1181
1182 /* BCM5701 A0/B0 CRC bug workaround */
1183 static void
1184 brgphy_crc_bug(struct mii_softc *sc)
1185 {
1186 static const struct {
1187 int reg;
1188 uint16_t val;
1189 } dspcode[] = {
1190 { BRGPHY_MII_DSP_ADDR_REG, 0x0a75 },
1191 { 0x1c, 0x8c68 },
1192 { 0x1c, 0x8d68 },
1193 { 0x1c, 0x8c68 },
1194 { 0, 0 },
1195 };
1196 int i;
1197
1198 for (i = 0; dspcode[i].reg != 0; i++)
1199 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
1200 }
1201
1202 static void
1203 brgphy_disable_early_dac(struct mii_softc *sc)
1204 {
1205 uint16_t val;
1206
1207 PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x0f08);
1208 PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT, &val);
1209 val &= ~(1 << 8);
1210 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, val);
1211
1212 }
1213
1214 static void
1215 brgphy_jumbo_settings(struct mii_softc *sc)
1216 {
1217 uint16_t val;
1218
1219 /* Set Jumbo frame settings in the PHY. */
1220 if ((sc->mii_mpd_oui == MII_OUI_BROADCOM)
1221 && (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5401)) {
1222 /* Cannot do read-modify-write on the BCM5401 */
1223 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x4c20);
1224 } else {
1225 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7);
1226 PHY_READ(sc, BRGPHY_MII_AUXCTL, &val);
1227 PHY_WRITE(sc, BRGPHY_MII_AUXCTL,
1228 val & ~(BRGPHY_AUXCTL_LONG_PKT | 0x7));
1229 }
1230
1231 PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL, &val);
1232 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, val & ~BRGPHY_PHY_EXTCTL_HIGH_LA);
1233 }
1234
1235 static void
1236 brgphy_eth_wirespeed(struct mii_softc *sc)
1237 {
1238 uint16_t val;
1239
1240 /* Enable Ethernet@Wirespeed */
1241 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007);
1242 PHY_READ(sc, BRGPHY_MII_AUXCTL, &val);
1243 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, val | (1 << 15) | (1 << 4));
1244 }
1245