1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <linux/phy.h> 4 #include <linux/module.h> 5 6 #include <linux/netdevice.h> 7 #include <linux/etherdevice.h> 8 #include <linux/ethtool_netlink.h> 9 10 #include "qcom.h" 11 12 MODULE_DESCRIPTION("Qualcomm PHY driver Common Functions"); 13 MODULE_AUTHOR("Matus Ujhelyi"); 14 MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>"); 15 MODULE_LICENSE("GPL"); 16 17 int at803x_debug_reg_read(struct phy_device *phydev, u16 reg) 18 { 19 int ret; 20 21 ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg); 22 if (ret < 0) 23 return ret; 24 25 return phy_read(phydev, AT803X_DEBUG_DATA); 26 } 27 EXPORT_SYMBOL_GPL(at803x_debug_reg_read); 28 29 int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg, 30 u16 clear, u16 set) 31 { 32 u16 val; 33 int ret; 34 35 ret = at803x_debug_reg_read(phydev, reg); 36 if (ret < 0) 37 return ret; 38 39 val = ret & 0xffff; 40 val &= ~clear; 41 val |= set; 42 43 return phy_write(phydev, AT803X_DEBUG_DATA, val); 44 } 45 EXPORT_SYMBOL_GPL(at803x_debug_reg_mask); 46 47 int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data) 48 { 49 int ret; 50 51 ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg); 52 if (ret < 0) 53 return ret; 54 55 return phy_write(phydev, AT803X_DEBUG_DATA, data); 56 } 57 EXPORT_SYMBOL_GPL(at803x_debug_reg_write); 58 59 int at803x_set_wol(struct phy_device *phydev, 60 struct ethtool_wolinfo *wol) 61 { 62 int ret, irq_enabled; 63 64 if (wol->wolopts & WAKE_MAGIC) { 65 struct net_device *ndev = phydev->attached_dev; 66 const u8 *mac; 67 unsigned int i; 68 static const unsigned int offsets[] = { 69 AT803X_LOC_MAC_ADDR_32_47_OFFSET, 70 AT803X_LOC_MAC_ADDR_16_31_OFFSET, 71 AT803X_LOC_MAC_ADDR_0_15_OFFSET, 72 }; 73 74 if (!ndev) 75 return -ENODEV; 76 77 mac = (const u8 *)ndev->dev_addr; 78 79 if (!is_valid_ether_addr(mac)) 80 return -EINVAL; 81 82 for (i = 0; i < 3; i++) 83 phy_write_mmd(phydev, MDIO_MMD_PCS, offsets[i], 84 mac[(i * 2) + 1] | (mac[(i * 2)] << 8)); 85 86 /* Enable WOL interrupt */ 87 ret = phy_modify(phydev, AT803X_INTR_ENABLE, 0, AT803X_INTR_ENABLE_WOL); 88 if (ret) 89 return ret; 90 } else { 91 /* Disable WOL interrupt */ 92 ret = phy_modify(phydev, AT803X_INTR_ENABLE, AT803X_INTR_ENABLE_WOL, 0); 93 if (ret) 94 return ret; 95 } 96 97 /* Clear WOL status */ 98 ret = phy_read(phydev, AT803X_INTR_STATUS); 99 if (ret < 0) 100 return ret; 101 102 /* Check if there are other interrupts except for WOL triggered when PHY is 103 * in interrupt mode, only the interrupts enabled by AT803X_INTR_ENABLE can 104 * be passed up to the interrupt PIN. 105 */ 106 irq_enabled = phy_read(phydev, AT803X_INTR_ENABLE); 107 if (irq_enabled < 0) 108 return irq_enabled; 109 110 irq_enabled &= ~AT803X_INTR_ENABLE_WOL; 111 if (ret & irq_enabled && !phy_polling_mode(phydev)) 112 phy_trigger_machine(phydev); 113 114 return 0; 115 } 116 EXPORT_SYMBOL_GPL(at803x_set_wol); 117 118 int at8031_set_wol(struct phy_device *phydev, 119 struct ethtool_wolinfo *wol) 120 { 121 int ret; 122 123 /* First setup MAC address and enable WOL interrupt */ 124 ret = at803x_set_wol(phydev, wol); 125 if (ret) 126 return ret; 127 128 if (wol->wolopts & WAKE_MAGIC) 129 /* Enable WOL function for 1588 */ 130 ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, 131 AT803X_PHY_MMD3_WOL_CTRL, 132 0, AT803X_WOL_EN); 133 else 134 /* Disable WoL function for 1588 */ 135 ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, 136 AT803X_PHY_MMD3_WOL_CTRL, 137 AT803X_WOL_EN, 0); 138 139 return ret; 140 } 141 EXPORT_SYMBOL_GPL(at8031_set_wol); 142 143 void at803x_get_wol(struct phy_device *phydev, 144 struct ethtool_wolinfo *wol) 145 { 146 int value; 147 148 wol->supported = WAKE_MAGIC; 149 wol->wolopts = 0; 150 151 value = phy_read(phydev, AT803X_INTR_ENABLE); 152 if (value < 0) 153 return; 154 155 if (value & AT803X_INTR_ENABLE_WOL) 156 wol->wolopts |= WAKE_MAGIC; 157 } 158 EXPORT_SYMBOL_GPL(at803x_get_wol); 159 160 int at803x_ack_interrupt(struct phy_device *phydev) 161 { 162 int err; 163 164 err = phy_read(phydev, AT803X_INTR_STATUS); 165 166 return (err < 0) ? err : 0; 167 } 168 EXPORT_SYMBOL_GPL(at803x_ack_interrupt); 169 170 int at803x_config_intr(struct phy_device *phydev) 171 { 172 int err; 173 int value; 174 175 value = phy_read(phydev, AT803X_INTR_ENABLE); 176 177 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 178 /* Clear any pending interrupts */ 179 err = at803x_ack_interrupt(phydev); 180 if (err) 181 return err; 182 183 value |= AT803X_INTR_ENABLE_AUTONEG_ERR; 184 value |= AT803X_INTR_ENABLE_SPEED_CHANGED; 185 value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED; 186 value |= AT803X_INTR_ENABLE_LINK_FAIL; 187 value |= AT803X_INTR_ENABLE_LINK_SUCCESS; 188 189 err = phy_write(phydev, AT803X_INTR_ENABLE, value); 190 } else { 191 err = phy_write(phydev, AT803X_INTR_ENABLE, 0); 192 if (err) 193 return err; 194 195 /* Clear any pending interrupts */ 196 err = at803x_ack_interrupt(phydev); 197 } 198 199 return err; 200 } 201 EXPORT_SYMBOL_GPL(at803x_config_intr); 202 203 irqreturn_t at803x_handle_interrupt(struct phy_device *phydev) 204 { 205 int irq_status, int_enabled; 206 207 irq_status = phy_read(phydev, AT803X_INTR_STATUS); 208 if (irq_status < 0) { 209 phy_error(phydev); 210 return IRQ_NONE; 211 } 212 213 /* Read the current enabled interrupts */ 214 int_enabled = phy_read(phydev, AT803X_INTR_ENABLE); 215 if (int_enabled < 0) { 216 phy_error(phydev); 217 return IRQ_NONE; 218 } 219 220 /* See if this was one of our enabled interrupts */ 221 if (!(irq_status & int_enabled)) 222 return IRQ_NONE; 223 224 phy_trigger_machine(phydev); 225 226 return IRQ_HANDLED; 227 } 228 EXPORT_SYMBOL_GPL(at803x_handle_interrupt); 229 230 int at803x_read_specific_status(struct phy_device *phydev, 231 struct at803x_ss_mask ss_mask) 232 { 233 int ss; 234 235 /* Read the AT8035 PHY-Specific Status register, which indicates the 236 * speed and duplex that the PHY is actually using, irrespective of 237 * whether we are in autoneg mode or not. 238 */ 239 ss = phy_read(phydev, AT803X_SPECIFIC_STATUS); 240 if (ss < 0) 241 return ss; 242 243 if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) { 244 int sfc, speed; 245 246 sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL); 247 if (sfc < 0) 248 return sfc; 249 250 speed = ss & ss_mask.speed_mask; 251 speed >>= ss_mask.speed_shift; 252 253 switch (speed) { 254 case AT803X_SS_SPEED_10: 255 phydev->speed = SPEED_10; 256 break; 257 case AT803X_SS_SPEED_100: 258 phydev->speed = SPEED_100; 259 break; 260 case AT803X_SS_SPEED_1000: 261 phydev->speed = SPEED_1000; 262 break; 263 case QCA808X_SS_SPEED_2500: 264 phydev->speed = SPEED_2500; 265 break; 266 } 267 if (ss & AT803X_SS_DUPLEX) 268 phydev->duplex = DUPLEX_FULL; 269 else 270 phydev->duplex = DUPLEX_HALF; 271 272 if (ss & AT803X_SS_MDIX) 273 phydev->mdix = ETH_TP_MDI_X; 274 else 275 phydev->mdix = ETH_TP_MDI; 276 277 switch (FIELD_GET(AT803X_SFC_MDI_CROSSOVER_MODE_M, sfc)) { 278 case AT803X_SFC_MANUAL_MDI: 279 phydev->mdix_ctrl = ETH_TP_MDI; 280 break; 281 case AT803X_SFC_MANUAL_MDIX: 282 phydev->mdix_ctrl = ETH_TP_MDI_X; 283 break; 284 case AT803X_SFC_AUTOMATIC_CROSSOVER: 285 phydev->mdix_ctrl = ETH_TP_MDI_AUTO; 286 break; 287 } 288 } 289 290 return 0; 291 } 292 EXPORT_SYMBOL_GPL(at803x_read_specific_status); 293 294 int at803x_config_mdix(struct phy_device *phydev, u8 ctrl) 295 { 296 u16 val; 297 298 switch (ctrl) { 299 case ETH_TP_MDI: 300 val = AT803X_SFC_MANUAL_MDI; 301 break; 302 case ETH_TP_MDI_X: 303 val = AT803X_SFC_MANUAL_MDIX; 304 break; 305 case ETH_TP_MDI_AUTO: 306 val = AT803X_SFC_AUTOMATIC_CROSSOVER; 307 break; 308 default: 309 return 0; 310 } 311 312 return phy_modify_changed(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL, 313 AT803X_SFC_MDI_CROSSOVER_MODE_M, 314 FIELD_PREP(AT803X_SFC_MDI_CROSSOVER_MODE_M, val)); 315 } 316 EXPORT_SYMBOL_GPL(at803x_config_mdix); 317 318 int at803x_prepare_config_aneg(struct phy_device *phydev) 319 { 320 int ret; 321 322 ret = at803x_config_mdix(phydev, phydev->mdix_ctrl); 323 if (ret < 0) 324 return ret; 325 326 /* Changes of the midx bits are disruptive to the normal operation; 327 * therefore any changes to these registers must be followed by a 328 * software reset to take effect. 329 */ 330 if (ret == 1) { 331 ret = genphy_soft_reset(phydev); 332 if (ret < 0) 333 return ret; 334 } 335 336 return 0; 337 } 338 EXPORT_SYMBOL_GPL(at803x_prepare_config_aneg); 339 340 int at803x_read_status(struct phy_device *phydev) 341 { 342 struct at803x_ss_mask ss_mask = { 0 }; 343 int err, old_link = phydev->link; 344 345 /* Update the link, but return if there was an error */ 346 err = genphy_update_link(phydev); 347 if (err) 348 return err; 349 350 /* why bother the PHY if nothing can have changed */ 351 if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) 352 return 0; 353 354 phydev->speed = SPEED_UNKNOWN; 355 phydev->duplex = DUPLEX_UNKNOWN; 356 phydev->pause = 0; 357 phydev->asym_pause = 0; 358 359 err = genphy_read_lpa(phydev); 360 if (err < 0) 361 return err; 362 363 ss_mask.speed_mask = AT803X_SS_SPEED_MASK; 364 ss_mask.speed_shift = __bf_shf(AT803X_SS_SPEED_MASK); 365 err = at803x_read_specific_status(phydev, ss_mask); 366 if (err < 0) 367 return err; 368 369 if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) 370 phy_resolve_aneg_pause(phydev); 371 372 return 0; 373 } 374 EXPORT_SYMBOL_GPL(at803x_read_status); 375 376 static int at803x_get_downshift(struct phy_device *phydev, u8 *d) 377 { 378 int val; 379 380 val = phy_read(phydev, AT803X_SMART_SPEED); 381 if (val < 0) 382 return val; 383 384 if (val & AT803X_SMART_SPEED_ENABLE) 385 *d = FIELD_GET(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, val) + 2; 386 else 387 *d = DOWNSHIFT_DEV_DISABLE; 388 389 return 0; 390 } 391 392 static int at803x_set_downshift(struct phy_device *phydev, u8 cnt) 393 { 394 u16 mask, set; 395 int ret; 396 397 switch (cnt) { 398 case DOWNSHIFT_DEV_DEFAULT_COUNT: 399 cnt = AT803X_DEFAULT_DOWNSHIFT; 400 fallthrough; 401 case AT803X_MIN_DOWNSHIFT ... AT803X_MAX_DOWNSHIFT: 402 set = AT803X_SMART_SPEED_ENABLE | 403 AT803X_SMART_SPEED_BYPASS_TIMER | 404 FIELD_PREP(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, cnt - 2); 405 mask = AT803X_SMART_SPEED_RETRY_LIMIT_MASK; 406 break; 407 case DOWNSHIFT_DEV_DISABLE: 408 set = 0; 409 mask = AT803X_SMART_SPEED_ENABLE | 410 AT803X_SMART_SPEED_BYPASS_TIMER; 411 break; 412 default: 413 return -EINVAL; 414 } 415 416 ret = phy_modify_changed(phydev, AT803X_SMART_SPEED, mask, set); 417 418 /* After changing the smart speed settings, we need to perform a 419 * software reset, use phy_init_hw() to make sure we set the 420 * reapply any values which might got lost during software reset. 421 */ 422 if (ret == 1) 423 ret = phy_init_hw(phydev); 424 425 return ret; 426 } 427 428 int at803x_get_tunable(struct phy_device *phydev, 429 struct ethtool_tunable *tuna, void *data) 430 { 431 switch (tuna->id) { 432 case ETHTOOL_PHY_DOWNSHIFT: 433 return at803x_get_downshift(phydev, data); 434 default: 435 return -EOPNOTSUPP; 436 } 437 } 438 EXPORT_SYMBOL_GPL(at803x_get_tunable); 439 440 int at803x_set_tunable(struct phy_device *phydev, 441 struct ethtool_tunable *tuna, const void *data) 442 { 443 switch (tuna->id) { 444 case ETHTOOL_PHY_DOWNSHIFT: 445 return at803x_set_downshift(phydev, *(const u8 *)data); 446 default: 447 return -EOPNOTSUPP; 448 } 449 } 450 EXPORT_SYMBOL_GPL(at803x_set_tunable); 451 452 int at803x_cdt_fault_length(int dt) 453 { 454 /* According to the datasheet the distance to the fault is 455 * DELTA_TIME * 0.824 meters. 456 * 457 * The author suspect the correct formula is: 458 * 459 * fault_distance = DELTA_TIME * (c * VF) / 125MHz / 2 460 * 461 * where c is the speed of light, VF is the velocity factor of 462 * the twisted pair cable, 125MHz the counter frequency and 463 * we need to divide by 2 because the hardware will measure the 464 * round trip time to the fault and back to the PHY. 465 * 466 * With a VF of 0.69 we get the factor 0.824 mentioned in the 467 * datasheet. 468 */ 469 return (dt * 824) / 10; 470 } 471 EXPORT_SYMBOL_GPL(at803x_cdt_fault_length); 472 473 int at803x_cdt_start(struct phy_device *phydev, u32 cdt_start) 474 { 475 return phy_write(phydev, AT803X_CDT, cdt_start); 476 } 477 EXPORT_SYMBOL_GPL(at803x_cdt_start); 478 479 int at803x_cdt_wait_for_completion(struct phy_device *phydev, 480 u32 cdt_en) 481 { 482 int val, ret; 483 484 /* One test run takes about 25ms */ 485 ret = phy_read_poll_timeout(phydev, AT803X_CDT, val, 486 !(val & cdt_en), 487 30000, 100000, true); 488 489 return ret < 0 ? ret : 0; 490 } 491 EXPORT_SYMBOL_GPL(at803x_cdt_wait_for_completion); 492 493 static bool qca808x_cdt_fault_length_valid(int cdt_code) 494 { 495 switch (cdt_code) { 496 case QCA808X_CDT_STATUS_STAT_SAME_SHORT: 497 case QCA808X_CDT_STATUS_STAT_SAME_OPEN: 498 case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL: 499 case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN: 500 case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT: 501 case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL: 502 case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN: 503 case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT: 504 case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL: 505 case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN: 506 case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT: 507 return true; 508 default: 509 return false; 510 } 511 } 512 513 static int qca808x_cable_test_result_trans(int cdt_code) 514 { 515 switch (cdt_code) { 516 case QCA808X_CDT_STATUS_STAT_NORMAL: 517 return ETHTOOL_A_CABLE_RESULT_CODE_OK; 518 case QCA808X_CDT_STATUS_STAT_SAME_SHORT: 519 return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; 520 case QCA808X_CDT_STATUS_STAT_SAME_OPEN: 521 return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; 522 case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL: 523 case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN: 524 case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT: 525 case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL: 526 case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN: 527 case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT: 528 case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL: 529 case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN: 530 case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT: 531 return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT; 532 case QCA808X_CDT_STATUS_STAT_FAIL: 533 default: 534 return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; 535 } 536 } 537 538 static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair, 539 int result) 540 { 541 int val; 542 u32 cdt_length_reg = 0; 543 544 switch (pair) { 545 case ETHTOOL_A_CABLE_PAIR_A: 546 cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_A; 547 break; 548 case ETHTOOL_A_CABLE_PAIR_B: 549 cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_B; 550 break; 551 case ETHTOOL_A_CABLE_PAIR_C: 552 cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_C; 553 break; 554 case ETHTOOL_A_CABLE_PAIR_D: 555 cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_D; 556 break; 557 default: 558 return -EINVAL; 559 } 560 561 val = phy_read_mmd(phydev, MDIO_MMD_PCS, cdt_length_reg); 562 if (val < 0) 563 return val; 564 565 if (result == ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT) 566 val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_SAME_SHORT, val); 567 else 568 val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT, val); 569 570 return at803x_cdt_fault_length(val); 571 } 572 573 static int qca808x_cable_test_get_pair_status(struct phy_device *phydev, u8 pair, 574 u16 status) 575 { 576 int length, result; 577 u16 pair_code; 578 579 switch (pair) { 580 case ETHTOOL_A_CABLE_PAIR_A: 581 pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, status); 582 break; 583 case ETHTOOL_A_CABLE_PAIR_B: 584 pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, status); 585 break; 586 case ETHTOOL_A_CABLE_PAIR_C: 587 pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, status); 588 break; 589 case ETHTOOL_A_CABLE_PAIR_D: 590 pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, status); 591 break; 592 default: 593 return -EINVAL; 594 } 595 596 result = qca808x_cable_test_result_trans(pair_code); 597 ethnl_cable_test_result(phydev, pair, result); 598 599 if (qca808x_cdt_fault_length_valid(pair_code)) { 600 length = qca808x_cdt_fault_length(phydev, pair, result); 601 ethnl_cable_test_fault_length(phydev, pair, length); 602 } 603 604 return 0; 605 } 606 607 int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished) 608 { 609 int ret, val; 610 611 *finished = false; 612 613 val = QCA808X_CDT_ENABLE_TEST | 614 QCA808X_CDT_LENGTH_UNIT; 615 ret = at803x_cdt_start(phydev, val); 616 if (ret) 617 return ret; 618 619 ret = at803x_cdt_wait_for_completion(phydev, QCA808X_CDT_ENABLE_TEST); 620 if (ret) 621 return ret; 622 623 val = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA808X_MMD3_CDT_STATUS); 624 if (val < 0) 625 return val; 626 627 ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_A, val); 628 if (ret) 629 return ret; 630 631 ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_B, val); 632 if (ret) 633 return ret; 634 635 ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_C, val); 636 if (ret) 637 return ret; 638 639 ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_D, val); 640 if (ret) 641 return ret; 642 643 *finished = true; 644 645 return 0; 646 } 647 EXPORT_SYMBOL_GPL(qca808x_cable_test_get_status); 648 649 int qca808x_led_reg_hw_control_enable(struct phy_device *phydev, u16 reg) 650 { 651 return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg, 652 QCA808X_LED_FORCE_EN); 653 } 654 EXPORT_SYMBOL_GPL(qca808x_led_reg_hw_control_enable); 655 656 bool qca808x_led_reg_hw_control_status(struct phy_device *phydev, u16 reg) 657 { 658 int val; 659 660 val = phy_read_mmd(phydev, MDIO_MMD_AN, reg); 661 return !(val & QCA808X_LED_FORCE_EN); 662 } 663 EXPORT_SYMBOL_GPL(qca808x_led_reg_hw_control_status); 664 665 int qca808x_led_reg_brightness_set(struct phy_device *phydev, 666 u16 reg, enum led_brightness value) 667 { 668 return phy_modify_mmd(phydev, MDIO_MMD_AN, reg, 669 QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK, 670 QCA808X_LED_FORCE_EN | (value ? QCA808X_LED_FORCE_ON : 671 QCA808X_LED_FORCE_OFF)); 672 } 673 EXPORT_SYMBOL_GPL(qca808x_led_reg_brightness_set); 674 675 int qca808x_led_reg_blink_set(struct phy_device *phydev, u16 reg, 676 unsigned long *delay_on, 677 unsigned long *delay_off) 678 { 679 int ret; 680 681 /* Set blink to 50% off, 50% on at 4Hz by default */ 682 ret = phy_modify_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_LED_GLOBAL, 683 QCA808X_LED_BLINK_FREQ_MASK | QCA808X_LED_BLINK_DUTY_MASK, 684 QCA808X_LED_BLINK_FREQ_4HZ | QCA808X_LED_BLINK_DUTY_50_50); 685 if (ret) 686 return ret; 687 688 /* We use BLINK_1 for normal blinking */ 689 ret = phy_modify_mmd(phydev, MDIO_MMD_AN, reg, 690 QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK, 691 QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_BLINK_1); 692 if (ret) 693 return ret; 694 695 /* We set blink to 4Hz, aka 250ms */ 696 *delay_on = 250 / 2; 697 *delay_off = 250 / 2; 698 699 return 0; 700 } 701 EXPORT_SYMBOL_GPL(qca808x_led_reg_blink_set); 702 703 /* Enable CRC checking for both received and transmitted frames to ensure 704 * accurate counter recording. The hardware supports a 32-bit counter, 705 * configure the counter to clear after it is read to facilitate the 706 * implementation of a 64-bit software counter 707 */ 708 int qcom_phy_counter_config(struct phy_device *phydev) 709 { 710 return phy_set_bits_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_CNT_CTRL, 711 QCA808X_MMD7_CNT_CTRL_CRC_CHECK_EN | 712 QCA808X_MMD7_CNT_CTRL_READ_CLEAR_EN); 713 } 714 EXPORT_SYMBOL_GPL(qcom_phy_counter_config); 715 716 int qcom_phy_update_stats(struct phy_device *phydev, 717 struct qcom_phy_hw_stats *hw_stats) 718 { 719 int ret; 720 u32 cnt; 721 722 /* PHY 32-bit counter for RX packets. */ 723 ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_CNT_RX_PKT_15_0); 724 if (ret < 0) 725 return ret; 726 727 cnt = ret; 728 729 ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_CNT_RX_PKT_31_16); 730 if (ret < 0) 731 return ret; 732 733 cnt |= ret << 16; 734 hw_stats->rx_pkts += cnt; 735 736 /* PHY 16-bit counter for RX CRC error packets. */ 737 ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_CNT_RX_ERR_PKT); 738 if (ret < 0) 739 return ret; 740 741 hw_stats->rx_err_pkts += ret; 742 743 /* PHY 32-bit counter for TX packets. */ 744 ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_CNT_TX_PKT_15_0); 745 if (ret < 0) 746 return ret; 747 748 cnt = ret; 749 750 ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_CNT_TX_PKT_31_16); 751 if (ret < 0) 752 return ret; 753 754 cnt |= ret << 16; 755 hw_stats->tx_pkts += cnt; 756 757 /* PHY 16-bit counter for TX CRC error packets. */ 758 ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_CNT_TX_ERR_PKT); 759 if (ret < 0) 760 return ret; 761 762 hw_stats->tx_err_pkts += ret; 763 764 return 0; 765 } 766 EXPORT_SYMBOL_GPL(qcom_phy_update_stats); 767 768 void qcom_phy_get_stats(struct ethtool_phy_stats *stats, 769 struct qcom_phy_hw_stats hw_stats) 770 { 771 stats->tx_packets = hw_stats.tx_pkts; 772 stats->tx_errors = hw_stats.tx_err_pkts; 773 stats->rx_packets = hw_stats.rx_pkts; 774 stats->rx_errors = hw_stats.rx_err_pkts; 775 } 776 EXPORT_SYMBOL_GPL(qcom_phy_get_stats); 777