1 // SPDX-License-Identifier: GPL-2.0 2 // Broadcom BCM84881 NBASE-T PHY driver, as found on a SFP+ module. 3 // Copyright (C) 2019 Russell King, Deep Blue Solutions Ltd. 4 // 5 // Like the Marvell 88x3310, the Broadcom 84881 changes its host-side 6 // interface according to the operating speed between 10GBASE-R, 7 // 2500BASE-X and SGMII (but unlike the 88x3310, without the control 8 // word). 9 // 10 // This driver only supports those aspects of the PHY that I'm able to 11 // observe and test with the SFP+ module, which is an incomplete subset 12 // of what this PHY is able to support. For example, I only assume it 13 // supports a single lane Serdes connection, but it may be that the PHY 14 // is able to support more than that. 15 #include <linux/delay.h> 16 #include <linux/module.h> 17 #include <linux/phy.h> 18 19 enum { 20 MDIO_AN_C22 = 0xffe0, 21 }; 22 23 /* BCM8489x LED controller (BCM84891L datasheet 2.4.1.58). Each pin has 24 * CTL bits in 0xA83B (stride 3: 2-bit CTL + 1-bit OE_N) plus MASK_LOW/ 25 * MASK_EXT source selects. LED4 is firmware-controlled; always RMW. 26 */ 27 #define BCM8489X_LED_CTL 0xa83b 28 #define BCM8489X_LED_CTL_ON(i) (0x2 << ((i) * 3)) 29 #define BCM8489X_LED_CTL_MASK(i) (0x3 << ((i) * 3)) 30 31 #define BCM8489X_LED_SRC_RX BIT(1) 32 #define BCM8489X_LED_SRC_TX BIT(2) 33 #define BCM8489X_LED_SRC_1000 BIT(3) /* high only at 1000 */ 34 #define BCM8489X_LED_SRC_100_1000 BIT(4) /* high at 100 and 1000 */ 35 #define BCM8489X_LED_SRC_FORCE BIT(5) /* always-1 source */ 36 #define BCM8489X_LED_SRC_10G BIT(7) 37 #define BCM8489X_LED_SRCX_2500 BIT(2) 38 #define BCM8489X_LED_SRCX_5000 BIT(3) 39 40 #define BCM8489X_MAX_LEDS 2 41 42 static const struct { 43 u16 mask_low; 44 u16 mask_ext; 45 } bcm8489x_led_regs[BCM8489X_MAX_LEDS] = { 46 { 0xa82c, 0xa8ef }, /* LED1 */ 47 { 0xa82f, 0xa8f0 }, /* LED2 */ 48 }; 49 50 static int bcm84881_wait_init(struct phy_device *phydev) 51 { 52 int val; 53 54 return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1, 55 val, !(val & MDIO_CTRL1_RESET), 56 100000, 2000000, false); 57 } 58 59 static void bcm84881_fill_possible_interfaces(struct phy_device *phydev) 60 { 61 unsigned long *possible = phydev->possible_interfaces; 62 63 __set_bit(PHY_INTERFACE_MODE_SGMII, possible); 64 __set_bit(PHY_INTERFACE_MODE_2500BASEX, possible); 65 __set_bit(PHY_INTERFACE_MODE_10GBASER, possible); 66 } 67 68 static int bcm84881_config_init(struct phy_device *phydev) 69 { 70 bcm84881_fill_possible_interfaces(phydev); 71 72 switch (phydev->interface) { 73 case PHY_INTERFACE_MODE_SGMII: 74 case PHY_INTERFACE_MODE_2500BASEX: 75 case PHY_INTERFACE_MODE_10GBASER: 76 break; 77 default: 78 return -ENODEV; 79 } 80 81 return 0; 82 } 83 84 static int bcm8489x_config_init(struct phy_device *phydev) 85 { 86 __set_bit(PHY_INTERFACE_MODE_USXGMII, phydev->possible_interfaces); 87 88 if (phydev->interface != PHY_INTERFACE_MODE_USXGMII) 89 return -ENODEV; 90 91 /* MDIO_CTRL1_LPOWER is set at boot on the tested platform. Does not 92 * recur on ifdown/ifup, cable events, or link-partner advertisement 93 * changes; clear it once. 94 */ 95 return phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1, 96 MDIO_CTRL1_LPOWER); 97 } 98 99 static int bcm8489x_led_write(struct phy_device *phydev, u8 index, 100 u16 low, u16 ext) 101 { 102 int ret; 103 104 ret = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, 105 bcm8489x_led_regs[index].mask_low, low); 106 if (ret) 107 return ret; 108 ret = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, 109 bcm8489x_led_regs[index].mask_ext, ext); 110 if (ret) 111 return ret; 112 return phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, BCM8489X_LED_CTL, 113 BCM8489X_LED_CTL_MASK(index), 114 (low | ext) ? BCM8489X_LED_CTL_ON(index) : 0); 115 } 116 117 static int bcm8489x_led_brightness_set(struct phy_device *phydev, 118 u8 index, enum led_brightness value) 119 { 120 if (index >= BCM8489X_MAX_LEDS) 121 return -EINVAL; 122 123 return bcm8489x_led_write(phydev, index, 124 value ? BCM8489X_LED_SRC_FORCE : 0, 0); 125 } 126 127 static const unsigned long bcm8489x_supported_triggers = 128 BIT(TRIGGER_NETDEV_LINK) | 129 BIT(TRIGGER_NETDEV_LINK_100) | 130 BIT(TRIGGER_NETDEV_LINK_1000) | 131 BIT(TRIGGER_NETDEV_LINK_2500) | 132 BIT(TRIGGER_NETDEV_LINK_5000) | 133 BIT(TRIGGER_NETDEV_LINK_10000) | 134 BIT(TRIGGER_NETDEV_RX) | 135 BIT(TRIGGER_NETDEV_TX); 136 137 static int bcm8489x_led_hw_is_supported(struct phy_device *phydev, u8 index, 138 unsigned long rules) 139 { 140 if (index >= BCM8489X_MAX_LEDS) 141 return -EINVAL; 142 143 if (rules & ~bcm8489x_supported_triggers) 144 return -EOPNOTSUPP; 145 146 /* Source bit 4 lights at both 100 and 1000; "100 only" isn't 147 * representable in hardware. Accept LINK_100 only alongside 148 * LINK_1000 or LINK so the offload is precise. 149 */ 150 if ((rules & BIT(TRIGGER_NETDEV_LINK_100)) && 151 !(rules & (BIT(TRIGGER_NETDEV_LINK_1000) | 152 BIT(TRIGGER_NETDEV_LINK)))) 153 return -EOPNOTSUPP; 154 155 return 0; 156 } 157 158 static int bcm8489x_led_hw_control_set(struct phy_device *phydev, u8 index, 159 unsigned long rules) 160 { 161 u16 low = 0, ext = 0; 162 163 if (index >= BCM8489X_MAX_LEDS) 164 return -EINVAL; 165 166 if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK))) 167 low |= BCM8489X_LED_SRC_100_1000; 168 if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK))) 169 low |= BCM8489X_LED_SRC_1000; 170 if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK))) 171 ext |= BCM8489X_LED_SRCX_2500; 172 if (rules & (BIT(TRIGGER_NETDEV_LINK_5000) | BIT(TRIGGER_NETDEV_LINK))) 173 ext |= BCM8489X_LED_SRCX_5000; 174 if (rules & (BIT(TRIGGER_NETDEV_LINK_10000) | BIT(TRIGGER_NETDEV_LINK))) 175 low |= BCM8489X_LED_SRC_10G; 176 if (rules & BIT(TRIGGER_NETDEV_RX)) 177 low |= BCM8489X_LED_SRC_RX; 178 if (rules & BIT(TRIGGER_NETDEV_TX)) 179 low |= BCM8489X_LED_SRC_TX; 180 181 return bcm8489x_led_write(phydev, index, low, ext); 182 } 183 184 static int bcm8489x_led_hw_control_get(struct phy_device *phydev, u8 index, 185 unsigned long *rules) 186 { 187 int low, ext; 188 189 if (index >= BCM8489X_MAX_LEDS) 190 return -EINVAL; 191 192 low = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, 193 bcm8489x_led_regs[index].mask_low); 194 if (low < 0) 195 return low; 196 ext = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, 197 bcm8489x_led_regs[index].mask_ext); 198 if (ext < 0) 199 return ext; 200 201 *rules = 0; 202 if (low & BCM8489X_LED_SRC_100_1000) 203 *rules |= BIT(TRIGGER_NETDEV_LINK_100); 204 if (low & BCM8489X_LED_SRC_1000) 205 *rules |= BIT(TRIGGER_NETDEV_LINK_1000); 206 if (ext & BCM8489X_LED_SRCX_2500) 207 *rules |= BIT(TRIGGER_NETDEV_LINK_2500); 208 if (ext & BCM8489X_LED_SRCX_5000) 209 *rules |= BIT(TRIGGER_NETDEV_LINK_5000); 210 if (low & BCM8489X_LED_SRC_10G) 211 *rules |= BIT(TRIGGER_NETDEV_LINK_10000); 212 if (low & BCM8489X_LED_SRC_RX) 213 *rules |= BIT(TRIGGER_NETDEV_RX); 214 if (low & BCM8489X_LED_SRC_TX) 215 *rules |= BIT(TRIGGER_NETDEV_TX); 216 217 return 0; 218 } 219 220 static int bcm84881_probe(struct phy_device *phydev) 221 { 222 /* This driver requires PMAPMD and AN blocks */ 223 const u32 mmd_mask = MDIO_DEVS_PMAPMD | MDIO_DEVS_AN; 224 225 if (!phydev->is_c45 || 226 (phydev->c45_ids.devices_in_package & mmd_mask) != mmd_mask) 227 return -ENODEV; 228 229 return 0; 230 } 231 232 static int bcm84881_get_features(struct phy_device *phydev) 233 { 234 int ret; 235 236 ret = genphy_c45_pma_read_abilities(phydev); 237 if (ret) 238 return ret; 239 240 /* Although the PHY sets bit 1.11.8, it does not support 10M modes */ 241 linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, 242 phydev->supported); 243 linkmode_clear_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, 244 phydev->supported); 245 246 return 0; 247 } 248 249 static int bcm84881_config_aneg(struct phy_device *phydev) 250 { 251 bool changed = false; 252 u32 adv; 253 int ret; 254 255 /* Wait for the PHY to finish initialising, otherwise our 256 * advertisement may be overwritten. 257 */ 258 ret = bcm84881_wait_init(phydev); 259 if (ret) 260 return ret; 261 262 /* We don't support manual MDI control */ 263 phydev->mdix_ctrl = ETH_TP_MDI_AUTO; 264 265 /* disabled autoneg doesn't seem to work with this PHY */ 266 if (phydev->autoneg == AUTONEG_DISABLE) 267 return -EINVAL; 268 269 ret = genphy_c45_an_config_aneg(phydev); 270 if (ret < 0) 271 return ret; 272 if (ret > 0) 273 changed = true; 274 275 adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising); 276 ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, 277 MDIO_AN_C22 + MII_CTRL1000, 278 ADVERTISE_1000FULL | ADVERTISE_1000HALF, 279 adv); 280 if (ret < 0) 281 return ret; 282 if (ret > 0) 283 changed = true; 284 285 return genphy_c45_check_and_restart_aneg(phydev, changed); 286 } 287 288 static int bcm84881_aneg_done(struct phy_device *phydev) 289 { 290 int bmsr, val; 291 292 val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); 293 if (val < 0) 294 return val; 295 296 bmsr = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_C22 + MII_BMSR); 297 if (bmsr < 0) 298 return bmsr; 299 300 return !!(val & MDIO_AN_STAT1_COMPLETE) && 301 !!(bmsr & BMSR_ANEGCOMPLETE); 302 } 303 304 static int bcm84881_read_status(struct phy_device *phydev) 305 { 306 unsigned int mode; 307 int bmsr, val; 308 309 val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1); 310 if (val < 0) 311 return val; 312 313 if (val & MDIO_AN_CTRL1_RESTART) { 314 phydev->link = 0; 315 return 0; 316 } 317 318 val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); 319 if (val < 0) 320 return val; 321 322 bmsr = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_C22 + MII_BMSR); 323 if (bmsr < 0) 324 return bmsr; 325 326 phydev->autoneg_complete = !!(val & MDIO_AN_STAT1_COMPLETE) && 327 !!(bmsr & BMSR_ANEGCOMPLETE); 328 phydev->link = !!(val & MDIO_STAT1_LSTATUS) && 329 !!(bmsr & BMSR_LSTATUS); 330 if (phydev->autoneg == AUTONEG_ENABLE && !phydev->autoneg_complete) 331 phydev->link = false; 332 333 linkmode_zero(phydev->lp_advertising); 334 phydev->speed = SPEED_UNKNOWN; 335 phydev->duplex = DUPLEX_UNKNOWN; 336 phydev->pause = 0; 337 phydev->asym_pause = 0; 338 phydev->mdix = 0; 339 340 if (!phydev->link) 341 return 0; 342 343 if (phydev->autoneg_complete) { 344 val = genphy_c45_read_lpa(phydev); 345 if (val < 0) 346 return val; 347 348 val = phy_read_mmd(phydev, MDIO_MMD_AN, 349 MDIO_AN_C22 + MII_STAT1000); 350 if (val < 0) 351 return val; 352 353 mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val); 354 355 if (phydev->autoneg == AUTONEG_ENABLE) 356 phy_resolve_aneg_linkmode(phydev); 357 } 358 359 if (phydev->autoneg == AUTONEG_DISABLE) { 360 /* disabled autoneg doesn't seem to work, so force the link 361 * down. 362 */ 363 phydev->link = 0; 364 return 0; 365 } 366 367 /* BCM84891/92 on USXGMII: the host interface mode doesn't change 368 * with copper speed (USXGMII symbol replication; the MAC receives 369 * the negotiated copper speed, not 10G, so no rate adaptation). 370 * Skip 0x4011; phy_resolve_aneg_linkmode() above already set the 371 * speed. Only bcm8489x_config_init() allows USXGMII. 372 */ 373 if (phydev->interface == PHY_INTERFACE_MODE_USXGMII) 374 return genphy_c45_read_mdix(phydev); 375 376 /* Set the host link mode - we set the phy interface mode and 377 * the speed according to this register so that downshift works. 378 * We leave the duplex setting as per the resolution from the 379 * above. 380 */ 381 val = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x4011); 382 mode = (val & 0x1e) >> 1; 383 if (mode == 1 || mode == 2) 384 phydev->interface = PHY_INTERFACE_MODE_SGMII; 385 else if (mode == 3) 386 phydev->interface = PHY_INTERFACE_MODE_10GBASER; 387 else if (mode == 4) 388 phydev->interface = PHY_INTERFACE_MODE_2500BASEX; 389 switch (mode & 7) { 390 case 1: 391 phydev->speed = SPEED_100; 392 break; 393 case 2: 394 phydev->speed = SPEED_1000; 395 break; 396 case 3: 397 phydev->speed = SPEED_10000; 398 break; 399 case 4: 400 phydev->speed = SPEED_2500; 401 break; 402 case 5: 403 phydev->speed = SPEED_5000; 404 break; 405 } 406 407 return genphy_c45_read_mdix(phydev); 408 } 409 410 /* The Broadcom BCM84881 in the Methode DM7052 is unable to provide a SGMII 411 * or 802.3z control word, so inband will not work. 412 */ 413 static unsigned int bcm84881_inband_caps(struct phy_device *phydev, 414 phy_interface_t interface) 415 { 416 return LINK_INBAND_DISABLE; 417 } 418 419 static struct phy_driver bcm84881_drivers[] = { 420 { 421 .phy_id = 0xae025150, 422 .phy_id_mask = 0xfffffff0, 423 .name = "Broadcom BCM84881", 424 .inband_caps = bcm84881_inband_caps, 425 .config_init = bcm84881_config_init, 426 .probe = bcm84881_probe, 427 .get_features = bcm84881_get_features, 428 .config_aneg = bcm84881_config_aneg, 429 .aneg_done = bcm84881_aneg_done, 430 .read_status = bcm84881_read_status, 431 }, { 432 PHY_ID_MATCH_MODEL(0x35905080), 433 .name = "Broadcom BCM84891", 434 .inband_caps = bcm84881_inband_caps, 435 .config_init = bcm8489x_config_init, 436 .probe = bcm84881_probe, 437 .get_features = bcm84881_get_features, 438 .config_aneg = bcm84881_config_aneg, 439 .aneg_done = bcm84881_aneg_done, 440 .read_status = bcm84881_read_status, 441 .led_brightness_set = bcm8489x_led_brightness_set, 442 .led_hw_is_supported = bcm8489x_led_hw_is_supported, 443 .led_hw_control_set = bcm8489x_led_hw_control_set, 444 .led_hw_control_get = bcm8489x_led_hw_control_get, 445 }, { 446 PHY_ID_MATCH_MODEL(0x359050a0), 447 .name = "Broadcom BCM84892", 448 .inband_caps = bcm84881_inband_caps, 449 .config_init = bcm8489x_config_init, 450 .probe = bcm84881_probe, 451 .get_features = bcm84881_get_features, 452 .config_aneg = bcm84881_config_aneg, 453 .aneg_done = bcm84881_aneg_done, 454 .read_status = bcm84881_read_status, 455 .led_brightness_set = bcm8489x_led_brightness_set, 456 .led_hw_is_supported = bcm8489x_led_hw_is_supported, 457 .led_hw_control_set = bcm8489x_led_hw_control_set, 458 .led_hw_control_get = bcm8489x_led_hw_control_get, 459 }, 460 }; 461 462 module_phy_driver(bcm84881_drivers); 463 464 /* FIXME: module auto-loading for Clause 45 PHYs seems non-functional */ 465 static const struct mdio_device_id __maybe_unused bcm84881_tbl[] = { 466 { 0xae025150, 0xfffffff0 }, 467 { PHY_ID_MATCH_MODEL(0x35905080) }, 468 { PHY_ID_MATCH_MODEL(0x359050a0) }, 469 { }, 470 }; 471 MODULE_AUTHOR("Russell King"); 472 MODULE_DESCRIPTION("Broadcom BCM84881/BCM84891/BCM84892 PHY driver"); 473 MODULE_DEVICE_TABLE(mdio, bcm84881_tbl); 474 MODULE_LICENSE("GPL"); 475