| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: makphy.c,v 1.42.8.3 2019/08/01 14:27:30 martin Exp $ */ | | 1 | /* $NetBSD: makphy.c,v 1.42.8.4 2020/01/28 09:34:29 martin Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1998, 1999, 2000, 2001 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, | | 8 | * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, |
9 | * NASA Ames Research Center. | | 9 | * NASA Ames Research Center. |
10 | * | | 10 | * |
11 | * Redistribution and use in source and binary forms, with or without | | 11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions | | 12 | * modification, are permitted provided that the following conditions |
13 | * are met: | | 13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright | | 14 | * 1. Redistributions of source code must retain the above copyright |
| @@ -49,27 +49,27 @@ | | | @@ -49,27 +49,27 @@ |
49 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | | 49 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
50 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | | 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 | | 51 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
52 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | | 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 | | 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. | | 54 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
55 | */ | | 55 | */ |
56 | | | 56 | |
57 | /* | | 57 | /* |
58 | * Driver for the Marvell 88E1000 ``Alaska'' 10/100/1000 PHY. | | 58 | * Driver for the Marvell 88E1000 ``Alaska'' 10/100/1000 PHY. |
59 | */ | | 59 | */ |
60 | | | 60 | |
61 | #include <sys/cdefs.h> | | 61 | #include <sys/cdefs.h> |
62 | __KERNEL_RCSID(0, "$NetBSD: makphy.c,v 1.42.8.3 2019/08/01 14:27:30 martin Exp $"); | | 62 | __KERNEL_RCSID(0, "$NetBSD: makphy.c,v 1.42.8.4 2020/01/28 09:34:29 martin Exp $"); |
63 | | | 63 | |
64 | #include <sys/param.h> | | 64 | #include <sys/param.h> |
65 | #include <sys/systm.h> | | 65 | #include <sys/systm.h> |
66 | #include <sys/kernel.h> | | 66 | #include <sys/kernel.h> |
67 | #include <sys/device.h> | | 67 | #include <sys/device.h> |
68 | #include <sys/socket.h> | | 68 | #include <sys/socket.h> |
69 | #include <sys/errno.h> | | 69 | #include <sys/errno.h> |
70 | | | 70 | |
71 | #include <net/if.h> | | 71 | #include <net/if.h> |
72 | #include <net/if_media.h> | | 72 | #include <net/if_media.h> |
73 | | | 73 | |
74 | #include <dev/mii/mii.h> | | 74 | #include <dev/mii/mii.h> |
75 | #include <dev/mii/miivar.h> | | 75 | #include <dev/mii/miivar.h> |
| @@ -194,27 +194,27 @@ makphymatch(device_t parent, cfdata_t ma | | | @@ -194,27 +194,27 @@ makphymatch(device_t parent, cfdata_t ma |
194 | | | 194 | |
195 | return 0; | | 195 | return 0; |
196 | } | | 196 | } |
197 | | | 197 | |
198 | static void | | 198 | static void |
199 | makphyattach(device_t parent, device_t self, void *aux) | | 199 | makphyattach(device_t parent, device_t self, void *aux) |
200 | { | | 200 | { |
201 | struct mii_softc *sc = device_private(self); | | 201 | struct mii_softc *sc = device_private(self); |
202 | struct mii_attach_args *ma = aux; | | 202 | struct mii_attach_args *ma = aux; |
203 | struct mii_data *mii = ma->mii_data; | | 203 | struct mii_data *mii = ma->mii_data; |
204 | const struct mii_phydesc *mpd; | | 204 | const struct mii_phydesc *mpd; |
205 | struct makphy_softc *maksc = (struct makphy_softc *)sc; | | 205 | struct makphy_softc *maksc = (struct makphy_softc *)sc; |
206 | const char *name; | | 206 | const char *name; |
207 | int model, val; | | 207 | int reg, model; |
208 | | | 208 | |
209 | mpd = mii_phy_match(ma, makphys); | | 209 | mpd = mii_phy_match(ma, makphys); |
210 | aprint_naive(": Media interface\n"); | | 210 | aprint_naive(": Media interface\n"); |
211 | if (mpd) | | 211 | if (mpd) |
212 | name = mpd->mpd_name; | | 212 | name = mpd->mpd_name; |
213 | else if (makphy_isi210(parent, ma)) { | | 213 | else if (makphy_isi210(parent, ma)) { |
214 | name = MII_STR_xxMARVELL_I210; | | 214 | name = MII_STR_xxMARVELL_I210; |
215 | maksc->sc_flags |= MAKPHY_F_I210; | | 215 | maksc->sc_flags |= MAKPHY_F_I210; |
216 | } else | | 216 | } else |
217 | panic("Unknown PHY"); | | 217 | panic("Unknown PHY"); |
218 | aprint_normal(": %s, rev. %d\n", name, MII_REV(ma->mii_id2)); | | 218 | aprint_normal(": %s, rev. %d\n", name, MII_REV(ma->mii_id2)); |
219 | | | 219 | |
220 | sc->mii_dev = self; | | 220 | sc->mii_dev = self; |
| @@ -235,64 +235,99 @@ makphyattach(device_t parent, device_t s | | | @@ -235,64 +235,99 @@ makphyattach(device_t parent, device_t s |
235 | /* FALLTHROUGH */ | | 235 | /* FALLTHROUGH */ |
236 | case MII_MODEL_xxMARVELL_E1000_3: | | 236 | case MII_MODEL_xxMARVELL_E1000_3: |
237 | case MII_MODEL_xxMARVELL_E1000S: | | 237 | case MII_MODEL_xxMARVELL_E1000S: |
238 | case MII_MODEL_xxMARVELL_E1000_5: | | 238 | case MII_MODEL_xxMARVELL_E1000_5: |
239 | /* 88E1000 series has no EADR */ | | 239 | /* 88E1000 series has no EADR */ |
240 | break; | | 240 | break; |
241 | default: | | 241 | default: |
242 | page0: | | 242 | page0: |
243 | /* Make sure page 0 is selected. */ | | 243 | /* Make sure page 0 is selected. */ |
244 | PHY_WRITE(sc, MAKPHY_EADR, 0); | | 244 | PHY_WRITE(sc, MAKPHY_EADR, 0); |
245 | break; | | 245 | break; |
246 | } | | 246 | } |
247 | | | 247 | |
248 | switch (model) { | | | |
249 | case MII_MODEL_xxMARVELL_E1011: | | | |
250 | case MII_MODEL_xxMARVELL_E1112: | | | |
251 | val = PHY_READ(sc, MAKPHY_ESSR); | | | |
252 | if ((val != 0) && (((u_int)val & 0x0000ffffU) != 0x0000ffffU) | | | |
253 | && ((val & ESSR_FIBER_LINK) != 0)) | | | |
254 | sc->mii_flags |= MIIF_HAVEFIBER; | | | |
255 | break; | | | |
256 | default: | | | |
257 | break; | | | |
258 | } | | | |
259 | | | | |
260 | PHY_RESET(sc); | | 248 | PHY_RESET(sc); |
261 | | | 249 | |
262 | sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; | | 250 | sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; |
263 | if (sc->mii_capabilities & BMSR_EXTSTAT) | | 251 | if (sc->mii_capabilities & BMSR_EXTSTAT) |
264 | sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); | | 252 | sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR); |
265 | | | 253 | |
| | | 254 | if (((sc->mii_extcapabilities & (EXTSR_1000TFDX | EXTSR_1000THDX)) |
| | | 255 | != 0) |
| | | 256 | && ((sc->mii_extcapabilities & (EXTSR_1000XFDX | EXTSR_1000XHDX)) |
| | | 257 | != 0)) { |
| | | 258 | bool fiberonly = false, copperonly = false; |
| | | 259 | |
| | | 260 | /* Both copper and fiber are set. check MODE[] */ |
| | | 261 | switch (sc->mii_mpd_model) { |
| | | 262 | case MII_MODEL_xxMARVELL_E1011: |
| | | 263 | case MII_MODEL_xxMARVELL_E1111: |
| | | 264 | /* These devices have ESSR register */ |
| | | 265 | reg = PHY_READ(sc, MAKPHY_ESSR); |
| | | 266 | if ((reg & ESSR_AUTOSEL_DISABLE) != 0) { |
| | | 267 | switch (reg & ESSR_HWCFG_MODE) { |
| | | 268 | case ESSR_RTBI_FIBER: |
| | | 269 | case ESSR_RGMII_FIBER: |
| | | 270 | case ESSR_RGMII_SGMII: /* right? */ |
| | | 271 | case ESSR_TBI_FIBER: |
| | | 272 | case ESSR_GMII_FIBER: |
| | | 273 | fiberonly = true; |
| | | 274 | break; |
| | | 275 | case ESSR_SGMII_WC_COPPER: |
| | | 276 | case ESSR_SGMII_WOC_COPPER: |
| | | 277 | case ESSR_RTBI_COPPER: |
| | | 278 | case ESSR_RGMII_COPPER: |
| | | 279 | case ESSR_GMII_COPPER: |
| | | 280 | copperonly = true; |
| | | 281 | default: |
| | | 282 | break; |
| | | 283 | } |
| | | 284 | } |
| | | 285 | break; |
| | | 286 | default: |
| | | 287 | break; |
| | | 288 | } |
| | | 289 | if (fiberonly || copperonly) |
| | | 290 | aprint_debug_dev(self, "both copper and fiber are set " |
| | | 291 | "but MODE[] is %s only.\n", |
| | | 292 | fiberonly ? "fiber" : "copper"); |
| | | 293 | if (fiberonly) |
| | | 294 | sc->mii_extcapabilities |
| | | 295 | &= ~(EXTSR_1000TFDX | EXTSR_1000THDX); |
| | | 296 | else if (copperonly) { |
| | | 297 | sc->mii_extcapabilities |
| | | 298 | &= ~(EXTSR_1000XFDX | EXTSR_1000XHDX); |
| | | 299 | sc->mii_flags &= ~MIIF_IS_1000X; |
| | | 300 | } |
| | | 301 | } |
| | | 302 | |
266 | aprint_normal_dev(self, ""); | | 303 | aprint_normal_dev(self, ""); |
267 | if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 && | | 304 | if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 && |
268 | (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0) | | 305 | (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0) |
269 | aprint_error("no media present"); | | 306 | aprint_error("no media present"); |
270 | else | | 307 | else |
271 | mii_phy_add_media(sc); | | 308 | mii_phy_add_media(sc); |
272 | aprint_normal("\n"); | | 309 | aprint_normal("\n"); |
273 | } | | 310 | } |
274 | | | 311 | |
275 | static void | | 312 | static void |
276 | makphy_reset(struct mii_softc *sc) | | 313 | makphy_reset(struct mii_softc *sc) |
277 | { | | 314 | { |
278 | struct makphy_softc *maksc = (struct makphy_softc *)sc; | | 315 | struct makphy_softc *maksc = (struct makphy_softc *)sc; |
279 | uint16_t reg; | | 316 | uint16_t reg; |
280 | | | 317 | |
281 | mii_phy_reset(sc); | | 318 | mii_phy_reset(sc); |
282 | | | 319 | |
283 | /* | | 320 | /* Initialize PHY Specific Control Register. */ |
284 | * Initialize PHY Specific Control Register. | | | |
285 | */ | | | |
286 | reg = PHY_READ(sc, MAKPHY_PSCR); | | 321 | reg = PHY_READ(sc, MAKPHY_PSCR); |
287 | | | 322 | |
288 | /* Assert CRS on transmit. */ | | 323 | /* Assert CRS on transmit. */ |
289 | switch (sc->mii_mpd_model) { | | 324 | switch (sc->mii_mpd_model) { |
290 | case MII_MODEL_MARVELL_E1000_0: | | 325 | case MII_MODEL_MARVELL_E1000_0: |
291 | if ((maksc->sc_flags & MAKPHY_F_I210) != 0) | | 326 | if ((maksc->sc_flags & MAKPHY_F_I210) != 0) |
292 | break; | | 327 | break; |
293 | /* FALLTHROUGH */ | | 328 | /* FALLTHROUGH */ |
294 | case MII_MODEL_MARVELL_E1000_3: | | 329 | case MII_MODEL_MARVELL_E1000_3: |
295 | case MII_MODEL_MARVELL_E1000_5: | | 330 | case MII_MODEL_MARVELL_E1000_5: |
296 | case MII_MODEL_MARVELL_E1000_6: | | 331 | case MII_MODEL_MARVELL_E1000_6: |
297 | case MII_MODEL_xxMARVELL_E1000S: | | 332 | case MII_MODEL_xxMARVELL_E1000S: |
298 | case MII_MODEL_xxMARVELL_E1011: | | 333 | case MII_MODEL_xxMARVELL_E1011: |
| @@ -415,27 +450,27 @@ makphy_service(struct mii_softc *sc, str | | | @@ -415,27 +450,27 @@ makphy_service(struct mii_softc *sc, str |
415 | | | 450 | |
416 | /* Update the media status. */ | | 451 | /* Update the media status. */ |
417 | mii_phy_status(sc); | | 452 | mii_phy_status(sc); |
418 | | | 453 | |
419 | /* Callback if something changed. */ | | 454 | /* Callback if something changed. */ |
420 | mii_phy_update(sc, cmd); | | 455 | mii_phy_update(sc, cmd); |
421 | return 0; | | 456 | return 0; |
422 | } | | 457 | } |
423 | | | 458 | |
424 | static void | | 459 | static void |
425 | makphy_status(struct mii_softc *sc) | | 460 | makphy_status(struct mii_softc *sc) |
426 | { | | 461 | { |
427 | struct mii_data *mii = sc->mii_pdata; | | 462 | struct mii_data *mii = sc->mii_pdata; |
428 | int bmcr, gsr, pssr; | | 463 | int bmcr, gsr, pssr, essr; |
429 | | | 464 | |
430 | mii->mii_media_status = IFM_AVALID; | | 465 | mii->mii_media_status = IFM_AVALID; |
431 | mii->mii_media_active = IFM_ETHER; | | 466 | mii->mii_media_active = IFM_ETHER; |
432 | | | 467 | |
433 | bmcr = PHY_READ(sc, MII_BMCR); | | 468 | bmcr = PHY_READ(sc, MII_BMCR); |
434 | /* XXX FIXME: Use different page for Fiber on newer chips */ | | 469 | /* XXX FIXME: Use different page for Fiber on newer chips */ |
435 | pssr = PHY_READ(sc, MAKPHY_PSSR); | | 470 | pssr = PHY_READ(sc, MAKPHY_PSSR); |
436 | | | 471 | |
437 | if (pssr & PSSR_LINK) | | 472 | if (pssr & PSSR_LINK) |
438 | mii->mii_media_status |= IFM_ACTIVE; | | 473 | mii->mii_media_status |= IFM_ACTIVE; |
439 | | | 474 | |
440 | if (bmcr & BMCR_LOOP) | | 475 | if (bmcr & BMCR_LOOP) |
441 | mii->mii_media_active |= IFM_LOOP; | | 476 | mii->mii_media_active |= IFM_LOOP; |
| @@ -453,30 +488,65 @@ makphy_status(struct mii_softc *sc) | | | @@ -453,30 +488,65 @@ makphy_status(struct mii_softc *sc) |
453 | */ | | 488 | */ |
454 | if (!(pssr & PSSR_RESOLVED)) { | | 489 | if (!(pssr & PSSR_RESOLVED)) { |
455 | /* Erg, still trying, I guess... */ | | 490 | /* Erg, still trying, I guess... */ |
456 | mii->mii_media_active |= IFM_NONE; | | 491 | mii->mii_media_active |= IFM_NONE; |
457 | return; | | 492 | return; |
458 | } | | 493 | } |
459 | } else { | | 494 | } else { |
460 | if ((pssr & PSSR_LINK) == 0) { | | 495 | if ((pssr & PSSR_LINK) == 0) { |
461 | mii->mii_media_active |= IFM_NONE; | | 496 | mii->mii_media_active |= IFM_NONE; |
462 | return; | | 497 | return; |
463 | } | | 498 | } |
464 | } | | 499 | } |
465 | | | 500 | |
466 | /* XXX FIXME: Use different page for Fiber on newer chips */ | | 501 | /* |
| | | 502 | * XXX The following code support Fiber/Copper auto select mode |
| | | 503 | * only for 88E1011, 88E1111 and 88E1112. For other chips, the document |
| | | 504 | * is required. |
| | | 505 | */ |
467 | if (sc->mii_flags & MIIF_IS_1000X) { | | 506 | if (sc->mii_flags & MIIF_IS_1000X) { |
| | | 507 | /* Not in Fiber/Copper auto select mode */ |
| | | 508 | mii->mii_media_active |= IFM_1000_SX; |
| | | 509 | } else if ((sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1011) || |
| | | 510 | (sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1111)) { |
| | | 511 | /* Fiber/Copper auto select mode */ |
| | | 512 | |
| | | 513 | essr = PHY_READ(sc, MAKPHY_ESSR); |
| | | 514 | if ((essr & ESSR_FIBER_LINK) == 0) |
| | | 515 | goto copper; |
| | | 516 | |
| | | 517 | /* XXX Assume 1000BASE-SX only */ |
468 | mii->mii_media_active |= IFM_1000_SX; | | 518 | mii->mii_media_active |= IFM_1000_SX; |
| | | 519 | } else if (sc->mii_mpd_model == MII_MODEL_xxMARVELL_E1112) { |
| | | 520 | /* Fiber/Copper auto select mode */ |
| | | 521 | |
| | | 522 | pssr = PHY_READ(sc, MAKPHY_PSSR); |
| | | 523 | if ((pssr & PSSR_RESOLUTION_FIBER) == 0) |
| | | 524 | goto copper; |
| | | 525 | |
| | | 526 | switch (PSSR_SPEED_get(pssr)) { |
| | | 527 | case SPEED_1000: |
| | | 528 | mii->mii_media_active |= IFM_1000_SX; |
| | | 529 | break; |
| | | 530 | case SPEED_100: |
| | | 531 | mii->mii_media_active |= IFM_100_FX; |
| | | 532 | break; |
| | | 533 | default: /* Undefined (reserved) value */ |
| | | 534 | mii->mii_media_active |= IFM_NONE; |
| | | 535 | mii->mii_media_status = 0; |
| | | 536 | return; |
| | | 537 | } |
469 | } else { | | 538 | } else { |
| | | 539 | copper: |
470 | switch (PSSR_SPEED_get(pssr)) { | | 540 | switch (PSSR_SPEED_get(pssr)) { |
471 | case SPEED_1000: | | 541 | case SPEED_1000: |
472 | mii->mii_media_active |= IFM_1000_T; | | 542 | mii->mii_media_active |= IFM_1000_T; |
473 | break; | | 543 | break; |
474 | case SPEED_100: | | 544 | case SPEED_100: |
475 | mii->mii_media_active |= IFM_100_TX; | | 545 | mii->mii_media_active |= IFM_100_TX; |
476 | break; | | 546 | break; |
477 | case SPEED_10: | | 547 | case SPEED_10: |
478 | mii->mii_media_active |= IFM_10_T; | | 548 | mii->mii_media_active |= IFM_10_T; |
479 | break; | | 549 | break; |
480 | default: /* Undefined (reserved) value */ | | 550 | default: /* Undefined (reserved) value */ |
481 | mii->mii_media_active |= IFM_NONE; | | 551 | mii->mii_media_active |= IFM_NONE; |
482 | mii->mii_media_status = 0; | | 552 | mii->mii_media_status = 0; |