brgphy.c revision 1.36 1 /* $NetBSD: brgphy.c,v 1.36 2008/02/20 11:26:03 markd 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.36 2008/02/20 11:26:03 markd 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_BROADCOM, MII_MODEL_BROADCOM_BCM5708C,
185 MII_STR_BROADCOM_BCM5708C },
186
187 { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5755,
188 MII_STR_BROADCOM2_BCM5755 },
189
190 { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5754,
191 MII_STR_BROADCOM2_BCM5754 },
192
193 { 0, 0,
194 NULL },
195 };
196
197 static void bcm5401_load_dspcode(struct mii_softc *);
198 static void bcm5411_load_dspcode(struct mii_softc *);
199 static void bcm5703_load_dspcode(struct mii_softc *);
200 static void bcm5704_load_dspcode(struct mii_softc *);
201 static void bcm5750_load_dspcode(struct mii_softc *);
202 static void bcm5755_load_dspcode(struct mii_softc *);
203
204 static int
205 brgphymatch(struct device *parent, struct cfdata *match,
206 void *aux)
207 {
208 struct mii_attach_args *ma = aux;
209
210 if (mii_phy_match(ma, brgphys) != NULL)
211 return (10);
212
213 return (0);
214 }
215
216 static void
217 brgphyattach(struct device *parent, struct device *self, void *aux)
218 {
219 struct mii_softc *sc = device_private(self);
220 struct mii_attach_args *ma = aux;
221 struct mii_data *mii = ma->mii_data;
222 const struct mii_phydesc *mpd;
223
224 mpd = mii_phy_match(ma, brgphys);
225 aprint_naive(": Media interface\n");
226 aprint_normal(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
227
228 sc->mii_inst = mii->mii_instance;
229 sc->mii_phy = ma->mii_phyno;
230 sc->mii_mpd_model = MII_MODEL(ma->mii_id2);
231 sc->mii_pdata = mii;
232 sc->mii_flags = ma->mii_flags;
233 sc->mii_anegticks = MII_ANEGTICKS;
234
235 switch (MII_MODEL(ma->mii_id2)) {
236 case MII_MODEL_BROADCOM_BCM5400:
237 sc->mii_funcs = &brgphy_5401_funcs;
238 aprint_normal("%s: using BCM5401 DSP patch\n",
239 sc->mii_dev.dv_xname);
240 break;
241
242 case MII_MODEL_BROADCOM_BCM5401:
243 if (MII_REV(ma->mii_id2) == 1 || MII_REV(ma->mii_id2) == 3) {
244 sc->mii_funcs = &brgphy_5401_funcs;
245 aprint_normal("%s: using BCM5401 DSP patch\n",
246 sc->mii_dev.dv_xname);
247 } else
248 sc->mii_funcs = &brgphy_funcs;
249 break;
250
251 case MII_MODEL_BROADCOM_BCM5411:
252 sc->mii_funcs = &brgphy_5411_funcs;
253 aprint_normal("%s: using BCM5411 DSP patch\n",
254 sc->mii_dev.dv_xname);
255 break;
256
257 #ifdef notyet /* unverified, untested */
258 case MII_MODEL_BROADCOM_BCM5703:
259 sc->mii_funcs = &brgphy_5703_funcs;
260 aprint_normal("%s: using BCM5703 DSP patch\n",
261 sc->mii_dev.dv_xname);
262 break;
263 #endif
264
265 case MII_MODEL_BROADCOM_BCM5704:
266 sc->mii_funcs = &brgphy_5704_funcs;
267 aprint_normal("%s: using BCM5704 DSP patch\n",
268 sc->mii_dev.dv_xname);
269 break;
270
271 case MII_MODEL_BROADCOM_BCM5705:
272 sc->mii_funcs = &brgphy_5705_funcs;
273 break;
274
275 case MII_MODEL_BROADCOM_BCM5714:
276 case MII_MODEL_BROADCOM_BCM5780:
277 case MII_MODEL_BROADCOM_BCM5708C:
278 case MII_MODEL_BROADCOM_BCM5750:
279 case MII_MODEL_BROADCOM_BCM5752:
280 sc->mii_funcs = &brgphy_5750_funcs;
281 break;
282
283 case MII_MODEL_BROADCOM2_BCM5754:
284 case MII_MODEL_BROADCOM2_BCM5755:
285 sc->mii_funcs = &brgphy_5755_funcs;
286 break;
287
288 default:
289 sc->mii_funcs = &brgphy_funcs;
290 break;
291 }
292
293 PHY_RESET(sc);
294
295 sc->mii_capabilities =
296 PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
297 if (sc->mii_capabilities & BMSR_EXTSTAT)
298 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
299
300 aprint_normal("%s: ", sc->mii_dev.dv_xname);
301 if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
302 (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
303 aprint_error("no media present");
304 else
305 mii_phy_add_media(sc);
306 aprint_normal("\n");
307
308 if (!pmf_device_register(self, NULL, mii_phy_resume))
309 aprint_error_dev(self, "couldn't establish power handler\n");
310 }
311
312 static int
313 brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
314 {
315 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
316 int reg, speed, gig;
317
318 switch (cmd) {
319 case MII_POLLSTAT:
320 /*
321 * If we're not polling our PHY instance, just return.
322 */
323 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
324 return (0);
325 break;
326
327 case MII_MEDIACHG:
328 /*
329 * If the media indicates a different PHY instance,
330 * isolate ourselves.
331 */
332 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
333 reg = PHY_READ(sc, MII_BMCR);
334 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
335 return (0);
336 }
337
338 /*
339 * If the interface is not up, don't do anything.
340 */
341 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
342 break;
343
344 PHY_RESET(sc); /* XXX hardware bug work-around */
345
346 switch (IFM_SUBTYPE(ife->ifm_media)) {
347 case IFM_AUTO:
348 (void) brgphy_mii_phy_auto(sc);
349 break;
350 case IFM_1000_T:
351 speed = BMCR_S1000;
352 goto setit;
353 case IFM_100_TX:
354 speed = BMCR_S100;
355 goto setit;
356 case IFM_10_T:
357 speed = BMCR_S10;
358 setit:
359 brgphy_loop(sc);
360 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
361 speed |= BMCR_FDX;
362 gig = GTCR_ADV_1000TFDX;
363 } else {
364 gig = GTCR_ADV_1000THDX;
365 }
366
367 PHY_WRITE(sc, MII_100T2CR, 0);
368 PHY_WRITE(sc, MII_BMCR, speed);
369 PHY_WRITE(sc, MII_ANAR, ANAR_CSMA);
370
371 if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T)
372 break;
373
374 PHY_WRITE(sc, MII_100T2CR, gig);
375 PHY_WRITE(sc, MII_BMCR,
376 speed|BMCR_AUTOEN|BMCR_STARTNEG);
377
378 if (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 /*
392 * If we're not currently selected, just return.
393 */
394 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
395 return (0);
396
397 if (mii_phy_tick(sc) == EJUSTRETURN)
398 return (0);
399 break;
400
401 case MII_DOWN:
402 mii_phy_down(sc);
403 return (0);
404 }
405
406 /* Update the media status. */
407 mii_phy_status(sc);
408
409 /*
410 * Callback if something changed. Note that we need to poke the DSP on
411 * the Broadcom PHYs if the media changes.
412 */
413 if (sc->mii_media_active != mii->mii_media_active ||
414 sc->mii_media_status != mii->mii_media_status ||
415 cmd == MII_MEDIACHG) {
416 mii_phy_update(sc, cmd);
417 if (sc->mii_funcs == &brgphy_5401_funcs)
418 bcm5401_load_dspcode(sc);
419 else if (sc->mii_funcs == &brgphy_5411_funcs)
420 bcm5411_load_dspcode(sc);
421 }
422 return (0);
423 }
424
425 static void
426 brgphy_status(struct mii_softc *sc)
427 {
428 struct mii_data *mii = sc->mii_pdata;
429 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
430 int bmcr, auxsts, gtsr;
431
432 mii->mii_media_status = IFM_AVALID;
433 mii->mii_media_active = IFM_ETHER;
434
435 auxsts = PHY_READ(sc, BRGPHY_MII_AUXSTS);
436
437 if (auxsts & BRGPHY_AUXSTS_LINK)
438 mii->mii_media_status |= IFM_ACTIVE;
439
440 bmcr = PHY_READ(sc, MII_BMCR);
441 if (bmcr & BMCR_ISO) {
442 mii->mii_media_active |= IFM_NONE;
443 mii->mii_media_status = 0;
444 return;
445 }
446
447 if (bmcr & BMCR_LOOP)
448 mii->mii_media_active |= IFM_LOOP;
449
450 if (bmcr & BMCR_AUTOEN) {
451 /*
452 * The media status bits are only valid of autonegotiation
453 * has completed (or it's disabled).
454 */
455 if ((auxsts & BRGPHY_AUXSTS_ACOMP) == 0) {
456 /* Erg, still trying, I guess... */
457 mii->mii_media_active |= IFM_NONE;
458 return;
459 }
460
461 switch (auxsts & BRGPHY_AUXSTS_AN_RES) {
462 case BRGPHY_RES_1000FD:
463 mii->mii_media_active |= IFM_1000_T|IFM_FDX;
464 gtsr = PHY_READ(sc, MII_100T2SR);
465 if (gtsr & GTSR_MS_RES)
466 mii->mii_media_active |= IFM_ETH_MASTER;
467 break;
468
469 case BRGPHY_RES_1000HD:
470 mii->mii_media_active |= IFM_1000_T;
471 gtsr = PHY_READ(sc, MII_100T2SR);
472 if (gtsr & GTSR_MS_RES)
473 mii->mii_media_active |= IFM_ETH_MASTER;
474 break;
475
476 case BRGPHY_RES_100FD:
477 mii->mii_media_active |= IFM_100_TX|IFM_FDX;
478 break;
479
480 case BRGPHY_RES_100T4:
481 mii->mii_media_active |= IFM_100_T4;
482 break;
483
484 case BRGPHY_RES_100HD:
485 mii->mii_media_active |= IFM_100_TX;
486 break;
487
488 case BRGPHY_RES_10FD:
489 mii->mii_media_active |= IFM_10_T|IFM_FDX;
490 break;
491
492 case BRGPHY_RES_10HD:
493 mii->mii_media_active |= IFM_10_T;
494 break;
495
496 default:
497 mii->mii_media_active |= IFM_NONE;
498 mii->mii_media_status = 0;
499 }
500 if (mii->mii_media_active & IFM_FDX)
501 mii->mii_media_active |= mii_phy_flowstatus(sc);
502 } else
503 mii->mii_media_active = ife->ifm_media;
504 }
505
506 int
507 brgphy_mii_phy_auto(struct mii_softc *sc)
508 {
509 int anar, ktcr = 0;
510
511 brgphy_loop(sc);
512 PHY_RESET(sc);
513 ktcr = GTCR_ADV_1000TFDX|GTCR_ADV_1000THDX;
514 if (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5701)
515 ktcr |= GTCR_MAN_MS|GTCR_ADV_MS;
516 PHY_WRITE(sc, MII_100T2CR, ktcr);
517 ktcr = PHY_READ(sc, MII_100T2CR);
518 DELAY(1000);
519 anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA;
520 if (sc->mii_flags & MIIF_DOPAUSE)
521 anar |= ANAR_FC| ANAR_X_PAUSE_ASYM;
522
523 PHY_WRITE(sc, MII_ANAR, anar);
524 DELAY(1000);
525 PHY_WRITE(sc, MII_BMCR,
526 BMCR_AUTOEN | BMCR_STARTNEG);
527 PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00);
528
529 return (EJUSTRETURN);
530 }
531
532 void
533 brgphy_loop(struct mii_softc *sc)
534 {
535 u_int32_t bmsr;
536 int i;
537
538 PHY_WRITE(sc, MII_BMCR, BMCR_LOOP);
539 for (i = 0; i < 15000; i++) {
540 bmsr = PHY_READ(sc, MII_BMSR);
541 if (!(bmsr & BMSR_LINK))
542 break;
543 DELAY(10);
544 }
545 }
546
547 static void
548 brgphy_5401_reset(struct mii_softc *sc)
549 {
550
551 mii_phy_reset(sc);
552 bcm5401_load_dspcode(sc);
553 }
554
555 static void
556 brgphy_5411_reset(struct mii_softc *sc)
557 {
558
559 mii_phy_reset(sc);
560 bcm5411_load_dspcode(sc);
561 }
562
563
564 static void
565 brgphy_5703_reset(struct mii_softc *sc)
566 {
567
568 mii_phy_reset(sc);
569 bcm5703_load_dspcode(sc);
570 }
571
572 static void
573 brgphy_5704_reset(struct mii_softc *sc)
574 {
575
576 mii_phy_reset(sc);
577 bcm5704_load_dspcode(sc);
578 }
579
580 /*
581 * Hardware bug workaround. Do nothing since after
582 * reset the 5705 PHY would get stuck in 10/100 MII mode.
583 */
584
585 static void
586 brgphy_5705_reset(struct mii_softc *sc)
587 {
588 }
589
590 static void
591 brgphy_5750_reset(struct mii_softc *sc)
592 {
593 mii_phy_reset(sc);
594 bcm5750_load_dspcode(sc);
595 }
596
597 static void
598 brgphy_5755_reset(struct mii_softc *sc)
599 {
600 mii_phy_reset(sc);
601 bcm5755_load_dspcode(sc);
602 }
603
604 /* Turn off tap power management on 5401. */
605 static void
606 bcm5401_load_dspcode(struct mii_softc *sc)
607 {
608 static const struct {
609 int reg;
610 uint16_t val;
611 } dspcode[] = {
612 { BRGPHY_MII_AUXCTL, 0x0c20 },
613 { BRGPHY_MII_DSP_ADDR_REG, 0x0012 },
614 { BRGPHY_MII_DSP_RW_PORT, 0x1804 },
615 { BRGPHY_MII_DSP_ADDR_REG, 0x0013 },
616 { BRGPHY_MII_DSP_RW_PORT, 0x1204 },
617 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 },
618 { BRGPHY_MII_DSP_RW_PORT, 0x0132 },
619 { BRGPHY_MII_DSP_ADDR_REG, 0x8006 },
620 { BRGPHY_MII_DSP_RW_PORT, 0x0232 },
621 { BRGPHY_MII_DSP_ADDR_REG, 0x201f },
622 { BRGPHY_MII_DSP_RW_PORT, 0x0a20 },
623 { 0, 0 },
624 };
625 int i;
626
627 for (i = 0; dspcode[i].reg != 0; i++)
628 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
629 delay(40);
630 }
631
632 static void
633 bcm5411_load_dspcode(struct mii_softc *sc)
634 {
635 static const struct {
636 int reg;
637 uint16_t val;
638 } dspcode[] = {
639 { 0x1c, 0x8c23 },
640 { 0x1c, 0x8ca3 },
641 { 0x1c, 0x8c23 },
642 { 0, 0 },
643 };
644 int i;
645
646 for (i = 0; dspcode[i].reg != 0; i++)
647 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
648 }
649
650 static void
651 bcm5703_load_dspcode(struct mii_softc *sc)
652 {
653 static const struct {
654 int reg;
655 uint16_t val;
656 } dspcode[] = {
657 { BRGPHY_MII_AUXCTL, 0x0c00 },
658 { BRGPHY_MII_DSP_ADDR_REG, 0x201f },
659 { BRGPHY_MII_DSP_RW_PORT, 0x2aaa },
660 { 0, 0 },
661 };
662 int i;
663
664 for (i = 0; dspcode[i].reg != 0; i++)
665 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
666 }
667
668 static void
669 bcm5704_load_dspcode(struct mii_softc *sc)
670 {
671 static const struct {
672 int reg;
673 uint16_t val;
674 } dspcode[] = {
675 { 0x1c, 0x8d68 },
676 { 0x1c, 0x8d68 },
677 { 0, 0 },
678 };
679 int i;
680
681 for (i = 0; dspcode[i].reg != 0; i++)
682 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
683 }
684
685 static void
686 bcm5750_load_dspcode(struct mii_softc *sc)
687 {
688 static const struct {
689 int reg;
690 uint16_t val;
691 } dspcode[] = {
692 { BRGPHY_MII_AUXCTL, 0x0c00 },
693 { BRGPHY_MII_DSP_ADDR_REG, 0x000a },
694 { BRGPHY_MII_DSP_RW_PORT, 0x310b },
695 { BRGPHY_MII_DSP_ADDR_REG, 0x201f },
696 { BRGPHY_MII_DSP_RW_PORT, 0x9506 },
697 { BRGPHY_MII_DSP_ADDR_REG, 0x401f },
698 { BRGPHY_MII_DSP_RW_PORT, 0x14e2 },
699 { BRGPHY_MII_AUXCTL, 0x0400 },
700 { 0, 0 },
701 };
702 int i;
703
704 for (i = 0; dspcode[i].reg != 0; i++)
705 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
706 }
707
708 static void
709 bcm5755_load_dspcode(struct mii_softc *sc)
710 {
711 static const struct {
712 int reg;
713 uint16_t val;
714 } dspcode[] = {
715 { BRGPHY_MII_AUXCTL, 0x0c00 },
716 { BRGPHY_MII_DSP_ADDR_REG, 0x000a },
717 { BRGPHY_MII_DSP_RW_PORT, 0x010b },
718
719 { BRGPHY_MII_AUXCTL, 0x0400 },
720 { 0, 0 },
721 };
722 int i;
723
724 for (i = 0; dspcode[i].reg != 0; i++)
725 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
726 }
727