diff options
| -rw-r--r-- | drivers/net/phy/broadcom.c | 119 |
1 files changed, 118 insertions, 1 deletions
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 7e935924793d..fd4fc66b6d6e 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
| 18 | #include <linux/phy.h> | 18 | #include <linux/phy.h> |
| 19 | 19 | ||
| 20 | #define PHY_ID_BCM50610 0x0143bd60 | ||
| 21 | |||
| 20 | #define MII_BCM54XX_ECR 0x10 /* BCM54xx extended control register */ | 22 | #define MII_BCM54XX_ECR 0x10 /* BCM54xx extended control register */ |
| 21 | #define MII_BCM54XX_ECR_IM 0x1000 /* Interrupt mask */ | 23 | #define MII_BCM54XX_ECR_IM 0x1000 /* Interrupt mask */ |
| 22 | #define MII_BCM54XX_ECR_IF 0x0800 /* Interrupt force */ | 24 | #define MII_BCM54XX_ECR_IF 0x0800 /* Interrupt force */ |
| @@ -54,6 +56,21 @@ | |||
| 54 | #define MII_BCM54XX_SHD_DATA(x) ((x & 0x3ff) << 0) | 56 | #define MII_BCM54XX_SHD_DATA(x) ((x & 0x3ff) << 0) |
| 55 | 57 | ||
| 56 | /* | 58 | /* |
| 59 | * AUXILIARY CONTROL SHADOW ACCESS REGISTERS. (PHY REG 0x18) | ||
| 60 | */ | ||
| 61 | #define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL 0x0000 | ||
| 62 | #define MII_BCM54XX_AUXCTL_ACTL_TX_6DB 0x0400 | ||
| 63 | #define MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA 0x0800 | ||
| 64 | |||
| 65 | #define MII_BCM54XX_AUXCTL_MISC_WREN 0x8000 | ||
| 66 | #define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX 0x0200 | ||
| 67 | #define MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC 0x7000 | ||
| 68 | #define MII_BCM54XX_AUXCTL_SHDWSEL_MISC 0x0007 | ||
| 69 | |||
| 70 | #define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL 0x0000 | ||
| 71 | |||
| 72 | |||
| 73 | /* | ||
| 57 | * Broadcom LED source encodings. These are used in BCM5461, BCM5481, | 74 | * Broadcom LED source encodings. These are used in BCM5461, BCM5481, |
| 58 | * BCM5482, and possibly some others. | 75 | * BCM5482, and possibly some others. |
| 59 | */ | 76 | */ |
| @@ -88,6 +105,24 @@ | |||
| 88 | #define BCM5482_SHD_MODE_1000BX 0x0001 /* Enable 1000BASE-X registers */ | 105 | #define BCM5482_SHD_MODE_1000BX 0x0001 /* Enable 1000BASE-X registers */ |
| 89 | 106 | ||
| 90 | /* | 107 | /* |
| 108 | * EXPANSION SHADOW ACCESS REGISTERS. (PHY REG 0x15, 0x16, and 0x17) | ||
| 109 | */ | ||
| 110 | #define MII_BCM54XX_EXP_AADJ1CH0 0x001f | ||
| 111 | #define MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN 0x0200 | ||
| 112 | #define MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF 0x0100 | ||
| 113 | #define MII_BCM54XX_EXP_AADJ1CH3 0x601f | ||
| 114 | #define MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ 0x0002 | ||
| 115 | #define MII_BCM54XX_EXP_EXP08 0x0F08 | ||
| 116 | #define MII_BCM54XX_EXP_EXP08_RJCT_2MHZ 0x0001 | ||
| 117 | #define MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE 0x0200 | ||
| 118 | #define MII_BCM54XX_EXP_EXP75 0x0f75 | ||
| 119 | #define MII_BCM54XX_EXP_EXP75_VDACCTRL 0x003c | ||
| 120 | #define MII_BCM54XX_EXP_EXP96 0x0f96 | ||
| 121 | #define MII_BCM54XX_EXP_EXP96_MYST 0x0010 | ||
| 122 | #define MII_BCM54XX_EXP_EXP97 0x0f97 | ||
| 123 | #define MII_BCM54XX_EXP_EXP97_MYST 0x0c0c | ||
| 124 | |||
| 125 | /* | ||
| 91 | * BCM5482: Secondary SerDes registers | 126 | * BCM5482: Secondary SerDes registers |
| 92 | */ | 127 | */ |
| 93 | #define BCM5482_SSD_1000BX_CTL 0x00 /* 1000BASE-X Control */ | 128 | #define BCM5482_SSD_1000BX_CTL 0x00 /* 1000BASE-X Control */ |
| @@ -145,7 +180,7 @@ static int bcm54xx_exp_read(struct phy_device *phydev, u8 regnum) | |||
| 145 | return val; | 180 | return val; |
| 146 | } | 181 | } |
| 147 | 182 | ||
| 148 | static int bcm54xx_exp_write(struct phy_device *phydev, u8 regnum, u16 val) | 183 | static int bcm54xx_exp_write(struct phy_device *phydev, u16 regnum, u16 val) |
| 149 | { | 184 | { |
| 150 | int ret; | 185 | int ret; |
| 151 | 186 | ||
| @@ -161,6 +196,60 @@ static int bcm54xx_exp_write(struct phy_device *phydev, u8 regnum, u16 val) | |||
| 161 | return ret; | 196 | return ret; |
| 162 | } | 197 | } |
| 163 | 198 | ||
| 199 | static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val) | ||
| 200 | { | ||
| 201 | return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val); | ||
| 202 | } | ||
| 203 | |||
| 204 | static int bcm50610_a0_workaround(struct phy_device *phydev) | ||
| 205 | { | ||
| 206 | int err; | ||
| 207 | |||
| 208 | err = bcm54xx_auxctl_write(phydev, | ||
| 209 | MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, | ||
| 210 | MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA | | ||
| 211 | MII_BCM54XX_AUXCTL_ACTL_TX_6DB); | ||
| 212 | if (err < 0) | ||
| 213 | return err; | ||
| 214 | |||
| 215 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP08, | ||
| 216 | MII_BCM54XX_EXP_EXP08_RJCT_2MHZ | | ||
| 217 | MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE); | ||
| 218 | if (err < 0) | ||
| 219 | goto error; | ||
| 220 | |||
| 221 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH0, | ||
| 222 | MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN | | ||
| 223 | MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF); | ||
| 224 | if (err < 0) | ||
| 225 | goto error; | ||
| 226 | |||
| 227 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH3, | ||
| 228 | MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ); | ||
| 229 | if (err < 0) | ||
| 230 | goto error; | ||
| 231 | |||
| 232 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, | ||
| 233 | MII_BCM54XX_EXP_EXP75_VDACCTRL); | ||
| 234 | if (err < 0) | ||
| 235 | goto error; | ||
| 236 | |||
| 237 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP96, | ||
| 238 | MII_BCM54XX_EXP_EXP96_MYST); | ||
| 239 | if (err < 0) | ||
| 240 | goto error; | ||
| 241 | |||
| 242 | err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP97, | ||
| 243 | MII_BCM54XX_EXP_EXP97_MYST); | ||
| 244 | |||
| 245 | error: | ||
| 246 | bcm54xx_auxctl_write(phydev, | ||
| 247 | MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, | ||
| 248 | MII_BCM54XX_AUXCTL_ACTL_TX_6DB); | ||
| 249 | |||
| 250 | return err; | ||
| 251 | } | ||
| 252 | |||
| 164 | static int bcm54xx_config_init(struct phy_device *phydev) | 253 | static int bcm54xx_config_init(struct phy_device *phydev) |
| 165 | { | 254 | { |
| 166 | int reg, err; | 255 | int reg, err; |
| @@ -182,6 +271,13 @@ static int bcm54xx_config_init(struct phy_device *phydev) | |||
| 182 | err = phy_write(phydev, MII_BCM54XX_IMR, reg); | 271 | err = phy_write(phydev, MII_BCM54XX_IMR, reg); |
| 183 | if (err < 0) | 272 | if (err < 0) |
| 184 | return err; | 273 | return err; |
| 274 | |||
| 275 | if (phydev->drv->phy_id == PHY_ID_BCM50610) { | ||
| 276 | err = bcm50610_a0_workaround(phydev); | ||
| 277 | if (err < 0) | ||
| 278 | return err; | ||
| 279 | } | ||
| 280 | |||
| 185 | return 0; | 281 | return 0; |
| 186 | } | 282 | } |
| 187 | 283 | ||
| @@ -429,6 +525,21 @@ static struct phy_driver bcm5482_driver = { | |||
| 429 | .driver = { .owner = THIS_MODULE }, | 525 | .driver = { .owner = THIS_MODULE }, |
| 430 | }; | 526 | }; |
| 431 | 527 | ||
| 528 | static struct phy_driver bcm50610_driver = { | ||
| 529 | .phy_id = PHY_ID_BCM50610, | ||
| 530 | .phy_id_mask = 0xfffffff0, | ||
| 531 | .name = "Broadcom BCM50610", | ||
| 532 | .features = PHY_GBIT_FEATURES | | ||
| 533 | SUPPORTED_Pause | SUPPORTED_Asym_Pause, | ||
| 534 | .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, | ||
| 535 | .config_init = bcm54xx_config_init, | ||
| 536 | .config_aneg = genphy_config_aneg, | ||
| 537 | .read_status = genphy_read_status, | ||
| 538 | .ack_interrupt = bcm54xx_ack_interrupt, | ||
| 539 | .config_intr = bcm54xx_config_intr, | ||
| 540 | .driver = { .owner = THIS_MODULE }, | ||
| 541 | }; | ||
| 542 | |||
| 432 | static int __init broadcom_init(void) | 543 | static int __init broadcom_init(void) |
| 433 | { | 544 | { |
| 434 | int ret; | 545 | int ret; |
| @@ -451,8 +562,13 @@ static int __init broadcom_init(void) | |||
| 451 | ret = phy_driver_register(&bcm5482_driver); | 562 | ret = phy_driver_register(&bcm5482_driver); |
| 452 | if (ret) | 563 | if (ret) |
| 453 | goto out_5482; | 564 | goto out_5482; |
| 565 | ret = phy_driver_register(&bcm50610_driver); | ||
| 566 | if (ret) | ||
| 567 | goto out_50610; | ||
| 454 | return ret; | 568 | return ret; |
| 455 | 569 | ||
| 570 | out_50610: | ||
| 571 | phy_driver_unregister(&bcm5482_driver); | ||
| 456 | out_5482: | 572 | out_5482: |
| 457 | phy_driver_unregister(&bcm5481_driver); | 573 | phy_driver_unregister(&bcm5481_driver); |
| 458 | out_5481: | 574 | out_5481: |
| @@ -469,6 +585,7 @@ out_5411: | |||
| 469 | 585 | ||
| 470 | static void __exit broadcom_exit(void) | 586 | static void __exit broadcom_exit(void) |
| 471 | { | 587 | { |
| 588 | phy_driver_unregister(&bcm50610_driver); | ||
| 472 | phy_driver_unregister(&bcm5482_driver); | 589 | phy_driver_unregister(&bcm5482_driver); |
| 473 | phy_driver_unregister(&bcm5481_driver); | 590 | phy_driver_unregister(&bcm5481_driver); |
| 474 | phy_driver_unregister(&bcm5464_driver); | 591 | phy_driver_unregister(&bcm5464_driver); |
