Commit 88578468 authored by David S. Miller's avatar David S. Miller

Merge branch 'mdix_ctrl'

Raju Lakkaraju says:

====================
Adding PHY MDI(X) support

I updated all review comments which were given by Andrew and Florian.

This series add support for PHY MDI(X), and implement it for MSCC phys.

Tested on Beaglebone Black with VSC 8531 PHY.

Change set:
v1:
- Initial patch submit the WoL and MDI-X in single set of patches

v2:
- Split the mdi(x) as signal set of patches.
- Remove the out_unlock as suggested by Andrew.
- Add mdix_ctrl parameter in "phy_device" to handle the user configure
  mdi(x). Proposed implementation accepted by Florian.
- phydev->mdix_ctrl initialize with ETH_TP_MDI_AUTO. Ethernet controller
  never initialize this parameter.
- Fix the mdix changes in marvell and microchip driver.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 8f679ed8 4e26c5c3
...@@ -268,7 +268,7 @@ static int marvell_config_aneg(struct phy_device *phydev) ...@@ -268,7 +268,7 @@ static int marvell_config_aneg(struct phy_device *phydev)
if (err < 0) if (err < 0)
return err; return err;
err = marvell_set_polarity(phydev, phydev->mdix); err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
if (err < 0) if (err < 0)
return err; return err;
...@@ -311,7 +311,7 @@ static int m88e1111_config_aneg(struct phy_device *phydev) ...@@ -311,7 +311,7 @@ static int m88e1111_config_aneg(struct phy_device *phydev)
*/ */
err = phy_write(phydev, MII_BMCR, BMCR_RESET); err = phy_write(phydev, MII_BMCR, BMCR_RESET);
err = marvell_set_polarity(phydev, phydev->mdix); err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
if (err < 0) if (err < 0)
return err; return err;
......
...@@ -111,7 +111,7 @@ static void lan88xx_set_mdix(struct phy_device *phydev) ...@@ -111,7 +111,7 @@ static void lan88xx_set_mdix(struct phy_device *phydev)
int buf; int buf;
int val; int val;
switch (phydev->mdix) { switch (phydev->mdix_ctrl) {
case ETH_TP_MDI: case ETH_TP_MDI:
val = LAN88XX_EXT_MODE_CTRL_MDI_; val = LAN88XX_EXT_MODE_CTRL_MDI_;
break; break;
......
...@@ -27,6 +27,11 @@ enum rgmii_rx_clock_delay { ...@@ -27,6 +27,11 @@ enum rgmii_rx_clock_delay {
/* Microsemi VSC85xx PHY registers */ /* Microsemi VSC85xx PHY registers */
/* IEEE 802. Std Registers */ /* IEEE 802. Std Registers */
#define MSCC_PHY_BYPASS_CONTROL 18
#define DISABLE_HP_AUTO_MDIX_MASK 0x0080
#define DISABLE_PAIR_SWAP_CORR_MASK 0x0020
#define DISABLE_POLARITY_CORR_MASK 0x0010
#define MSCC_PHY_EXT_PHY_CNTL_1 23 #define MSCC_PHY_EXT_PHY_CNTL_1 23
#define MAC_IF_SELECTION_MASK 0x1800 #define MAC_IF_SELECTION_MASK 0x1800
#define MAC_IF_SELECTION_GMII 0 #define MAC_IF_SELECTION_GMII 0
...@@ -44,12 +49,20 @@ enum rgmii_rx_clock_delay { ...@@ -44,12 +49,20 @@ enum rgmii_rx_clock_delay {
#define EDGE_RATE_CNTL_POS 5 #define EDGE_RATE_CNTL_POS 5
#define EDGE_RATE_CNTL_MASK 0x00E0 #define EDGE_RATE_CNTL_MASK 0x00E0
#define MSCC_PHY_DEV_AUX_CNTL 28
#define HP_AUTO_MDIX_X_OVER_IND_MASK 0x2000
#define MSCC_EXT_PAGE_ACCESS 31 #define MSCC_EXT_PAGE_ACCESS 31
#define MSCC_PHY_PAGE_STANDARD 0x0000 /* Standard registers */ #define MSCC_PHY_PAGE_STANDARD 0x0000 /* Standard registers */
#define MSCC_PHY_PAGE_EXTENDED 0x0001 /* Extended registers */ #define MSCC_PHY_PAGE_EXTENDED 0x0001 /* Extended registers */
#define MSCC_PHY_PAGE_EXTENDED_2 0x0002 /* Extended reg - page 2 */ #define MSCC_PHY_PAGE_EXTENDED_2 0x0002 /* Extended reg - page 2 */
/* Extended Page 1 Registers */ /* Extended Page 1 Registers */
#define MSCC_PHY_EXT_MODE_CNTL 19
#define FORCE_MDI_CROSSOVER_MASK 0x000C
#define FORCE_MDI_CROSSOVER_MDIX 0x000C
#define FORCE_MDI_CROSSOVER_MDI 0x0008
#define MSCC_PHY_ACTIPHY_CNTL 20 #define MSCC_PHY_ACTIPHY_CNTL 20
#define DOWNSHIFT_CNTL_MASK 0x001C #define DOWNSHIFT_CNTL_MASK 0x001C
#define DOWNSHIFT_EN 0x0010 #define DOWNSHIFT_EN 0x0010
...@@ -110,6 +123,59 @@ static int vsc85xx_phy_page_set(struct phy_device *phydev, u8 page) ...@@ -110,6 +123,59 @@ static int vsc85xx_phy_page_set(struct phy_device *phydev, u8 page)
return rc; return rc;
} }
static int vsc85xx_mdix_get(struct phy_device *phydev, u8 *mdix)
{
u16 reg_val;
reg_val = phy_read(phydev, MSCC_PHY_DEV_AUX_CNTL);
if (reg_val & HP_AUTO_MDIX_X_OVER_IND_MASK)
*mdix = ETH_TP_MDI_X;
else
*mdix = ETH_TP_MDI;
return 0;
}
static int vsc85xx_mdix_set(struct phy_device *phydev, u8 mdix)
{
int rc;
u16 reg_val;
reg_val = phy_read(phydev, MSCC_PHY_BYPASS_CONTROL);
if ((mdix == ETH_TP_MDI) || (mdix == ETH_TP_MDI_X)) {
reg_val |= (DISABLE_PAIR_SWAP_CORR_MASK |
DISABLE_POLARITY_CORR_MASK |
DISABLE_HP_AUTO_MDIX_MASK);
} else {
reg_val &= ~(DISABLE_PAIR_SWAP_CORR_MASK |
DISABLE_POLARITY_CORR_MASK |
DISABLE_HP_AUTO_MDIX_MASK);
}
rc = phy_write(phydev, MSCC_PHY_BYPASS_CONTROL, reg_val);
if (rc != 0)
return rc;
rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED);
if (rc != 0)
return rc;
reg_val = phy_read(phydev, MSCC_PHY_EXT_MODE_CNTL);
reg_val &= ~(FORCE_MDI_CROSSOVER_MASK);
if (mdix == ETH_TP_MDI)
reg_val |= FORCE_MDI_CROSSOVER_MDI;
else if (mdix == ETH_TP_MDI_X)
reg_val |= FORCE_MDI_CROSSOVER_MDIX;
rc = phy_write(phydev, MSCC_PHY_EXT_MODE_CNTL, reg_val);
if (rc != 0)
return rc;
rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
if (rc != 0)
return rc;
return genphy_restart_aneg(phydev);
}
static int vsc85xx_downshift_get(struct phy_device *phydev, u8 *count) static int vsc85xx_downshift_get(struct phy_device *phydev, u8 *count)
{ {
int rc; int rc;
...@@ -375,6 +441,7 @@ static int vsc85xx_default_config(struct phy_device *phydev) ...@@ -375,6 +441,7 @@ static int vsc85xx_default_config(struct phy_device *phydev)
int rc; int rc;
u16 reg_val; u16 reg_val;
phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
mutex_lock(&phydev->lock); mutex_lock(&phydev->lock);
rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2); rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
if (rc != 0) if (rc != 0)
...@@ -464,6 +531,28 @@ static int vsc85xx_config_intr(struct phy_device *phydev) ...@@ -464,6 +531,28 @@ static int vsc85xx_config_intr(struct phy_device *phydev)
return rc; return rc;
} }
static int vsc85xx_config_aneg(struct phy_device *phydev)
{
int rc;
rc = vsc85xx_mdix_set(phydev, phydev->mdix_ctrl);
if (rc < 0)
return rc;
return genphy_config_aneg(phydev);
}
static int vsc85xx_read_status(struct phy_device *phydev)
{
int rc;
rc = vsc85xx_mdix_get(phydev, &phydev->mdix);
if (rc < 0)
return rc;
return genphy_read_status(phydev);
}
static int vsc85xx_probe(struct phy_device *phydev) static int vsc85xx_probe(struct phy_device *phydev)
{ {
int rate_magic; int rate_magic;
...@@ -494,9 +583,9 @@ static struct phy_driver vsc85xx_driver[] = { ...@@ -494,9 +583,9 @@ static struct phy_driver vsc85xx_driver[] = {
.flags = PHY_HAS_INTERRUPT, .flags = PHY_HAS_INTERRUPT,
.soft_reset = &genphy_soft_reset, .soft_reset = &genphy_soft_reset,
.config_init = &vsc85xx_config_init, .config_init = &vsc85xx_config_init,
.config_aneg = &genphy_config_aneg, .config_aneg = &vsc85xx_config_aneg,
.aneg_done = &genphy_aneg_done, .aneg_done = &genphy_aneg_done,
.read_status = &genphy_read_status, .read_status = &vsc85xx_read_status,
.ack_interrupt = &vsc85xx_ack_interrupt, .ack_interrupt = &vsc85xx_ack_interrupt,
.config_intr = &vsc85xx_config_intr, .config_intr = &vsc85xx_config_intr,
.suspend = &genphy_suspend, .suspend = &genphy_suspend,
...@@ -515,9 +604,9 @@ static struct phy_driver vsc85xx_driver[] = { ...@@ -515,9 +604,9 @@ static struct phy_driver vsc85xx_driver[] = {
.flags = PHY_HAS_INTERRUPT, .flags = PHY_HAS_INTERRUPT,
.soft_reset = &genphy_soft_reset, .soft_reset = &genphy_soft_reset,
.config_init = &vsc85xx_config_init, .config_init = &vsc85xx_config_init,
.config_aneg = &genphy_config_aneg, .config_aneg = &vsc85xx_config_aneg,
.aneg_done = &genphy_aneg_done, .aneg_done = &genphy_aneg_done,
.read_status = &genphy_read_status, .read_status = &vsc85xx_read_status,
.ack_interrupt = &vsc85xx_ack_interrupt, .ack_interrupt = &vsc85xx_ack_interrupt,
.config_intr = &vsc85xx_config_intr, .config_intr = &vsc85xx_config_intr,
.suspend = &genphy_suspend, .suspend = &genphy_suspend,
...@@ -536,9 +625,9 @@ static struct phy_driver vsc85xx_driver[] = { ...@@ -536,9 +625,9 @@ static struct phy_driver vsc85xx_driver[] = {
.flags = PHY_HAS_INTERRUPT, .flags = PHY_HAS_INTERRUPT,
.soft_reset = &genphy_soft_reset, .soft_reset = &genphy_soft_reset,
.config_init = &vsc85xx_config_init, .config_init = &vsc85xx_config_init,
.config_aneg = &genphy_config_aneg, .config_aneg = &vsc85xx_config_aneg,
.aneg_done = &genphy_aneg_done, .aneg_done = &genphy_aneg_done,
.read_status = &genphy_read_status, .read_status = &vsc85xx_read_status,
.ack_interrupt = &vsc85xx_ack_interrupt, .ack_interrupt = &vsc85xx_ack_interrupt,
.config_intr = &vsc85xx_config_intr, .config_intr = &vsc85xx_config_intr,
.suspend = &genphy_suspend, .suspend = &genphy_suspend,
...@@ -557,9 +646,9 @@ static struct phy_driver vsc85xx_driver[] = { ...@@ -557,9 +646,9 @@ static struct phy_driver vsc85xx_driver[] = {
.flags = PHY_HAS_INTERRUPT, .flags = PHY_HAS_INTERRUPT,
.soft_reset = &genphy_soft_reset, .soft_reset = &genphy_soft_reset,
.config_init = &vsc85xx_config_init, .config_init = &vsc85xx_config_init,
.config_aneg = &genphy_config_aneg, .config_aneg = &vsc85xx_config_aneg,
.aneg_done = &genphy_aneg_done, .aneg_done = &genphy_aneg_done,
.read_status = &genphy_read_status, .read_status = &vsc85xx_read_status,
.ack_interrupt = &vsc85xx_ack_interrupt, .ack_interrupt = &vsc85xx_ack_interrupt,
.config_intr = &vsc85xx_config_intr, .config_intr = &vsc85xx_config_intr,
.suspend = &genphy_suspend, .suspend = &genphy_suspend,
......
...@@ -389,7 +389,7 @@ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) ...@@ -389,7 +389,7 @@ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd)
phydev->duplex = cmd->duplex; phydev->duplex = cmd->duplex;
phydev->mdix = cmd->eth_tp_mdix_ctrl; phydev->mdix_ctrl = cmd->eth_tp_mdix_ctrl;
/* Restart the PHY */ /* Restart the PHY */
phy_start_aneg(phydev); phy_start_aneg(phydev);
...@@ -443,7 +443,7 @@ int phy_ethtool_ksettings_set(struct phy_device *phydev, ...@@ -443,7 +443,7 @@ int phy_ethtool_ksettings_set(struct phy_device *phydev,
phydev->duplex = duplex; phydev->duplex = duplex;
phydev->mdix = cmd->base.eth_tp_mdix_ctrl; phydev->mdix_ctrl = cmd->base.eth_tp_mdix_ctrl;
/* Restart the PHY */ /* Restart the PHY */
phy_start_aneg(phydev); phy_start_aneg(phydev);
...@@ -469,7 +469,8 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) ...@@ -469,7 +469,8 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd)
cmd->transceiver = phy_is_internal(phydev) ? cmd->transceiver = phy_is_internal(phydev) ?
XCVR_INTERNAL : XCVR_EXTERNAL; XCVR_INTERNAL : XCVR_EXTERNAL;
cmd->autoneg = phydev->autoneg; cmd->autoneg = phydev->autoneg;
cmd->eth_tp_mdix_ctrl = phydev->mdix; cmd->eth_tp_mdix_ctrl = phydev->mdix_ctrl;
cmd->eth_tp_mdix = phydev->mdix;
return 0; return 0;
} }
...@@ -496,7 +497,8 @@ int phy_ethtool_ksettings_get(struct phy_device *phydev, ...@@ -496,7 +497,8 @@ int phy_ethtool_ksettings_get(struct phy_device *phydev,
cmd->base.phy_address = phydev->mdio.addr; cmd->base.phy_address = phydev->mdio.addr;
cmd->base.autoneg = phydev->autoneg; cmd->base.autoneg = phydev->autoneg;
cmd->base.eth_tp_mdix_ctrl = phydev->mdix; cmd->base.eth_tp_mdix_ctrl = phydev->mdix_ctrl;
cmd->base.eth_tp_mdix = phydev->mdix;
return 0; return 0;
} }
......
...@@ -450,6 +450,7 @@ struct phy_device { ...@@ -450,6 +450,7 @@ struct phy_device {
struct net_device *attached_dev; struct net_device *attached_dev;
u8 mdix; u8 mdix;
u8 mdix_ctrl;
void (*adjust_link)(struct net_device *dev); void (*adjust_link)(struct net_device *dev);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment