bce(4): Add BCM5709 and BCM5716 support
[dragonfly.git] / sys / dev / netif / mii_layer / brgphy.c
1 /*      $OpenBSD: brgphy.c,v 1.48 2006/05/20 23:03:53 brad Exp $        */
2
3 /*
4  * Copyright (c) 2000
5  *      Bill Paul <wpaul@ee.columbia.edu>.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Bill Paul.
18  * 4. Neither the name of the author nor the names of any co-contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32  * THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  * $FreeBSD: src/sys/dev/mii/brgphy.c,v 1.1.2.7 2003/05/11 18:00:55 ps Exp $
35  */
36
37 /*
38  * Driver for the Broadcom BCR5400 1000baseT PHY. Speed is always
39  * 1000mbps; all we need to negotiate here is full or half duplex.
40  */
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/socket.h>
46 #include <sys/bus.h>
47 #include <sys/sysctl.h>
48
49 #include <net/ethernet.h>
50 #include <net/if.h>
51 #include <net/if_media.h>
52 #include <net/if_arp.h>
53
54 #include "mii.h"
55 #include "miivar.h"
56 #include "miidevs.h"
57
58 #include "brgphyreg.h"
59 #include <dev/netif/bge/if_bgereg.h>
60 #include <dev/netif/bce/if_bcereg.h>
61
62 #include "miibus_if.h"
63
64 static int brgphy_probe(device_t);
65 static int brgphy_attach(device_t);
66
67 static const struct mii_phydesc brgphys[] = {
68         MII_PHYDESC(xxBROADCOM, BCM5400),
69         MII_PHYDESC(xxBROADCOM, BCM5401),
70         MII_PHYDESC(xxBROADCOM, BCM5411),
71         MII_PHYDESC(xxBROADCOM, BCM5421),
72         MII_PHYDESC(xxBROADCOM, BCM54K2),
73         MII_PHYDESC(xxBROADCOM, BCM5462),
74
75         MII_PHYDESC(xxBROADCOM, BCM5701),
76         MII_PHYDESC(xxBROADCOM, BCM5703),
77         MII_PHYDESC(xxBROADCOM, BCM5704),
78         MII_PHYDESC(xxBROADCOM, BCM5705),
79
80         MII_PHYDESC(xxBROADCOM, BCM5714),
81         MII_PHYDESC(xxBROADCOM2,BCM5722),
82         MII_PHYDESC(xxBROADCOM, BCM5750),
83         MII_PHYDESC(xxBROADCOM, BCM5752),
84         MII_PHYDESC(xxBROADCOM2,BCM5755),
85         MII_PHYDESC(xxBROADCOM, BCM5780),
86         MII_PHYDESC(xxBROADCOM2,BCM5787),
87
88         MII_PHYDESC(xxBROADCOM, BCM5706C),
89         MII_PHYDESC(xxBROADCOM, BCM5708C),
90         MII_PHYDESC(xxBROADCOM2, BCM5709CAX),
91         MII_PHYDESC(xxBROADCOM2, BCM5709C),
92
93         MII_PHYDESC(BROADCOM2, BCM5906),
94
95         MII_PHYDESC_NULL
96 };
97
98 static device_method_t brgphy_methods[] = {
99         /* device interface */
100         DEVMETHOD(device_probe,         brgphy_probe),
101         DEVMETHOD(device_attach,        brgphy_attach),
102         DEVMETHOD(device_detach,        ukphy_detach),
103         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
104         { 0, 0 }
105 };
106
107 static devclass_t brgphy_devclass;
108
109 static driver_t brgphy_driver = {
110         "brgphy",
111         brgphy_methods,
112         sizeof(struct mii_softc)
113 };
114
115 DRIVER_MODULE(brgphy, miibus, brgphy_driver, brgphy_devclass, NULL, NULL);
116
117 static int      brgphy_service(struct mii_softc *, struct mii_data *, int);
118 static void     brgphy_status(struct mii_softc *);
119 static void     brgphy_mii_phy_auto(struct mii_softc *);
120 static void     brgphy_reset(struct mii_softc *);
121 static void     brgphy_loop(struct mii_softc *);
122
123 static void     brgphy_bcm5401_dspcode(struct mii_softc *);
124 static void     brgphy_bcm5411_dspcode(struct mii_softc *);
125 static void     brgphy_bcm5421_dspcode(struct mii_softc *);
126 static void     brgphy_bcm54k2_dspcode(struct mii_softc *);
127
128 static void     brgphy_adc_bug(struct mii_softc *);
129 static void     brgphy_5704_a0_bug(struct mii_softc *);
130 static void     brgphy_ber_bug(struct mii_softc *);
131 static void     brgphy_crc_bug(struct mii_softc *);
132
133 static void     brgphy_disable_early_dac(struct mii_softc *);
134 static void     brgphy_jumbo_settings(struct mii_softc *, u_long);
135 static void     brgphy_eth_wirespeed(struct mii_softc *);
136
137 static int
138 brgphy_probe(device_t dev)
139 {
140         struct mii_attach_args *ma = device_get_ivars(dev);
141         const struct mii_phydesc *mpd;
142
143         mpd = mii_phy_match(ma, brgphys);
144         if (mpd != NULL) {
145                 device_set_desc(dev, mpd->mpd_name);
146                 return (0);
147         }
148         return(ENXIO);
149 }
150
151 static int
152 brgphy_attach(device_t dev)
153 {
154         struct mii_softc *sc;
155         struct mii_attach_args *ma;
156         struct mii_data *mii;
157
158         sc = device_get_softc(dev);
159         ma = device_get_ivars(dev);
160         mii_softc_init(sc, ma);
161         sc->mii_dev = device_get_parent(dev);
162         mii = device_get_softc(sc->mii_dev);
163         LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
164
165         sc->mii_inst = mii->mii_instance;
166         sc->mii_service = brgphy_service;
167         sc->mii_reset = brgphy_reset;
168         sc->mii_pdata = mii;
169
170         sc->mii_flags |= MIIF_NOISOLATE;
171         mii->mii_instance++;
172
173         brgphy_reset(sc);
174
175 #define ADD(m, c)       ifmedia_add(&mii->mii_media, (m), (c), NULL)
176
177         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
178             MII_MEDIA_NONE);
179 #if 0
180         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
181             MII_MEDIA_100_TX);
182 #endif
183
184 #undef ADD
185
186         sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
187         if (sc->mii_capabilities & BMSR_EXTSTAT)
188                 sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
189
190         device_printf(dev, " ");
191         if ((sc->mii_capabilities & BMSR_MEDIAMASK) ||
192             (sc->mii_extcapabilities & EXTSR_MEDIAMASK))
193                 mii_phy_add_media(sc);
194         else
195                 kprintf("no media present");
196         kprintf("\n");
197
198         MIIBUS_MEDIAINIT(sc->mii_dev);
199         return(0);
200 }
201
202 static int
203 brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
204 {
205         struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
206         int reg, speed, gig;
207
208         switch (cmd) {
209         case MII_POLLSTAT:
210                 /*
211                  * If we're not polling our PHY instance, just return.
212                  */
213                 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
214                         return (0);
215                 break;
216
217         case MII_MEDIACHG:
218                 /*
219                  * If the media indicates a different PHY instance,
220                  * isolate ourselves.
221                  */
222                 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
223                         reg = PHY_READ(sc, MII_BMCR);
224                         PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
225                         return (0);
226                 }
227
228                 /*
229                  * If the interface is not up, don't do anything.
230                  */
231                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
232                         break;
233
234                 brgphy_reset(sc);       /* XXX hardware bug work-around */
235
236                 switch (IFM_SUBTYPE(ife->ifm_media)) {
237                 case IFM_AUTO:
238 #ifdef foo
239                         /*
240                          * If we're already in auto mode, just return.
241                          */
242                         if (PHY_READ(sc, BRGPHY_MII_BMCR) & BRGPHY_BMCR_AUTOEN)
243                                 return (0);
244 #endif
245                         brgphy_mii_phy_auto(sc);
246                         break;
247                 case IFM_1000_T:
248                         speed = BRGPHY_S1000;
249                         goto setit;
250                 case IFM_100_TX:
251                         speed = BRGPHY_S100;
252                         goto setit;
253                 case IFM_10_T:
254                         speed = BRGPHY_S10;
255 setit:
256                         brgphy_loop(sc);
257                         if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
258                                 speed |= BRGPHY_BMCR_FDX;
259                                 gig = BRGPHY_1000CTL_AFD;
260                         } else {
261                                 gig = BRGPHY_1000CTL_AHD;
262                         }
263
264                         PHY_WRITE(sc, BRGPHY_MII_1000CTL, 0);
265                         PHY_WRITE(sc, BRGPHY_MII_ANAR, BRGPHY_SEL_TYPE);
266                         PHY_WRITE(sc, BRGPHY_MII_BMCR, speed);
267
268                         if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T)
269                                 break;
270
271                         PHY_WRITE(sc, BRGPHY_MII_1000CTL, gig);
272                         PHY_WRITE(sc, BRGPHY_MII_BMCR,
273                             speed|BRGPHY_BMCR_AUTOEN|BRGPHY_BMCR_STARTNEG);
274
275                         if (sc->mii_model != MII_MODEL_xxBROADCOM_BCM5701)
276                                 break;
277
278                         /*
279                          * When settning the link manually, one side must
280                          * be the master and the other the slave. However
281                          * ifmedia doesn't give us a good way to specify
282                          * this, so we fake it by using one of the LINK
283                          * flags. If LINK0 is set, we program the PHY to
284                          * be a master, otherwise it's a slave.
285                          */
286                         if ((mii->mii_ifp->if_flags & IFF_LINK0)) {
287                                 PHY_WRITE(sc, BRGPHY_MII_1000CTL,
288                                     gig|BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC);
289                         } else {
290                                 PHY_WRITE(sc, BRGPHY_MII_1000CTL,
291                                     gig|BRGPHY_1000CTL_MSE);
292                         }
293                         break;
294 #ifdef foo
295                 case IFM_NONE:
296                         PHY_WRITE(sc, MII_BMCR, BMCR_ISO|BMCR_PDOWN);
297                         break;
298 #endif
299                 case IFM_100_T4:
300                 default:
301                         return (EINVAL);
302                 }
303                 break;
304
305         case MII_TICK:
306                 /*
307                  * If we're not currently selected, just return.
308                  */
309                 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
310                         return (0);
311
312                 /*
313                  * Is the interface even up?
314                  */
315                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
316                         return (0);
317
318                 /*
319                  * Only used for autonegotiation.
320                  */
321                 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
322                         break;
323
324                 /*
325                  * Check to see if we have link.  If we do, we don't
326                  * need to restart the autonegotiation process.
327                  */
328                 reg = PHY_READ(sc, BRGPHY_MII_AUXSTS);
329                 if (reg & BRGPHY_AUXSTS_LINK) {
330                         sc->mii_ticks = 0;
331                         break;
332                 }
333
334                 /*
335                  * Only retry autonegotiation every 5 seconds.
336                  */
337                 if (++sc->mii_ticks <= sc->mii_anegticks)
338                         break;
339                 
340                 sc->mii_ticks = 0;
341                 brgphy_mii_phy_auto(sc);
342                 break;
343         }
344
345         /* Update the media status. */
346         brgphy_status(sc);
347
348         /*
349          * Callback if something changed. Note that we need to poke
350          * the DSP on the Broadcom PHYs if the media changes.
351          */
352         if (sc->mii_media_active != mii->mii_media_active ||
353             sc->mii_media_status != mii->mii_media_status ||
354             cmd == MII_MEDIACHG) {
355                 switch (sc->mii_model) {
356                 case MII_MODEL_xxBROADCOM_BCM5400:
357                         brgphy_bcm5401_dspcode(sc);
358                         break;
359                 case MII_MODEL_xxBROADCOM_BCM5401:
360                         if (sc->mii_rev == 1 || sc->mii_rev == 3)
361                                 brgphy_bcm5401_dspcode(sc);
362                         break;
363                 case MII_MODEL_xxBROADCOM_BCM5411:
364                         brgphy_bcm5411_dspcode(sc);
365                         break;
366                 }
367         }
368         mii_phy_update(sc, cmd);
369         return (0);
370 }
371
372 static void
373 brgphy_status(struct mii_softc *sc)
374 {
375         struct mii_data *mii = sc->mii_pdata;
376         int bmcr, aux;
377
378         mii->mii_media_status = IFM_AVALID;
379         mii->mii_media_active = IFM_ETHER;
380
381         aux = PHY_READ(sc, BRGPHY_MII_AUXSTS);
382         if (aux & BRGPHY_AUXSTS_LINK)
383                 mii->mii_media_status |= IFM_ACTIVE;
384
385         bmcr = PHY_READ(sc, BRGPHY_MII_BMCR);
386         if (bmcr & BRGPHY_BMCR_LOOP)
387                 mii->mii_media_active |= IFM_LOOP;
388
389         if (bmcr & BRGPHY_BMCR_AUTOEN) {
390                 if ((PHY_READ(sc, BRGPHY_MII_BMSR) & BRGPHY_BMSR_ACOMP) == 0) {
391                         /* Erg, still trying, I guess... */
392                         mii->mii_media_active |= IFM_NONE;
393                         return;
394                 }
395
396                 switch (aux & BRGPHY_AUXSTS_AN_RES) {
397                 case BRGPHY_RES_1000FD:
398                         mii->mii_media_active |= IFM_1000_T | IFM_FDX;
399                         break;
400                 case BRGPHY_RES_1000HD:
401                         mii->mii_media_active |= IFM_1000_T | IFM_HDX;
402                         break;
403                 case BRGPHY_RES_100FD:
404                         mii->mii_media_active |= IFM_100_TX | IFM_FDX;
405                         break;
406                 case BRGPHY_RES_100T4:
407                         mii->mii_media_active |= IFM_100_T4;
408                         break;
409                 case BRGPHY_RES_100HD:
410                         mii->mii_media_active |= IFM_100_TX | IFM_HDX;
411                         break;
412                 case BRGPHY_RES_10FD:
413                         mii->mii_media_active |= IFM_10_T | IFM_FDX;
414                         break;
415                 case BRGPHY_RES_10HD:
416                         mii->mii_media_active |= IFM_10_T | IFM_HDX;
417                         break;
418                 default:
419                         mii->mii_media_active |= IFM_NONE;
420                         break;
421                 }
422         } else {
423                 mii->mii_media_active = mii->mii_media.ifm_cur->ifm_media;
424         }
425 }
426
427
428 static void
429 brgphy_mii_phy_auto(struct mii_softc *sc)
430 {
431         int ktcr = 0;
432
433         brgphy_loop(sc);
434         brgphy_reset(sc);
435         ktcr = BRGPHY_1000CTL_AFD|BRGPHY_1000CTL_AHD;
436         if (sc->mii_model == MII_MODEL_xxBROADCOM_BCM5701)
437                 ktcr |= BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC;
438         PHY_WRITE(sc, BRGPHY_MII_1000CTL, ktcr);
439         ktcr = PHY_READ(sc, BRGPHY_MII_1000CTL);
440         DELAY(1000);
441         PHY_WRITE(sc, BRGPHY_MII_ANAR,
442             BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA);
443         DELAY(1000);
444         PHY_WRITE(sc, BRGPHY_MII_BMCR,
445             BRGPHY_BMCR_AUTOEN | BRGPHY_BMCR_STARTNEG);
446         PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00);
447 }
448
449 static void
450 brgphy_loop(struct mii_softc *sc)
451 {
452         uint32_t bmsr;
453         int i;
454
455         PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_LOOP);
456         for (i = 0; i < 15000; i++) {
457                 bmsr = PHY_READ(sc, BRGPHY_MII_BMSR);
458                 if (!(bmsr & BRGPHY_BMSR_LINK))
459                         break;
460                 DELAY(10);
461         }
462 }
463
464 static void
465 brgphy_reset(struct mii_softc *sc)
466 {
467         struct ifnet *ifp;
468
469         mii_phy_reset(sc);
470
471         switch (sc->mii_model) {
472         case MII_MODEL_xxBROADCOM_BCM5400:
473                 brgphy_bcm5401_dspcode(sc);
474                         break;
475         case MII_MODEL_xxBROADCOM_BCM5401:
476                 if (sc->mii_rev == 1 || sc->mii_rev == 3)
477                         brgphy_bcm5401_dspcode(sc);
478                 break;
479         case MII_MODEL_xxBROADCOM_BCM5411:
480                 brgphy_bcm5411_dspcode(sc);
481                 break;
482         case MII_MODEL_xxBROADCOM_BCM5421:
483                 brgphy_bcm5421_dspcode(sc);
484                 break;
485         case MII_MODEL_xxBROADCOM_BCM54K2:
486                 brgphy_bcm54k2_dspcode(sc);
487                 break;
488         }
489
490         ifp = sc->mii_pdata->mii_ifp;
491         if (strncmp(ifp->if_xname, "bge", 3) == 0) {
492                 struct bge_softc *bge_sc = ifp->if_softc;
493
494                 if (bge_sc->bge_flags & BGE_FLAG_ADC_BUG)
495                         brgphy_adc_bug(sc);
496                 if (bge_sc->bge_flags & BGE_FLAG_5704_A0_BUG)
497                         brgphy_5704_a0_bug(sc);
498                 if (bge_sc->bge_flags & BGE_FLAG_BER_BUG) {
499                         brgphy_ber_bug(sc);
500                 } else if (bge_sc->bge_flags & BGE_FLAG_JITTER_BUG) {
501                         PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0c00);
502                         PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a);
503
504                         if (bge_sc->bge_flags & BGE_FLAG_ADJUST_TRIM) {
505                                 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, 0x110b);
506                                 PHY_WRITE(sc, BRGPHY_TEST1,
507                                     BRGPHY_TEST1_TRIM_EN | 0x4);
508                         } else {
509                                 PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, 0x010b);
510                         }
511
512                         PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0400);
513                 }
514                 if (bge_sc->bge_flags & BGE_FLAG_CRC_BUG)
515                         brgphy_crc_bug(sc);
516
517                 /* Set Jumbo frame settings in the PHY. */
518                 brgphy_jumbo_settings(sc, ifp->if_mtu);
519
520                 /* Enable Ethernet@Wirespeed */
521                 if (bge_sc->bge_flags & BGE_FLAG_ETH_WIRESPEED)
522                         brgphy_eth_wirespeed(sc);
523
524                 /* Enable Link LED on Dell boxes */
525                 if (bge_sc->bge_flags & BGE_FLAG_NO_3LED) {
526                         PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, 
527                         PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL)
528                                 & ~BRGPHY_PHY_EXTCTL_3_LED);
529                 }
530
531                 /* Adjust output voltage (From Linux driver) */
532                 if (bge_sc->bge_asicrev == BGE_ASICREV_BCM5906)
533                         PHY_WRITE(sc, BRGPHY_MII_EPHY_PTEST, 0x12);
534         } else if (strncmp(ifp->if_xname, "bce", 3) == 0) {
535                 struct bce_softc *bce_sc = ifp->if_softc;
536
537                 if (BCE_CHIP_NUM(bce_sc) == BCE_CHIP_NUM_5709) {
538                         if (BCE_CHIP_REV(bce_sc) == BCE_CHIP_REV_Ax ||
539                             BCE_CHIP_REV(bce_sc) == BCE_CHIP_REV_Bx)
540                                 brgphy_disable_early_dac(sc);
541                         brgphy_jumbo_settings(sc, ifp->if_mtu);
542                         brgphy_eth_wirespeed(sc);
543                 } else {
544                         brgphy_ber_bug(sc);
545                         brgphy_jumbo_settings(sc, ifp->if_mtu);
546                         brgphy_eth_wirespeed(sc);
547                 }
548         }
549 }
550
551 /* Turn off tap power management on 5401. */
552 static void
553 brgphy_bcm5401_dspcode(struct mii_softc *sc)
554 {
555         static const struct {
556                 int             reg;
557                 uint16_t        val;
558         } dspcode[] = {
559                 { BRGPHY_MII_AUXCTL,            0x0c20 },
560                 { BRGPHY_MII_DSP_ADDR_REG,      0x0012 },
561                 { BRGPHY_MII_DSP_RW_PORT,       0x1804 },
562                 { BRGPHY_MII_DSP_ADDR_REG,      0x0013 },
563                 { BRGPHY_MII_DSP_RW_PORT,       0x1204 },
564                 { BRGPHY_MII_DSP_ADDR_REG,      0x8006 },
565                 { BRGPHY_MII_DSP_RW_PORT,       0x0132 },
566                 { BRGPHY_MII_DSP_ADDR_REG,      0x8006 },
567                 { BRGPHY_MII_DSP_RW_PORT,       0x0232 },
568                 { BRGPHY_MII_DSP_ADDR_REG,      0x201f },
569                 { BRGPHY_MII_DSP_RW_PORT,       0x0a20 },
570                 { 0,                            0 },
571         };
572         int i;
573
574         for (i = 0; dspcode[i].reg != 0; i++)
575                 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
576         DELAY(40);
577 }
578
579 /* Setting some undocumented voltage */
580 static void
581 brgphy_bcm5411_dspcode(struct mii_softc *sc)
582 {
583         static const struct {
584                 int             reg;
585                 uint16_t        val;
586         } dspcode[] = {
587                 { 0x1c,                         0x8c23 },
588                 { 0x1c,                         0x8ca3 },
589                 { 0x1c,                         0x8c23 },
590                 { 0,                            0 },
591         };
592         int i;
593
594         for (i = 0; dspcode[i].reg != 0; i++)
595                 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
596 }
597
598 static void
599 brgphy_bcm5421_dspcode(struct mii_softc *sc)
600 {
601         uint16_t data;
602
603         /* Set Class A mode */
604         PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x1007);
605         data = PHY_READ(sc, BRGPHY_MII_AUXCTL);
606         PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0400);
607
608         /* Set FFE gamma override to -0.125 */
609         PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0007);
610         data = PHY_READ(sc, BRGPHY_MII_AUXCTL);
611         PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0800);
612         PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a);
613         data = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT);
614         PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, data | 0x0200);
615 }
616
617 static void
618 brgphy_bcm54k2_dspcode(struct mii_softc *sc)
619 {
620         static const struct {
621                 int             reg;
622                 uint16_t        val;
623         } dspcode[] = {
624                 { 4,                            0x01e1 },
625                 { 9,                            0x0300 },
626                 { 0,                            0 },
627         };
628         int i;
629
630         for (i = 0; dspcode[i].reg != 0; i++)
631                 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
632 }
633
634 static void
635 brgphy_adc_bug(struct mii_softc *sc)
636 {
637         static const struct {
638                 int             reg;
639                 uint16_t        val;
640         } dspcode[] = {
641                 { BRGPHY_MII_AUXCTL,            0x0c00 },
642                 { BRGPHY_MII_DSP_ADDR_REG,      0x201f },
643                 { BRGPHY_MII_DSP_RW_PORT,       0x2aaa },
644                 { BRGPHY_MII_DSP_ADDR_REG,      0x000a },
645                 { BRGPHY_MII_DSP_RW_PORT,       0x0323 },
646                 { BRGPHY_MII_AUXCTL,            0x0400 },
647                 { 0,                            0 },
648         };
649         int i;
650
651         for (i = 0; dspcode[i].reg != 0; i++)
652                 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
653 }
654
655 static void
656 brgphy_5704_a0_bug(struct mii_softc *sc)
657 {
658         static const struct {
659                 int             reg;
660                 u_int16_t       val;
661         } dspcode[] = {
662                 { 0x1c,                         0x8d68 },
663                 { 0x1c,                         0x8d68 },
664                 { 0,                            0 },
665         };
666         int i;
667
668         for (i = 0; dspcode[i].reg != 0; i++)
669                 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
670 }
671
672 static void
673 brgphy_ber_bug(struct mii_softc *sc)
674 {
675         static const struct {
676                 int             reg;
677                 uint16_t        val;
678         } dspcode[] = {
679                 { BRGPHY_MII_AUXCTL,            0x0c00 },
680                 { BRGPHY_MII_DSP_ADDR_REG,      0x000a },
681                 { BRGPHY_MII_DSP_RW_PORT,       0x310b },
682                 { BRGPHY_MII_DSP_ADDR_REG,      0x201f },
683                 { BRGPHY_MII_DSP_RW_PORT,       0x9506 },
684                 { BRGPHY_MII_DSP_ADDR_REG,      0x401f },
685                 { BRGPHY_MII_DSP_RW_PORT,       0x14e2 },
686                 { BRGPHY_MII_AUXCTL,            0x0400 },
687                 { 0,                            0 },
688         };
689         int i;
690
691         for (i = 0; dspcode[i].reg != 0; i++)
692                 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
693 }
694
695 static void
696 brgphy_crc_bug(struct mii_softc *sc)
697 {
698         static const struct {
699                 int             reg;
700                 uint16_t        val;
701         } dspcode[] = {
702                 { BRGPHY_MII_DSP_ADDR_REG,      0x0a75 },
703                 { 0x1c,                         0x8c68 },
704                 { 0x1c,                         0x8d68 },
705                 { 0x1c,                         0x8c68 },
706                 { 0,                            0 },
707         };
708         int i;
709
710         for (i = 0; dspcode[i].reg != 0; i++)
711                 PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
712 }
713
714 static void
715 brgphy_jumbo_settings(struct mii_softc *sc, u_long mtu)
716 {
717         uint32_t val;
718
719         /* Set or clear jumbo frame settings in the PHY. */
720         if (mtu > ETHER_MAX_LEN) {
721                 if (sc->mii_model == MII_MODEL_xxBROADCOM_BCM5401) {
722                         /* BCM5401 PHY cannot read-modify-write. */
723                         PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x4c20);
724                 } else {
725                         PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7);
726                         val = PHY_READ(sc, BRGPHY_MII_AUXCTL);
727                         PHY_WRITE(sc, BRGPHY_MII_AUXCTL,
728                             val | BRGPHY_AUXCTL_LONG_PKT);
729                 }
730
731                 val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL);
732                 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL,
733                     val | BRGPHY_PHY_EXTCTL_HIGH_LA);
734         } else {
735                 PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7);
736                 val = PHY_READ(sc, BRGPHY_MII_AUXCTL);
737                 PHY_WRITE(sc, BRGPHY_MII_AUXCTL,
738                     val & ~(BRGPHY_AUXCTL_LONG_PKT | 0x7));
739
740                 val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL);
741                 PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL,
742                     val & ~BRGPHY_PHY_EXTCTL_HIGH_LA);
743         }
744 }
745
746 static void
747 brgphy_eth_wirespeed(struct mii_softc *sc)
748 {
749         u_int32_t val;
750
751         /* Enable Ethernet@Wirespeed */
752         PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007);
753         val = PHY_READ(sc, BRGPHY_MII_AUXCTL);
754         PHY_WRITE(sc, BRGPHY_MII_AUXCTL, (val | (1 << 15) | (1 << 4)));
755 }
756
757 static void
758 brgphy_disable_early_dac(struct mii_softc *sc)
759 {
760         uint32_t val;
761
762         PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x0f08);
763         val = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT);
764         val &= ~(1 << 8);
765         PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, val);
766 }