1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2015-2017 Broadcom 4 */ 5 6 #include "bcm-phy-lib.h" 7 #include <linux/bitfield.h> 8 #include <linux/brcmphy.h> 9 #include <linux/etherdevice.h> 10 #include <linux/export.h> 11 #include <linux/mdio.h> 12 #include <linux/module.h> 13 #include <linux/phy.h> 14 #include <linux/ethtool.h> 15 #include <linux/ethtool_netlink.h> 16 #include <linux/netdevice.h> 17 18 #define MII_BCM_CHANNEL_WIDTH 0x2000 19 #define BCM_CL45VEN_EEE_ADV 0x3c 20 21 int __bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val) 22 { 23 int rc; 24 25 rc = __phy_write(phydev, MII_BCM54XX_EXP_SEL, reg); 26 if (rc < 0) 27 return rc; 28 29 return __phy_write(phydev, MII_BCM54XX_EXP_DATA, val); 30 } 31 EXPORT_SYMBOL_GPL(__bcm_phy_write_exp); 32 33 int bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val) 34 { 35 int rc; 36 37 phy_lock_mdio_bus(phydev); 38 rc = __bcm_phy_write_exp(phydev, reg, val); 39 phy_unlock_mdio_bus(phydev); 40 41 return rc; 42 } 43 EXPORT_SYMBOL_GPL(bcm_phy_write_exp); 44 45 int __bcm_phy_read_exp(struct phy_device *phydev, u16 reg) 46 { 47 int val; 48 49 val = __phy_write(phydev, MII_BCM54XX_EXP_SEL, reg); 50 if (val < 0) 51 return val; 52 53 val = __phy_read(phydev, MII_BCM54XX_EXP_DATA); 54 55 /* Restore default value. It's O.K. if this write fails. */ 56 __phy_write(phydev, MII_BCM54XX_EXP_SEL, 0); 57 58 return val; 59 } 60 EXPORT_SYMBOL_GPL(__bcm_phy_read_exp); 61 62 int bcm_phy_read_exp(struct phy_device *phydev, u16 reg) 63 { 64 int rc; 65 66 phy_lock_mdio_bus(phydev); 67 rc = __bcm_phy_read_exp(phydev, reg); 68 phy_unlock_mdio_bus(phydev); 69 70 return rc; 71 } 72 EXPORT_SYMBOL_GPL(bcm_phy_read_exp); 73 74 int __bcm_phy_modify_exp(struct phy_device *phydev, u16 reg, u16 mask, u16 set) 75 { 76 int new, ret; 77 78 ret = __phy_write(phydev, MII_BCM54XX_EXP_SEL, reg); 79 if (ret < 0) 80 return ret; 81 82 ret = __phy_read(phydev, MII_BCM54XX_EXP_DATA); 83 if (ret < 0) 84 return ret; 85 86 new = (ret & ~mask) | set; 87 if (new == ret) 88 return 0; 89 90 return __phy_write(phydev, MII_BCM54XX_EXP_DATA, new); 91 } 92 EXPORT_SYMBOL_GPL(__bcm_phy_modify_exp); 93 94 int bcm_phy_modify_exp(struct phy_device *phydev, u16 reg, u16 mask, u16 set) 95 { 96 int ret; 97 98 phy_lock_mdio_bus(phydev); 99 ret = __bcm_phy_modify_exp(phydev, reg, mask, set); 100 phy_unlock_mdio_bus(phydev); 101 102 return ret; 103 } 104 EXPORT_SYMBOL_GPL(bcm_phy_modify_exp); 105 106 int bcm54xx_auxctl_read(struct phy_device *phydev, u16 regnum) 107 { 108 /* The register must be written to both the Shadow Register Select and 109 * the Shadow Read Register Selector 110 */ 111 phy_write(phydev, MII_BCM54XX_AUX_CTL, MII_BCM54XX_AUXCTL_SHDWSEL_MASK | 112 regnum << MII_BCM54XX_AUXCTL_SHDWSEL_READ_SHIFT); 113 return phy_read(phydev, MII_BCM54XX_AUX_CTL); 114 } 115 EXPORT_SYMBOL_GPL(bcm54xx_auxctl_read); 116 117 int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val) 118 { 119 return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val); 120 } 121 EXPORT_SYMBOL(bcm54xx_auxctl_write); 122 123 int bcm_phy_write_misc(struct phy_device *phydev, 124 u16 reg, u16 chl, u16 val) 125 { 126 int rc; 127 int tmp; 128 129 rc = phy_write(phydev, MII_BCM54XX_AUX_CTL, 130 MII_BCM54XX_AUXCTL_SHDWSEL_MISC); 131 if (rc < 0) 132 return rc; 133 134 tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL); 135 tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA; 136 rc = phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp); 137 if (rc < 0) 138 return rc; 139 140 tmp = (chl * MII_BCM_CHANNEL_WIDTH) | reg; 141 rc = bcm_phy_write_exp(phydev, tmp, val); 142 143 return rc; 144 } 145 EXPORT_SYMBOL_GPL(bcm_phy_write_misc); 146 147 int bcm_phy_read_misc(struct phy_device *phydev, 148 u16 reg, u16 chl) 149 { 150 int rc; 151 int tmp; 152 153 rc = phy_write(phydev, MII_BCM54XX_AUX_CTL, 154 MII_BCM54XX_AUXCTL_SHDWSEL_MISC); 155 if (rc < 0) 156 return rc; 157 158 tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL); 159 tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA; 160 rc = phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp); 161 if (rc < 0) 162 return rc; 163 164 tmp = (chl * MII_BCM_CHANNEL_WIDTH) | reg; 165 rc = bcm_phy_read_exp(phydev, tmp); 166 167 return rc; 168 } 169 EXPORT_SYMBOL_GPL(bcm_phy_read_misc); 170 171 int bcm_phy_ack_intr(struct phy_device *phydev) 172 { 173 int reg; 174 175 /* Clear pending interrupts. */ 176 reg = phy_read(phydev, MII_BCM54XX_ISR); 177 if (reg < 0) 178 return reg; 179 180 return 0; 181 } 182 EXPORT_SYMBOL_GPL(bcm_phy_ack_intr); 183 184 int bcm_phy_config_intr(struct phy_device *phydev) 185 { 186 int reg, err; 187 188 reg = phy_read(phydev, MII_BCM54XX_ECR); 189 if (reg < 0) 190 return reg; 191 192 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 193 err = bcm_phy_ack_intr(phydev); 194 if (err) 195 return err; 196 197 reg &= ~MII_BCM54XX_ECR_IM; 198 err = phy_write(phydev, MII_BCM54XX_ECR, reg); 199 } else { 200 reg |= MII_BCM54XX_ECR_IM; 201 err = phy_write(phydev, MII_BCM54XX_ECR, reg); 202 if (err) 203 return err; 204 205 err = bcm_phy_ack_intr(phydev); 206 } 207 return err; 208 } 209 EXPORT_SYMBOL_GPL(bcm_phy_config_intr); 210 211 irqreturn_t bcm_phy_handle_interrupt(struct phy_device *phydev) 212 { 213 int irq_status, irq_mask; 214 215 irq_status = phy_read(phydev, MII_BCM54XX_ISR); 216 if (irq_status < 0) { 217 phy_error(phydev); 218 return IRQ_NONE; 219 } 220 221 /* If a bit from the Interrupt Mask register is set, the corresponding 222 * bit from the Interrupt Status register is masked. So read the IMR 223 * and then flip the bits to get the list of possible interrupt 224 * sources. 225 */ 226 irq_mask = phy_read(phydev, MII_BCM54XX_IMR); 227 if (irq_mask < 0) { 228 phy_error(phydev); 229 return IRQ_NONE; 230 } 231 irq_mask = ~irq_mask; 232 233 if (!(irq_status & irq_mask)) 234 return IRQ_NONE; 235 236 phy_trigger_machine(phydev); 237 238 return IRQ_HANDLED; 239 } 240 EXPORT_SYMBOL_GPL(bcm_phy_handle_interrupt); 241 242 int bcm_phy_read_shadow(struct phy_device *phydev, u16 shadow) 243 { 244 phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow)); 245 return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD)); 246 } 247 EXPORT_SYMBOL_GPL(bcm_phy_read_shadow); 248 249 int bcm_phy_write_shadow(struct phy_device *phydev, u16 shadow, 250 u16 val) 251 { 252 return phy_write(phydev, MII_BCM54XX_SHD, 253 MII_BCM54XX_SHD_WRITE | 254 MII_BCM54XX_SHD_VAL(shadow) | 255 MII_BCM54XX_SHD_DATA(val)); 256 } 257 EXPORT_SYMBOL_GPL(bcm_phy_write_shadow); 258 259 int __bcm_phy_read_rdb(struct phy_device *phydev, u16 rdb) 260 { 261 int val; 262 263 val = __phy_write(phydev, MII_BCM54XX_RDB_ADDR, rdb); 264 if (val < 0) 265 return val; 266 267 return __phy_read(phydev, MII_BCM54XX_RDB_DATA); 268 } 269 EXPORT_SYMBOL_GPL(__bcm_phy_read_rdb); 270 271 int bcm_phy_read_rdb(struct phy_device *phydev, u16 rdb) 272 { 273 int ret; 274 275 phy_lock_mdio_bus(phydev); 276 ret = __bcm_phy_read_rdb(phydev, rdb); 277 phy_unlock_mdio_bus(phydev); 278 279 return ret; 280 } 281 EXPORT_SYMBOL_GPL(bcm_phy_read_rdb); 282 283 int __bcm_phy_write_rdb(struct phy_device *phydev, u16 rdb, u16 val) 284 { 285 int ret; 286 287 ret = __phy_write(phydev, MII_BCM54XX_RDB_ADDR, rdb); 288 if (ret < 0) 289 return ret; 290 291 return __phy_write(phydev, MII_BCM54XX_RDB_DATA, val); 292 } 293 EXPORT_SYMBOL_GPL(__bcm_phy_write_rdb); 294 295 int bcm_phy_write_rdb(struct phy_device *phydev, u16 rdb, u16 val) 296 { 297 int ret; 298 299 phy_lock_mdio_bus(phydev); 300 ret = __bcm_phy_write_rdb(phydev, rdb, val); 301 phy_unlock_mdio_bus(phydev); 302 303 return ret; 304 } 305 EXPORT_SYMBOL_GPL(bcm_phy_write_rdb); 306 307 int __bcm_phy_modify_rdb(struct phy_device *phydev, u16 rdb, u16 mask, u16 set) 308 { 309 int new, ret; 310 311 ret = __phy_write(phydev, MII_BCM54XX_RDB_ADDR, rdb); 312 if (ret < 0) 313 return ret; 314 315 ret = __phy_read(phydev, MII_BCM54XX_RDB_DATA); 316 if (ret < 0) 317 return ret; 318 319 new = (ret & ~mask) | set; 320 if (new == ret) 321 return 0; 322 323 return __phy_write(phydev, MII_BCM54XX_RDB_DATA, new); 324 } 325 EXPORT_SYMBOL_GPL(__bcm_phy_modify_rdb); 326 327 int bcm_phy_modify_rdb(struct phy_device *phydev, u16 rdb, u16 mask, u16 set) 328 { 329 int ret; 330 331 phy_lock_mdio_bus(phydev); 332 ret = __bcm_phy_modify_rdb(phydev, rdb, mask, set); 333 phy_unlock_mdio_bus(phydev); 334 335 return ret; 336 } 337 EXPORT_SYMBOL_GPL(bcm_phy_modify_rdb); 338 339 int bcm_phy_enable_apd(struct phy_device *phydev, bool dll_pwr_down) 340 { 341 int val; 342 343 if (dll_pwr_down) { 344 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3); 345 if (val < 0) 346 return val; 347 348 val |= BCM54XX_SHD_SCR3_DLLAPD_DIS; 349 bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR3, val); 350 } 351 352 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_APD); 353 if (val < 0) 354 return val; 355 356 /* Clear APD bits */ 357 val &= BCM_APD_CLR_MASK; 358 359 if (phydev->autoneg == AUTONEG_ENABLE) 360 val |= BCM54XX_SHD_APD_EN; 361 else 362 val |= BCM_NO_ANEG_APD_EN; 363 364 /* Enable energy detect single link pulse for easy wakeup */ 365 val |= BCM_APD_SINGLELP_EN; 366 367 /* Enable Auto Power-Down (APD) for the PHY */ 368 return bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val); 369 } 370 EXPORT_SYMBOL_GPL(bcm_phy_enable_apd); 371 372 int bcm_phy_set_eee(struct phy_device *phydev, bool enable) 373 { 374 int val, mask = 0; 375 376 /* Enable EEE at PHY level */ 377 val = phy_read_mmd(phydev, MDIO_MMD_AN, BRCM_CL45VEN_EEE_CONTROL); 378 if (val < 0) 379 return val; 380 381 if (enable) 382 val |= LPI_FEATURE_EN | LPI_FEATURE_EN_DIG1000X; 383 else 384 val &= ~(LPI_FEATURE_EN | LPI_FEATURE_EN_DIG1000X); 385 386 phy_write_mmd(phydev, MDIO_MMD_AN, BRCM_CL45VEN_EEE_CONTROL, (u32)val); 387 388 /* Advertise EEE */ 389 val = phy_read_mmd(phydev, MDIO_MMD_AN, BCM_CL45VEN_EEE_ADV); 390 if (val < 0) 391 return val; 392 393 if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, 394 phydev->supported)) 395 mask |= MDIO_EEE_1000T; 396 if (linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, 397 phydev->supported)) 398 mask |= MDIO_EEE_100TX; 399 400 if (enable) 401 val |= mask; 402 else 403 val &= ~mask; 404 405 phy_write_mmd(phydev, MDIO_MMD_AN, BCM_CL45VEN_EEE_ADV, (u32)val); 406 407 return 0; 408 } 409 EXPORT_SYMBOL_GPL(bcm_phy_set_eee); 410 411 int bcm_phy_downshift_get(struct phy_device *phydev, u8 *count) 412 { 413 int val; 414 415 val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC); 416 if (val < 0) 417 return val; 418 419 /* Check if wirespeed is enabled or not */ 420 if (!(val & MII_BCM54XX_AUXCTL_SHDWSEL_MISC_WIRESPEED_EN)) { 421 *count = DOWNSHIFT_DEV_DISABLE; 422 return 0; 423 } 424 425 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR2); 426 if (val < 0) 427 return val; 428 429 /* Downgrade after one link attempt */ 430 if (val & BCM54XX_SHD_SCR2_WSPD_RTRY_DIS) { 431 *count = 1; 432 } else { 433 /* Downgrade after configured retry count */ 434 val >>= BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_SHIFT; 435 val &= BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_MASK; 436 *count = val + BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_OFFSET; 437 } 438 439 return 0; 440 } 441 EXPORT_SYMBOL_GPL(bcm_phy_downshift_get); 442 443 int bcm_phy_downshift_set(struct phy_device *phydev, u8 count) 444 { 445 int val = 0, ret = 0; 446 447 /* Range check the number given */ 448 if (count - BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_OFFSET > 449 BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_MASK && 450 count != DOWNSHIFT_DEV_DEFAULT_COUNT) { 451 return -ERANGE; 452 } 453 454 val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC); 455 if (val < 0) 456 return val; 457 458 /* Se the write enable bit */ 459 val |= MII_BCM54XX_AUXCTL_MISC_WREN; 460 461 if (count == DOWNSHIFT_DEV_DISABLE) { 462 val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_WIRESPEED_EN; 463 return bcm54xx_auxctl_write(phydev, 464 MII_BCM54XX_AUXCTL_SHDWSEL_MISC, 465 val); 466 } else { 467 val |= MII_BCM54XX_AUXCTL_SHDWSEL_MISC_WIRESPEED_EN; 468 ret = bcm54xx_auxctl_write(phydev, 469 MII_BCM54XX_AUXCTL_SHDWSEL_MISC, 470 val); 471 if (ret < 0) 472 return ret; 473 } 474 475 val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR2); 476 val &= ~(BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_MASK << 477 BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_SHIFT | 478 BCM54XX_SHD_SCR2_WSPD_RTRY_DIS); 479 480 switch (count) { 481 case 1: 482 val |= BCM54XX_SHD_SCR2_WSPD_RTRY_DIS; 483 break; 484 case DOWNSHIFT_DEV_DEFAULT_COUNT: 485 val |= 1 << BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_SHIFT; 486 break; 487 default: 488 val |= (count - BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_OFFSET) << 489 BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_SHIFT; 490 break; 491 } 492 493 return bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR2, val); 494 } 495 EXPORT_SYMBOL_GPL(bcm_phy_downshift_set); 496 497 struct bcm_phy_hw_stat { 498 const char *string; 499 int devad; 500 u16 reg; 501 u8 shift; 502 u8 bits; 503 }; 504 505 /* Counters freeze at either 0xffff or 0xff, better than nothing */ 506 static const struct bcm_phy_hw_stat bcm_phy_hw_stats[] = { 507 { "phy_receive_errors", -1, MII_BRCM_CORE_BASE12, 0, 16 }, 508 { "phy_serdes_ber_errors", -1, MII_BRCM_CORE_BASE13, 8, 8 }, 509 { "phy_false_carrier_sense_errors", -1, MII_BRCM_CORE_BASE13, 0, 8 }, 510 { "phy_local_rcvr_nok", -1, MII_BRCM_CORE_BASE14, 8, 8 }, 511 { "phy_remote_rcv_nok", -1, MII_BRCM_CORE_BASE14, 0, 8 }, 512 { "phy_lpi_count", MDIO_MMD_AN, BRCM_CL45VEN_EEE_LPI_CNT, 0, 16 }, 513 }; 514 515 int bcm_phy_get_sset_count(struct phy_device *phydev) 516 { 517 return ARRAY_SIZE(bcm_phy_hw_stats); 518 } 519 EXPORT_SYMBOL_GPL(bcm_phy_get_sset_count); 520 521 void bcm_phy_get_strings(struct phy_device *phydev, u8 *data) 522 { 523 unsigned int i; 524 525 for (i = 0; i < ARRAY_SIZE(bcm_phy_hw_stats); i++) 526 strscpy(data + i * ETH_GSTRING_LEN, 527 bcm_phy_hw_stats[i].string, ETH_GSTRING_LEN); 528 } 529 EXPORT_SYMBOL_GPL(bcm_phy_get_strings); 530 531 /* Caller is supposed to provide appropriate storage for the library code to 532 * access the shadow copy 533 */ 534 static u64 bcm_phy_get_stat(struct phy_device *phydev, u64 *shadow, 535 unsigned int i) 536 { 537 struct bcm_phy_hw_stat stat = bcm_phy_hw_stats[i]; 538 int val; 539 u64 ret; 540 541 if (stat.devad < 0) 542 val = phy_read(phydev, stat.reg); 543 else 544 val = phy_read_mmd(phydev, stat.devad, stat.reg); 545 if (val < 0) { 546 ret = U64_MAX; 547 } else { 548 val >>= stat.shift; 549 val = val & ((1 << stat.bits) - 1); 550 shadow[i] += val; 551 ret = shadow[i]; 552 } 553 554 return ret; 555 } 556 557 void bcm_phy_get_stats(struct phy_device *phydev, u64 *shadow, 558 struct ethtool_stats *stats, u64 *data) 559 { 560 unsigned int i; 561 562 for (i = 0; i < ARRAY_SIZE(bcm_phy_hw_stats); i++) 563 data[i] = bcm_phy_get_stat(phydev, shadow, i); 564 } 565 EXPORT_SYMBOL_GPL(bcm_phy_get_stats); 566 567 void bcm_phy_r_rc_cal_reset(struct phy_device *phydev) 568 { 569 /* Reset R_CAL/RC_CAL Engine */ 570 bcm_phy_write_exp_sel(phydev, 0x00b0, 0x0010); 571 572 /* Disable Reset R_AL/RC_CAL Engine */ 573 bcm_phy_write_exp_sel(phydev, 0x00b0, 0x0000); 574 } 575 EXPORT_SYMBOL_GPL(bcm_phy_r_rc_cal_reset); 576 577 int bcm_phy_28nm_a0b0_afe_config_init(struct phy_device *phydev) 578 { 579 /* Increase VCO range to prevent unlocking problem of PLL at low 580 * temp 581 */ 582 bcm_phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048); 583 584 /* Change Ki to 011 */ 585 bcm_phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b); 586 587 /* Disable loading of TVCO buffer to bandgap, set bandgap trim 588 * to 111 589 */ 590 bcm_phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20); 591 592 /* Adjust bias current trim by -3 */ 593 bcm_phy_write_misc(phydev, DSP_TAP10, 0x690b); 594 595 /* Switch to CORE_BASE1E */ 596 phy_write(phydev, MII_BRCM_CORE_BASE1E, 0xd); 597 598 bcm_phy_r_rc_cal_reset(phydev); 599 600 /* write AFE_RXCONFIG_0 */ 601 bcm_phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19); 602 603 /* write AFE_RXCONFIG_1 */ 604 bcm_phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9a3f); 605 606 /* write AFE_RX_LP_COUNTER */ 607 bcm_phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0); 608 609 /* write AFE_HPF_TRIM_OTHERS */ 610 bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x000b); 611 612 /* write AFTE_TX_CONFIG */ 613 bcm_phy_write_misc(phydev, AFE_TX_CONFIG, 0x0800); 614 615 return 0; 616 } 617 EXPORT_SYMBOL_GPL(bcm_phy_28nm_a0b0_afe_config_init); 618 619 int bcm_phy_enable_jumbo(struct phy_device *phydev) 620 { 621 int ret; 622 623 ret = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL); 624 if (ret < 0) 625 return ret; 626 627 /* Enable extended length packet reception */ 628 ret = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, 629 ret | MII_BCM54XX_AUXCTL_ACTL_EXT_PKT_LEN); 630 if (ret < 0) 631 return ret; 632 633 /* Enable the elastic FIFO for raising the transmission limit from 634 * 4.5KB to 10KB, at the expense of an additional 16 ns in propagation 635 * latency. 636 */ 637 return phy_set_bits(phydev, MII_BCM54XX_ECR, MII_BCM54XX_ECR_FIFOE); 638 } 639 EXPORT_SYMBOL_GPL(bcm_phy_enable_jumbo); 640 641 static int __bcm_phy_enable_rdb_access(struct phy_device *phydev) 642 { 643 return __bcm_phy_write_exp(phydev, BCM54XX_EXP_REG7E, 0); 644 } 645 646 static int __bcm_phy_enable_legacy_access(struct phy_device *phydev) 647 { 648 return __bcm_phy_write_rdb(phydev, BCM54XX_RDB_REG0087, 649 BCM54XX_ACCESS_MODE_LEGACY_EN); 650 } 651 652 static int _bcm_phy_cable_test_start(struct phy_device *phydev, bool is_rdb) 653 { 654 u16 mask, set; 655 int ret; 656 657 /* Auto-negotiation must be enabled for cable diagnostics to work, but 658 * don't advertise any capabilities. 659 */ 660 phy_write(phydev, MII_BMCR, BMCR_ANENABLE); 661 phy_write(phydev, MII_ADVERTISE, ADVERTISE_CSMA); 662 phy_write(phydev, MII_CTRL1000, 0); 663 664 phy_lock_mdio_bus(phydev); 665 if (is_rdb) { 666 ret = __bcm_phy_enable_legacy_access(phydev); 667 if (ret) 668 goto out; 669 } 670 671 mask = BCM54XX_ECD_CTRL_CROSS_SHORT_DIS | BCM54XX_ECD_CTRL_UNIT_MASK; 672 set = BCM54XX_ECD_CTRL_RUN | BCM54XX_ECD_CTRL_BREAK_LINK | 673 FIELD_PREP(BCM54XX_ECD_CTRL_UNIT_MASK, 674 BCM54XX_ECD_CTRL_UNIT_CM); 675 676 ret = __bcm_phy_modify_exp(phydev, BCM54XX_EXP_ECD_CTRL, mask, set); 677 678 out: 679 /* re-enable the RDB access even if there was an error */ 680 if (is_rdb) 681 ret = __bcm_phy_enable_rdb_access(phydev) ? : ret; 682 683 phy_unlock_mdio_bus(phydev); 684 685 return ret; 686 } 687 688 static int bcm_phy_cable_test_report_trans(int result) 689 { 690 switch (result) { 691 case BCM54XX_ECD_FAULT_TYPE_OK: 692 return ETHTOOL_A_CABLE_RESULT_CODE_OK; 693 case BCM54XX_ECD_FAULT_TYPE_OPEN: 694 return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; 695 case BCM54XX_ECD_FAULT_TYPE_SAME_SHORT: 696 return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; 697 case BCM54XX_ECD_FAULT_TYPE_CROSS_SHORT: 698 return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT; 699 case BCM54XX_ECD_FAULT_TYPE_INVALID: 700 case BCM54XX_ECD_FAULT_TYPE_BUSY: 701 default: 702 return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; 703 } 704 } 705 706 static bool bcm_phy_distance_valid(int result) 707 { 708 switch (result) { 709 case BCM54XX_ECD_FAULT_TYPE_OPEN: 710 case BCM54XX_ECD_FAULT_TYPE_SAME_SHORT: 711 case BCM54XX_ECD_FAULT_TYPE_CROSS_SHORT: 712 return true; 713 } 714 return false; 715 } 716 717 static int bcm_phy_report_length(struct phy_device *phydev, int pair) 718 { 719 int val; 720 721 val = __bcm_phy_read_exp(phydev, 722 BCM54XX_EXP_ECD_PAIR_A_LENGTH_RESULTS + pair); 723 if (val < 0) 724 return val; 725 726 if (val == BCM54XX_ECD_LENGTH_RESULTS_INVALID) 727 return 0; 728 729 ethnl_cable_test_fault_length(phydev, pair, val); 730 731 return 0; 732 } 733 734 static int _bcm_phy_cable_test_get_status(struct phy_device *phydev, 735 bool *finished, bool is_rdb) 736 { 737 int pair_a, pair_b, pair_c, pair_d, ret; 738 739 *finished = false; 740 741 phy_lock_mdio_bus(phydev); 742 743 if (is_rdb) { 744 ret = __bcm_phy_enable_legacy_access(phydev); 745 if (ret) 746 goto out; 747 } 748 749 ret = __bcm_phy_read_exp(phydev, BCM54XX_EXP_ECD_CTRL); 750 if (ret < 0) 751 goto out; 752 753 if (ret & BCM54XX_ECD_CTRL_IN_PROGRESS) { 754 ret = 0; 755 goto out; 756 } 757 758 ret = __bcm_phy_read_exp(phydev, BCM54XX_EXP_ECD_FAULT_TYPE); 759 if (ret < 0) 760 goto out; 761 762 pair_a = FIELD_GET(BCM54XX_ECD_FAULT_TYPE_PAIR_A_MASK, ret); 763 pair_b = FIELD_GET(BCM54XX_ECD_FAULT_TYPE_PAIR_B_MASK, ret); 764 pair_c = FIELD_GET(BCM54XX_ECD_FAULT_TYPE_PAIR_C_MASK, ret); 765 pair_d = FIELD_GET(BCM54XX_ECD_FAULT_TYPE_PAIR_D_MASK, ret); 766 767 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A, 768 bcm_phy_cable_test_report_trans(pair_a)); 769 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_B, 770 bcm_phy_cable_test_report_trans(pair_b)); 771 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_C, 772 bcm_phy_cable_test_report_trans(pair_c)); 773 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_D, 774 bcm_phy_cable_test_report_trans(pair_d)); 775 776 if (bcm_phy_distance_valid(pair_a)) 777 bcm_phy_report_length(phydev, 0); 778 if (bcm_phy_distance_valid(pair_b)) 779 bcm_phy_report_length(phydev, 1); 780 if (bcm_phy_distance_valid(pair_c)) 781 bcm_phy_report_length(phydev, 2); 782 if (bcm_phy_distance_valid(pair_d)) 783 bcm_phy_report_length(phydev, 3); 784 785 ret = 0; 786 *finished = true; 787 out: 788 /* re-enable the RDB access even if there was an error */ 789 if (is_rdb) 790 ret = __bcm_phy_enable_rdb_access(phydev) ? : ret; 791 792 phy_unlock_mdio_bus(phydev); 793 794 return ret; 795 } 796 797 int bcm_phy_cable_test_start(struct phy_device *phydev) 798 { 799 return _bcm_phy_cable_test_start(phydev, false); 800 } 801 EXPORT_SYMBOL_GPL(bcm_phy_cable_test_start); 802 803 int bcm_phy_cable_test_get_status(struct phy_device *phydev, bool *finished) 804 { 805 return _bcm_phy_cable_test_get_status(phydev, finished, false); 806 } 807 EXPORT_SYMBOL_GPL(bcm_phy_cable_test_get_status); 808 809 /* We assume that all PHYs which support RDB access can be switched to legacy 810 * mode. If, in the future, this is not true anymore, we have to re-implement 811 * this with RDB access. 812 */ 813 int bcm_phy_cable_test_start_rdb(struct phy_device *phydev) 814 { 815 return _bcm_phy_cable_test_start(phydev, true); 816 } 817 EXPORT_SYMBOL_GPL(bcm_phy_cable_test_start_rdb); 818 819 int bcm_phy_cable_test_get_status_rdb(struct phy_device *phydev, 820 bool *finished) 821 { 822 return _bcm_phy_cable_test_get_status(phydev, finished, true); 823 } 824 EXPORT_SYMBOL_GPL(bcm_phy_cable_test_get_status_rdb); 825 826 #define BCM54XX_WOL_SUPPORTED_MASK (WAKE_UCAST | \ 827 WAKE_MCAST | \ 828 WAKE_BCAST | \ 829 WAKE_MAGIC | \ 830 WAKE_MAGICSECURE) 831 832 int bcm_phy_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) 833 { 834 struct net_device *ndev = phydev->attached_dev; 835 u8 da[ETH_ALEN], mask[ETH_ALEN]; 836 unsigned int i; 837 u16 ctl; 838 int ret; 839 840 /* Allow a MAC driver to play through its own Wake-on-LAN 841 * implementation 842 */ 843 if (wol->wolopts & ~BCM54XX_WOL_SUPPORTED_MASK) 844 return -EOPNOTSUPP; 845 846 /* The PHY supports passwords of 4, 6 and 8 bytes in size, but Linux's 847 * ethtool only supports 6, for now. 848 */ 849 BUILD_BUG_ON(sizeof(wol->sopass) != ETH_ALEN); 850 851 /* Clear previous interrupts */ 852 ret = bcm_phy_read_exp(phydev, BCM54XX_WOL_INT_STATUS); 853 if (ret < 0) 854 return ret; 855 856 ret = bcm_phy_read_exp(phydev, BCM54XX_WOL_MAIN_CTL); 857 if (ret < 0) 858 return ret; 859 860 ctl = ret; 861 862 if (!wol->wolopts) { 863 if (phy_interrupt_is_valid(phydev)) 864 disable_irq_wake(phydev->irq); 865 866 /* Leave all interrupts disabled */ 867 ret = bcm_phy_write_exp(phydev, BCM54XX_WOL_INT_MASK, 868 BCM54XX_WOL_ALL_INTRS); 869 if (ret < 0) 870 return ret; 871 872 /* Disable the global Wake-on-LAN enable bit */ 873 ctl &= ~BCM54XX_WOL_EN; 874 875 return bcm_phy_write_exp(phydev, BCM54XX_WOL_MAIN_CTL, ctl); 876 } 877 878 /* Clear the previously configured mode and mask mode for Wake-on-LAN */ 879 ctl &= ~(BCM54XX_WOL_MODE_MASK << BCM54XX_WOL_MODE_SHIFT); 880 ctl &= ~(BCM54XX_WOL_MASK_MODE_MASK << BCM54XX_WOL_MASK_MODE_SHIFT); 881 ctl &= ~BCM54XX_WOL_DIR_PKT_EN; 882 ctl &= ~(BCM54XX_WOL_SECKEY_OPT_MASK << BCM54XX_WOL_SECKEY_OPT_SHIFT); 883 884 /* When using WAKE_MAGIC, we program the magic pattern filter to match 885 * the device's MAC address and we accept any MAC DA in the Ethernet 886 * frame. 887 * 888 * When using WAKE_UCAST, WAKE_BCAST or WAKE_MCAST, we program the 889 * following: 890 * - WAKE_UCAST -> MAC DA is the device's MAC with a perfect match 891 * - WAKE_MCAST -> MAC DA is X1:XX:XX:XX:XX:XX where XX is don't care 892 * - WAKE_BCAST -> MAC DA is FF:FF:FF:FF:FF:FF with a perfect match 893 * 894 * Note that the Broadcast MAC DA is inherently going to match the 895 * multicast pattern being matched. 896 */ 897 memset(mask, 0, sizeof(mask)); 898 899 if (wol->wolopts & WAKE_MCAST) { 900 memset(da, 0, sizeof(da)); 901 memset(mask, 0xff, sizeof(mask)); 902 da[0] = 0x01; 903 mask[0] = ~da[0]; 904 } else { 905 if (wol->wolopts & WAKE_UCAST) { 906 ether_addr_copy(da, ndev->dev_addr); 907 } else if (wol->wolopts & WAKE_BCAST) { 908 eth_broadcast_addr(da); 909 } else if (wol->wolopts & WAKE_MAGICSECURE) { 910 ether_addr_copy(da, wol->sopass); 911 } else if (wol->wolopts & WAKE_MAGIC) { 912 memset(da, 0, sizeof(da)); 913 memset(mask, 0xff, sizeof(mask)); 914 } 915 } 916 917 for (i = 0; i < ETH_ALEN / 2; i++) { 918 if (wol->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) { 919 ret = bcm_phy_write_exp(phydev, 920 BCM54XX_WOL_MPD_DATA1(2 - i), 921 ndev->dev_addr[i * 2] << 8 | 922 ndev->dev_addr[i * 2 + 1]); 923 if (ret < 0) 924 return ret; 925 } 926 927 ret = bcm_phy_write_exp(phydev, BCM54XX_WOL_MPD_DATA2(2 - i), 928 da[i * 2] << 8 | da[i * 2 + 1]); 929 if (ret < 0) 930 return ret; 931 932 ret = bcm_phy_write_exp(phydev, BCM54XX_WOL_MASK(2 - i), 933 mask[i * 2] << 8 | mask[i * 2 + 1]); 934 if (ret) 935 return ret; 936 } 937 938 if (wol->wolopts & WAKE_MAGICSECURE) { 939 ctl |= BCM54XX_WOL_SECKEY_OPT_6B << 940 BCM54XX_WOL_SECKEY_OPT_SHIFT; 941 ctl |= BCM54XX_WOL_MODE_SINGLE_MPDSEC << BCM54XX_WOL_MODE_SHIFT; 942 ctl |= BCM54XX_WOL_MASK_MODE_DA_FF << 943 BCM54XX_WOL_MASK_MODE_SHIFT; 944 } else { 945 if (wol->wolopts & WAKE_MAGIC) 946 ctl |= BCM54XX_WOL_MODE_SINGLE_MPD; 947 else 948 ctl |= BCM54XX_WOL_DIR_PKT_EN; 949 ctl |= BCM54XX_WOL_MASK_MODE_DA_ONLY << 950 BCM54XX_WOL_MASK_MODE_SHIFT; 951 } 952 953 /* Globally enable Wake-on-LAN */ 954 ctl |= BCM54XX_WOL_EN | BCM54XX_WOL_CRC_CHK; 955 956 ret = bcm_phy_write_exp(phydev, BCM54XX_WOL_MAIN_CTL, ctl); 957 if (ret < 0) 958 return ret; 959 960 /* Enable WOL interrupt on LED4 */ 961 ret = bcm_phy_read_exp(phydev, BCM54XX_TOP_MISC_LED_CTL); 962 if (ret < 0) 963 return ret; 964 965 ret |= BCM54XX_LED4_SEL_INTR; 966 ret = bcm_phy_write_exp(phydev, BCM54XX_TOP_MISC_LED_CTL, ret); 967 if (ret < 0) 968 return ret; 969 970 /* Enable all Wake-on-LAN interrupt sources */ 971 ret = bcm_phy_write_exp(phydev, BCM54XX_WOL_INT_MASK, 0); 972 if (ret < 0) 973 return ret; 974 975 if (phy_interrupt_is_valid(phydev)) 976 enable_irq_wake(phydev->irq); 977 978 return 0; 979 } 980 EXPORT_SYMBOL_GPL(bcm_phy_set_wol); 981 982 void bcm_phy_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) 983 { 984 struct net_device *ndev = phydev->attached_dev; 985 u8 da[ETH_ALEN]; 986 unsigned int i; 987 int ret; 988 u16 ctl; 989 990 wol->supported = BCM54XX_WOL_SUPPORTED_MASK; 991 wol->wolopts = 0; 992 993 ret = bcm_phy_read_exp(phydev, BCM54XX_WOL_MAIN_CTL); 994 if (ret < 0) 995 return; 996 997 ctl = ret; 998 999 if (!(ctl & BCM54XX_WOL_EN)) 1000 return; 1001 1002 for (i = 0; i < sizeof(da) / 2; i++) { 1003 ret = bcm_phy_read_exp(phydev, 1004 BCM54XX_WOL_MPD_DATA2(2 - i)); 1005 if (ret < 0) 1006 return; 1007 1008 da[i * 2] = ret >> 8; 1009 da[i * 2 + 1] = ret & 0xff; 1010 } 1011 1012 if (ctl & BCM54XX_WOL_DIR_PKT_EN) { 1013 if (is_broadcast_ether_addr(da)) 1014 wol->wolopts |= WAKE_BCAST; 1015 else if (is_multicast_ether_addr(da)) 1016 wol->wolopts |= WAKE_MCAST; 1017 else if (ether_addr_equal(da, ndev->dev_addr)) 1018 wol->wolopts |= WAKE_UCAST; 1019 } else { 1020 ctl = (ctl >> BCM54XX_WOL_MODE_SHIFT) & BCM54XX_WOL_MODE_MASK; 1021 switch (ctl) { 1022 case BCM54XX_WOL_MODE_SINGLE_MPD: 1023 wol->wolopts |= WAKE_MAGIC; 1024 break; 1025 case BCM54XX_WOL_MODE_SINGLE_MPDSEC: 1026 wol->wolopts |= WAKE_MAGICSECURE; 1027 memcpy(wol->sopass, da, sizeof(da)); 1028 break; 1029 default: 1030 break; 1031 } 1032 } 1033 } 1034 EXPORT_SYMBOL_GPL(bcm_phy_get_wol); 1035 1036 irqreturn_t bcm_phy_wol_isr(int irq, void *dev_id) 1037 { 1038 return IRQ_HANDLED; 1039 } 1040 EXPORT_SYMBOL_GPL(bcm_phy_wol_isr); 1041 1042 int bcm_phy_led_brightness_set(struct phy_device *phydev, 1043 u8 index, enum led_brightness value) 1044 { 1045 u8 led_num; 1046 int ret; 1047 u16 reg; 1048 1049 if (index >= 4) 1050 return -EINVAL; 1051 1052 /* Two LEDS per register */ 1053 led_num = index % 2; 1054 reg = index >= 2 ? BCM54XX_SHD_LEDS2 : BCM54XX_SHD_LEDS1; 1055 1056 ret = bcm_phy_read_shadow(phydev, reg); 1057 if (ret < 0) 1058 return ret; 1059 1060 ret &= ~(BCM_LED_SRC_MASK << BCM54XX_SHD_LEDS_SHIFT(led_num)); 1061 if (value == LED_OFF) 1062 ret |= BCM_LED_SRC_OFF << BCM54XX_SHD_LEDS_SHIFT(led_num); 1063 else 1064 ret |= BCM_LED_SRC_ON << BCM54XX_SHD_LEDS_SHIFT(led_num); 1065 return bcm_phy_write_shadow(phydev, reg, ret); 1066 } 1067 EXPORT_SYMBOL_GPL(bcm_phy_led_brightness_set); 1068 1069 MODULE_DESCRIPTION("Broadcom PHY Library"); 1070 MODULE_LICENSE("GPL v2"); 1071 MODULE_AUTHOR("Broadcom Corporation"); 1072