Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: phy: Add mdi(x) support in Microsemi PHYs driver

To connect two ports of the same configuration (MDI to MDI or
MDI-X to MDI-X) with a 10/100/1000 Mbit/s connection, an
Ethernet crossover cable is needed to cross over the transmit
and receive signals in the cable, so that they are matched at
the connector level.
When connecting an MDI port to an MDI-X port a straight through
cable is used while to connect two MDI ports or two MDI-X ports
a crossover cable must be used. Conventionally MDI is used on end
devices while MDI-X is used on hubs and switches

Auto MDI-X automatically detects the required cable connection
type and configures the connection appropriately, removing the
need for crossover cables to interconnect switches or connecting
PCs peer-to-peer.

Signed-off-by: Raju Lakkaraju <Raju.Lakkaraju@microsemi.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Raju Lakkaraju and committed by
David S. Miller
233275ec 1004ee61

+97 -8
+97 -8
drivers/net/phy/mscc.c
··· 27 27 28 28 /* Microsemi VSC85xx PHY registers */ 29 29 /* IEEE 802. Std Registers */ 30 + #define MSCC_PHY_BYPASS_CONTROL 18 31 + #define DISABLE_HP_AUTO_MDIX_MASK 0x0080 32 + #define DISABLE_PAIR_SWAP_CORR_MASK 0x0020 33 + #define DISABLE_POLARITY_CORR_MASK 0x0010 34 + 30 35 #define MSCC_PHY_EXT_PHY_CNTL_1 23 31 36 #define MAC_IF_SELECTION_MASK 0x1800 32 37 #define MAC_IF_SELECTION_GMII 0 ··· 49 44 #define EDGE_RATE_CNTL_POS 5 50 45 #define EDGE_RATE_CNTL_MASK 0x00E0 51 46 47 + #define MSCC_PHY_DEV_AUX_CNTL 28 48 + #define HP_AUTO_MDIX_X_OVER_IND_MASK 0x2000 49 + 52 50 #define MSCC_EXT_PAGE_ACCESS 31 53 51 #define MSCC_PHY_PAGE_STANDARD 0x0000 /* Standard registers */ 54 52 #define MSCC_PHY_PAGE_EXTENDED 0x0001 /* Extended registers */ 55 53 #define MSCC_PHY_PAGE_EXTENDED_2 0x0002 /* Extended reg - page 2 */ 56 54 57 55 /* Extended Page 1 Registers */ 56 + #define MSCC_PHY_EXT_MODE_CNTL 19 57 + #define FORCE_MDI_CROSSOVER_MASK 0x000C 58 + #define FORCE_MDI_CROSSOVER_MDIX 0x000C 59 + #define FORCE_MDI_CROSSOVER_MDI 0x0008 60 + 58 61 #define MSCC_PHY_ACTIPHY_CNTL 20 59 62 #define DOWNSHIFT_CNTL_MASK 0x001C 60 63 #define DOWNSHIFT_EN 0x0010 ··· 121 108 122 109 rc = phy_write(phydev, MSCC_EXT_PAGE_ACCESS, page); 123 110 return rc; 111 + } 112 + 113 + static int vsc85xx_mdix_get(struct phy_device *phydev, u8 *mdix) 114 + { 115 + u16 reg_val; 116 + 117 + reg_val = phy_read(phydev, MSCC_PHY_DEV_AUX_CNTL); 118 + if (reg_val & HP_AUTO_MDIX_X_OVER_IND_MASK) 119 + *mdix = ETH_TP_MDI_X; 120 + else 121 + *mdix = ETH_TP_MDI; 122 + 123 + return 0; 124 + } 125 + 126 + static int vsc85xx_mdix_set(struct phy_device *phydev, u8 mdix) 127 + { 128 + int rc; 129 + u16 reg_val; 130 + 131 + reg_val = phy_read(phydev, MSCC_PHY_BYPASS_CONTROL); 132 + if ((mdix == ETH_TP_MDI) || (mdix == ETH_TP_MDI_X)) { 133 + reg_val |= (DISABLE_PAIR_SWAP_CORR_MASK | 134 + DISABLE_POLARITY_CORR_MASK | 135 + DISABLE_HP_AUTO_MDIX_MASK); 136 + } else { 137 + reg_val &= ~(DISABLE_PAIR_SWAP_CORR_MASK | 138 + DISABLE_POLARITY_CORR_MASK | 139 + DISABLE_HP_AUTO_MDIX_MASK); 140 + } 141 + rc = phy_write(phydev, MSCC_PHY_BYPASS_CONTROL, reg_val); 142 + if (rc != 0) 143 + return rc; 144 + 145 + rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED); 146 + if (rc != 0) 147 + return rc; 148 + 149 + reg_val = phy_read(phydev, MSCC_PHY_EXT_MODE_CNTL); 150 + reg_val &= ~(FORCE_MDI_CROSSOVER_MASK); 151 + if (mdix == ETH_TP_MDI) 152 + reg_val |= FORCE_MDI_CROSSOVER_MDI; 153 + else if (mdix == ETH_TP_MDI_X) 154 + reg_val |= FORCE_MDI_CROSSOVER_MDIX; 155 + rc = phy_write(phydev, MSCC_PHY_EXT_MODE_CNTL, reg_val); 156 + if (rc != 0) 157 + return rc; 158 + 159 + rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD); 160 + if (rc != 0) 161 + return rc; 162 + 163 + return genphy_restart_aneg(phydev); 124 164 } 125 165 126 166 static int vsc85xx_downshift_get(struct phy_device *phydev, u8 *count) ··· 441 375 int rc; 442 376 u16 reg_val; 443 377 378 + phydev->mdix_ctrl = ETH_TP_MDI_AUTO; 444 379 mutex_lock(&phydev->lock); 445 380 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2); 446 381 if (rc != 0) ··· 531 464 return rc; 532 465 } 533 466 467 + static int vsc85xx_config_aneg(struct phy_device *phydev) 468 + { 469 + int rc; 470 + 471 + rc = vsc85xx_mdix_set(phydev, phydev->mdix_ctrl); 472 + if (rc < 0) 473 + return rc; 474 + 475 + return genphy_config_aneg(phydev); 476 + } 477 + 478 + static int vsc85xx_read_status(struct phy_device *phydev) 479 + { 480 + int rc; 481 + 482 + rc = vsc85xx_mdix_get(phydev, &phydev->mdix); 483 + if (rc < 0) 484 + return rc; 485 + 486 + return genphy_read_status(phydev); 487 + } 488 + 534 489 static int vsc85xx_probe(struct phy_device *phydev) 535 490 { 536 491 int rate_magic; ··· 583 494 .flags = PHY_HAS_INTERRUPT, 584 495 .soft_reset = &genphy_soft_reset, 585 496 .config_init = &vsc85xx_config_init, 586 - .config_aneg = &genphy_config_aneg, 497 + .config_aneg = &vsc85xx_config_aneg, 587 498 .aneg_done = &genphy_aneg_done, 588 - .read_status = &genphy_read_status, 499 + .read_status = &vsc85xx_read_status, 589 500 .ack_interrupt = &vsc85xx_ack_interrupt, 590 501 .config_intr = &vsc85xx_config_intr, 591 502 .suspend = &genphy_suspend, ··· 604 515 .flags = PHY_HAS_INTERRUPT, 605 516 .soft_reset = &genphy_soft_reset, 606 517 .config_init = &vsc85xx_config_init, 607 - .config_aneg = &genphy_config_aneg, 518 + .config_aneg = &vsc85xx_config_aneg, 608 519 .aneg_done = &genphy_aneg_done, 609 - .read_status = &genphy_read_status, 520 + .read_status = &vsc85xx_read_status, 610 521 .ack_interrupt = &vsc85xx_ack_interrupt, 611 522 .config_intr = &vsc85xx_config_intr, 612 523 .suspend = &genphy_suspend, ··· 625 536 .flags = PHY_HAS_INTERRUPT, 626 537 .soft_reset = &genphy_soft_reset, 627 538 .config_init = &vsc85xx_config_init, 628 - .config_aneg = &genphy_config_aneg, 539 + .config_aneg = &vsc85xx_config_aneg, 629 540 .aneg_done = &genphy_aneg_done, 630 - .read_status = &genphy_read_status, 541 + .read_status = &vsc85xx_read_status, 631 542 .ack_interrupt = &vsc85xx_ack_interrupt, 632 543 .config_intr = &vsc85xx_config_intr, 633 544 .suspend = &genphy_suspend, ··· 646 557 .flags = PHY_HAS_INTERRUPT, 647 558 .soft_reset = &genphy_soft_reset, 648 559 .config_init = &vsc85xx_config_init, 649 - .config_aneg = &genphy_config_aneg, 560 + .config_aneg = &vsc85xx_config_aneg, 650 561 .aneg_done = &genphy_aneg_done, 651 - .read_status = &genphy_read_status, 562 + .read_status = &vsc85xx_read_status, 652 563 .ack_interrupt = &vsc85xx_ack_interrupt, 653 564 .config_intr = &vsc85xx_config_intr, 654 565 .suspend = &genphy_suspend,