Commit d06f78c4 authored by Florian Fainelli's avatar Florian Fainelli Committed by David S. Miller

net: phy: broadcom: Add support code for downshift/Wirespeed

Broadcom's Wirespeed feature allows us to configure how auto-negotiation
should behave with fewer working pairs of wires on a cable. Add support
code for retrieving and setting such downshift counters using the
recently added ethtool downshift tunables.
Signed-off-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5519da87
...@@ -225,6 +225,92 @@ int bcm_phy_enable_eee(struct phy_device *phydev) ...@@ -225,6 +225,92 @@ int bcm_phy_enable_eee(struct phy_device *phydev)
} }
EXPORT_SYMBOL_GPL(bcm_phy_enable_eee); EXPORT_SYMBOL_GPL(bcm_phy_enable_eee);
int bcm_phy_downshift_get(struct phy_device *phydev, u8 *count)
{
int val;
val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
if (val < 0)
return val;
/* Check if wirespeed is enabled or not */
if (!(val & MII_BCM54XX_AUXCTL_SHDWSEL_MISC_WIRESPEED_EN)) {
*count = DOWNSHIFT_DEV_DISABLE;
return 0;
}
val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR2);
if (val < 0)
return val;
/* Downgrade after one link attempt */
if (val & BCM54XX_SHD_SCR2_WSPD_RTRY_DIS) {
*count = 1;
} else {
/* Downgrade after configured retry count */
val >>= BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_SHIFT;
val &= BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_MASK;
*count = val + BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_OFFSET;
}
return 0;
}
EXPORT_SYMBOL_GPL(bcm_phy_downshift_get);
int bcm_phy_downshift_set(struct phy_device *phydev, u8 count)
{
int val = 0, ret = 0;
/* Range check the number given */
if (count - BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_OFFSET >
BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_MASK &&
count != DOWNSHIFT_DEV_DEFAULT_COUNT) {
return -ERANGE;
}
val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
if (val < 0)
return val;
/* Se the write enable bit */
val |= MII_BCM54XX_AUXCTL_MISC_WREN;
if (count == DOWNSHIFT_DEV_DISABLE) {
val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_WIRESPEED_EN;
return bcm54xx_auxctl_write(phydev,
MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
val);
} else {
val |= MII_BCM54XX_AUXCTL_SHDWSEL_MISC_WIRESPEED_EN;
ret = bcm54xx_auxctl_write(phydev,
MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
val);
if (ret < 0)
return ret;
}
val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR2);
val &= ~(BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_MASK <<
BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_SHIFT |
BCM54XX_SHD_SCR2_WSPD_RTRY_DIS);
switch (count) {
case 1:
val |= BCM54XX_SHD_SCR2_WSPD_RTRY_DIS;
break;
case DOWNSHIFT_DEV_DEFAULT_COUNT:
val |= 1 << BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_SHIFT;
break;
default:
val |= (count - BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_OFFSET) <<
BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_SHIFT;
break;
}
return bcm_phy_write_shadow(phydev, BCM54XX_SHD_SCR2, val);
}
EXPORT_SYMBOL_GPL(bcm_phy_downshift_set);
MODULE_DESCRIPTION("Broadcom PHY Library"); MODULE_DESCRIPTION("Broadcom PHY Library");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Broadcom Corporation"); MODULE_AUTHOR("Broadcom Corporation");
...@@ -37,4 +37,9 @@ int bcm_phy_config_intr(struct phy_device *phydev); ...@@ -37,4 +37,9 @@ int bcm_phy_config_intr(struct phy_device *phydev);
int bcm_phy_enable_apd(struct phy_device *phydev, bool dll_pwr_down); int bcm_phy_enable_apd(struct phy_device *phydev, bool dll_pwr_down);
int bcm_phy_enable_eee(struct phy_device *phydev); int bcm_phy_enable_eee(struct phy_device *phydev);
int bcm_phy_downshift_get(struct phy_device *phydev, u8 *count);
int bcm_phy_downshift_set(struct phy_device *phydev, u8 count);
#endif /* _LINUX_BCM_PHY_LIB_H */ #endif /* _LINUX_BCM_PHY_LIB_H */
...@@ -114,6 +114,7 @@ ...@@ -114,6 +114,7 @@
#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC 0x0007 #define MII_BCM54XX_AUXCTL_SHDWSEL_MISC 0x0007
#define MII_BCM54XX_AUXCTL_SHDWSEL_READ_SHIFT 12 #define MII_BCM54XX_AUXCTL_SHDWSEL_READ_SHIFT 12
#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN (1 << 8) #define MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN (1 << 8)
#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC_WIRESPEED_EN (1 << 4)
#define MII_BCM54XX_AUXCTL_SHDWSEL_MASK 0x0007 #define MII_BCM54XX_AUXCTL_SHDWSEL_MASK 0x0007
...@@ -130,6 +131,7 @@ ...@@ -130,6 +131,7 @@
#define BCM_LED_SRC_INTR 0x6 #define BCM_LED_SRC_INTR 0x6
#define BCM_LED_SRC_QUALITY 0x7 #define BCM_LED_SRC_QUALITY 0x7
#define BCM_LED_SRC_RCVLED 0x8 #define BCM_LED_SRC_RCVLED 0x8
#define BCM_LED_SRC_WIRESPEED 0x9
#define BCM_LED_SRC_MULTICOLOR1 0xa #define BCM_LED_SRC_MULTICOLOR1 0xa
#define BCM_LED_SRC_OPENSHORT 0xb #define BCM_LED_SRC_OPENSHORT 0xb
#define BCM_LED_SRC_OFF 0xe /* Tied high */ #define BCM_LED_SRC_OFF 0xe /* Tied high */
...@@ -141,6 +143,14 @@ ...@@ -141,6 +143,14 @@
* Shadow values go into bits [14:10] of register 0x1c to select a shadow * Shadow values go into bits [14:10] of register 0x1c to select a shadow
* register to access. * register to access.
*/ */
/* 00100: Reserved control register 2 */
#define BCM54XX_SHD_SCR2 0x04
#define BCM54XX_SHD_SCR2_WSPD_RTRY_DIS 0x100
#define BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_SHIFT 2
#define BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_OFFSET 2
#define BCM54XX_SHD_SCR2_WSPD_RTRY_LMT_MASK 0x7
/* 00101: Spare Control Register 3 */ /* 00101: Spare Control Register 3 */
#define BCM54XX_SHD_SCR3 0x05 #define BCM54XX_SHD_SCR3 0x05
#define BCM54XX_SHD_SCR3_DEF_CLK125 0x0001 #define BCM54XX_SHD_SCR3_DEF_CLK125 0x0001
......
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