Commit 310d9ad5 authored by Raju Lakkaraju's avatar Raju Lakkaraju Committed by David S. Miller

net: phy: Add downshift get/set support in Microsemi PHYs driver

Implements the phy tunable function pointers and implement downshift
functionality for MSCC PHYs.
Signed-off-by: default avatarRaju Lakkaraju <Raju.Lakkaraju@microsemi.com>
Reviewed-by: default avatarAndrew Lunn <andrew@lunn.ch>
Signed-off-by: default avatarAllan W. Nielsen <allan.nielsen@microsemi.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 65feddd5
...@@ -46,8 +46,15 @@ enum rgmii_rx_clock_delay { ...@@ -46,8 +46,15 @@ enum rgmii_rx_clock_delay {
#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_2 0x0002 /* Extended reg - page 2 */ #define MSCC_PHY_PAGE_EXTENDED_2 0x0002 /* Extended reg - page 2 */
/* Extended Page 1 Registers */
#define MSCC_PHY_ACTIPHY_CNTL 20
#define DOWNSHIFT_CNTL_MASK 0x001C
#define DOWNSHIFT_EN 0x0010
#define DOWNSHIFT_CNTL_POS 2
/* Extended Page 2 Registers */ /* Extended Page 2 Registers */
#define MSCC_PHY_RGMII_CNTL 20 #define MSCC_PHY_RGMII_CNTL 20
#define RGMII_RX_CLK_DELAY_MASK 0x0070 #define RGMII_RX_CLK_DELAY_MASK 0x0070
...@@ -75,6 +82,8 @@ enum rgmii_rx_clock_delay { ...@@ -75,6 +82,8 @@ enum rgmii_rx_clock_delay {
#define MSCC_VDDMAC_2500 2500 #define MSCC_VDDMAC_2500 2500
#define MSCC_VDDMAC_3300 3300 #define MSCC_VDDMAC_3300 3300
#define DOWNSHIFT_COUNT_MAX 5
struct vsc8531_private { struct vsc8531_private {
int rate_magic; int rate_magic;
}; };
...@@ -101,6 +110,66 @@ static int vsc85xx_phy_page_set(struct phy_device *phydev, u8 page) ...@@ -101,6 +110,66 @@ static int vsc85xx_phy_page_set(struct phy_device *phydev, u8 page)
return rc; return rc;
} }
static int vsc85xx_downshift_get(struct phy_device *phydev, u8 *count)
{
int rc;
u16 reg_val;
mutex_lock(&phydev->lock);
rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED);
if (rc != 0)
goto out_unlock;
reg_val = phy_read(phydev, MSCC_PHY_ACTIPHY_CNTL);
reg_val &= DOWNSHIFT_CNTL_MASK;
if (!(reg_val & DOWNSHIFT_EN))
*count = DOWNSHIFT_DEV_DISABLE;
else
*count = ((reg_val & ~DOWNSHIFT_EN) >> DOWNSHIFT_CNTL_POS) + 2;
rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
out_unlock:
mutex_unlock(&phydev->lock);
return rc;
}
static int vsc85xx_downshift_set(struct phy_device *phydev, u8 count)
{
int rc;
u16 reg_val;
if (count == DOWNSHIFT_DEV_DEFAULT_COUNT) {
/* Default downshift count 3 (i.e. Bit3:2 = 0b01) */
count = ((1 << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN);
} else if (count > DOWNSHIFT_COUNT_MAX || count == 1) {
phydev_err(phydev, "Downshift count should be 2,3,4 or 5\n");
return -ERANGE;
} else if (count) {
/* Downshift count is either 2,3,4 or 5 */
count = (((count - 2) << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN);
}
mutex_lock(&phydev->lock);
rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED);
if (rc != 0)
goto out_unlock;
reg_val = phy_read(phydev, MSCC_PHY_ACTIPHY_CNTL);
reg_val &= ~(DOWNSHIFT_CNTL_MASK);
reg_val |= count;
rc = phy_write(phydev, MSCC_PHY_ACTIPHY_CNTL, reg_val);
if (rc != 0)
goto out_unlock;
rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
out_unlock:
mutex_unlock(&phydev->lock);
return rc;
}
static int vsc85xx_wol_set(struct phy_device *phydev, static int vsc85xx_wol_set(struct phy_device *phydev,
struct ethtool_wolinfo *wol) struct ethtool_wolinfo *wol)
{ {
...@@ -329,6 +398,29 @@ static int vsc85xx_default_config(struct phy_device *phydev) ...@@ -329,6 +398,29 @@ static int vsc85xx_default_config(struct phy_device *phydev)
return rc; return rc;
} }
static int vsc85xx_get_tunable(struct phy_device *phydev,
struct ethtool_tunable *tuna, void *data)
{
switch (tuna->id) {
case ETHTOOL_PHY_DOWNSHIFT:
return vsc85xx_downshift_get(phydev, (u8 *)data);
default:
return -EINVAL;
}
}
static int vsc85xx_set_tunable(struct phy_device *phydev,
struct ethtool_tunable *tuna,
const void *data)
{
switch (tuna->id) {
case ETHTOOL_PHY_DOWNSHIFT:
return vsc85xx_downshift_set(phydev, *(u8 *)data);
default:
return -EINVAL;
}
}
static int vsc85xx_config_init(struct phy_device *phydev) static int vsc85xx_config_init(struct phy_device *phydev)
{ {
int rc; int rc;
...@@ -418,6 +510,8 @@ static struct phy_driver vsc85xx_driver[] = { ...@@ -418,6 +510,8 @@ static struct phy_driver vsc85xx_driver[] = {
.probe = &vsc85xx_probe, .probe = &vsc85xx_probe,
.set_wol = &vsc85xx_wol_set, .set_wol = &vsc85xx_wol_set,
.get_wol = &vsc85xx_wol_get, .get_wol = &vsc85xx_wol_get,
.get_tunable = &vsc85xx_get_tunable,
.set_tunable = &vsc85xx_set_tunable,
}, },
{ {
.phy_id = PHY_ID_VSC8531, .phy_id = PHY_ID_VSC8531,
...@@ -437,6 +531,8 @@ static struct phy_driver vsc85xx_driver[] = { ...@@ -437,6 +531,8 @@ static struct phy_driver vsc85xx_driver[] = {
.probe = &vsc85xx_probe, .probe = &vsc85xx_probe,
.set_wol = &vsc85xx_wol_set, .set_wol = &vsc85xx_wol_set,
.get_wol = &vsc85xx_wol_get, .get_wol = &vsc85xx_wol_get,
.get_tunable = &vsc85xx_get_tunable,
.set_tunable = &vsc85xx_set_tunable,
}, },
{ {
.phy_id = PHY_ID_VSC8540, .phy_id = PHY_ID_VSC8540,
...@@ -456,6 +552,8 @@ static struct phy_driver vsc85xx_driver[] = { ...@@ -456,6 +552,8 @@ static struct phy_driver vsc85xx_driver[] = {
.probe = &vsc85xx_probe, .probe = &vsc85xx_probe,
.set_wol = &vsc85xx_wol_set, .set_wol = &vsc85xx_wol_set,
.get_wol = &vsc85xx_wol_get, .get_wol = &vsc85xx_wol_get,
.get_tunable = &vsc85xx_get_tunable,
.set_tunable = &vsc85xx_set_tunable,
}, },
{ {
.phy_id = PHY_ID_VSC8541, .phy_id = PHY_ID_VSC8541,
...@@ -475,6 +573,8 @@ static struct phy_driver vsc85xx_driver[] = { ...@@ -475,6 +573,8 @@ static struct phy_driver vsc85xx_driver[] = {
.probe = &vsc85xx_probe, .probe = &vsc85xx_probe,
.set_wol = &vsc85xx_wol_set, .set_wol = &vsc85xx_wol_set,
.get_wol = &vsc85xx_wol_get, .get_wol = &vsc85xx_wol_get,
.get_tunable = &vsc85xx_get_tunable,
.set_tunable = &vsc85xx_set_tunable,
} }
}; };
......
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