brgphy.c revision 1.35 1 /* $NetBSD: brgphy.c,v 1.35 2007/12/09 20:28:02 jmcneill Exp $ */
2
3 /*-
4 * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 /*
41 * Copyright (c) 1997 Manuel Bouyer. All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software
52 * must display the following acknowledgement:
53 * This product includes software developed by Manuel Bouyer.
54 * 4. The name of the author may not be used to endorse or promote products
55 * derived from this software without specific prior written permission.
56 *
57 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
58 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
59 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
60 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
61 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
62 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
63 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
64 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
65 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
66 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
67 */
68
69 /*
70 * driver for the Broadcom BCM5400 Gig-E PHY.
71 *
72 * Programming information for this PHY was gleaned from FreeBSD
73 * (they were apparently able to get a datasheet from Broadcom).
74 */
75
76 #include <sys/cdefs.h>
77 __KERNEL_RCSID(0, "$NetBSD: brgphy.c,v 1.35 2007/12/09 20:28:02 jmcneill Exp $");
78
79 #include <sys/param.h>
80 #include <sys/systm.h>
81 #include <sys/kernel.h>
82 #include <sys/device.h>
83 #include <sys/socket.h>
84 #include <sys/errno.h>
85
86 #include <net/if.h>
87 #include <net/if_media.h>
88
89 #include <dev/mii/mii.h>
90 #include <dev/mii/miivar.h>
91 #include <dev/mii/miidevs.h>
92
93 #include <dev/mii/brgphyreg.h>
94
95 static int brgphymatch(struct device *, struct cfdata *, void *);
96 static void brgphyattach(struct device *, struct device *, void *);
97
98 CFATTACH_DECL(brgphy, sizeof(struct mii_softc),
99 brgphymatch, brgphyattach, mii_phy_detach, mii_phy_activate);
100
101 static int brgphy_service(struct mii_softc *, struct mii_data *, int);
102 static void brgphy_status(struct mii_softc *);
103 static int brgphy_mii_phy_auto(struct mii_softc *);
104 static void brgphy_loop(struct mii_softc *);
105
106 static void brgphy_5401_reset(struct mii_softc *);
107 static void brgphy_5411_reset(struct mii_softc *);
108 static void brgphy_5703_reset(struct mii_softc *);
109 static void brgphy_5704_reset(struct mii_softc *);
110 static void brgphy_5705_reset(struct mii_softc *);
111 static void brgphy_5750_reset(struct mii_softc *);
112 static void brgphy_5755_reset(struct mii_softc *);
113
114 static const struct mii_phy_funcs brgphy_funcs = {
115 brgphy_service, brgphy_status, mii_phy_reset,
116 };
117
118 static const struct mii_phy_funcs brgphy_5401_funcs = {
119 brgphy_service, brgphy_status, brgphy_5401_reset,
120 };
121
122 static const struct mii_phy_funcs brgphy_5411_funcs = {
123 brgphy_service, brgphy_status, brgphy_5411_reset,
124 };
125
126 static const struct mii_phy_funcs brgphy_5703_funcs = {
127 brgphy_service, brgphy_status, brgphy_5703_reset,
128 };
129
130 static const struct mii_phy_funcs brgphy_5704_funcs = {
131 brgphy_service, brgphy_status, brgphy_5704_reset,
132 };
133
134 static const struct mii_phy_funcs brgphy_5705_funcs = {
135 brgphy_service, brgphy_status, brgphy_5705_reset,
136 };
137
138 const struct mii_phy_funcs brgphy_5750_funcs = {
139 brgphy_service, brgphy_status, brgphy_5750_reset,
140 };
141
142 const struct mii_phy_funcs brgphy_5755_funcs = {
143 brgphy_service, brgphy_status, brgphy_5755_reset,
144 };
145
146
147 static const struct mii_phydesc brgphys[] = {
148 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5400,
149 MII_STR_BROADCOM_BCM5400 },
150
151 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5401,
152 MII_STR_BROADCOM_BCM5401 },
153
154 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5411,
155 MII_STR_BROADCOM_BCM5411 },
156
157 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5421,
158 MII_STR_BROADCOM_BCM5421 },
159
160 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5701,
161 MII_STR_BROADCOM_BCM5701 },
162
163 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5703,
164 MII_STR_BROADCOM_BCM5703 },
165
166 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5704,
167 MII_STR_BROADCOM_BCM5704 },
168
169 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5705,
170 MII_STR_BROADCOM_BCM5705 },
171
172 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5714,
173 MII_STR_BROADCOM_BCM5714 },
174
175 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5750,
176 MII_STR_BROADCOM_BCM5750 },
177
178 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5752,
179 MII_STR_BROADCOM_BCM5752 },
180
181 { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5780,
182 MII_STR_BROADCOM_BCM5780 },
183
184 { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5755,
185 MII_STR_BROADCOM2_BCM5755 },
186
187 { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5754,
188 MII_STR_BROADCOM2_BCM5754 },
189
190 { 0, 0,
191 NULL },
192 };
193
194 static void bcm5401_load_dspcode(struct mii_softc *);
195 static void bcm5411_load_dspcode(struct mii_softc *);
196 static void bcm5703_load_dspcode(struct mii_softc *);
197 static void bcm5704_load_dspcode(struct mii_softc *);
198 static void bcm5750_load_dspcode(struct mii_softc *);
199 static void bcm5755_load_dspcode(struct mii_softc *);
200
201 static int
202 brgphymatch(struct device *parent, struct cfdata *match,
203 void *aux)
204 {
205 struct mii_attach_args *ma = aux;
206
207 if (mii_phy_match(ma, brgphys) != NULL)
208 return (10);
209
210 return (0);
211 }
212
213 static void
214 brgphyattach(struct device *parent, struct device *self, void *aux)
215 {
216 struct mii_softc *sc = device_private(self);
217 struct mii_attach_args *ma = aux;
218 struct mii_data *mii = ma->mii_data;
219 const struct mii_phydesc *mpd;
220
221 mpd = mii_phy_match(ma, brgphys);
222 aprint_naive(": Media interface\n");
223 aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
224
225 sc->mii_inst = mii->mii_instance;
226 sc->mii_phy = ma->mii_phyno;
227 sc->mii_mpd_model = MII_MODEL(ma->mii_id2);
228 sc->mii_pdata = mii;
229 sc->mii_flags = ma->mii_flags;
230 sc->mii_anegticks = MII_ANEGTICKS;
231
232 switch (MII_MODEL(ma->mii_id2)) {
233 case MII_MODEL_BROADCOM_BCM5400:
234 sc->mii_funcs = &brgphy_5401_funcs;
235 aprint_normal("%s: using BCM5401 DSP patch\n",
236 sc->mii_dev.dv_xname);
237 break;
238
239 case MII_MODEL_BROADCOM_BCM5401:
240 if (MII_REV(ma->mii_id2) == 1 || MII_REV(ma->mii_id2) == 3) {
241 sc->mii_funcs = &brgphy_5401_funcs;
242 aprint_normal("%s: using BCM5401 DSP patch\n",
243 sc->mii_dev.dv_xname);
244 } else
245 sc->mii_funcs = &brgphy_funcs;
246 break;
247
248 case MII_MODEL_BROADCOM_BCM5411:
249 sc->mii_funcs = &brgphy_5411_funcs;
250 aprint_normal("%s: using BCM5411 DSP patch\n",
251 sc->mii_dev.dv_xname);
252 break;
253
254 #ifdef notyet /* unverified, untested */
255 case MII_MODEL_BROADCOM_BCM5703:
256 sc->mii_funcs = &brgphy_5703_funcs;
257 aprint_normal("%s: using BCM5703 DSP patch\n",
258 sc->mii_dev.dv_xname);
259 break;
260 #endif
261
262 case MII_MODEL_BROADCOM_BCM5704:
263 sc->mii_funcs = &brgphy_5704_funcs;
264 aprint_normal("%s: using BCM5704 DSP patch\n",
265 sc->mii_dev.dv_xname);
266 break;
267
268 case MII_MODEL_BROADCOM_BCM5705:
269 sc->mii_funcs = &brgphy_5705_funcs;
270 break;
271
272 case MII_MODEL_BROADCOM_BCM5714:
273 case MII_MODEL_BROADCOM_BCM5780:
274 case MII_MODEL_BROADCOM_BCM5750:
275 case MII_MODEL_BROADCOM_BCM5752:
276 sc->mii_funcs = &brgphy_5750_funcs;
277 break;
278
279 case MII_MODEL_BROADCOM2_BCM5754:
280 case MII_MODEL_BROADCOM2_BCM5755:
281 sc->mii_funcs = &brgphy_5755_funcs;
282 break;
283
284 default:
285 sc->mii_funcs = &brgphy_funcs;
286 break;
287 }
288
289 PHY_RESET(sc);
290
291 sc->mii_capabilities =
292 PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
293 if (sc->mii_capabilities & BMSR_EXTSTAT)
294 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
295
296 aprint_normal("%s: ", sc->mii_dev.dv_xname);
297 if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
298 (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
299 aprint_error("no media present");
300 else
301 mii_phy_add_media(sc);
302 aprint_normal("\n");
303
304 if (!pmf_device_register(self, NULL, mii_phy_resume))
305 aprint_error_dev(self, "couldn't establish power handler\n");
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 int reg, speed, gig;
313
314 switch (cmd) {
315 case MII_POLLSTAT:
316 /*
317 * If we're not polling our PHY instance, just return.
318 */
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 reg = PHY_READ(sc, MII_BMCR);
330 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
331 return (0);
332 }
333
334 /*
335 * If the interface is not up, don't do anything.
336 */
337 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
338 break;
339
340 PHY_RESET(sc); /* XXX hardware bug work-around */
341
342 switch (IFM_SUBTYPE(ife->ifm_media)) {
343 case IFM_AUTO:
344 (void) brgphy_mii_phy_auto(sc);
345 break;
346 case IFM_1000_T:
347 speed = BMCR_S1000;
348 goto setit;
349 case IFM_100_TX:
350 speed = BMCR_S100;
351 goto setit;
352 case IFM_10_T:
353 speed = BMCR_S10;
354 setit:
355 brgphy_loop(sc);
356 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
357 speed |= BMCR_FDX;
358 gig = GTCR_ADV_1000TFDX;
359 } else {
360 gig = GTCR_ADV_1000THDX;
361 }
362
363 PHY_WRITE(sc, MII_100T2CR, 0);
364 PHY_WRITE(sc, MII_BMCR, speed);
365 PHY_WRITE(sc, MII_ANAR, ANAR_CSMA);
366
367 if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T)
368 break;
369
370 PHY_WRITE(sc, MII_100T2CR, gig);
371 PHY_WRITE(sc, MII_BMCR,
372 speed|BMCR_AUTOEN|BMCR_STARTNEG);
373
374 if (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 /*
388 * If we're not currently selected, just return.
389 */
390 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
391 return (0);
392
393 if (mii_phy_tick(sc) == EJUSTRETURN)
394 return (0);
395 break;
396
397 case MII_DOWN:
398 mii_phy_down(sc);
399 return (0);
400 }
401
402 /* Update the media status. */
403 mii_phy_status(sc);
404
405 /*
406 * Callback if something changed. Note that we need to poke the DSP on
407 * the Broadcom PHYs if the media changes.
408 */
409 if (sc->mii_media_active != mii->mii_media_active ||
410 sc->mii_media_status != mii->mii_media_status ||
411 cmd == MII_MEDIACHG) {
412 mii_phy_update(sc, cmd);
413 if (sc->mii_funcs == &brgphy_5401_funcs)
414 bcm5401_load_dspcode(sc);
415 else if (sc->mii_funcs == &brgphy_5411_funcs)
416 bcm5411_load_dspcode(sc);
417 }
418 return (0);
419 }
420
421 static void
422 brgphy_status(struct mii_softc *sc)
423 {
424 struct mii_data *mii = sc->mii_pdata;
425 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
426 int bmcr, auxsts, gtsr;
427
428 mii->mii_media_status = IFM_AVALID;
429 mii->mii_media_active = IFM_ETHER;
430
431 auxsts = PHY_READ(sc, BRGPHY_MII_AUXSTS);
432
433 if (auxsts & BRGPHY_AUXSTS_LINK)
434 mii->mii_media_status |= IFM_ACTIVE;
435
436 bmcr = PHY_READ(sc, MII_BMCR);
437 if (bmcr & BMCR_ISO) {
438 mii->mii_media_active |= IFM_NONE;
439 mii->mii_media_status = 0;
440 return;
441 }
442
443 if (bmcr & BMCR_LOOP)
444 mii->mii_media_active |= IFM_LOOP;
445
446 if (bmcr & BMCR_AUTOEN) {
447 /*
448 * The media status bits are only valid of autonegotiation
449 * has completed (or it's disabled).
450 */
451 if ((auxsts & BRGPHY_AUXSTS_ACOMP) == 0) {
452 /* Erg, still trying, I guess... */
453 mii->mii_media_active |= IFM_NONE;
454 return;
455 }
456
457 switch (auxsts & BRGPHY_AUXSTS_AN_RES) {
458 case BRGPHY_RES_1000FD:
459 mii->mii_media_active |= IFM_1000_T|IFM_FDX;
460 gtsr = PHY_READ(sc, MII_100T2SR);
461 if (gtsr & GTSR_MS_RES)
462 mii->mii_media_active |= IFM_ETH_MASTER;
463 break;
464
465 case BRGPHY_RES_1000HD:
466 mii->mii_media_active |= IFM_1000_T;
467 gtsr = PHY_READ(sc, MII_100T2SR);
468 if (gtsr & GTSR_MS_RES)
469 mii->mii_media_active |= IFM_ETH_MASTER;
470 break;
471
472 case BRGPHY_RES_100FD:
473 mii->mii_media_active |= IFM_100_TX|IFM_FDX;
474 break;
475
476 case BRGPHY_RES_100T4:
477 mii->mii_media_active |= IFM_100_T4;
478 break;
479
480 case BRGPHY_RES_100HD:
481 mii->mii_media_active |= IFM_100_TX;
482 break;
483
484 case BRGPHY_RES_10FD:
485 mii->mii_media_active |= IFM_10_T|IFM_FDX;
486 break;
487
488 case BRGPHY_RES_10HD:
489 mii->mii_media_active |= IFM_10_T;
490 break;
491
492 default:
493 mii->mii_media_active |= IFM_NONE;
494 mii->mii_media_status = 0;
495 }
496 if (mii->mii_media_active & IFM_FDX)
497 mii->mii_media_active |= mii_phy_flowstatus(sc);
498 } else
499 mii->mii_media_active = ife->ifm_media;
500 }
501
502 int
503 brgphy_mii_phy_auto(struct mii_softc *sc)
504 {
505 int anar, ktcr = 0;
506
507 brgphy_loop(sc);
508 PHY_RESET(sc);
509 ktcr = GTCR_ADV_1000TFDX|GTCR_ADV_1000THDX;
510 if (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5701)
511 ktcr |= GTCR_MAN_MS|GTCR_ADV_MS;
512 PHY_WRITE(sc, MII_100T2CR, ktcr);
513 ktcr = PHY_READ(sc, MII_100T2CR);
514 DELAY(1000);
515 anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA;
516 if (sc->mii_flags & MIIF_DOPAUSE)
517 anar |= ANAR_FC| ANAR_X_PAUSE_ASYM;
518
519 PHY_WRITE(sc, MII_ANAR, anar);
520 DELAY(1000);
521 PHY_WRITE(sc, MII_BMCR,
522 BMCR_AUTOEN | BMCR_STARTNEG);
523 PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00);
524
525 return (EJUSTRETURN);
526 }
527
528 void
529 brgphy_loop(struct mii_softc *sc)
530 {
531 u_int32_t bmsr;
532 int i;
533
534 PHY_WRITE(sc, MII_BMCR, BMCR_LOOP);
535 for (i = 0; i < 15000; i++) {
536 bmsr = PHY_READ(sc, MII_BMSR);
537 if (!(bmsr & BMSR_LINK))
538 break;
539 DELAY(10);
540 }
541 }
542
543 static void
544 brgphy_5401_reset(struct mii_softc *sc)
545 {
546
547 mii_phy_reset(sc);
548 bcm5401_load_dspcode(sc);
549 }
550
551 static void
552 brgphy_5411_reset(struct mii_softc *sc)
553 {
554
555 mii_phy_reset(sc);
556 bcm5411_load_dspcode(sc);
557 }
558
559
560 static void
561 brgphy_5703_reset(struct mii_softc *sc)
562 {
563
564 mii_phy_reset(sc);
565 bcm5703_load_dspcode(sc);
566 }
567
568 static void
569 brgphy_5704_reset(struct mii_softc *sc)
570 {
571
572 mii_phy_reset(sc);
573 bcm5704_load_dspcode(sc);
574 }
575
576 /*
577 * Hardware bug workaround. Do nothing since after
578 * reset the 5705 PHY would get stuck in 10/100 MII mode.
579 */
580
581 static void
582 brgphy_5705_reset(struct mii_softc *sc)
583 {
584 }
585
586 static void
587 brgphy_5750_reset(struct mii_softc *sc)
588 {
589 mii_phy_reset(sc);
590 bcm5750_load_dspcode(sc);
591 }
592
593 static void
594 brgphy_5755_reset(struct mii_softc *sc)
595 {
596 mii_phy_reset(sc);
597 bcm5755_load_dspcode(sc);
598 }
599
600 /* Turn off tap power management on 5401. */
601 static void
602 bcm5401_load_dspcode(struct mii_softc *sc)
603 {
604 static const struct {
605 int reg;
606 uint16_t val;
607 } dspcode[] = {
608 { BRGPHY_MII_AUXCTL, 0x0c20 },
609 { BRGPHY_MII_DSP_ADDR_REG, 0x0012 },
610 { BRGPHY_MII_DSP_RW_PORT, 0x1804 },
611 { BRGPHY_MII_DSP_ADDR_REG, 0x0013 },
612 { BRGPHY_MII_DSP_RW_PORT, 0x1204 },
613 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 },
614 { BRGPHY_MII_DSP_RW_PORT, 0x0132 },
615 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 },
616 { BRGPHY_MII_DSP_RW_PORT, 0x0232 },
617 { BRGPHY_MII_DSP_ADDR_REG, 0x201f },
618 { BRGPHY_MII_DSP_RW_PORT, 0x0a20 },
619 { 0, 0 },
620 };
621 int i;
622
623 for (i = 0; dspcode[i].reg != 0; i++)
624 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
625 delay(40);
626 }
627
628 static void
629 bcm5411_load_dspcode(struct mii_softc *sc)
630 {
631 static const struct {
632 int reg;
633 uint16_t val;
634 } dspcode[] = {
635 { 0x1c, 0x8c23 },
636 { 0x1c, 0x8ca3 },
637 { 0x1c, 0x8c23 },
638 { 0, 0 },
639 };
640 int i;
641
642 for (i = 0; dspcode[i].reg != 0; i++)
643 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
644 }
645
646 static void
647 bcm5703_load_dspcode(struct mii_softc *sc)
648 {
649 static const struct {
650 int reg;
651 uint16_t val;
652 } dspcode[] = {
653 { BRGPHY_MII_AUXCTL, 0x0c00 },
654 { BRGPHY_MII_DSP_ADDR_REG, 0x201f },
655 { BRGPHY_MII_DSP_RW_PORT, 0x2aaa },
656 { 0, 0 },
657 };
658 int i;
659
660 for (i = 0; dspcode[i].reg != 0; i++)
661 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
662 }
663
664 static void
665 bcm5704_load_dspcode(struct mii_softc *sc)
666 {
667 static const struct {
668 int reg;
669 uint16_t val;
670 } dspcode[] = {
671 { 0x1c, 0x8d68 },
672 { 0x1c, 0x8d68 },
673 { 0, 0 },
674 };
675 int i;
676
677 for (i = 0; dspcode[i].reg != 0; i++)
678 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
679 }
680
681 static void
682 bcm5750_load_dspcode(struct mii_softc *sc)
683 {
684 static const struct {
685 int reg;
686 uint16_t val;
687 } dspcode[] = {
688 { BRGPHY_MII_AUXCTL, 0x0c00 },
689 { BRGPHY_MII_DSP_ADDR_REG, 0x000a },
690 { BRGPHY_MII_DSP_RW_PORT, 0x310b },
691 { BRGPHY_MII_DSP_ADDR_REG, 0x201f },
692 { BRGPHY_MII_DSP_RW_PORT, 0x9506 },
693 { BRGPHY_MII_DSP_ADDR_REG, 0x401f },
694 { BRGPHY_MII_DSP_RW_PORT, 0x14e2 },
695 { BRGPHY_MII_AUXCTL, 0x0400 },
696 { 0, 0 },
697 };
698 int i;
699
700 for (i = 0; dspcode[i].reg != 0; i++)
701 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
702 }
703
704 static void
705 bcm5755_load_dspcode(struct mii_softc *sc)
706 {
707 static const struct {
708 int reg;
709 uint16_t val;
710 } dspcode[] = {
711 { BRGPHY_MII_AUXCTL, 0x0c00 },
712 { BRGPHY_MII_DSP_ADDR_REG, 0x000a },
713 { BRGPHY_MII_DSP_RW_PORT, 0x010b },
714
715 { BRGPHY_MII_AUXCTL, 0x0400 },
716 { 0, 0 },
717 };
718 int i;
719
720 for (i = 0; dspcode[i].reg != 0; i++)
721 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
722 }
723