1 | /* $NetBSD: brgphy.c,v 1.76 2014/07/02 22:35:10 msaitoh Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, |
9 | * NASA Ames Research Center. |
10 | * |
11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions |
13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright |
15 | * notice, this list of conditions and the following disclaimer. |
16 | * 2. Redistributions in binary form must reproduce the above copyright |
17 | * notice, this list of conditions and the following disclaimer in the |
18 | * documentation and/or other materials provided with the distribution. |
19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | * POSSIBILITY OF SUCH DAMAGE. |
31 | */ |
32 | |
33 | /* |
34 | * Copyright (c) 1997 Manuel Bouyer. All rights reserved. |
35 | * |
36 | * Redistribution and use in source and binary forms, with or without |
37 | * modification, are permitted provided that the following conditions |
38 | * are met: |
39 | * 1. Redistributions of source code must retain the above copyright |
40 | * notice, this list of conditions and the following disclaimer. |
41 | * 2. Redistributions in binary form must reproduce the above copyright |
42 | * notice, this list of conditions and the following disclaimer in the |
43 | * documentation and/or other materials provided with the distribution. |
44 | * |
45 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
46 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
47 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
48 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
49 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
50 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
51 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
52 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
53 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
54 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
55 | */ |
56 | |
57 | /* |
58 | * driver for the Broadcom BCM5400 and BCM5700 Gig-E PHYs. |
59 | * |
60 | * Programming information for this PHY was gleaned from FreeBSD |
61 | * (they were apparently able to get a datasheet from Broadcom). |
62 | */ |
63 | |
64 | #include <sys/cdefs.h> |
65 | __KERNEL_RCSID(0, "$NetBSD: brgphy.c,v 1.76 2014/07/02 22:35:10 msaitoh Exp $" ); |
66 | |
67 | #include <sys/param.h> |
68 | #include <sys/systm.h> |
69 | #include <sys/kernel.h> |
70 | #include <sys/device.h> |
71 | #include <sys/socket.h> |
72 | #include <sys/errno.h> |
73 | #include <prop/proplib.h> |
74 | |
75 | #include <net/if.h> |
76 | #include <net/if_media.h> |
77 | |
78 | #include <dev/mii/mii.h> |
79 | #include <dev/mii/miivar.h> |
80 | #include <dev/mii/miidevs.h> |
81 | #include <dev/mii/brgphyreg.h> |
82 | |
83 | #include <dev/pci/if_bgereg.h> |
84 | #include <dev/pci/if_bnxreg.h> |
85 | |
86 | static int brgphymatch(device_t, cfdata_t, void *); |
87 | static void brgphyattach(device_t, device_t, void *); |
88 | |
89 | struct brgphy_softc { |
90 | struct mii_softc sc_mii; |
91 | bool sc_isbge; |
92 | bool sc_isbnx; |
93 | uint32_t sc_chipid; /* parent's chipid */ |
94 | uint32_t sc_phyflags; /* parent's phyflags */ |
95 | uint32_t sc_shared_hwcfg; /* shared hw config */ |
96 | uint32_t sc_port_hwcfg; /* port specific hw config */ |
97 | }; |
98 | |
99 | CFATTACH_DECL3_NEW(brgphy, sizeof(struct brgphy_softc), |
100 | brgphymatch, brgphyattach, mii_phy_detach, mii_phy_activate, NULL, NULL, |
101 | DVF_DETACH_SHUTDOWN); |
102 | |
103 | static int brgphy_service(struct mii_softc *, struct mii_data *, int); |
104 | static void brgphy_copper_status(struct mii_softc *); |
105 | static void brgphy_fiber_status(struct mii_softc *); |
106 | static void brgphy_5708s_status(struct mii_softc *); |
107 | static void brgphy_5709s_status(struct mii_softc *); |
108 | static int brgphy_mii_phy_auto(struct mii_softc *); |
109 | static void brgphy_loop(struct mii_softc *); |
110 | static void brgphy_reset(struct mii_softc *); |
111 | static void brgphy_bcm5401_dspcode(struct mii_softc *); |
112 | static void brgphy_bcm5411_dspcode(struct mii_softc *); |
113 | static void brgphy_bcm5421_dspcode(struct mii_softc *); |
114 | static void brgphy_bcm54k2_dspcode(struct mii_softc *); |
115 | static void brgphy_adc_bug(struct mii_softc *); |
116 | static void brgphy_5704_a0_bug(struct mii_softc *); |
117 | static void brgphy_ber_bug(struct mii_softc *); |
118 | static void brgphy_crc_bug(struct mii_softc *); |
119 | static void brgphy_disable_early_dac(struct mii_softc *); |
120 | static void brgphy_jumbo_settings(struct mii_softc *); |
121 | static void brgphy_eth_wirespeed(struct mii_softc *); |
122 | |
123 | |
124 | static const struct mii_phy_funcs brgphy_copper_funcs = { |
125 | brgphy_service, brgphy_copper_status, brgphy_reset, |
126 | }; |
127 | |
128 | static const struct mii_phy_funcs brgphy_fiber_funcs = { |
129 | brgphy_service, brgphy_fiber_status, brgphy_reset, |
130 | }; |
131 | |
132 | static const struct mii_phy_funcs brgphy_5708s_funcs = { |
133 | brgphy_service, brgphy_5708s_status, brgphy_reset, |
134 | }; |
135 | |
136 | static const struct mii_phy_funcs brgphy_5709s_funcs = { |
137 | brgphy_service, brgphy_5709s_status, brgphy_reset, |
138 | }; |
139 | |
140 | static const struct mii_phydesc brgphys[] = { |
141 | { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5400, |
142 | MII_STR_BROADCOM_BCM5400 }, |
143 | |
144 | { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5401, |
145 | MII_STR_BROADCOM_BCM5401 }, |
146 | |
147 | { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5411, |
148 | MII_STR_BROADCOM_BCM5411 }, |
149 | |
150 | { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5421, |
151 | MII_STR_BROADCOM_BCM5421 }, |
152 | |
153 | { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5462, |
154 | MII_STR_BROADCOM_BCM5462 }, |
155 | |
156 | { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5461, |
157 | MII_STR_BROADCOM_BCM5461 }, |
158 | |
159 | { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM54K2, |
160 | MII_STR_BROADCOM_BCM54K2 }, |
161 | |
162 | { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5464, |
163 | MII_STR_BROADCOM_BCM5464 }, |
164 | |
165 | { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5701, |
166 | MII_STR_BROADCOM_BCM5701 }, |
167 | |
168 | { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5703, |
169 | MII_STR_BROADCOM_BCM5703 }, |
170 | |
171 | { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5704, |
172 | MII_STR_BROADCOM_BCM5704 }, |
173 | |
174 | { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5705, |
175 | MII_STR_BROADCOM_BCM5705 }, |
176 | |
177 | { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5706, |
178 | MII_STR_BROADCOM_BCM5706 }, |
179 | |
180 | { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5714, |
181 | MII_STR_BROADCOM_BCM5714 }, |
182 | |
183 | { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5750, |
184 | MII_STR_BROADCOM_BCM5750 }, |
185 | |
186 | { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5752, |
187 | MII_STR_BROADCOM_BCM5752 }, |
188 | |
189 | { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5780, |
190 | MII_STR_BROADCOM_BCM5780 }, |
191 | |
192 | { MII_OUI_BROADCOM, MII_MODEL_BROADCOM_BCM5708C, |
193 | MII_STR_BROADCOM_BCM5708C }, |
194 | |
195 | { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5481, |
196 | MII_STR_BROADCOM2_BCM5481 }, |
197 | |
198 | { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5482, |
199 | MII_STR_BROADCOM2_BCM5482 }, |
200 | |
201 | { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5708S, |
202 | MII_STR_BROADCOM2_BCM5708S }, |
203 | |
204 | { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5709C, |
205 | MII_STR_BROADCOM2_BCM5709C }, |
206 | |
207 | { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5709S, |
208 | MII_STR_BROADCOM2_BCM5709S }, |
209 | |
210 | { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5709CAX, |
211 | MII_STR_BROADCOM2_BCM5709CAX }, |
212 | |
213 | { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5722, |
214 | MII_STR_BROADCOM2_BCM5722 }, |
215 | |
216 | { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5754, |
217 | MII_STR_BROADCOM2_BCM5754 }, |
218 | |
219 | { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5755, |
220 | MII_STR_BROADCOM2_BCM5755 }, |
221 | |
222 | { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5756, |
223 | MII_STR_BROADCOM2_BCM5756 }, |
224 | |
225 | { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5761, |
226 | MII_STR_BROADCOM2_BCM5761 }, |
227 | |
228 | { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5784, |
229 | MII_STR_BROADCOM2_BCM5784 }, |
230 | |
231 | { MII_OUI_BROADCOM2, MII_MODEL_BROADCOM2_BCM5785, |
232 | MII_STR_BROADCOM2_BCM5785 }, |
233 | |
234 | { MII_OUI_BROADCOM3, MII_MODEL_BROADCOM3_BCM5717C, |
235 | MII_STR_BROADCOM3_BCM5717C }, |
236 | |
237 | { MII_OUI_BROADCOM3, MII_MODEL_BROADCOM3_BCM5719C, |
238 | MII_STR_BROADCOM3_BCM5719C }, |
239 | |
240 | { MII_OUI_BROADCOM3, MII_MODEL_BROADCOM3_BCM5720C, |
241 | MII_STR_BROADCOM3_BCM5720C }, |
242 | |
243 | { MII_OUI_BROADCOM3, MII_MODEL_BROADCOM3_BCM57765, |
244 | MII_STR_BROADCOM3_BCM57765 }, |
245 | |
246 | { MII_OUI_BROADCOM3, MII_MODEL_BROADCOM3_BCM57780, |
247 | MII_STR_BROADCOM3_BCM57780 }, |
248 | |
249 | { MII_OUI_xxBROADCOM_ALT1, MII_MODEL_xxBROADCOM_ALT1_BCM5906, |
250 | MII_STR_xxBROADCOM_ALT1_BCM5906 }, |
251 | |
252 | { 0, 0, |
253 | NULL }, |
254 | }; |
255 | |
256 | static int |
257 | brgphymatch(device_t parent, cfdata_t match, void *aux) |
258 | { |
259 | struct mii_attach_args *ma = aux; |
260 | |
261 | if (mii_phy_match(ma, brgphys) != NULL) |
262 | return (10); |
263 | |
264 | return (0); |
265 | } |
266 | |
267 | static void |
268 | brgphyattach(device_t parent, device_t self, void *aux) |
269 | { |
270 | struct brgphy_softc *bsc = device_private(self); |
271 | struct mii_softc *sc = &bsc->sc_mii; |
272 | struct mii_attach_args *ma = aux; |
273 | struct mii_data *mii = ma->mii_data; |
274 | const struct mii_phydesc *mpd; |
275 | prop_dictionary_t dict; |
276 | |
277 | mpd = mii_phy_match(ma, brgphys); |
278 | aprint_naive(": Media interface\n" ); |
279 | aprint_normal(": %s, rev. %d\n" , mpd->mpd_name, MII_REV(ma->mii_id2)); |
280 | |
281 | sc->mii_dev = self; |
282 | sc->mii_inst = mii->mii_instance; |
283 | sc->mii_phy = ma->mii_phyno; |
284 | sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2); |
285 | sc->mii_mpd_model = MII_MODEL(ma->mii_id2); |
286 | sc->mii_mpd_rev = MII_REV(ma->mii_id2); |
287 | sc->mii_pdata = mii; |
288 | sc->mii_flags = ma->mii_flags; |
289 | sc->mii_anegticks = MII_ANEGTICKS; |
290 | |
291 | if (device_is_a(parent, "bge" )) |
292 | bsc->sc_isbge = true; |
293 | else if (device_is_a(parent, "bnx" )) |
294 | bsc->sc_isbnx = true; |
295 | |
296 | dict = device_properties(parent); |
297 | if (bsc->sc_isbge || bsc->sc_isbnx) { |
298 | if (!prop_dictionary_get_uint32(dict, "phyflags" , |
299 | &bsc->sc_phyflags)) |
300 | aprint_error_dev(self, "failed to get phyflags\n" ); |
301 | if (!prop_dictionary_get_uint32(dict, "chipid" , |
302 | &bsc->sc_chipid)) |
303 | aprint_error_dev(self, "failed to get chipid\n" ); |
304 | } |
305 | |
306 | if (bsc->sc_isbnx) { |
307 | /* Currently, only bnx use sc_shared_hwcfg and sc_port_hwcfg */ |
308 | if (!prop_dictionary_get_uint32(dict, "shared_hwcfg" , |
309 | &bsc->sc_shared_hwcfg)) |
310 | aprint_error_dev(self, "failed to get shared_hwcfg\n" ); |
311 | if (!prop_dictionary_get_uint32(dict, "port_hwcfg" , |
312 | &bsc->sc_port_hwcfg)) |
313 | aprint_error_dev(self, "failed to get port_hwcfg\n" ); |
314 | } |
315 | |
316 | if (sc->mii_flags & MIIF_HAVEFIBER) { |
317 | if ((sc->mii_mpd_oui == MII_OUI_BROADCOM2) |
318 | && sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5708S) |
319 | sc->mii_funcs = &brgphy_5708s_funcs; |
320 | else if ((sc->mii_mpd_oui == MII_OUI_BROADCOM2) |
321 | && (sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5709S)) { |
322 | if (bsc->sc_isbnx) |
323 | sc->mii_funcs = &brgphy_5709s_funcs; |
324 | else { |
325 | /* |
326 | * XXX |
327 | * 5720S and 5709S shares the same PHY id. |
328 | * Assume 5720S PHY if parent device is bge(4). |
329 | */ |
330 | sc->mii_funcs = &brgphy_5708s_funcs; |
331 | } |
332 | } else |
333 | sc->mii_funcs = &brgphy_fiber_funcs; |
334 | } else |
335 | sc->mii_funcs = &brgphy_copper_funcs; |
336 | |
337 | PHY_RESET(sc); |
338 | |
339 | sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; |
340 | if (sc->mii_capabilities & BMSR_EXTSTAT) |
341 | sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); |
342 | |
343 | aprint_normal_dev(self, "" ); |
344 | if (sc->mii_flags & MIIF_HAVEFIBER) { |
345 | sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP; |
346 | |
347 | /* |
348 | * Set the proper bits for capabilities so that the |
349 | * correct media get selected by mii_phy_add_media() |
350 | */ |
351 | sc->mii_capabilities |= BMSR_ANEG; |
352 | sc->mii_capabilities &= ~BMSR_100T4; |
353 | sc->mii_extcapabilities |= EXTSR_1000XFDX; |
354 | |
355 | if (bsc->sc_isbnx) { |
356 | /* |
357 | * 2.5Gb support is a software enabled feature |
358 | * on the BCM5708S and BCM5709S controllers. |
359 | */ |
360 | #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) |
361 | if (bsc->sc_phyflags |
362 | & BNX_PHY_2_5G_CAPABLE_FLAG) { |
363 | ADD(IFM_MAKEWORD(IFM_ETHER, IFM_2500_SX, |
364 | IFM_FDX, sc->mii_inst), 0); |
365 | aprint_normal("2500baseSX-FDX, " ); |
366 | #undef ADD |
367 | } |
368 | } |
369 | } |
370 | mii_phy_add_media(sc); |
371 | |
372 | aprint_normal("\n" ); |
373 | } |
374 | |
375 | static int |
376 | brgphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) |
377 | { |
378 | struct ifmedia_entry *ife = mii->mii_media.ifm_cur; |
379 | int reg, speed, gig; |
380 | |
381 | switch (cmd) { |
382 | case MII_POLLSTAT: |
383 | /* If we're not polling our PHY instance, just return. */ |
384 | if (IFM_INST(ife->ifm_media) != sc->mii_inst) |
385 | return (0); |
386 | break; |
387 | |
388 | case MII_MEDIACHG: |
389 | /* |
390 | * If the media indicates a different PHY instance, |
391 | * isolate ourselves. |
392 | */ |
393 | if (IFM_INST(ife->ifm_media) != sc->mii_inst) { |
394 | reg = PHY_READ(sc, MII_BMCR); |
395 | PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); |
396 | return (0); |
397 | } |
398 | |
399 | /* If the interface is not up, don't do anything. */ |
400 | if ((mii->mii_ifp->if_flags & IFF_UP) == 0) |
401 | break; |
402 | |
403 | PHY_RESET(sc); /* XXX hardware bug work-around */ |
404 | |
405 | switch (IFM_SUBTYPE(ife->ifm_media)) { |
406 | case IFM_AUTO: |
407 | (void) brgphy_mii_phy_auto(sc); |
408 | break; |
409 | case IFM_2500_SX: |
410 | speed = BRGPHY_5708S_BMCR_2500; |
411 | goto setit; |
412 | case IFM_1000_SX: |
413 | case IFM_1000_T: |
414 | speed = BMCR_S1000; |
415 | goto setit; |
416 | case IFM_100_TX: |
417 | speed = BMCR_S100; |
418 | goto setit; |
419 | case IFM_10_T: |
420 | speed = BMCR_S10; |
421 | setit: |
422 | brgphy_loop(sc); |
423 | if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { |
424 | speed |= BMCR_FDX; |
425 | gig = GTCR_ADV_1000TFDX; |
426 | } else |
427 | gig = GTCR_ADV_1000THDX; |
428 | |
429 | PHY_WRITE(sc, MII_100T2CR, 0); |
430 | PHY_WRITE(sc, MII_ANAR, ANAR_CSMA); |
431 | PHY_WRITE(sc, MII_BMCR, speed); |
432 | |
433 | if ((IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) && |
434 | (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_SX) && |
435 | (IFM_SUBTYPE(ife->ifm_media) != IFM_2500_SX)) |
436 | break; |
437 | |
438 | PHY_WRITE(sc, MII_100T2CR, gig); |
439 | PHY_WRITE(sc, MII_BMCR, |
440 | speed | BMCR_AUTOEN | BMCR_STARTNEG); |
441 | |
442 | if ((sc->mii_mpd_oui != MII_OUI_BROADCOM) |
443 | || (sc->mii_mpd_model != MII_MODEL_BROADCOM_BCM5701)) |
444 | break; |
445 | |
446 | if (mii->mii_media.ifm_media & IFM_ETH_MASTER) |
447 | gig |= GTCR_MAN_MS | GTCR_ADV_MS; |
448 | PHY_WRITE(sc, MII_100T2CR, gig); |
449 | break; |
450 | default: |
451 | return (EINVAL); |
452 | } |
453 | break; |
454 | |
455 | case MII_TICK: |
456 | /* If we're not currently selected, just return. */ |
457 | if (IFM_INST(ife->ifm_media) != sc->mii_inst) |
458 | return (0); |
459 | |
460 | /* Is the interface even up? */ |
461 | if ((mii->mii_ifp->if_flags & IFF_UP) == 0) |
462 | return 0; |
463 | |
464 | /* Only used for autonegotiation. */ |
465 | if ((IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) && |
466 | (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T)) { |
467 | sc->mii_ticks = 0; |
468 | break; |
469 | } |
470 | |
471 | /* |
472 | * Check for link. |
473 | * Read the status register twice; BMSR_LINK is latch-low. |
474 | */ |
475 | reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); |
476 | if (reg & BMSR_LINK) { |
477 | sc->mii_ticks = 0; |
478 | break; |
479 | } |
480 | |
481 | /* |
482 | * mii_ticks == 0 means it's the first tick after changing the |
483 | * media or the link became down since the last tick |
484 | * (see above), so break to update the status. |
485 | */ |
486 | if (sc->mii_ticks++ == 0) |
487 | break; |
488 | |
489 | /* Only retry autonegotiation every mii_anegticks seconds. */ |
490 | KASSERT(sc->mii_anegticks != 0); |
491 | if (sc->mii_ticks <= sc->mii_anegticks) |
492 | break; |
493 | |
494 | brgphy_mii_phy_auto(sc); |
495 | break; |
496 | |
497 | case MII_DOWN: |
498 | mii_phy_down(sc); |
499 | return (0); |
500 | } |
501 | |
502 | /* Update the media status. */ |
503 | mii_phy_status(sc); |
504 | |
505 | /* |
506 | * Callback if something changed. Note that we need to poke the DSP on |
507 | * the Broadcom PHYs if the media changes. |
508 | */ |
509 | if (sc->mii_media_active != mii->mii_media_active || |
510 | sc->mii_media_status != mii->mii_media_status || |
511 | cmd == MII_MEDIACHG) { |
512 | switch (sc->mii_mpd_oui) { |
513 | case MII_OUI_BROADCOM: |
514 | switch (sc->mii_mpd_model) { |
515 | case MII_MODEL_BROADCOM_BCM5400: |
516 | brgphy_bcm5401_dspcode(sc); |
517 | break; |
518 | case MII_MODEL_BROADCOM_BCM5401: |
519 | if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3) |
520 | brgphy_bcm5401_dspcode(sc); |
521 | break; |
522 | case MII_MODEL_BROADCOM_BCM5411: |
523 | brgphy_bcm5411_dspcode(sc); |
524 | break; |
525 | } |
526 | break; |
527 | } |
528 | } |
529 | |
530 | /* Callback if something changed. */ |
531 | mii_phy_update(sc, cmd); |
532 | return (0); |
533 | } |
534 | |
535 | static void |
536 | brgphy_copper_status(struct mii_softc *sc) |
537 | { |
538 | struct mii_data *mii = sc->mii_pdata; |
539 | struct ifmedia_entry *ife = mii->mii_media.ifm_cur; |
540 | int bmcr, bmsr, auxsts, gtsr; |
541 | |
542 | mii->mii_media_status = IFM_AVALID; |
543 | mii->mii_media_active = IFM_ETHER; |
544 | |
545 | bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); |
546 | if (bmsr & BMSR_LINK) |
547 | mii->mii_media_status |= IFM_ACTIVE; |
548 | |
549 | bmcr = PHY_READ(sc, MII_BMCR); |
550 | if (bmcr & BMCR_ISO) { |
551 | mii->mii_media_active |= IFM_NONE; |
552 | mii->mii_media_status = 0; |
553 | return; |
554 | } |
555 | |
556 | if (bmcr & BMCR_LOOP) |
557 | mii->mii_media_active |= IFM_LOOP; |
558 | |
559 | if (bmcr & BMCR_AUTOEN) { |
560 | /* |
561 | * The media status bits are only valid of autonegotiation |
562 | * has completed (or it's disabled). |
563 | */ |
564 | if ((bmsr & BMSR_ACOMP) == 0) { |
565 | /* Erg, still trying, I guess... */ |
566 | mii->mii_media_active |= IFM_NONE; |
567 | return; |
568 | } |
569 | |
570 | auxsts = PHY_READ(sc, BRGPHY_MII_AUXSTS); |
571 | |
572 | switch (auxsts & BRGPHY_AUXSTS_AN_RES) { |
573 | case BRGPHY_RES_1000FD: |
574 | mii->mii_media_active |= IFM_1000_T | IFM_FDX; |
575 | gtsr = PHY_READ(sc, MII_100T2SR); |
576 | if (gtsr & GTSR_MS_RES) |
577 | mii->mii_media_active |= IFM_ETH_MASTER; |
578 | break; |
579 | |
580 | case BRGPHY_RES_1000HD: |
581 | mii->mii_media_active |= IFM_1000_T | IFM_HDX; |
582 | gtsr = PHY_READ(sc, MII_100T2SR); |
583 | if (gtsr & GTSR_MS_RES) |
584 | mii->mii_media_active |= IFM_ETH_MASTER; |
585 | break; |
586 | |
587 | case BRGPHY_RES_100FD: |
588 | mii->mii_media_active |= IFM_100_TX | IFM_FDX; |
589 | break; |
590 | |
591 | case BRGPHY_RES_100T4: |
592 | mii->mii_media_active |= IFM_100_T4 | IFM_HDX; |
593 | break; |
594 | |
595 | case BRGPHY_RES_100HD: |
596 | mii->mii_media_active |= IFM_100_TX | IFM_HDX; |
597 | break; |
598 | |
599 | case BRGPHY_RES_10FD: |
600 | mii->mii_media_active |= IFM_10_T | IFM_FDX; |
601 | break; |
602 | |
603 | case BRGPHY_RES_10HD: |
604 | mii->mii_media_active |= IFM_10_T | IFM_HDX; |
605 | break; |
606 | |
607 | default: |
608 | mii->mii_media_active |= IFM_NONE; |
609 | mii->mii_media_status = 0; |
610 | } |
611 | |
612 | if (mii->mii_media_active & IFM_FDX) |
613 | mii->mii_media_active |= mii_phy_flowstatus(sc); |
614 | |
615 | } else |
616 | mii->mii_media_active = ife->ifm_media; |
617 | } |
618 | |
619 | void |
620 | brgphy_fiber_status(struct mii_softc *sc) |
621 | { |
622 | struct mii_data *mii = sc->mii_pdata; |
623 | struct ifmedia_entry *ife = mii->mii_media.ifm_cur; |
624 | int bmcr, bmsr; |
625 | |
626 | mii->mii_media_status = IFM_AVALID; |
627 | mii->mii_media_active = IFM_ETHER; |
628 | |
629 | bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); |
630 | if (bmsr & BMSR_LINK) |
631 | mii->mii_media_status |= IFM_ACTIVE; |
632 | |
633 | bmcr = PHY_READ(sc, MII_BMCR); |
634 | if (bmcr & BMCR_LOOP) |
635 | mii->mii_media_active |= IFM_LOOP; |
636 | |
637 | if (bmcr & BMCR_AUTOEN) { |
638 | int val; |
639 | |
640 | if ((bmsr & BMSR_ACOMP) == 0) { |
641 | /* Erg, still trying, I guess... */ |
642 | mii->mii_media_active |= IFM_NONE; |
643 | return; |
644 | } |
645 | |
646 | mii->mii_media_active |= IFM_1000_SX; |
647 | |
648 | val = PHY_READ(sc, MII_ANAR) & |
649 | PHY_READ(sc, MII_ANLPAR); |
650 | |
651 | if (val & ANAR_X_FD) |
652 | mii->mii_media_active |= IFM_FDX; |
653 | else |
654 | mii->mii_media_active |= IFM_HDX; |
655 | |
656 | if (mii->mii_media_active & IFM_FDX) |
657 | mii->mii_media_active |= mii_phy_flowstatus(sc); |
658 | } else |
659 | mii->mii_media_active = ife->ifm_media; |
660 | } |
661 | |
662 | void |
663 | brgphy_5708s_status(struct mii_softc *sc) |
664 | { |
665 | struct mii_data *mii = sc->mii_pdata; |
666 | struct ifmedia_entry *ife = mii->mii_media.ifm_cur; |
667 | int bmcr, bmsr; |
668 | |
669 | mii->mii_media_status = IFM_AVALID; |
670 | mii->mii_media_active = IFM_ETHER; |
671 | |
672 | bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); |
673 | if (bmsr & BMSR_LINK) |
674 | mii->mii_media_status |= IFM_ACTIVE; |
675 | |
676 | bmcr = PHY_READ(sc, MII_BMCR); |
677 | if (bmcr & BMCR_LOOP) |
678 | mii->mii_media_active |= IFM_LOOP; |
679 | |
680 | if (bmcr & BMCR_AUTOEN) { |
681 | int xstat; |
682 | |
683 | if ((bmsr & BMSR_ACOMP) == 0) { |
684 | PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, |
685 | BRGPHY_5708S_DIG_PG0); |
686 | xstat = PHY_READ(sc, BRGPHY_5708S_PG0_1000X_STAT1); |
687 | if ((xstat & BRGPHY_5708S_PG0_1000X_STAT1_LINK) == 0) { |
688 | /* Erg, still trying, I guess... */ |
689 | mii->mii_media_active |= IFM_NONE; |
690 | return; |
691 | } |
692 | } |
693 | |
694 | PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, |
695 | BRGPHY_5708S_DIG_PG0); |
696 | xstat = PHY_READ(sc, BRGPHY_5708S_PG0_1000X_STAT1); |
697 | |
698 | switch (xstat & BRGPHY_5708S_PG0_1000X_STAT1_SPEED_MASK) { |
699 | case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_10: |
700 | mii->mii_media_active |= IFM_10_FL; |
701 | break; |
702 | case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_100: |
703 | mii->mii_media_active |= IFM_100_FX; |
704 | break; |
705 | case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_1G: |
706 | mii->mii_media_active |= IFM_1000_SX; |
707 | break; |
708 | case BRGPHY_5708S_PG0_1000X_STAT1_SPEED_25G: |
709 | mii->mii_media_active |= IFM_2500_SX; |
710 | break; |
711 | } |
712 | |
713 | if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_FDX) |
714 | mii->mii_media_active |= IFM_FDX; |
715 | else |
716 | mii->mii_media_active |= IFM_HDX; |
717 | |
718 | if (mii->mii_media_active & IFM_FDX) { |
719 | if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_TX_PAUSE) |
720 | mii->mii_media_active |= IFM_FLOW | IFM_ETH_TXPAUSE; |
721 | if (xstat & BRGPHY_5708S_PG0_1000X_STAT1_RX_PAUSE) |
722 | mii->mii_media_active |= IFM_FLOW | IFM_ETH_RXPAUSE; |
723 | } |
724 | } else |
725 | mii->mii_media_active = ife->ifm_media; |
726 | } |
727 | |
728 | static void |
729 | brgphy_5709s_status(struct mii_softc *sc) |
730 | { |
731 | struct mii_data *mii = sc->mii_pdata; |
732 | struct ifmedia_entry *ife = mii->mii_media.ifm_cur; |
733 | int bmcr, bmsr, auxsts; |
734 | |
735 | mii->mii_media_status = IFM_AVALID; |
736 | mii->mii_media_active = IFM_ETHER; |
737 | |
738 | bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); |
739 | if (bmsr & BMSR_LINK) |
740 | mii->mii_media_status |= IFM_ACTIVE; |
741 | |
742 | bmcr = PHY_READ(sc, MII_BMCR); |
743 | if (bmcr & BMCR_ISO) { |
744 | mii->mii_media_active |= IFM_NONE; |
745 | mii->mii_media_status = 0; |
746 | return; |
747 | } |
748 | |
749 | if (bmcr & BMCR_LOOP) |
750 | mii->mii_media_active |= IFM_LOOP; |
751 | |
752 | if (bmcr & BMCR_AUTOEN) { |
753 | /* |
754 | * The media status bits are only valid of autonegotiation |
755 | * has completed (or it's disabled). |
756 | */ |
757 | if ((bmsr & BMSR_ACOMP) == 0) { |
758 | /* Erg, still trying, I guess... */ |
759 | mii->mii_media_active |= IFM_NONE; |
760 | return; |
761 | } |
762 | |
763 | /* 5709S has its own general purpose status registers */ |
764 | PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, |
765 | BRGPHY_BLOCK_ADDR_GP_STATUS); |
766 | auxsts = PHY_READ(sc, BRGPHY_GP_STATUS_TOP_ANEG_STATUS); |
767 | |
768 | PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, |
769 | BRGPHY_BLOCK_ADDR_COMBO_IEEE0); |
770 | |
771 | switch (auxsts & BRGPHY_GP_STATUS_TOP_ANEG_SPEED_MASK) { |
772 | case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_10: |
773 | mii->mii_media_active |= IFM_10_FL; |
774 | break; |
775 | case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_100: |
776 | mii->mii_media_active |= IFM_100_FX; |
777 | break; |
778 | case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_1G: |
779 | mii->mii_media_active |= IFM_1000_SX; |
780 | break; |
781 | case BRGPHY_GP_STATUS_TOP_ANEG_SPEED_25G: |
782 | mii->mii_media_active |= IFM_2500_SX; |
783 | break; |
784 | default: |
785 | mii->mii_media_active |= IFM_NONE; |
786 | mii->mii_media_status = 0; |
787 | break; |
788 | } |
789 | |
790 | if (auxsts & BRGPHY_GP_STATUS_TOP_ANEG_FDX) |
791 | mii->mii_media_active |= IFM_FDX; |
792 | else |
793 | mii->mii_media_active |= IFM_HDX; |
794 | |
795 | if (mii->mii_media_active & IFM_FDX) |
796 | mii->mii_media_active |= mii_phy_flowstatus(sc); |
797 | } else |
798 | mii->mii_media_active = ife->ifm_media; |
799 | } |
800 | |
801 | int |
802 | brgphy_mii_phy_auto(struct mii_softc *sc) |
803 | { |
804 | int anar, ktcr = 0; |
805 | |
806 | sc->mii_ticks = 0; |
807 | brgphy_loop(sc); |
808 | PHY_RESET(sc); |
809 | |
810 | if (sc->mii_flags & MIIF_HAVEFIBER) { |
811 | anar = ANAR_X_FD | ANAR_X_HD; |
812 | if (sc->mii_flags & MIIF_DOPAUSE) |
813 | anar |= ANAR_X_PAUSE_TOWARDS; |
814 | } else { |
815 | anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA; |
816 | if (sc->mii_flags & MIIF_DOPAUSE) |
817 | anar |= ANAR_FC | ANAR_PAUSE_ASYM; |
818 | ktcr = GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX; |
819 | if ((sc->mii_mpd_oui == MII_OUI_BROADCOM) |
820 | && (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5701)) |
821 | ktcr |= GTCR_MAN_MS | GTCR_ADV_MS; |
822 | PHY_WRITE(sc, MII_100T2CR, ktcr); |
823 | ktcr = PHY_READ(sc, MII_100T2CR); |
824 | } |
825 | PHY_WRITE(sc, MII_ANAR, anar); |
826 | |
827 | /* Start autonegotiation */ |
828 | PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG); |
829 | PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00); |
830 | |
831 | return (EJUSTRETURN); |
832 | } |
833 | |
834 | void |
835 | brgphy_loop(struct mii_softc *sc) |
836 | { |
837 | uint32_t bmsr; |
838 | int i; |
839 | |
840 | PHY_WRITE(sc, MII_BMCR, BMCR_LOOP); |
841 | for (i = 0; i < 15000; i++) { |
842 | bmsr = PHY_READ(sc, MII_BMSR); |
843 | if (!(bmsr & BMSR_LINK)) |
844 | break; |
845 | DELAY(10); |
846 | } |
847 | } |
848 | |
849 | static void |
850 | brgphy_reset(struct mii_softc *sc) |
851 | { |
852 | struct brgphy_softc *bsc = device_private(sc->mii_dev); |
853 | |
854 | mii_phy_reset(sc); |
855 | switch (sc->mii_mpd_oui) { |
856 | case MII_OUI_BROADCOM: |
857 | switch (sc->mii_mpd_model) { |
858 | case MII_MODEL_BROADCOM_BCM5400: |
859 | brgphy_bcm5401_dspcode(sc); |
860 | break; |
861 | case MII_MODEL_BROADCOM_BCM5401: |
862 | if (sc->mii_mpd_rev == 1 || sc->mii_mpd_rev == 3) |
863 | brgphy_bcm5401_dspcode(sc); |
864 | break; |
865 | case MII_MODEL_BROADCOM_BCM5411: |
866 | brgphy_bcm5411_dspcode(sc); |
867 | break; |
868 | case MII_MODEL_BROADCOM_BCM5421: |
869 | brgphy_bcm5421_dspcode(sc); |
870 | break; |
871 | case MII_MODEL_BROADCOM_BCM54K2: |
872 | brgphy_bcm54k2_dspcode(sc); |
873 | break; |
874 | } |
875 | break; |
876 | case MII_OUI_BROADCOM3: |
877 | switch (sc->mii_mpd_model) { |
878 | case MII_MODEL_BROADCOM3_BCM5717C: |
879 | case MII_MODEL_BROADCOM3_BCM5719C: |
880 | case MII_MODEL_BROADCOM3_BCM5720C: |
881 | case MII_MODEL_BROADCOM3_BCM57765: |
882 | return; |
883 | } |
884 | break; |
885 | default: |
886 | break; |
887 | } |
888 | |
889 | /* Handle any bge (NetXtreme/NetLink) workarounds. */ |
890 | if (bsc->sc_isbge) { |
891 | if (!(sc->mii_flags & MIIF_HAVEFIBER)) { |
892 | |
893 | if (bsc->sc_phyflags & BGEPHYF_ADC_BUG) |
894 | brgphy_adc_bug(sc); |
895 | if (bsc->sc_phyflags & BGEPHYF_5704_A0_BUG) |
896 | brgphy_5704_a0_bug(sc); |
897 | if (bsc->sc_phyflags & BGEPHYF_BER_BUG) |
898 | brgphy_ber_bug(sc); |
899 | else if (bsc->sc_phyflags & BGEPHYF_JITTER_BUG) { |
900 | PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0c00); |
901 | PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, |
902 | 0x000a); |
903 | |
904 | if (bsc->sc_phyflags |
905 | & BGEPHYF_ADJUST_TRIM) { |
906 | PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, |
907 | 0x110b); |
908 | PHY_WRITE(sc, BRGPHY_TEST1, |
909 | BRGPHY_TEST1_TRIM_EN | 0x4); |
910 | } else { |
911 | PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, |
912 | 0x010b); |
913 | } |
914 | |
915 | PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0400); |
916 | } |
917 | if (bsc->sc_phyflags & BGEPHYF_CRC_BUG) |
918 | brgphy_crc_bug(sc); |
919 | |
920 | /* Set Jumbo frame settings in the PHY. */ |
921 | if (bsc->sc_phyflags & BGEPHYF_JUMBO_CAPABLE) |
922 | brgphy_jumbo_settings(sc); |
923 | |
924 | /* Adjust output voltage */ |
925 | if ((sc->mii_mpd_oui == MII_OUI_BROADCOM2) |
926 | && (sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5906)) |
927 | PHY_WRITE(sc, BRGPHY_MII_EPHY_PTEST, 0x12); |
928 | |
929 | /* Enable Ethernet@Wirespeed */ |
930 | if (!(bsc->sc_phyflags & BGEPHYF_NO_WIRESPEED)) |
931 | brgphy_eth_wirespeed(sc); |
932 | |
933 | #if 0 |
934 | /* Enable Link LED on Dell boxes */ |
935 | if (bsc->sc_phyflags & BGEPHYF_NO_3LED) { |
936 | PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, |
937 | PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL) |
938 | & ~BRGPHY_PHY_EXTCTL_3_LED); |
939 | } |
940 | #endif |
941 | } |
942 | /* Handle any bnx (NetXtreme II) workarounds. */ |
943 | } else if (bsc->sc_isbnx) { |
944 | if ((sc->mii_mpd_oui == MII_OUI_BROADCOM2) |
945 | && sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5708S) { |
946 | /* Store autoneg capabilities/results in digital block (Page 0) */ |
947 | PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG3_PG2); |
948 | PHY_WRITE(sc, BRGPHY_5708S_PG2_DIGCTL_3_0, |
949 | BRGPHY_5708S_PG2_DIGCTL_3_0_USE_IEEE); |
950 | PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, BRGPHY_5708S_DIG_PG0); |
951 | |
952 | /* Enable fiber mode and autodetection */ |
953 | PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL1, |
954 | PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL1) | |
955 | BRGPHY_5708S_PG0_1000X_CTL1_AUTODET_EN | |
956 | BRGPHY_5708S_PG0_1000X_CTL1_FIBER_MODE); |
957 | |
958 | /* Enable parallel detection */ |
959 | PHY_WRITE(sc, BRGPHY_5708S_PG0_1000X_CTL2, |
960 | PHY_READ(sc, BRGPHY_5708S_PG0_1000X_CTL2) | |
961 | BRGPHY_5708S_PG0_1000X_CTL2_PAR_DET_EN); |
962 | |
963 | /* Advertise 2.5G support through next page during autoneg */ |
964 | if (bsc->sc_phyflags & BNX_PHY_2_5G_CAPABLE_FLAG) |
965 | PHY_WRITE(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1, |
966 | PHY_READ(sc, BRGPHY_5708S_ANEG_NXT_PG_XMIT1) | |
967 | BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G); |
968 | |
969 | /* Increase TX signal amplitude */ |
970 | if ((_BNX_CHIP_ID(bsc->sc_chipid) == BNX_CHIP_ID_5708_A0) || |
971 | (_BNX_CHIP_ID(bsc->sc_chipid) == BNX_CHIP_ID_5708_B0) || |
972 | (_BNX_CHIP_ID(bsc->sc_chipid) == BNX_CHIP_ID_5708_B1)) { |
973 | PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, |
974 | BRGPHY_5708S_TX_MISC_PG5); |
975 | PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL1, |
976 | PHY_READ(sc, BRGPHY_5708S_PG5_TXACTL1) & |
977 | ~BRGPHY_5708S_PG5_TXACTL1_VCM); |
978 | PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, |
979 | BRGPHY_5708S_DIG_PG0); |
980 | } |
981 | |
982 | /* Backplanes use special driver/pre-driver/pre-emphasis values. */ |
983 | if ((bsc->sc_shared_hwcfg & BNX_SHARED_HW_CFG_PHY_BACKPLANE) && |
984 | (bsc->sc_port_hwcfg & BNX_PORT_HW_CFG_CFG_TXCTL3_MASK)) { |
985 | PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, |
986 | BRGPHY_5708S_TX_MISC_PG5); |
987 | PHY_WRITE(sc, BRGPHY_5708S_PG5_TXACTL3, |
988 | bsc->sc_port_hwcfg & |
989 | BNX_PORT_HW_CFG_CFG_TXCTL3_MASK); |
990 | PHY_WRITE(sc, BRGPHY_5708S_BLOCK_ADDR, |
991 | BRGPHY_5708S_DIG_PG0); |
992 | } |
993 | } else if ((sc->mii_mpd_oui == MII_OUI_BROADCOM2) |
994 | && (sc->mii_mpd_model == MII_MODEL_BROADCOM2_BCM5709S)) { |
995 | /* Select the SerDes Digital block of the AN MMD. */ |
996 | PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, |
997 | BRGPHY_BLOCK_ADDR_SERDES_DIG); |
998 | |
999 | PHY_WRITE(sc, BRGPHY_SERDES_DIG_1000X_CTL1, |
1000 | (PHY_READ(sc, BRGPHY_SERDES_DIG_1000X_CTL1) & |
1001 | ~BRGPHY_SD_DIG_1000X_CTL1_AUTODET) | |
1002 | BRGPHY_SD_DIG_1000X_CTL1_FIBER); |
1003 | |
1004 | if (bsc->sc_phyflags & BNX_PHY_2_5G_CAPABLE_FLAG) { |
1005 | /* Select the Over 1G block of the AN MMD. */ |
1006 | PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, |
1007 | BRGPHY_BLOCK_ADDR_OVER_1G); |
1008 | |
1009 | /* |
1010 | * Enable autoneg "Next Page" to advertise |
1011 | * 2.5G support. |
1012 | */ |
1013 | PHY_WRITE(sc, BRGPHY_OVER_1G_UNFORMAT_PG1, |
1014 | PHY_READ(sc, BRGPHY_OVER_1G_UNFORMAT_PG1) | |
1015 | BRGPHY_5708S_ANEG_NXT_PG_XMIT1_25G); |
1016 | } |
1017 | |
1018 | /* |
1019 | * Select the Multi-Rate Backplane Ethernet block of |
1020 | * the AN MMD. |
1021 | */ |
1022 | PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, |
1023 | BRGPHY_BLOCK_ADDR_MRBE); |
1024 | |
1025 | /* Enable MRBE speed autoneg. */ |
1026 | PHY_WRITE(sc, BRGPHY_MRBE_MSG_PG5_NP, |
1027 | PHY_READ(sc, BRGPHY_MRBE_MSG_PG5_NP) | |
1028 | BRGPHY_MRBE_MSG_PG5_NP_MBRE | |
1029 | BRGPHY_MRBE_MSG_PG5_NP_T2); |
1030 | |
1031 | /* Select the Clause 73 User B0 block of the AN MMD. */ |
1032 | PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, |
1033 | BRGPHY_BLOCK_ADDR_CL73_USER_B0); |
1034 | |
1035 | /* Enable MRBE speed autoneg. */ |
1036 | PHY_WRITE(sc, BRGPHY_CL73_USER_B0_MBRE_CTL1, |
1037 | BRGPHY_CL73_USER_B0_MBRE_CTL1_NP_AFT_BP | |
1038 | BRGPHY_CL73_USER_B0_MBRE_CTL1_STA_MGR | |
1039 | BRGPHY_CL73_USER_B0_MBRE_CTL1_ANEG); |
1040 | |
1041 | PHY_WRITE(sc, BRGPHY_BLOCK_ADDR, |
1042 | BRGPHY_BLOCK_ADDR_COMBO_IEEE0); |
1043 | |
1044 | } else if (_BNX_CHIP_NUM(bsc->sc_chipid) == BNX_CHIP_NUM_5709) { |
1045 | if (_BNX_CHIP_REV(bsc->sc_chipid) == BNX_CHIP_REV_Ax || |
1046 | _BNX_CHIP_REV(bsc->sc_chipid) == BNX_CHIP_REV_Bx) |
1047 | brgphy_disable_early_dac(sc); |
1048 | |
1049 | /* Set Jumbo frame settings in the PHY. */ |
1050 | brgphy_jumbo_settings(sc); |
1051 | |
1052 | /* Enable Ethernet@Wirespeed */ |
1053 | brgphy_eth_wirespeed(sc); |
1054 | } else { |
1055 | if (!(sc->mii_flags & MIIF_HAVEFIBER)) { |
1056 | brgphy_ber_bug(sc); |
1057 | |
1058 | /* Set Jumbo frame settings in the PHY. */ |
1059 | brgphy_jumbo_settings(sc); |
1060 | |
1061 | /* Enable Ethernet@Wirespeed */ |
1062 | brgphy_eth_wirespeed(sc); |
1063 | } |
1064 | } |
1065 | } |
1066 | } |
1067 | |
1068 | /* Turn off tap power management on 5401. */ |
1069 | static void |
1070 | brgphy_bcm5401_dspcode(struct mii_softc *sc) |
1071 | { |
1072 | static const struct { |
1073 | int reg; |
1074 | uint16_t val; |
1075 | } dspcode[] = { |
1076 | { BRGPHY_MII_AUXCTL, 0x0c20 }, |
1077 | { BRGPHY_MII_DSP_ADDR_REG, 0x0012 }, |
1078 | { BRGPHY_MII_DSP_RW_PORT, 0x1804 }, |
1079 | { BRGPHY_MII_DSP_ADDR_REG, 0x0013 }, |
1080 | { BRGPHY_MII_DSP_RW_PORT, 0x1204 }, |
1081 | { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, |
1082 | { BRGPHY_MII_DSP_RW_PORT, 0x0132 }, |
1083 | { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, |
1084 | { BRGPHY_MII_DSP_RW_PORT, 0x0232 }, |
1085 | { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, |
1086 | { BRGPHY_MII_DSP_RW_PORT, 0x0a20 }, |
1087 | { 0, 0 }, |
1088 | }; |
1089 | int i; |
1090 | |
1091 | for (i = 0; dspcode[i].reg != 0; i++) |
1092 | PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); |
1093 | delay(40); |
1094 | } |
1095 | |
1096 | static void |
1097 | brgphy_bcm5411_dspcode(struct mii_softc *sc) |
1098 | { |
1099 | static const struct { |
1100 | int reg; |
1101 | uint16_t val; |
1102 | } dspcode[] = { |
1103 | { 0x1c, 0x8c23 }, |
1104 | { 0x1c, 0x8ca3 }, |
1105 | { 0x1c, 0x8c23 }, |
1106 | { 0, 0 }, |
1107 | }; |
1108 | int i; |
1109 | |
1110 | for (i = 0; dspcode[i].reg != 0; i++) |
1111 | PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); |
1112 | } |
1113 | |
1114 | void |
1115 | brgphy_bcm5421_dspcode(struct mii_softc *sc) |
1116 | { |
1117 | uint16_t data; |
1118 | |
1119 | /* Set Class A mode */ |
1120 | PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x1007); |
1121 | data = PHY_READ(sc, BRGPHY_MII_AUXCTL); |
1122 | PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0400); |
1123 | |
1124 | /* Set FFE gamma override to -0.125 */ |
1125 | PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x0007); |
1126 | data = PHY_READ(sc, BRGPHY_MII_AUXCTL); |
1127 | PHY_WRITE(sc, BRGPHY_MII_AUXCTL, data | 0x0800); |
1128 | PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x000a); |
1129 | data = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT); |
1130 | PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, data | 0x0200); |
1131 | } |
1132 | |
1133 | void |
1134 | brgphy_bcm54k2_dspcode(struct mii_softc *sc) |
1135 | { |
1136 | static const struct { |
1137 | int reg; |
1138 | uint16_t val; |
1139 | } dspcode[] = { |
1140 | { 4, 0x01e1 }, |
1141 | { 9, 0x0300 }, |
1142 | { 0, 0 }, |
1143 | }; |
1144 | int i; |
1145 | |
1146 | for (i = 0; dspcode[i].reg != 0; i++) |
1147 | PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); |
1148 | } |
1149 | |
1150 | static void |
1151 | brgphy_adc_bug(struct mii_softc *sc) |
1152 | { |
1153 | static const struct { |
1154 | int reg; |
1155 | uint16_t val; |
1156 | } dspcode[] = { |
1157 | { BRGPHY_MII_AUXCTL, 0x0c00 }, |
1158 | { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, |
1159 | { BRGPHY_MII_DSP_RW_PORT, 0x2aaa }, |
1160 | { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, |
1161 | { BRGPHY_MII_DSP_RW_PORT, 0x0323 }, |
1162 | { BRGPHY_MII_AUXCTL, 0x0400 }, |
1163 | { 0, 0 }, |
1164 | }; |
1165 | int i; |
1166 | |
1167 | for (i = 0; dspcode[i].reg != 0; i++) |
1168 | PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); |
1169 | } |
1170 | |
1171 | static void |
1172 | brgphy_5704_a0_bug(struct mii_softc *sc) |
1173 | { |
1174 | static const struct { |
1175 | int reg; |
1176 | uint16_t val; |
1177 | } dspcode[] = { |
1178 | { 0x1c, 0x8d68 }, |
1179 | { 0x1c, 0x8d68 }, |
1180 | { 0, 0 }, |
1181 | }; |
1182 | int i; |
1183 | |
1184 | for (i = 0; dspcode[i].reg != 0; i++) |
1185 | PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); |
1186 | } |
1187 | |
1188 | static void |
1189 | brgphy_ber_bug(struct mii_softc *sc) |
1190 | { |
1191 | static const struct { |
1192 | int reg; |
1193 | uint16_t val; |
1194 | } dspcode[] = { |
1195 | { BRGPHY_MII_AUXCTL, 0x0c00 }, |
1196 | { BRGPHY_MII_DSP_ADDR_REG, 0x000a }, |
1197 | { BRGPHY_MII_DSP_RW_PORT, 0x310b }, |
1198 | { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, |
1199 | { BRGPHY_MII_DSP_RW_PORT, 0x9506 }, |
1200 | { BRGPHY_MII_DSP_ADDR_REG, 0x401f }, |
1201 | { BRGPHY_MII_DSP_RW_PORT, 0x14e2 }, |
1202 | { BRGPHY_MII_AUXCTL, 0x0400 }, |
1203 | { 0, 0 }, |
1204 | }; |
1205 | int i; |
1206 | |
1207 | for (i = 0; dspcode[i].reg != 0; i++) |
1208 | PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); |
1209 | } |
1210 | |
1211 | /* BCM5701 A0/B0 CRC bug workaround */ |
1212 | void |
1213 | brgphy_crc_bug(struct mii_softc *sc) |
1214 | { |
1215 | static const struct { |
1216 | int reg; |
1217 | uint16_t val; |
1218 | } dspcode[] = { |
1219 | { BRGPHY_MII_DSP_ADDR_REG, 0x0a75 }, |
1220 | { 0x1c, 0x8c68 }, |
1221 | { 0x1c, 0x8d68 }, |
1222 | { 0x1c, 0x8c68 }, |
1223 | { 0, 0 }, |
1224 | }; |
1225 | int i; |
1226 | |
1227 | for (i = 0; dspcode[i].reg != 0; i++) |
1228 | PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); |
1229 | } |
1230 | |
1231 | static void |
1232 | brgphy_disable_early_dac(struct mii_softc *sc) |
1233 | { |
1234 | uint32_t val; |
1235 | |
1236 | PHY_WRITE(sc, BRGPHY_MII_DSP_ADDR_REG, 0x0f08); |
1237 | val = PHY_READ(sc, BRGPHY_MII_DSP_RW_PORT); |
1238 | val &= ~(1 << 8); |
1239 | PHY_WRITE(sc, BRGPHY_MII_DSP_RW_PORT, val); |
1240 | |
1241 | } |
1242 | |
1243 | static void |
1244 | brgphy_jumbo_settings(struct mii_softc *sc) |
1245 | { |
1246 | uint32_t val; |
1247 | |
1248 | /* Set Jumbo frame settings in the PHY. */ |
1249 | if ((sc->mii_mpd_oui == MII_OUI_BROADCOM) |
1250 | && (sc->mii_mpd_model == MII_MODEL_BROADCOM_BCM5401)) { |
1251 | /* Cannot do read-modify-write on the BCM5401 */ |
1252 | PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x4c20); |
1253 | } else { |
1254 | PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7); |
1255 | val = PHY_READ(sc, BRGPHY_MII_AUXCTL); |
1256 | PHY_WRITE(sc, BRGPHY_MII_AUXCTL, |
1257 | val & ~(BRGPHY_AUXCTL_LONG_PKT | 0x7)); |
1258 | } |
1259 | |
1260 | val = PHY_READ(sc, BRGPHY_MII_PHY_EXTCTL); |
1261 | PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, |
1262 | val & ~BRGPHY_PHY_EXTCTL_HIGH_LA); |
1263 | } |
1264 | |
1265 | static void |
1266 | brgphy_eth_wirespeed(struct mii_softc *sc) |
1267 | { |
1268 | uint32_t val; |
1269 | |
1270 | /* Enable Ethernet@Wirespeed */ |
1271 | PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007); |
1272 | val = PHY_READ(sc, BRGPHY_MII_AUXCTL); |
1273 | PHY_WRITE(sc, BRGPHY_MII_AUXCTL, |
1274 | (val | (1 << 15) | (1 << 4))); |
1275 | } |
1276 | |