1 /* 2 * drivers/net/phy/broadcom.c 3 * 4 * Broadcom BCM5411, BCM5421 and BCM5461 Gigabit Ethernet 5 * transceivers. 6 * 7 * Copyright (c) 2006 Maciej W. Rozycki 8 * 9 * Inspired by code written by Amy Fong. 10 * 11 * This program is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License 13 * as published by the Free Software Foundation; either version 14 * 2 of the License, or (at your option) any later version. 15 */ 16 17 #include <linux/module.h> 18 #include <linux/phy.h> 19 20 #define MII_BCM54XX_ECR 0x10 /* BCM54xx extended control register */ 21 #define MII_BCM54XX_ECR_IM 0x1000 /* Interrupt mask */ 22 #define MII_BCM54XX_ECR_IF 0x0800 /* Interrupt force */ 23 24 #define MII_BCM54XX_ESR 0x11 /* BCM54xx extended status register */ 25 #define MII_BCM54XX_ESR_IS 0x1000 /* Interrupt status */ 26 27 #define MII_BCM54XX_EXP_DATA 0x15 /* Expansion register data */ 28 #define MII_BCM54XX_EXP_SEL 0x17 /* Expansion register select */ 29 #define MII_BCM54XX_EXP_SEL_SSD 0x0e00 /* Secondary SerDes select */ 30 #define MII_BCM54XX_EXP_SEL_ER 0x0f00 /* Expansion register select */ 31 32 #define MII_BCM54XX_AUX_CTL 0x18 /* Auxiliary control register */ 33 #define MII_BCM54XX_ISR 0x1a /* BCM54xx interrupt status register */ 34 #define MII_BCM54XX_IMR 0x1b /* BCM54xx interrupt mask register */ 35 #define MII_BCM54XX_INT_CRCERR 0x0001 /* CRC error */ 36 #define MII_BCM54XX_INT_LINK 0x0002 /* Link status changed */ 37 #define MII_BCM54XX_INT_SPEED 0x0004 /* Link speed change */ 38 #define MII_BCM54XX_INT_DUPLEX 0x0008 /* Duplex mode changed */ 39 #define MII_BCM54XX_INT_LRS 0x0010 /* Local receiver status changed */ 40 #define MII_BCM54XX_INT_RRS 0x0020 /* Remote receiver status changed */ 41 #define MII_BCM54XX_INT_SSERR 0x0040 /* Scrambler synchronization error */ 42 #define MII_BCM54XX_INT_UHCD 0x0080 /* Unsupported HCD negotiated */ 43 #define MII_BCM54XX_INT_NHCD 0x0100 /* No HCD */ 44 #define MII_BCM54XX_INT_NHCDL 0x0200 /* No HCD link */ 45 #define MII_BCM54XX_INT_ANPR 0x0400 /* Auto-negotiation page received */ 46 #define MII_BCM54XX_INT_LC 0x0800 /* All counters below 128 */ 47 #define MII_BCM54XX_INT_HC 0x1000 /* Counter above 32768 */ 48 #define MII_BCM54XX_INT_MDIX 0x2000 /* MDIX status change */ 49 #define MII_BCM54XX_INT_PSERR 0x4000 /* Pair swap error */ 50 51 #define MII_BCM54XX_SHD 0x1c /* 0x1c shadow registers */ 52 #define MII_BCM54XX_SHD_WRITE 0x8000 53 #define MII_BCM54XX_SHD_VAL(x) ((x & 0x1f) << 10) 54 #define MII_BCM54XX_SHD_DATA(x) ((x & 0x3ff) << 0) 55 56 /* 57 * Broadcom LED source encodings. These are used in BCM5461, BCM5481, 58 * BCM5482, and possibly some others. 59 */ 60 #define BCM_LED_SRC_LINKSPD1 0x0 61 #define BCM_LED_SRC_LINKSPD2 0x1 62 #define BCM_LED_SRC_XMITLED 0x2 63 #define BCM_LED_SRC_ACTIVITYLED 0x3 64 #define BCM_LED_SRC_FDXLED 0x4 65 #define BCM_LED_SRC_SLAVE 0x5 66 #define BCM_LED_SRC_INTR 0x6 67 #define BCM_LED_SRC_QUALITY 0x7 68 #define BCM_LED_SRC_RCVLED 0x8 69 #define BCM_LED_SRC_MULTICOLOR1 0xa 70 #define BCM_LED_SRC_OPENSHORT 0xb 71 #define BCM_LED_SRC_OFF 0xe /* Tied high */ 72 #define BCM_LED_SRC_ON 0xf /* Tied low */ 73 74 /* 75 * BCM5482: Shadow registers 76 * Shadow values go into bits [14:10] of register 0x1c to select a shadow 77 * register to access. 78 */ 79 #define BCM5482_SHD_LEDS1 0x0d /* 01101: LED Selector 1 */ 80 /* LED3 / ~LINKSPD[2] selector */ 81 #define BCM5482_SHD_LEDS1_LED3(src) ((src & 0xf) << 4) 82 /* LED1 / ~LINKSPD[1] selector */ 83 #define BCM5482_SHD_LEDS1_LED1(src) ((src & 0xf) << 0) 84 #define BCM5482_SHD_SSD 0x14 /* 10100: Secondary SerDes control */ 85 #define BCM5482_SHD_SSD_LEDM 0x0008 /* SSD LED Mode enable */ 86 #define BCM5482_SHD_SSD_EN 0x0001 /* SSD enable */ 87 #define BCM5482_SHD_MODE 0x1f /* 11111: Mode Control Register */ 88 #define BCM5482_SHD_MODE_1000BX 0x0001 /* Enable 1000BASE-X registers */ 89 90 /* 91 * BCM5482: Secondary SerDes registers 92 */ 93 #define BCM5482_SSD_1000BX_CTL 0x00 /* 1000BASE-X Control */ 94 #define BCM5482_SSD_1000BX_CTL_PWRDOWN 0x0800 /* Power-down SSD */ 95 #define BCM5482_SSD_SGMII_SLAVE 0x15 /* SGMII Slave Register */ 96 #define BCM5482_SSD_SGMII_SLAVE_EN 0x0002 /* Slave mode enable */ 97 #define BCM5482_SSD_SGMII_SLAVE_AD 0x0001 /* Slave auto-detection */ 98 99 /* 100 * Device flags for PHYs that can be configured for different operating 101 * modes. 102 */ 103 #define PHY_BCM_FLAGS_VALID 0x80000000 104 #define PHY_BCM_FLAGS_INTF_XAUI 0x00000020 105 #define PHY_BCM_FLAGS_INTF_SGMII 0x00000010 106 #define PHY_BCM_FLAGS_MODE_1000BX 0x00000002 107 #define PHY_BCM_FLAGS_MODE_COPPER 0x00000001 108 109 MODULE_DESCRIPTION("Broadcom PHY driver"); 110 MODULE_AUTHOR("Maciej W. Rozycki"); 111 MODULE_LICENSE("GPL"); 112 113 /* 114 * Indirect register access functions for the 1000BASE-T/100BASE-TX/10BASE-T 115 * 0x1c shadow registers. 116 */ 117 static int bcm54xx_shadow_read(struct phy_device *phydev, u16 shadow) 118 { 119 phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow)); 120 return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD)); 121 } 122 123 static int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow, u16 val) 124 { 125 return phy_write(phydev, MII_BCM54XX_SHD, 126 MII_BCM54XX_SHD_WRITE | 127 MII_BCM54XX_SHD_VAL(shadow) | 128 MII_BCM54XX_SHD_DATA(val)); 129 } 130 131 /* 132 * Indirect register access functions for the Expansion Registers 133 * and Secondary SerDes registers (when sec_serdes=1). 134 */ 135 static int bcm54xx_exp_read(struct phy_device *phydev, 136 int sec_serdes, u8 regnum) 137 { 138 int val; 139 140 phy_write(phydev, MII_BCM54XX_EXP_SEL, 141 (sec_serdes ? MII_BCM54XX_EXP_SEL_SSD : 142 MII_BCM54XX_EXP_SEL_ER) | 143 regnum); 144 val = phy_read(phydev, MII_BCM54XX_EXP_DATA); 145 phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum); 146 147 return val; 148 } 149 150 static int bcm54xx_exp_write(struct phy_device *phydev, 151 int sec_serdes, u8 regnum, u16 val) 152 { 153 int ret; 154 155 phy_write(phydev, MII_BCM54XX_EXP_SEL, 156 (sec_serdes ? MII_BCM54XX_EXP_SEL_SSD : 157 MII_BCM54XX_EXP_SEL_ER) | 158 regnum); 159 ret = phy_write(phydev, MII_BCM54XX_EXP_DATA, val); 160 phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum); 161 162 return ret; 163 } 164 165 static int bcm54xx_config_init(struct phy_device *phydev) 166 { 167 int reg, err; 168 169 reg = phy_read(phydev, MII_BCM54XX_ECR); 170 if (reg < 0) 171 return reg; 172 173 /* Mask interrupts globally. */ 174 reg |= MII_BCM54XX_ECR_IM; 175 err = phy_write(phydev, MII_BCM54XX_ECR, reg); 176 if (err < 0) 177 return err; 178 179 /* Unmask events we are interested in. */ 180 reg = ~(MII_BCM54XX_INT_DUPLEX | 181 MII_BCM54XX_INT_SPEED | 182 MII_BCM54XX_INT_LINK); 183 err = phy_write(phydev, MII_BCM54XX_IMR, reg); 184 if (err < 0) 185 return err; 186 return 0; 187 } 188 189 static int bcm5482_config_init(struct phy_device *phydev) 190 { 191 int err, reg; 192 193 err = bcm54xx_config_init(phydev); 194 195 if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) { 196 /* 197 * Enable secondary SerDes and its use as an LED source 198 */ 199 reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_SSD); 200 bcm54xx_shadow_write(phydev, BCM5482_SHD_SSD, 201 reg | 202 BCM5482_SHD_SSD_LEDM | 203 BCM5482_SHD_SSD_EN); 204 205 /* 206 * Enable SGMII slave mode and auto-detection 207 */ 208 reg = bcm54xx_exp_read(phydev, 1, BCM5482_SSD_SGMII_SLAVE); 209 bcm54xx_exp_write(phydev, 1, BCM5482_SSD_SGMII_SLAVE, 210 reg | 211 BCM5482_SSD_SGMII_SLAVE_EN | 212 BCM5482_SSD_SGMII_SLAVE_AD); 213 214 /* 215 * Disable secondary SerDes powerdown 216 */ 217 reg = bcm54xx_exp_read(phydev, 1, BCM5482_SSD_1000BX_CTL); 218 bcm54xx_exp_write(phydev, 1, BCM5482_SSD_1000BX_CTL, 219 reg & ~BCM5482_SSD_1000BX_CTL_PWRDOWN); 220 221 /* 222 * Select 1000BASE-X register set (primary SerDes) 223 */ 224 reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_MODE); 225 bcm54xx_shadow_write(phydev, BCM5482_SHD_MODE, 226 reg | BCM5482_SHD_MODE_1000BX); 227 228 /* 229 * LED1=ACTIVITYLED, LED3=LINKSPD[2] 230 * (Use LED1 as secondary SerDes ACTIVITY LED) 231 */ 232 bcm54xx_shadow_write(phydev, BCM5482_SHD_LEDS1, 233 BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) | 234 BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2)); 235 236 /* 237 * Auto-negotiation doesn't seem to work quite right 238 * in this mode, so we disable it and force it to the 239 * right speed/duplex setting. Only 'link status' 240 * is important. 241 */ 242 phydev->autoneg = AUTONEG_DISABLE; 243 phydev->speed = SPEED_1000; 244 phydev->duplex = DUPLEX_FULL; 245 } 246 247 return err; 248 } 249 250 static int bcm5482_read_status(struct phy_device *phydev) 251 { 252 int err; 253 254 err = genphy_read_status(phydev); 255 256 if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) { 257 /* 258 * Only link status matters for 1000Base-X mode, so force 259 * 1000 Mbit/s full-duplex status 260 */ 261 if (phydev->link) { 262 phydev->speed = SPEED_1000; 263 phydev->duplex = DUPLEX_FULL; 264 } 265 } 266 267 return err; 268 } 269 270 static int bcm54xx_ack_interrupt(struct phy_device *phydev) 271 { 272 int reg; 273 274 /* Clear pending interrupts. */ 275 reg = phy_read(phydev, MII_BCM54XX_ISR); 276 if (reg < 0) 277 return reg; 278 279 return 0; 280 } 281 282 static int bcm54xx_config_intr(struct phy_device *phydev) 283 { 284 int reg, err; 285 286 reg = phy_read(phydev, MII_BCM54XX_ECR); 287 if (reg < 0) 288 return reg; 289 290 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 291 reg &= ~MII_BCM54XX_ECR_IM; 292 else 293 reg |= MII_BCM54XX_ECR_IM; 294 295 err = phy_write(phydev, MII_BCM54XX_ECR, reg); 296 return err; 297 } 298 299 static int bcm5481_config_aneg(struct phy_device *phydev) 300 { 301 int ret; 302 303 /* Aneg firsly. */ 304 ret = genphy_config_aneg(phydev); 305 306 /* Then we can set up the delay. */ 307 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { 308 u16 reg; 309 310 /* 311 * There is no BCM5481 specification available, so down 312 * here is everything we know about "register 0x18". This 313 * at least helps BCM5481 to successfuly receive packets 314 * on MPC8360E-RDK board. Peter Barada <peterb@logicpd.com> 315 * says: "This sets delay between the RXD and RXC signals 316 * instead of using trace lengths to achieve timing". 317 */ 318 319 /* Set RDX clk delay. */ 320 reg = 0x7 | (0x7 << 12); 321 phy_write(phydev, 0x18, reg); 322 323 reg = phy_read(phydev, 0x18); 324 /* Set RDX-RXC skew. */ 325 reg |= (1 << 8); 326 /* Write bits 14:0. */ 327 reg |= (1 << 15); 328 phy_write(phydev, 0x18, reg); 329 } 330 331 return ret; 332 } 333 334 static struct phy_driver bcm5411_driver = { 335 .phy_id = 0x00206070, 336 .phy_id_mask = 0xfffffff0, 337 .name = "Broadcom BCM5411", 338 .features = PHY_GBIT_FEATURES, 339 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 340 .config_init = bcm54xx_config_init, 341 .config_aneg = genphy_config_aneg, 342 .read_status = genphy_read_status, 343 .ack_interrupt = bcm54xx_ack_interrupt, 344 .config_intr = bcm54xx_config_intr, 345 .driver = { .owner = THIS_MODULE }, 346 }; 347 348 static struct phy_driver bcm5421_driver = { 349 .phy_id = 0x002060e0, 350 .phy_id_mask = 0xfffffff0, 351 .name = "Broadcom BCM5421", 352 .features = PHY_GBIT_FEATURES, 353 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 354 .config_init = bcm54xx_config_init, 355 .config_aneg = genphy_config_aneg, 356 .read_status = genphy_read_status, 357 .ack_interrupt = bcm54xx_ack_interrupt, 358 .config_intr = bcm54xx_config_intr, 359 .driver = { .owner = THIS_MODULE }, 360 }; 361 362 static struct phy_driver bcm5461_driver = { 363 .phy_id = 0x002060c0, 364 .phy_id_mask = 0xfffffff0, 365 .name = "Broadcom BCM5461", 366 .features = PHY_GBIT_FEATURES, 367 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 368 .config_init = bcm54xx_config_init, 369 .config_aneg = genphy_config_aneg, 370 .read_status = genphy_read_status, 371 .ack_interrupt = bcm54xx_ack_interrupt, 372 .config_intr = bcm54xx_config_intr, 373 .driver = { .owner = THIS_MODULE }, 374 }; 375 376 static struct phy_driver bcm5464_driver = { 377 .phy_id = 0x002060b0, 378 .phy_id_mask = 0xfffffff0, 379 .name = "Broadcom BCM5464", 380 .features = PHY_GBIT_FEATURES, 381 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 382 .config_init = bcm54xx_config_init, 383 .config_aneg = genphy_config_aneg, 384 .read_status = genphy_read_status, 385 .ack_interrupt = bcm54xx_ack_interrupt, 386 .config_intr = bcm54xx_config_intr, 387 .driver = { .owner = THIS_MODULE }, 388 }; 389 390 static struct phy_driver bcm5481_driver = { 391 .phy_id = 0x0143bca0, 392 .phy_id_mask = 0xfffffff0, 393 .name = "Broadcom BCM5481", 394 .features = PHY_GBIT_FEATURES, 395 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 396 .config_init = bcm54xx_config_init, 397 .config_aneg = bcm5481_config_aneg, 398 .read_status = genphy_read_status, 399 .ack_interrupt = bcm54xx_ack_interrupt, 400 .config_intr = bcm54xx_config_intr, 401 .driver = { .owner = THIS_MODULE }, 402 }; 403 404 static struct phy_driver bcm5482_driver = { 405 .phy_id = 0x0143bcb0, 406 .phy_id_mask = 0xfffffff0, 407 .name = "Broadcom BCM5482", 408 .features = PHY_GBIT_FEATURES, 409 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 410 .config_init = bcm5482_config_init, 411 .config_aneg = genphy_config_aneg, 412 .read_status = bcm5482_read_status, 413 .ack_interrupt = bcm54xx_ack_interrupt, 414 .config_intr = bcm54xx_config_intr, 415 .driver = { .owner = THIS_MODULE }, 416 }; 417 418 static int __init broadcom_init(void) 419 { 420 int ret; 421 422 ret = phy_driver_register(&bcm5411_driver); 423 if (ret) 424 goto out_5411; 425 ret = phy_driver_register(&bcm5421_driver); 426 if (ret) 427 goto out_5421; 428 ret = phy_driver_register(&bcm5461_driver); 429 if (ret) 430 goto out_5461; 431 ret = phy_driver_register(&bcm5464_driver); 432 if (ret) 433 goto out_5464; 434 ret = phy_driver_register(&bcm5481_driver); 435 if (ret) 436 goto out_5481; 437 ret = phy_driver_register(&bcm5482_driver); 438 if (ret) 439 goto out_5482; 440 return ret; 441 442 out_5482: 443 phy_driver_unregister(&bcm5481_driver); 444 out_5481: 445 phy_driver_unregister(&bcm5464_driver); 446 out_5464: 447 phy_driver_unregister(&bcm5461_driver); 448 out_5461: 449 phy_driver_unregister(&bcm5421_driver); 450 out_5421: 451 phy_driver_unregister(&bcm5411_driver); 452 out_5411: 453 return ret; 454 } 455 456 static void __exit broadcom_exit(void) 457 { 458 phy_driver_unregister(&bcm5482_driver); 459 phy_driver_unregister(&bcm5481_driver); 460 phy_driver_unregister(&bcm5464_driver); 461 phy_driver_unregister(&bcm5461_driver); 462 phy_driver_unregister(&bcm5421_driver); 463 phy_driver_unregister(&bcm5411_driver); 464 } 465 466 module_init(broadcom_init); 467 module_exit(broadcom_exit); 468