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