xref: /openbsd/sys/dev/mii/brgphy.c (revision 3b9d585e)
1 /*	$OpenBSD: brgphy.c,v 1.109 2024/04/13 23:44:11 jsg 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: brgphy.c,v 1.8 2002/03/22 06:38:52 wpaul Exp $
35  */
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/device.h>
41 #include <sys/socket.h>
42 #include <sys/errno.h>
43 
44 #include <machine/bus.h>
45 
46 #include <net/if.h>
47 #include <net/if_media.h>
48 
49 #include <netinet/in.h>
50 #include <netinet/if_ether.h>
51 
52 #include <dev/pci/pcivar.h>
53 
54 #include <dev/mii/mii.h>
55 #include <dev/mii/miivar.h>
56 #include <dev/mii/miidevs.h>
57 
58 #include <dev/mii/brgphyreg.h>
59 
60 #include <dev/pci/if_bgereg.h>
61 #include <dev/pci/if_bnxreg.h>
62 
63 int brgphy_probe(struct device *, void *, void *);
64 void brgphy_attach(struct device *, struct device *, void *);
65 
66 const struct cfattach brgphy_ca = {
67 	sizeof(struct mii_softc), brgphy_probe, brgphy_attach, mii_phy_detach
68 };
69 
70 struct cfdriver brgphy_cd = {
71 	NULL, "brgphy", DV_DULL
72 };
73 
74 int	brgphy_service(struct mii_softc *, struct mii_data *, int);
75 void	brgphy_copper_status(struct mii_softc *);
76 void	brgphy_fiber_status(struct mii_softc *);
77 void	brgphy_5708s_status(struct mii_softc *);
78 void	brgphy_5709s_status(struct mii_softc *);
79 int	brgphy_mii_phy_auto(struct mii_softc *);
80 void	brgphy_loop(struct mii_softc *);
81 void	brgphy_reset(struct mii_softc *);
82 void	brgphy_reset_bge(struct mii_softc *);
83 void	brgphy_reset_bnx(struct mii_softc *);
84 void	brgphy_bcm5401_dspcode(struct mii_softc *);
85 void	brgphy_bcm5411_dspcode(struct mii_softc *);
86 void	brgphy_bcm5421_dspcode(struct mii_softc *);
87 void	brgphy_bcm54k2_dspcode(struct mii_softc *);
88 void	brgphy_adc_bug(struct mii_softc *);
89 void	brgphy_5704_a0_bug(struct mii_softc *);
90 void	brgphy_ber_bug(struct mii_softc *);
91 void	brgphy_crc_bug(struct mii_softc *);
92 void	brgphy_disable_early_dac(struct mii_softc *sc);
93 void	brgphy_jumbo_settings(struct mii_softc *);
94 void	brgphy_eth_wirespeed(struct mii_softc *);
95 void	brgphy_bcm54xx_clock_delay(struct mii_softc *);
96 
97 const struct mii_phy_funcs brgphy_copper_funcs = {
98 	brgphy_service, brgphy_copper_status, brgphy_reset,
99 };
100 
101 const struct mii_phy_funcs brgphy_fiber_funcs = {
102 	brgphy_service, brgphy_fiber_status, brgphy_reset,
103 };
104 
105 const struct mii_phy_funcs brgphy_5708s_funcs = {
106 	brgphy_service, brgphy_5708s_status, brgphy_reset,
107 };
108 
109 const struct mii_phy_funcs brgphy_5709s_funcs = {
110 	brgphy_service, brgphy_5709s_status, brgphy_reset,
111 };
112 
113 static const struct mii_phydesc brgphys[] = {
114 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5400,
115 	  MII_STR_xxBROADCOM_BCM5400 },
116 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5401,
117 	  MII_STR_xxBROADCOM_BCM5401 },
118 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5411,
119 	  MII_STR_xxBROADCOM_BCM5411 },
120 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5421,
121 	  MII_STR_xxBROADCOM_BCM5421 },
122 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM54K2,
123 	  MII_STR_xxBROADCOM_BCM54K2 },
124 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5461,
125 	  MII_STR_xxBROADCOM_BCM5461 },
126 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5462,
127 	  MII_STR_xxBROADCOM_BCM5462 },
128 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5464,
129 	  MII_STR_xxBROADCOM_BCM5464 },
130 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5701,
131 	  MII_STR_xxBROADCOM_BCM5701 },
132 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5703,
133 	  MII_STR_xxBROADCOM_BCM5703 },
134 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5704,
135 	  MII_STR_xxBROADCOM_BCM5704 },
136 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5705,
137 	  MII_STR_xxBROADCOM_BCM5705 },
138 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5714,
139 	  MII_STR_xxBROADCOM_BCM5714 },
140 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5750,
141 	  MII_STR_xxBROADCOM_BCM5750 },
142 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5752,
143 	  MII_STR_xxBROADCOM_BCM5752 },
144 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5780,
145 	  MII_STR_xxBROADCOM_BCM5780 },
146 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM54XX,
147 	  MII_STR_xxBROADCOM2_BCM54XX },
148 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM5481,
149 	  MII_STR_xxBROADCOM2_BCM5481 },
150 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM5482,
151 	  MII_STR_xxBROADCOM2_BCM5482 },
152 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM5722,
153 	  MII_STR_xxBROADCOM2_BCM5722 },
154 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM5755,
155 	  MII_STR_xxBROADCOM2_BCM5755 },
156 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM5761,
157 	  MII_STR_xxBROADCOM2_BCM5761 },
158 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM5784,
159 	  MII_STR_xxBROADCOM2_BCM5784 },
160 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM5787,
161 	  MII_STR_xxBROADCOM2_BCM5787 },
162 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5706,
163 	  MII_STR_xxBROADCOM_BCM5706 },
164 	{ MII_OUI_xxBROADCOM,		MII_MODEL_xxBROADCOM_BCM5708C,
165 	  MII_STR_xxBROADCOM_BCM5708C },
166 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM5708S,
167 	  MII_STR_xxBROADCOM2_BCM5708S },
168 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM5709C,
169 	  MII_STR_xxBROADCOM2_BCM5709C },
170 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM5709S,
171 	  MII_STR_xxBROADCOM2_BCM5709S },
172 	{ MII_OUI_xxBROADCOM2,		MII_MODEL_xxBROADCOM2_BCM5709CAX,
173 	  MII_STR_xxBROADCOM2_BCM5709CAX },
174 	{ MII_OUI_xxBROADCOM3,		MII_MODEL_xxBROADCOM3_BCM5717C,
175 	  MII_STR_xxBROADCOM3_BCM5717C },
176 	{ MII_OUI_xxBROADCOM3,		MII_MODEL_xxBROADCOM3_BCM5719C,
177 	  MII_STR_xxBROADCOM3_BCM5719C },
178 	{ MII_OUI_xxBROADCOM3,		MII_MODEL_xxBROADCOM3_BCM5720C,
179 	  MII_STR_xxBROADCOM3_BCM5720C },
180 	{ MII_OUI_xxBROADCOM3,		MII_MODEL_xxBROADCOM3_BCM57765,
181 	  MII_STR_xxBROADCOM3_BCM57765 },
182 	{ MII_OUI_xxBROADCOM3,		MII_MODEL_xxBROADCOM3_BCM57780,
183 	  MII_STR_xxBROADCOM3_BCM57780 },
184 	{ MII_OUI_xxBROADCOM4,		MII_MODEL_xxBROADCOM4_BCM54210E,
185 	  MII_STR_xxBROADCOM4_BCM54210E },
186 	{ MII_OUI_xxBROADCOM4,		MII_MODEL_xxBROADCOM4_BCM5725,
187 	  MII_STR_xxBROADCOM4_BCM5725 },
188 	{ MII_OUI_BROADCOM2,		MII_MODEL_BROADCOM2_BCM5906,
189 	  MII_STR_BROADCOM2_BCM5906 },
190 
191 	{ 0,				0,
192 	  NULL },
193 };
194 
195 int
brgphy_probe(struct device * parent,void * match,void * aux)196 brgphy_probe(struct device *parent, void *match, void *aux)
197 {
198 	struct mii_attach_args *ma = aux;
199 
200 	if (mii_phy_match(ma, brgphys) != NULL)
201 		return (10);
202 
203 	return (0);
204 }
205 
206 void
brgphy_attach(struct device * parent,struct device * self,void * aux)207 brgphy_attach(struct device *parent, struct device *self, void *aux)
208 {
209 	struct mii_softc *sc = (struct mii_softc *)self;
210 	struct bge_softc *bge_sc = NULL;
211 	struct bnx_softc *bnx_sc = NULL;
212 	struct mii_attach_args *ma = aux;
213 	struct mii_data *mii = ma->mii_data;
214 	const struct mii_phydesc *mpd;
215 	char *devname;
216 	int fast_ether = 0;
217 
218 	devname = sc->mii_dev.dv_parent->dv_cfdata->cf_driver->cd_name;
219 
220 	if (strcmp(devname, "bge") == 0) {
221 		bge_sc = mii->mii_ifp->if_softc;
222 
223 		if (bge_sc->bge_phy_flags & BGE_PHY_10_100_ONLY)
224 			fast_ether = 1;
225 	} else if (strcmp(devname, "bnx") == 0)
226 		bnx_sc = mii->mii_ifp->if_softc;
227 
228 	mpd = mii_phy_match(ma, brgphys);
229 	printf(": %s, rev. %d\n", mpd->mpd_name, MII_REV(ma->mii_id2));
230 
231 	sc->mii_inst = mii->mii_instance;
232 	sc->mii_phy = ma->mii_phyno;
233 	sc->mii_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
234 	sc->mii_model = MII_MODEL(ma->mii_id2);
235 	sc->mii_rev = MII_REV(ma->mii_id2);
236 	sc->mii_pdata = mii;
237 	sc->mii_flags = ma->mii_flags;
238 
239 	if (sc->mii_flags & MIIF_HAVEFIBER) {
240 		if (strcmp(devname, "bnx") == 0) {
241 			if (BNX_CHIP_NUM(bnx_sc) == BNX_CHIP_NUM_5708)
242 				sc->mii_funcs = &brgphy_5708s_funcs;
243 			else if (BNX_CHIP_NUM(bnx_sc) == BNX_CHIP_NUM_5709)
244 				sc->mii_funcs = &brgphy_5709s_funcs;
245 			else
246 				sc->mii_funcs = &brgphy_fiber_funcs;
247 		} else
248 			sc->mii_funcs = &brgphy_fiber_funcs;
249 	} else
250 		sc->mii_funcs = &brgphy_copper_funcs;
251 
252 	if (fast_ether == 1)
253 		sc->mii_anegticks = MII_ANEGTICKS;
254 	else
255 		sc->mii_anegticks = MII_ANEGTICKS_GIGE;
256 
257 	sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP;
258 
259 	PHY_RESET(sc);
260 
261 	sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
262 	if (sc->mii_capabilities & BMSR_EXTSTAT)
263 		sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
264 
265 #define ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
266 
267 	/* Create an instance of Ethernet media. */
268 	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), BMCR_ISO);
269 
270 	/* Add the supported media types */
271 	if (sc->mii_flags & MIIF_HAVEFIBER) {
272 		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst),
273 		    BMCR_S1000 | BMCR_FDX);
274 
275 		/*
276 		 * 2.5Gb support is a software enabled feature on the
277 		 * BCM5708S and BCM5709S controllers.
278 		 */
279 		if (strcmp(devname, "bnx") == 0) {
280 			if (bnx_sc->bnx_phy_flags & BNX_PHY_2_5G_CAPABLE_FLAG)
281 				ADD(IFM_MAKEWORD(IFM_ETHER, IFM_2500_SX,
282 				    IFM_FDX, sc->mii_inst), 0);
283 		}
284 	} else {
285 		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst),
286 		    BMCR_S10);
287 		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
288 		    BMCR_S10 | BMCR_FDX);
289 		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
290 		    BMCR_S100);
291 		ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
292 		    BMCR_S100 | BMCR_FDX);
293 
294 		if (fast_ether == 0) {
295 			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0,
296 			    sc->mii_inst), BMCR_S1000);
297 			ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX,
298 			    sc->mii_inst), BMCR_S1000 | BMCR_FDX);
299 		}
300 	}
301 
302 	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0);
303 
304 #undef ADD
305 }
306 
307 int
brgphy_service(struct mii_softc * sc,struct mii_data * mii,int cmd)308 brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
309 {
310 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
311 	int reg, speed = 0, gig;
312 
313 	if ((sc->mii_dev.dv_flags & DVF_ACTIVE) == 0)
314 		return (ENXIO);
315 
316 	switch (cmd) {
317 	case MII_POLLSTAT:
318 		/*
319 		 * If we're not polling our PHY instance, just return.
320 		 */
321 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
322 			return (0);
323 		break;
324 
325 	case MII_MEDIACHG:
326 		/*
327 		 * If the media indicates a different PHY instance,
328 		 * isolate ourselves.
329 		 */
330 		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
331 			reg = PHY_READ(sc, MII_BMCR);
332 			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
333 			return (0);
334 		}
335 
336 		/*
337 		 * If the interface is not up, don't do anything.
338 		 */
339 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
340 			break;
341 
342 		PHY_RESET(sc); /* XXX hardware bug work-around */
343 
344 		switch (IFM_SUBTYPE(ife->ifm_media)) {
345 		case IFM_AUTO:
346 			(void) brgphy_mii_phy_auto(sc);
347 			break;
348 		case IFM_2500_SX:
349 			speed = BRGPHY_5708S_BMCR_2500;
350 			goto setit;
351 		case IFM_1000_T:
352 			speed = BMCR_S1000;
353 			goto setit;
354 		case IFM_100_TX:
355 			speed = BMCR_S100;
356 			goto setit;
357 		case IFM_10_T:
358 			speed = BMCR_S10;
359 setit:
360 			brgphy_loop(sc);
361 			if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
362 				speed |= BMCR_FDX;
363 				gig = GTCR_ADV_1000TFDX;
364 			} else {
365 				gig = GTCR_ADV_1000THDX;
366 			}
367 
368 			PHY_WRITE(sc, MII_100T2CR, 0);
369 			PHY_WRITE(sc, MII_ANAR, ANAR_CSMA);
370 			PHY_WRITE(sc, MII_BMCR, speed);
371 
372 			if ((IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) &&
373 			    (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_SX) &&
374 			    (IFM_SUBTYPE(ife->ifm_media) != IFM_2500_SX))
375 				break;
376 
377 			PHY_WRITE(sc, MII_100T2CR, gig);
378 			PHY_WRITE(sc, MII_BMCR,
379 			    speed|BMCR_AUTOEN|BMCR_STARTNEG);
380 
381 			if (sc->mii_oui != MII_OUI_xxBROADCOM ||
382 			    sc->mii_model != MII_MODEL_xxBROADCOM_BCM5701)
383  				break;
384 
385 			if (mii->mii_media.ifm_media & IFM_ETH_MASTER)
386 				gig |= GTCR_MAN_MS|GTCR_ADV_MS;
387 			PHY_WRITE(sc, MII_100T2CR, gig);
388 			break;
389 		default:
390 			return (EINVAL);
391 		}
392 		break;
393 
394 	case MII_TICK:
395 		/*
396 		 * If we're not currently selected, just return.
397 		 */
398 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
399 			return (0);
400 
401 		/*
402 		 * Is the interface even up?
403 		 */
404 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
405 			return (0);
406 
407 		/*
408 		 * Only used for autonegotiation.
409 		 */
410 		if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
411 			break;
412 
413 		/*
414 		 * Check to see if we have link.  If we do, we don't
415 		 * need to restart the autonegotiation process.  Read
416 		 * the BMSR twice in case it's latched.
417 		 */
418 		reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
419 		if (reg & BMSR_LINK) {
420 			sc->mii_ticks = 0;	/* Reset autoneg timer. */
421 			break;
422 		}
423 
424 		/*
425 		 * Only retry autonegotiation every mii_anegticks seconds.
426 		 */
427 		if (++sc->mii_ticks <= sc->mii_anegticks)
428 			break;
429 
430 		sc->mii_ticks = 0;
431 		brgphy_mii_phy_auto(sc);
432 		break;
433 	}
434 
435 	/* Update the media status. */
436 	mii_phy_status(sc);
437 
438 	/*
439 	 * Callback if something changed. Note that we need to poke the DSP on
440 	 * the Broadcom PHYs if the media changes.
441 	 */
442 	if (sc->mii_media_active != mii->mii_media_active ||
443 	    sc->mii_media_status != mii->mii_media_status ||
444 	    cmd == MII_MEDIACHG) {
445 		switch (sc->mii_oui) {
446 		case MII_OUI_BROADCOM:
447 			switch (sc->mii_model) {
448 			case MII_MODEL_BROADCOM_BCM5400:
449 				brgphy_bcm5401_dspcode(sc);
450 				break;
451 			}
452 			break;
453 		case MII_OUI_xxBROADCOM:
454 			switch (sc->mii_model) {
455 			case MII_MODEL_xxBROADCOM_BCM5401:
456 				if (sc->mii_rev == 1 || sc->mii_rev == 3)
457 					brgphy_bcm5401_dspcode(sc);
458 				break;
459 			case MII_MODEL_xxBROADCOM_BCM5411:
460 				brgphy_bcm5411_dspcode(sc);
461 				break;
462 			}
463 			break;
464 		}
465 	}
466 
467 	/* Callback if something changed. */
468 	mii_phy_update(sc, cmd);
469 
470 	return (0);
471 }
472 
473 void
brgphy_copper_status(struct mii_softc * sc)474 brgphy_copper_status(struct mii_softc *sc)
475 {
476 	struct mii_data *mii = sc->mii_pdata;
477 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
478 	int bmcr, bmsr;
479 
480 	mii->mii_media_status = IFM_AVALID;
481 	mii->mii_media_active = IFM_ETHER;
482 
483 	bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
484 	if (bmsr & BMSR_LINK)
485 		mii->mii_media_status |= IFM_ACTIVE;
486 
487 	bmcr = PHY_READ(sc, MII_BMCR);
488 	if (bmcr & BMCR_LOOP)
489 		mii->mii_media_active |= IFM_LOOP;
490 
491 	if (bmcr & BMCR_AUTOEN) {
492 		int auxsts;
493 
494 		if ((bmsr & BMSR_ACOMP) == 0) {
495 			/* Erg, still trying, I guess... */
496 			mii->mii_media_active |= IFM_NONE;
497 			return;
498 		}
499 
500 		auxsts = PHY_READ(sc, BRGPHY_MII_AUXSTS);
501 
502 		switch (auxsts & BRGPHY_AUXSTS_AN_RES) {
503 		case BRGPHY_RES_1000FD:
504 			mii->mii_media_active |= IFM_1000_T | IFM_FDX;
505 			break;
506 		case BRGPHY_RES_1000HD:
507 			mii->mii_media_active |= IFM_1000_T | IFM_HDX;
508 			break;
509 		case BRGPHY_RES_100FD:
510 			mii->mii_media_active |= IFM_100_TX | IFM_FDX;
511 			break;
512 		case BRGPHY_RES_100T4:
513 			mii->mii_media_active |= IFM_100_T4 | IFM_HDX;
514 			break;
515 		case BRGPHY_RES_100HD:
516 			mii->mii_media_active |= IFM_100_TX | IFM_HDX;
517 			break;
518 		case BRGPHY_RES_10FD:
519 			mii->mii_media_active |= IFM_10_T | IFM_FDX;
520 			break;
521 		case BRGPHY_RES_10HD:
522 			mii->mii_media_active |= IFM_10_T | IFM_HDX;
523 			break;
524 		default:
525 			if (sc->mii_oui == MII_OUI_BROADCOM2 &&
526 			    sc->mii_model == MII_MODEL_BROADCOM2_BCM5906) {
527 				mii->mii_media_active |= (auxsts &
528 				    BRGPHY_RES_100) ? IFM_100_TX : IFM_10_T;
529 				mii->mii_media_active |= (auxsts &
530 				    BRGPHY_RES_FULL) ? IFM_FDX : IFM_HDX;
531 				break;
532 			}
533 			mii->mii_media_active |= IFM_NONE;
534 			return;
535 		}
536 
537 		if (mii->mii_media_active & IFM_FDX)
538 			mii->mii_media_active |= mii_phy_flowstatus(sc);
539 
540 		if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) {
541 			if (PHY_READ(sc, MII_100T2SR) & GTSR_MS_RES)
542 				mii->mii_media_active |= IFM_ETH_MASTER;
543 		}
544 	} else
545 		mii->mii_media_active = ife->ifm_media;
546 }
547 
548 void
brgphy_fiber_status(struct mii_softc * sc)549 brgphy_fiber_status(struct mii_softc *sc)
550 {
551 	struct mii_data *mii = sc->mii_pdata;
552 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
553 	int bmcr, bmsr;
554 
555 	mii->mii_media_status = IFM_AVALID;
556 	mii->mii_media_active = IFM_ETHER;
557 
558 	bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
559 	if (bmsr & BMSR_LINK)
560 		mii->mii_media_status |= IFM_ACTIVE;
561 
562 	bmcr = PHY_READ(sc, MII_BMCR);
563 	if (bmcr & BMCR_LOOP)
564 		mii->mii_media_active |= IFM_LOOP;
565 
566 	if (bmcr & BMCR_AUTOEN) {
567 		int val;
568 
569 		if ((bmsr & BMSR_ACOMP) == 0) {
570 			/* Erg, still trying, I guess... */
571 			mii->mii_media_active |= IFM_NONE;
572 			return;
573 		}
574 
575 		mii->mii_media_active |= IFM_1000_SX;
576 
577 		val = PHY_READ(sc, MII_ANAR) & PHY_READ(sc, MII_ANLPAR);
578 
579 		if (val & ANAR_X_FD)
580 			mii->mii_media_active |= IFM_FDX;
581 		else
582 			mii->mii_media_active |= IFM_HDX;
583 
584 		if (mii->mii_media_active & IFM_FDX)
585 			mii->mii_media_active |= mii_phy_flowstatus(sc);
586 	} else
587 		mii->mii_media_active = ife->ifm_media;
588 }
589 
590 void
brgphy_5708s_status(struct mii_softc * sc)591 brgphy_5708s_status(struct mii_softc *sc)
592 {
593 	struct mii_data *mii = sc->mii_pdata;
594 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
595 	int bmcr, bmsr;
596 
597 	mii->mii_media_status = IFM_AVALID;
598 	mii->mii_media_active = IFM_ETHER;
599 
600 	bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
601 	if (bmsr & BMSR_LINK)
602 		mii->mii_media_status |= IFM_ACTIVE;
603 
604 	bmcr = PHY_READ(sc, MII_BMCR);
605 	if (bmcr & BMCR_LOOP)
606 		mii->mii_media_active |= IFM_LOOP;
607 
608 	if (bmcr & BMCR_AUTOEN) {
609 		int xstat;
610 
611 		if ((bmsr & BMSR_ACOMP) == 0) {
612 			/* Erg, still trying, I guess... */
613 			mii->mii_media_active |= IFM_NONE;
614 			return;
615 		}
616 
617 		PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
618 		    BRGPHY_5708S_DIG_PG0);
619 
620 		xstat = PHY_READ(sc, BRGPHY_5708S_PG0_1000X_STAT1);
621 
622 		switch (xstat & BRGPHY_5708S_PG0_1000X_STAT1_SPEED_MASK) {
623 		case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_10:
624 			mii->mii_media_active |= IFM_10_FL;
625 			break;
626 		case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_100:
627 			mii->mii_media_active |= IFM_100_FX;
628 			break;
629 		case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_1G:
630 			mii->mii_media_active |= IFM_1000_SX;
631 			break;
632 		case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_25G:
633 			mii->mii_media_active |= IFM_2500_SX;
634 			break;
635 		}
636 
637 		if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_FDX)
638 			mii->mii_media_active |= IFM_FDX;
639 		else
640 			mii->mii_media_active |= IFM_HDX;
641 
642 		if (mii->mii_media_active & IFM_FDX) {
643 			if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_TX_PAUSE)
644 				mii->mii_media_active |= IFM_FLOW | IFM_ETH_TXPAUSE;
645 			if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_RX_PAUSE)
646 				mii->mii_media_active |= IFM_FLOW | IFM_ETH_RXPAUSE;
647 		}
648 	} else
649 		mii->mii_media_active = ife->ifm_media;
650 }
651 
652 void
brgphy_5709s_status(struct mii_softc * sc)653 brgphy_5709s_status(struct mii_softc *sc)
654 {
655 	struct mii_data *mii = sc->mii_pdata;
656 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
657 	int bmcr, bmsr;
658 
659 	mii->mii_media_status = IFM_AVALID;
660 	mii->mii_media_active = IFM_ETHER;
661 
662         bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
663         if (bmsr & BMSR_LINK)
664                 mii->mii_media_status |= IFM_ACTIVE;
665 
666         bmcr = PHY_READ(sc, MII_BMCR);
667         if (bmcr & BMCR_LOOP)
668                 mii->mii_media_active |= IFM_LOOP;
669 
670         if (bmcr & BMCR_AUTOEN) {
671                 int xstat;
672 
673                 if ((bmsr & BMSR_ACOMP) == 0) {
674                         /* Erg, still trying, I guess... */
675                         mii->mii_media_active |= IFM_NONE;
676                         return;
677                 }
678 
679                 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
680                     BRGPHY_BLOCK_ADDR_GP_STATUS);
681 
682                 xstat = PHY_READ(sc, BRGPHY_GP_STATUS_TOP_ANEG_STATUS);
683 
684                 PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
685                     BRGPHY_BLOCK_ADDR_COMBO_IEEE0);
686 
687                 switch (xstat & BRGPHY_GP_STATUS_TOP_ANEG_SPEED_MASK) {
688                 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_10:
689                         mii->mii_media_active |= IFM_10_FL;
690                         break;
691                 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_100:
692                         mii->mii_media_active |= IFM_100_FX;
693                         break;
694                 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1G:
695                         mii->mii_media_active |= IFM_1000_SX;
696                         break;
697                 case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_25G:
698                         mii->mii_media_active |= IFM_2500_SX;
699                         break;
700                 }
701 
702                 if (xstat & BRGPHY_GP_STATUS_TOP_ANEG_FDX)
703                         mii->mii_media_active |= IFM_FDX;
704                 else
705                         mii->mii_media_active |= IFM_HDX;
706 
707 		if (mii->mii_media_active & IFM_FDX)
708 			mii->mii_media_active |= mii_phy_flowstatus(sc);
709 	} else
710 		mii->mii_media_active = ife->ifm_media;
711 }
712 
713 int
brgphy_mii_phy_auto(struct mii_softc * sc)714 brgphy_mii_phy_auto(struct mii_softc *sc)
715 {
716 	int anar, ktcr = 0;
717 
718 	PHY_RESET(sc);
719 
720 	if (sc->mii_flags & MIIF_HAVEFIBER) {
721 		anar = ANAR_X_FD | ANAR_X_HD;
722 		if (sc->mii_flags & MIIF_DOPAUSE)
723 			anar |= ANAR_X_PAUSE_TOWARDS;
724 		PHY_WRITE(sc, MII_ANAR, anar);
725 	} else {
726 		anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA;
727 		if (sc->mii_flags & MIIF_DOPAUSE)
728 			anar |= ANAR_PAUSE_ASYM | ANAR_FC;
729 		PHY_WRITE(sc, MII_ANAR, anar);
730 	}
731 
732 	/* Enable speed in the 1000baseT control register */
733 	ktcr = GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
734 	if (sc->mii_oui == MII_OUI_xxBROADCOM &&
735 	    sc->mii_model == MII_MODEL_xxBROADCOM_BCM5701)
736 		ktcr |= GTCR_MAN_MS | GTCR_ADV_MS;
737 	PHY_WRITE(sc, MII_100T2CR, ktcr);
738 	ktcr = PHY_READ(sc, MII_100T2CR);
739 
740 	/* Start autonegotiation */
741 	PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
742 	PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00);
743 
744 	return (EJUSTRETURN);
745 }
746 
747 /* Enable loopback to force the link down. */
748 void
brgphy_loop(struct mii_softc * sc)749 brgphy_loop(struct mii_softc *sc)
750 {
751 	u_int32_t bmsr;
752 	int i;
753 
754 	PHY_WRITE(sc, MII_BMCR, BMCR_LOOP);
755 	for (i = 0; i < 15000; i++) {
756 		bmsr = PHY_READ(sc, MII_BMSR);
757 		if (!(bmsr & BMSR_LINK))
758 			break;
759 		DELAY(10);
760 	}
761 }
762 
763 void
brgphy_reset(struct mii_softc * sc)764 brgphy_reset(struct mii_softc *sc)
765 {
766 	char *devname;
767 
768 	devname = sc->mii_dev.dv_parent->dv_cfdata->cf_driver->cd_name;
769 
770 	mii_phy_reset(sc);
771 
772 	switch (sc->mii_oui) {
773 	case MII_OUI_BROADCOM:
774 		switch (sc->mii_model) {
775 		case MII_MODEL_BROADCOM_BCM5400:
776 			brgphy_bcm5401_dspcode(sc);
777 			break;
778 		case MII_MODEL_BROADCOM_BCM5401:
779 			if (sc->mii_rev == 1 || sc->mii_rev == 3)
780 				brgphy_bcm5401_dspcode(sc);
781 			break;
782 		case MII_MODEL_BROADCOM_BCM5411:
783 			brgphy_bcm5411_dspcode(sc);
784 			break;
785 		}
786 		break;
787 	case MII_OUI_xxBROADCOM:
788 		switch (sc->mii_model) {
789 		case MII_MODEL_xxBROADCOM_BCM5421:
790 			brgphy_bcm5421_dspcode(sc);
791 			break;
792 		case MII_MODEL_xxBROADCOM_BCM54K2:
793 			brgphy_bcm54k2_dspcode(sc);
794 			break;
795 		}
796 		break;
797 	case MII_OUI_xxBROADCOM4:
798 		switch (sc->mii_model) {
799 		case MII_MODEL_xxBROADCOM4_BCM54210E:
800 			brgphy_bcm54xx_clock_delay(sc);
801 			break;
802 		}
803 	}
804 
805 	/* Handle any bge (NetXtreme/NetLink) workarounds. */
806 	if (strcmp(devname, "bge") == 0)
807 		brgphy_reset_bge(sc);
808 	/* Handle any bnx (NetXtreme II) workarounds. */
809 	else if (strcmp(devname, "bnx") == 0)
810 		brgphy_reset_bnx(sc);
811 }
812 
813 void
brgphy_reset_bge(struct mii_softc * sc)814 brgphy_reset_bge(struct mii_softc *sc)
815 {
816 	struct bge_softc *bge_sc = sc->mii_pdata->mii_ifp->if_softc;
817 
818 	if (sc->mii_flags & MIIF_HAVEFIBER)
819 		return;
820 
821 	switch (sc->mii_oui) {
822 	case MII_OUI_xxBROADCOM3:
823 		switch (sc->mii_model) {
824 		case MII_MODEL_xxBROADCOM3_BCM5717C:
825 		case MII_MODEL_xxBROADCOM3_BCM5719C:
826 		case MII_MODEL_xxBROADCOM3_BCM5720C:
827 		case MII_MODEL_xxBROADCOM3_BCM57765:
828 			return;
829 		}
830 	}
831 
832 	if (bge_sc->bge_phy_flags & BGE_PHY_ADC_BUG)
833 		brgphy_adc_bug(sc);
834 	if (bge_sc->bge_phy_flags & BGE_PHY_5704_A0_BUG)
835 		brgphy_5704_a0_bug(sc);
836 	if (bge_sc->bge_phy_flags & BGE_PHY_BER_BUG)
837 		brgphy_ber_bug(sc);
838 	else if (bge_sc->bge_phy_flags & BGE_PHY_JITTER_BUG) {
839 	    	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0c00);
840 		PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a);
841 
842 		if (bge_sc->bge_phy_flags & BGE_PHY_ADJUST_TRIM) {
843 			PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, 0x110b);
844 			PHY_WRITE(sc, BRGPHY_TEST1, BRGPHY_TEST1_TRIM_EN |
845 			    0x4);
846 		} else
847 			PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, 0x010b);
848 
849 		PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0400);
850 	}
851 
852 	if (bge_sc->bge_phy_flags & BGE_PHY_CRC_BUG)
853 		brgphy_crc_bug(sc);
854 
855 	/* Set Jumbo frame settings in the PHY. */
856 	if (bge_sc->bge_flags & BGE_JUMBO_CAPABLE)
857 		brgphy_jumbo_settings(sc);
858 
859 	/* Adjust output voltage */
860 	if (sc->mii_oui == MII_OUI_BROADCOM2 &&
861 	    sc->mii_model == MII_MODEL_BROADCOM2_BCM5906)
862 		PHY_WRITE(sc, BRGPHY_MII_EPHY_PTEST, 0x12);
863 
864 	/* Enable Ethernet@Wirespeed */
865 	if (!(bge_sc->bge_phy_flags & BGE_PHY_NO_WIRESPEED))
866 		brgphy_eth_wirespeed(sc);
867 
868 	/* Enable Link LED on Dell boxes */
869 	if (bge_sc->bge_phy_flags & BGE_PHY_NO_3LED) {
870 		PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL,
871 		    PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL)
872 		    & ~BRGPHY_PHY_EXTCTL_3_LED);
873 	}
874 }
875 
876 void
brgphy_reset_bnx(struct mii_softc * sc)877 brgphy_reset_bnx(struct mii_softc *sc)
878 {
879 	struct bnx_softc *bnx_sc = sc->mii_pdata->mii_ifp->if_softc;
880 
881 	if (BNX_CHIP_NUM(bnx_sc) == BNX_CHIP_NUM_5708 &&
882 	    sc->mii_flags & MIIF_HAVEFIBER) {
883 		/* Store autoneg capabilities/results in digital block (Page 0) */
884 		PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG3_PG2);
885 		PHY_WRITE(sc, BRGPHY_5708S_PG2_DIGCTL_3_0,
886 		    BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE);
887 		PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0);
888 
889 		/* Enable fiber mode and autodetection */
890 		PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL1,
891 		    PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL1) |
892 		    BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN |
893 		    BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE);
894 
895 		/* Enable parallel detection */
896 		PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL2,
897 		    PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL2) |
898 		    BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN);
899 
900 		/* Advertise 2.5G support through next page during autoneg */
901 		if (bnx_sc->bnx_phy_flags & BNX_PHY_2_5G_CAPABLE_FLAG) {
902 			PHY_WRITE(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1,
903 			    PHY_READ(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1) |
904 			    BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G);
905 		}
906 
907 		/* Increase TX signal amplitude */
908 		if ((BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_A0) ||
909 		    (BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_B0) ||
910 		    (BNX_CHIP_ID(bnx_sc) == BNX_CHIP_ID_5708_B1)) {
911 			PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
912 			    BRGPHY_5708S_TX_MISC_PG5);
913 			PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL1,
914 			    PHY_READ(sc, BRGPHY_5708S_PG5_TXACTL1) &
915 			    ~BRGPHY_5708S_PG5_TXACTL1_VCM);
916 			PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
917 			    BRGPHY_5708S_DIG_PG0);
918 		}
919 
920 		/* Backplanes use special driver/pre-driver/pre-emphasis values. */
921 		if ((bnx_sc->bnx_shared_hw_cfg & BNX_SHARED_HW_CFG_PHY_BACKPLANE) &&
922 		    (bnx_sc->bnx_port_hw_cfg & BNX_PORT_HW_CFG_CFG_TXCTL3_MASK)) {
923 			PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
924 			    BRGPHY_5708S_TX_MISC_PG5);
925 			PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL3,
926 			    bnx_sc->bnx_port_hw_cfg &
927 			    BNX_PORT_HW_CFG_CFG_TXCTL3_MASK);
928 			PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR,
929 			    BRGPHY_5708S_DIG_PG0);
930 		}
931 	} else if (BNX_CHIP_NUM(bnx_sc) == BNX_CHIP_NUM_5709 &&
932 	    sc->mii_flags & MIIF_HAVEFIBER) {
933 		/* Select the SerDes Digital block of the AN MMD. */
934 		PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_SERDES_DIG);
935 
936 		PHY_WRITE(sc, BRGPHY_SERDES_DIG_1000X_CTL1,
937 		    (PHY_READ(sc, BRGPHY_SERDES_DIG_1000X_CTL1) &
938 		    ~BRGPHY_SD_DIG_1000X_CTL1_AUTODET) |
939 		    BRGPHY_SD_DIG_1000X_CTL1_FIBER);
940 
941 		if (bnx_sc->bnx_phy_flags & BNX_PHY_2_5G_CAPABLE_FLAG) {
942 			/* Select the Over 1G block of the AN MMD. */
943 			PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
944 			    BRGPHY_BLOCK_ADDR_OVER_1G);
945 
946 			/*
947 			 * Enable autoneg "Next Page" to advertise
948 			 * 2.5G support.
949 			 */
950 			PHY_WRITE(sc, BRGPHY_OVER_1G_UNFORMAT_PG1,
951 			    PHY_READ(sc, BRGPHY_OVER_1G_UNFORMAT_PG1) |
952 			    BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G);
953 		}
954 
955 		/*
956 		 * Select the Multi-Rate Backplane Ethernet block of
957 		 * the AN MMD.
958 		 */
959 		PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, BRGPHY_BLOCK_ADDR_MRBE);
960 
961 		/* Enable MRBE speed autoneg. */
962 		PHY_WRITE(sc, BRGPHY_MRBE_MSG_PG5_NP,
963 		    PHY_READ(sc, BRGPHY_MRBE_MSG_PG5_NP) |
964 		    BRGPHY_MRBE_MSG_PG5_NP_MBRE |
965 		    BRGPHY_MRBE_MSG_PG5_NP_T2);
966 
967 		/* Select the Clause 73 User B0 block of the AN MMD. */
968 		PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
969 		    BRGPHY_BLOCK_ADDR_CL73_USER_B0);
970 
971 		/* Enable MRBE speed autoneg. */
972 		PHY_WRITE(sc, BRGPHY_CL73_USER_B0_MBRE_CTL1,
973 		    BRGPHY_CL73_USER_B0_MBRE_CTL1_NP_AFT_BP |
974 		    BRGPHY_CL73_USER_B0_MBRE_CTL1_STA_MGR |
975 		    BRGPHY_CL73_USER_B0_MBRE_CTL1_ANEG);
976 
977 		PHY_WRITE(sc, BRGPHY_BLOCK_ADDR,
978 		    BRGPHY_BLOCK_ADDR_COMBO_IEEE0);
979 	} else if (BNX_CHIP_NUM(bnx_sc) == BNX_CHIP_NUM_5709) {
980 		if (BNX_CHIP_REV(bnx_sc) == BNX_CHIP_REV_Ax ||
981 		    BNX_CHIP_REV(bnx_sc) == BNX_CHIP_REV_Bx)
982 			brgphy_disable_early_dac(sc);
983 
984 		/* Set Jumbo frame settings in the PHY. */
985 		brgphy_jumbo_settings(sc);
986 
987 		/* Enable Ethernet@Wirespeed */
988 		brgphy_eth_wirespeed(sc);
989 	} else if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) {
990 		brgphy_ber_bug(sc);
991 
992 		/* Set Jumbo frame settings in the PHY. */
993 		brgphy_jumbo_settings(sc);
994 
995 		/* Enable Ethernet@Wirespeed */
996 		brgphy_eth_wirespeed(sc);
997 	}
998 }
999 
1000 /* Disable tap power management */
1001 void
brgphy_bcm5401_dspcode(struct mii_softc * sc)1002 brgphy_bcm5401_dspcode(struct mii_softc *sc)
1003 {
1004 	static const struct {
1005 		int		reg;
1006 		uint16_t	val;
1007 	} dspcode[] = {
1008 		{ BRGPHY_MII_AUXCTL,		0x0c20 },
1009 		{ BRGPHY_MII_DSP_ADDR_REG,	0x0012 },
1010 		{ BRGPHY_MII_DSP_RW_PORT,	0x1804 },
1011 		{ BRGPHY_MII_DSP_ADDR_REG,	0x0013 },
1012 		{ BRGPHY_MII_DSP_RW_PORT,	0x1204 },
1013 		{ BRGPHY_MII_DSP_ADDR_REG,	0x8006 },
1014 		{ BRGPHY_MII_DSP_RW_PORT,	0x0132 },
1015 		{ BRGPHY_MII_DSP_ADDR_REG,	0x8006 },
1016 		{ BRGPHY_MII_DSP_RW_PORT,	0x0232 },
1017 		{ BRGPHY_MII_DSP_ADDR_REG,	0x201f },
1018 		{ BRGPHY_MII_DSP_RW_PORT,	0x0a20 },
1019 		{ 0,				0 },
1020 	};
1021 	int i;
1022 
1023 	for (i = 0; dspcode[i].reg != 0; i++)
1024 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
1025 	DELAY(40);
1026 }
1027 
1028 /* Setting some undocumented voltage */
1029 void
brgphy_bcm5411_dspcode(struct mii_softc * sc)1030 brgphy_bcm5411_dspcode(struct mii_softc *sc)
1031 {
1032 	static const struct {
1033 		int		reg;
1034 		uint16_t	val;
1035 	} dspcode[] = {
1036 		{ 0x1c,				0x8c23 },
1037 		{ 0x1c,				0x8ca3 },
1038 		{ 0x1c,				0x8c23 },
1039 		{ 0,				0 },
1040 	};
1041 	int i;
1042 
1043 	for (i = 0; dspcode[i].reg != 0; i++)
1044 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
1045 }
1046 
1047 void
brgphy_bcm5421_dspcode(struct mii_softc * sc)1048 brgphy_bcm5421_dspcode(struct mii_softc *sc)
1049 {
1050 	uint16_t data;
1051 
1052 	/* Set Class A mode */
1053 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x1007);
1054 	data = PHY_READ(sc, BRGPHY_MII_AUXCTL);
1055 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0400);
1056 
1057 	/* Set FFE gamma override to -0.125 */
1058 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0007);
1059 	data = PHY_READ(sc, BRGPHY_MII_AUXCTL);
1060 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0800);
1061 	PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a);
1062 	data = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT);
1063 	PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, data | 0x0200);
1064 }
1065 
1066 void
brgphy_bcm54k2_dspcode(struct mii_softc * sc)1067 brgphy_bcm54k2_dspcode(struct mii_softc *sc)
1068 {
1069 	static const struct {
1070 		int		reg;
1071 		uint16_t	val;
1072 	} dspcode[] = {
1073 		{ 4,				0x01e1 },
1074 		{ 9,				0x0300 },
1075 		{ 0,				0 },
1076 	};
1077 	int i;
1078 
1079 	for (i = 0; dspcode[i].reg != 0; i++)
1080 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
1081 }
1082 
1083 void
brgphy_adc_bug(struct mii_softc * sc)1084 brgphy_adc_bug(struct mii_softc *sc)
1085 {
1086 	static const struct {
1087 		int		reg;
1088 		uint16_t	val;
1089 	} dspcode[] = {
1090 		{ BRGPHY_MII_AUXCTL,		0x0c00 },
1091 		{ BRGPHY_MII_DSP_ADDR_REG,	0x201f },
1092 		{ BRGPHY_MII_DSP_RW_PORT,	0x2aaa },
1093 		{ BRGPHY_MII_DSP_ADDR_REG,	0x000a },
1094 		{ BRGPHY_MII_DSP_RW_PORT,	0x0323 },
1095 		{ BRGPHY_MII_AUXCTL,		0x0400 },
1096 		{ 0,				0 },
1097 	};
1098 	int i;
1099 
1100 	for (i = 0; dspcode[i].reg != 0; i++)
1101 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
1102 }
1103 
1104 void
brgphy_5704_a0_bug(struct mii_softc * sc)1105 brgphy_5704_a0_bug(struct mii_softc *sc)
1106 {
1107 	static const struct {
1108 		int		reg;
1109 		uint16_t	val;
1110 	} dspcode[] = {
1111 		{ 0x1c,				0x8d68 },
1112 		{ 0x1c,				0x8d68 },
1113 		{ 0,				0 },
1114 	};
1115 	int i;
1116 
1117 	for (i = 0; dspcode[i].reg != 0; i++)
1118 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
1119 }
1120 
1121 void
brgphy_ber_bug(struct mii_softc * sc)1122 brgphy_ber_bug(struct mii_softc *sc)
1123 {
1124 	static const struct {
1125 		int		reg;
1126 		uint16_t	val;
1127 	} dspcode[] = {
1128 		{ BRGPHY_MII_AUXCTL,		0x0c00 },
1129 		{ BRGPHY_MII_DSP_ADDR_REG,	0x000a },
1130 		{ BRGPHY_MII_DSP_RW_PORT,	0x310b },
1131 		{ BRGPHY_MII_DSP_ADDR_REG,	0x201f },
1132 		{ BRGPHY_MII_DSP_RW_PORT,	0x9506 },
1133 		{ BRGPHY_MII_DSP_ADDR_REG,	0x401f },
1134 		{ BRGPHY_MII_DSP_RW_PORT,	0x14e2 },
1135 		{ BRGPHY_MII_AUXCTL,		0x0400 },
1136 		{ 0,				0 },
1137 	};
1138 	int i;
1139 
1140 	for (i = 0; dspcode[i].reg != 0; i++)
1141 		PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val);
1142 }
1143 
1144 /* BCM5701 A0/B0 CRC bug workaround */
1145 void
brgphy_crc_bug(struct mii_softc * sc)1146 brgphy_crc_bug(struct mii_softc *sc)
1147 {
1148 	static const struct {
1149 		int		reg;
1150 		uint16_t	val;
1151 	} dspcode[] = {
1152 		{ BRGPHY_MII_DSP_ADDR_REG,	0x0a75 },
1153 		{ 0x1c,				0x8c68 },
1154 		{ 0x1c,				0x8d68 },
1155 		{ 0x1c,				0x8c68 },
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 void
brgphy_disable_early_dac(struct mii_softc * sc)1165 brgphy_disable_early_dac(struct mii_softc *sc)
1166 {
1167 	uint32_t val;
1168 
1169 	PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x0f08);
1170 	val = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT);
1171 	val &= ~(1 << 8);
1172 	PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, val);
1173 
1174 }
1175 
1176 void
brgphy_jumbo_settings(struct mii_softc * sc)1177 brgphy_jumbo_settings(struct mii_softc *sc)
1178 {
1179 	u_int32_t val;
1180 
1181 	/* Set Jumbo frame settings in the PHY. */
1182 	if (sc->mii_oui == MII_OUI_BROADCOM &&
1183 	    sc->mii_model == MII_MODEL_BROADCOM_BCM5401) {
1184 		/* Cannot do read-modify-write on the BCM5401 */
1185 		PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x4c20);
1186 	} else {
1187 		PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7);
1188 		val = PHY_READ(sc, BRGPHY_MII_AUXCTL);
1189 		PHY_WRITE(sc, BRGPHY_MII_AUXCTL,
1190 			val | BRGPHY_AUXCTL_LONG_PKT);
1191 	}
1192 
1193 	val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL);
1194 	PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL,
1195 		val | BRGPHY_PHY_EXTCTL_HIGH_LA);
1196 }
1197 
1198 void
brgphy_eth_wirespeed(struct mii_softc * sc)1199 brgphy_eth_wirespeed(struct mii_softc *sc)
1200 {
1201 	uint16_t val;
1202 
1203 	/* Enable Ethernet@Wirespeed */
1204 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, BRGPHY_AUXCTL_SHADOW_MISC |
1205 	    BRGPHY_AUXCTL_SHADOW_MISC << BRGPHY_AUXCTL_MISC_READ_SHIFT);
1206 	val = PHY_READ(sc, BRGPHY_MII_AUXCTL) & BRGPHY_AUXCTL_MISC_DATA_MASK;
1207 	val |= BRGPHY_AUXCTL_MISC_WIRESPEED_EN;
1208 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, BRGPHY_AUXCTL_MISC_WRITE_EN |
1209 	    BRGPHY_AUXCTL_SHADOW_MISC | val);
1210 }
1211 
1212 void
brgphy_bcm54xx_clock_delay(struct mii_softc * sc)1213 brgphy_bcm54xx_clock_delay(struct mii_softc *sc)
1214 {
1215 	uint16_t val;
1216 
1217 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, BRGPHY_AUXCTL_SHADOW_MISC |
1218 	    BRGPHY_AUXCTL_SHADOW_MISC << BRGPHY_AUXCTL_MISC_READ_SHIFT);
1219 	val = PHY_READ(sc, BRGPHY_MII_AUXCTL) & BRGPHY_AUXCTL_MISC_DATA_MASK;
1220 	if (sc->mii_flags & MIIF_RXID)
1221 		val |= BRGPHY_AUXCTL_MISC_RGMII_SKEW_EN;
1222 	else
1223 		val &= ~BRGPHY_AUXCTL_MISC_RGMII_SKEW_EN;
1224 	PHY_WRITE(sc, BRGPHY_MII_AUXCTL, BRGPHY_AUXCTL_MISC_WRITE_EN |
1225 	    BRGPHY_AUXCTL_SHADOW_MISC | val);
1226 
1227 	PHY_WRITE(sc, BRGPHY_MII_SHADOW_1C, BRGPHY_SHADOW_1C_CLK_CTRL);
1228 	val = PHY_READ(sc, BRGPHY_MII_SHADOW_1C) & BRGPHY_SHADOW_1C_DATA_MASK;
1229 	if (sc->mii_flags & MIIF_TXID)
1230 		val |= BRGPHY_SHADOW_1C_GTXCLK_EN;
1231 	else
1232 		val &= ~BRGPHY_SHADOW_1C_GTXCLK_EN;
1233 	PHY_WRITE(sc, BRGPHY_MII_SHADOW_1C, BRGPHY_SHADOW_1C_WRITE_EN |
1234 	    BRGPHY_SHADOW_1C_CLK_CTRL | val);
1235 }
1236