diff options
Diffstat (limited to 'drivers/net/phy/marvell.c')
| -rw-r--r-- | drivers/net/phy/marvell.c | 131 |
1 files changed, 124 insertions, 7 deletions
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index f0574073a2a3..32a8503a7acd 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c | |||
| @@ -58,9 +58,25 @@ | |||
| 58 | #define MII_M1111_RX_DELAY 0x80 | 58 | #define MII_M1111_RX_DELAY 0x80 |
| 59 | #define MII_M1111_TX_DELAY 0x2 | 59 | #define MII_M1111_TX_DELAY 0x2 |
| 60 | #define MII_M1111_PHY_EXT_SR 0x1b | 60 | #define MII_M1111_PHY_EXT_SR 0x1b |
| 61 | #define MII_M1111_HWCFG_MODE_MASK 0xf | 61 | |
| 62 | #define MII_M1111_HWCFG_MODE_RGMII 0xb | 62 | #define MII_M1111_HWCFG_MODE_MASK 0xf |
| 63 | #define MII_M1111_HWCFG_MODE_COPPER_RGMII 0xb | ||
| 64 | #define MII_M1111_HWCFG_MODE_FIBER_RGMII 0x3 | ||
| 63 | #define MII_M1111_HWCFG_MODE_SGMII_NO_CLK 0x4 | 65 | #define MII_M1111_HWCFG_MODE_SGMII_NO_CLK 0x4 |
| 66 | #define MII_M1111_HWCFG_FIBER_COPPER_AUTO 0x8000 | ||
| 67 | #define MII_M1111_HWCFG_FIBER_COPPER_RES 0x2000 | ||
| 68 | |||
| 69 | #define MII_M1111_COPPER 0 | ||
| 70 | #define MII_M1111_FIBER 1 | ||
| 71 | |||
| 72 | #define MII_M1011_PHY_STATUS 0x11 | ||
| 73 | #define MII_M1011_PHY_STATUS_1000 0x8000 | ||
| 74 | #define MII_M1011_PHY_STATUS_100 0x4000 | ||
| 75 | #define MII_M1011_PHY_STATUS_SPD_MASK 0xc000 | ||
| 76 | #define MII_M1011_PHY_STATUS_FULLDUPLEX 0x2000 | ||
| 77 | #define MII_M1011_PHY_STATUS_RESOLVED 0x0800 | ||
| 78 | #define MII_M1011_PHY_STATUS_LINK 0x0400 | ||
| 79 | |||
| 64 | 80 | ||
| 65 | MODULE_DESCRIPTION("Marvell PHY driver"); | 81 | MODULE_DESCRIPTION("Marvell PHY driver"); |
| 66 | MODULE_AUTHOR("Andy Fleming"); | 82 | MODULE_AUTHOR("Andy Fleming"); |
| @@ -141,12 +157,22 @@ static int marvell_config_aneg(struct phy_device *phydev) | |||
| 141 | static int m88e1111_config_init(struct phy_device *phydev) | 157 | static int m88e1111_config_init(struct phy_device *phydev) |
| 142 | { | 158 | { |
| 143 | int err; | 159 | int err; |
| 160 | int temp; | ||
| 161 | int mode; | ||
| 162 | |||
| 163 | /* Enable Fiber/Copper auto selection */ | ||
| 164 | temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); | ||
| 165 | temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO; | ||
| 166 | phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); | ||
| 167 | |||
| 168 | temp = phy_read(phydev, MII_BMCR); | ||
| 169 | temp |= BMCR_RESET; | ||
| 170 | phy_write(phydev, MII_BMCR, temp); | ||
| 144 | 171 | ||
| 145 | if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || | 172 | if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || |
| 146 | (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || | 173 | (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || |
| 147 | (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) || | 174 | (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) || |
| 148 | (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) { | 175 | (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) { |
| 149 | int temp; | ||
| 150 | 176 | ||
| 151 | temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); | 177 | temp = phy_read(phydev, MII_M1111_PHY_EXT_CR); |
| 152 | if (temp < 0) | 178 | if (temp < 0) |
| @@ -171,7 +197,13 @@ static int m88e1111_config_init(struct phy_device *phydev) | |||
| 171 | return temp; | 197 | return temp; |
| 172 | 198 | ||
| 173 | temp &= ~(MII_M1111_HWCFG_MODE_MASK); | 199 | temp &= ~(MII_M1111_HWCFG_MODE_MASK); |
| 174 | temp |= MII_M1111_HWCFG_MODE_RGMII; | 200 | |
| 201 | mode = phy_read(phydev, MII_M1111_PHY_EXT_CR); | ||
| 202 | |||
| 203 | if (mode & MII_M1111_HWCFG_FIBER_COPPER_RES) | ||
| 204 | temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII; | ||
| 205 | else | ||
| 206 | temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII; | ||
| 175 | 207 | ||
| 176 | err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); | 208 | err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp); |
| 177 | if (err < 0) | 209 | if (err < 0) |
| @@ -179,8 +211,6 @@ static int m88e1111_config_init(struct phy_device *phydev) | |||
| 179 | } | 211 | } |
| 180 | 212 | ||
| 181 | if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { | 213 | if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { |
| 182 | int temp; | ||
| 183 | |||
| 184 | temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); | 214 | temp = phy_read(phydev, MII_M1111_PHY_EXT_SR); |
| 185 | if (temp < 0) | 215 | if (temp < 0) |
| 186 | return temp; | 216 | return temp; |
| @@ -262,6 +292,93 @@ static int m88e1145_config_init(struct phy_device *phydev) | |||
| 262 | return 0; | 292 | return 0; |
| 263 | } | 293 | } |
| 264 | 294 | ||
| 295 | /* marvell_read_status | ||
| 296 | * | ||
| 297 | * Generic status code does not detect Fiber correctly! | ||
| 298 | * Description: | ||
| 299 | * Check the link, then figure out the current state | ||
| 300 | * by comparing what we advertise with what the link partner | ||
| 301 | * advertises. Start by checking the gigabit possibilities, | ||
| 302 | * then move on to 10/100. | ||
| 303 | */ | ||
| 304 | static int marvell_read_status(struct phy_device *phydev) | ||
| 305 | { | ||
| 306 | int adv; | ||
| 307 | int err; | ||
| 308 | int lpa; | ||
| 309 | int status = 0; | ||
| 310 | |||
| 311 | /* Update the link, but return if there | ||
| 312 | * was an error */ | ||
| 313 | err = genphy_update_link(phydev); | ||
| 314 | if (err) | ||
| 315 | return err; | ||
| 316 | |||
| 317 | if (AUTONEG_ENABLE == phydev->autoneg) { | ||
| 318 | status = phy_read(phydev, MII_M1011_PHY_STATUS); | ||
| 319 | if (status < 0) | ||
| 320 | return status; | ||
| 321 | |||
| 322 | lpa = phy_read(phydev, MII_LPA); | ||
| 323 | if (lpa < 0) | ||
| 324 | return lpa; | ||
| 325 | |||
| 326 | adv = phy_read(phydev, MII_ADVERTISE); | ||
| 327 | if (adv < 0) | ||
| 328 | return adv; | ||
| 329 | |||
| 330 | lpa &= adv; | ||
| 331 | |||
| 332 | if (status & MII_M1011_PHY_STATUS_FULLDUPLEX) | ||
| 333 | phydev->duplex = DUPLEX_FULL; | ||
| 334 | else | ||
| 335 | phydev->duplex = DUPLEX_HALF; | ||
| 336 | |||
| 337 | status = status & MII_M1011_PHY_STATUS_SPD_MASK; | ||
| 338 | phydev->pause = phydev->asym_pause = 0; | ||
| 339 | |||
| 340 | switch (status) { | ||
| 341 | case MII_M1011_PHY_STATUS_1000: | ||
| 342 | phydev->speed = SPEED_1000; | ||
| 343 | break; | ||
| 344 | |||
| 345 | case MII_M1011_PHY_STATUS_100: | ||
| 346 | phydev->speed = SPEED_100; | ||
| 347 | break; | ||
| 348 | |||
| 349 | default: | ||
| 350 | phydev->speed = SPEED_10; | ||
| 351 | break; | ||
| 352 | } | ||
| 353 | |||
| 354 | if (phydev->duplex == DUPLEX_FULL) { | ||
| 355 | phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; | ||
| 356 | phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; | ||
| 357 | } | ||
| 358 | } else { | ||
| 359 | int bmcr = phy_read(phydev, MII_BMCR); | ||
| 360 | |||
| 361 | if (bmcr < 0) | ||
| 362 | return bmcr; | ||
| 363 | |||
| 364 | if (bmcr & BMCR_FULLDPLX) | ||
| 365 | phydev->duplex = DUPLEX_FULL; | ||
| 366 | else | ||
| 367 | phydev->duplex = DUPLEX_HALF; | ||
| 368 | |||
| 369 | if (bmcr & BMCR_SPEED1000) | ||
| 370 | phydev->speed = SPEED_1000; | ||
| 371 | else if (bmcr & BMCR_SPEED100) | ||
| 372 | phydev->speed = SPEED_100; | ||
| 373 | else | ||
| 374 | phydev->speed = SPEED_10; | ||
| 375 | |||
| 376 | phydev->pause = phydev->asym_pause = 0; | ||
| 377 | } | ||
| 378 | |||
| 379 | return 0; | ||
| 380 | } | ||
| 381 | |||
| 265 | static struct phy_driver marvell_drivers[] = { | 382 | static struct phy_driver marvell_drivers[] = { |
| 266 | { | 383 | { |
| 267 | .phy_id = 0x01410c60, | 384 | .phy_id = 0x01410c60, |
| @@ -296,7 +413,7 @@ static struct phy_driver marvell_drivers[] = { | |||
| 296 | .flags = PHY_HAS_INTERRUPT, | 413 | .flags = PHY_HAS_INTERRUPT, |
| 297 | .config_init = &m88e1111_config_init, | 414 | .config_init = &m88e1111_config_init, |
| 298 | .config_aneg = &marvell_config_aneg, | 415 | .config_aneg = &marvell_config_aneg, |
| 299 | .read_status = &genphy_read_status, | 416 | .read_status = &marvell_read_status, |
| 300 | .ack_interrupt = &marvell_ack_interrupt, | 417 | .ack_interrupt = &marvell_ack_interrupt, |
| 301 | .config_intr = &marvell_config_intr, | 418 | .config_intr = &marvell_config_intr, |
| 302 | .driver = { .owner = THIS_MODULE }, | 419 | .driver = { .owner = THIS_MODULE }, |
