|
52 | 52 | BMCR_FULLDPLX | \
|
53 | 53 | BMCR_SPEED1000)
|
54 | 54 |
|
| 55 | +#define MII_DP83869_FIBER_ADVERTISE (ADVERTISED_FIBRE | \ |
| 56 | + ADVERTISED_Pause | \ |
| 57 | + ADVERTISED_Asym_Pause) |
| 58 | + |
55 | 59 | /* This is the same bit mask as the BMCR so re-use the BMCR default */
|
56 | 60 | #define DP83869_FX_CTRL_DEFAULT MII_DP83869_BMCR_DEFAULT
|
57 | 61 |
|
@@ -118,6 +122,28 @@ struct dp83869_private {
|
118 | 122 | int mode;
|
119 | 123 | };
|
120 | 124 |
|
| 125 | +static int dp83869_read_status(struct phy_device *phydev) |
| 126 | +{ |
| 127 | + struct dp83869_private *dp83869 = phydev->priv; |
| 128 | + int ret; |
| 129 | + |
| 130 | + ret = genphy_read_status(phydev); |
| 131 | + if (ret) |
| 132 | + return ret; |
| 133 | + |
| 134 | + if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported)) { |
| 135 | + if (phydev->link) { |
| 136 | + if (dp83869->mode == DP83869_RGMII_100_BASE) |
| 137 | + phydev->speed = SPEED_100; |
| 138 | + } else { |
| 139 | + phydev->speed = SPEED_UNKNOWN; |
| 140 | + phydev->duplex = DUPLEX_UNKNOWN; |
| 141 | + } |
| 142 | + } |
| 143 | + |
| 144 | + return 0; |
| 145 | +} |
| 146 | + |
121 | 147 | static int dp83869_ack_interrupt(struct phy_device *phydev)
|
122 | 148 | {
|
123 | 149 | int err = phy_read(phydev, MII_DP83869_ISR);
|
@@ -295,6 +321,51 @@ static int dp83869_configure_rgmii(struct phy_device *phydev,
|
295 | 321 | return ret;
|
296 | 322 | }
|
297 | 323 |
|
| 324 | +static int dp83869_configure_fiber(struct phy_device *phydev, |
| 325 | + struct dp83869_private *dp83869) |
| 326 | +{ |
| 327 | + int bmcr; |
| 328 | + int ret; |
| 329 | + |
| 330 | + /* Only allow advertising what this PHY supports */ |
| 331 | + linkmode_and(phydev->advertising, phydev->advertising, |
| 332 | + phydev->supported); |
| 333 | + |
| 334 | + linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported); |
| 335 | + linkmode_set_bit(ADVERTISED_FIBRE, phydev->advertising); |
| 336 | + |
| 337 | + if (dp83869->mode == DP83869_RGMII_1000_BASE) { |
| 338 | + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, |
| 339 | + phydev->supported); |
| 340 | + } else { |
| 341 | + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT, |
| 342 | + phydev->supported); |
| 343 | + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Half_BIT, |
| 344 | + phydev->supported); |
| 345 | + |
| 346 | + /* Auto neg is not supported in 100base FX mode */ |
| 347 | + bmcr = phy_read(phydev, MII_BMCR); |
| 348 | + if (bmcr < 0) |
| 349 | + return bmcr; |
| 350 | + |
| 351 | + phydev->autoneg = AUTONEG_DISABLE; |
| 352 | + linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported); |
| 353 | + linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->advertising); |
| 354 | + |
| 355 | + if (bmcr & BMCR_ANENABLE) { |
| 356 | + ret = phy_modify(phydev, MII_BMCR, BMCR_ANENABLE, 0); |
| 357 | + if (ret < 0) |
| 358 | + return ret; |
| 359 | + } |
| 360 | + } |
| 361 | + |
| 362 | + /* Update advertising from supported */ |
| 363 | + linkmode_or(phydev->advertising, phydev->advertising, |
| 364 | + phydev->supported); |
| 365 | + |
| 366 | + return 0; |
| 367 | +} |
| 368 | + |
298 | 369 | static int dp83869_configure_mode(struct phy_device *phydev,
|
299 | 370 | struct dp83869_private *dp83869)
|
300 | 371 | {
|
@@ -384,6 +455,7 @@ static int dp83869_configure_mode(struct phy_device *phydev,
|
384 | 455 | break;
|
385 | 456 | case DP83869_RGMII_1000_BASE:
|
386 | 457 | case DP83869_RGMII_100_BASE:
|
| 458 | + ret = dp83869_configure_fiber(phydev, dp83869); |
387 | 459 | break;
|
388 | 460 | default:
|
389 | 461 | return -EINVAL;
|
@@ -494,6 +566,7 @@ static struct phy_driver dp83869_driver[] = {
|
494 | 566 | /* IRQ related */
|
495 | 567 | .ack_interrupt = dp83869_ack_interrupt,
|
496 | 568 | .config_intr = dp83869_config_intr,
|
| 569 | + .read_status = dp83869_read_status, |
497 | 570 |
|
498 | 571 | .suspend = genphy_suspend,
|
499 | 572 | .resume = genphy_resume,
|
|
0 commit comments