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

Merge branch 'lan937x-t1-phy-driver'

Arun Ramadoss says:

====================
Add support for LAN937x T1 Phy Driver

LAN937x is a Multi-port 100Base-T1 Switch and it internally uses LAN87xx
T1 Phy.  This series of patch update the initialization routine for the
LAN87xx phy and also add LAN937x part support. Added the T1 Phy
master-slave configuration through ethtool.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 828553d2 8a1b415d
...@@ -8,11 +8,17 @@ ...@@ -8,11 +8,17 @@
#include <linux/phy.h> #include <linux/phy.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/ethtool_netlink.h> #include <linux/ethtool_netlink.h>
#include <linux/bitfield.h>
#define PHY_ID_LAN87XX 0x0007c150
#define PHY_ID_LAN937X 0x0007c180
/* External Register Control Register */ /* External Register Control Register */
#define LAN87XX_EXT_REG_CTL (0x14) #define LAN87XX_EXT_REG_CTL (0x14)
#define LAN87XX_EXT_REG_CTL_RD_CTL (0x1000) #define LAN87XX_EXT_REG_CTL_RD_CTL (0x1000)
#define LAN87XX_EXT_REG_CTL_WR_CTL (0x0800) #define LAN87XX_EXT_REG_CTL_WR_CTL (0x0800)
#define LAN87XX_REG_BANK_SEL_MASK GENMASK(10, 8)
#define LAN87XX_REG_ADDR_MASK GENMASK(7, 0)
/* External Register Read Data Register */ /* External Register Read Data Register */
#define LAN87XX_EXT_REG_RD_DATA (0x15) #define LAN87XX_EXT_REG_RD_DATA (0x15)
...@@ -37,6 +43,7 @@ ...@@ -37,6 +43,7 @@
#define PHYACC_ATTR_MODE_READ 0 #define PHYACC_ATTR_MODE_READ 0
#define PHYACC_ATTR_MODE_WRITE 1 #define PHYACC_ATTR_MODE_WRITE 1
#define PHYACC_ATTR_MODE_MODIFY 2 #define PHYACC_ATTR_MODE_MODIFY 2
#define PHYACC_ATTR_MODE_POLL 3
#define PHYACC_ATTR_BANK_SMI 0 #define PHYACC_ATTR_BANK_SMI 0
#define PHYACC_ATTR_BANK_MISC 1 #define PHYACC_ATTR_BANK_MISC 1
...@@ -50,8 +57,33 @@ ...@@ -50,8 +57,33 @@
#define LAN87XX_CABLE_TEST_OPEN 1 #define LAN87XX_CABLE_TEST_OPEN 1
#define LAN87XX_CABLE_TEST_SAME_SHORT 2 #define LAN87XX_CABLE_TEST_SAME_SHORT 2
/* T1 Registers */
#define T1_AFE_PORT_CFG1_REG 0x0B
#define T1_POWER_DOWN_CONTROL_REG 0x1A
#define T1_SLV_FD_MULT_CFG_REG 0x18
#define T1_CDR_CFG_PRE_LOCK_REG 0x05
#define T1_CDR_CFG_POST_LOCK_REG 0x06
#define T1_LCK_STG2_MUFACT_CFG_REG 0x1A
#define T1_LCK_STG3_MUFACT_CFG_REG 0x1B
#define T1_POST_LCK_MUFACT_CFG_REG 0x1C
#define T1_TX_RX_FIFO_CFG_REG 0x02
#define T1_TX_LPF_FIR_CFG_REG 0x55
#define T1_SQI_CONFIG_REG 0x2E
#define T1_MDIO_CONTROL2_REG 0x10
#define T1_INTERRUPT_SOURCE_REG 0x18
#define T1_INTERRUPT2_SOURCE_REG 0x08
#define T1_EQ_FD_STG1_FRZ_CFG 0x69
#define T1_EQ_FD_STG2_FRZ_CFG 0x6A
#define T1_EQ_FD_STG3_FRZ_CFG 0x6B
#define T1_EQ_FD_STG4_FRZ_CFG 0x6C
#define T1_EQ_WT_FD_LCK_FRZ_CFG 0x6D
#define T1_PST_EQ_LCK_STG1_FRZ_CFG 0x6E
#define T1_MODE_STAT_REG 0x11
#define T1_LINK_UP_MSK BIT(0)
#define DRIVER_AUTHOR "Nisar Sayed <nisar.sayed@microchip.com>" #define DRIVER_AUTHOR "Nisar Sayed <nisar.sayed@microchip.com>"
#define DRIVER_DESC "Microchip LAN87XX T1 PHY driver" #define DRIVER_DESC "Microchip LAN87XX/LAN937x T1 PHY driver"
struct access_ereg_val { struct access_ereg_val {
u8 mode; u8 mode;
...@@ -61,6 +93,37 @@ struct access_ereg_val { ...@@ -61,6 +93,37 @@ struct access_ereg_val {
u16 mask; u16 mask;
}; };
static int lan937x_dsp_workaround(struct phy_device *phydev, u16 ereg, u8 bank)
{
u8 prev_bank;
int rc = 0;
u16 val;
mutex_lock(&phydev->lock);
/* Read previous selected bank */
rc = phy_read(phydev, LAN87XX_EXT_REG_CTL);
if (rc < 0)
goto out_unlock;
/* store the prev_bank */
prev_bank = FIELD_GET(LAN87XX_REG_BANK_SEL_MASK, rc);
if (bank != prev_bank && bank == PHYACC_ATTR_BANK_DSP) {
val = ereg & ~LAN87XX_REG_ADDR_MASK;
val &= ~LAN87XX_EXT_REG_CTL_WR_CTL;
val |= LAN87XX_EXT_REG_CTL_RD_CTL;
/* access twice for DSP bank change,dummy access */
rc = phy_write(phydev, LAN87XX_EXT_REG_CTL, val);
}
out_unlock:
mutex_unlock(&phydev->lock);
return rc;
}
static int access_ereg(struct phy_device *phydev, u8 mode, u8 bank, static int access_ereg(struct phy_device *phydev, u8 mode, u8 bank,
u8 offset, u16 val) u8 offset, u16 val)
{ {
...@@ -89,6 +152,13 @@ static int access_ereg(struct phy_device *phydev, u8 mode, u8 bank, ...@@ -89,6 +152,13 @@ static int access_ereg(struct phy_device *phydev, u8 mode, u8 bank,
ereg |= (bank << 8) | offset; ereg |= (bank << 8) | offset;
/* DSP bank access workaround for lan937x */
if (phydev->phy_id == PHY_ID_LAN937X) {
rc = lan937x_dsp_workaround(phydev, ereg, bank);
if (rc < 0)
return rc;
}
rc = phy_write(phydev, LAN87XX_EXT_REG_CTL, ereg); rc = phy_write(phydev, LAN87XX_EXT_REG_CTL, ereg);
if (rc < 0) if (rc < 0)
return rc; return rc;
...@@ -117,6 +187,15 @@ static int access_ereg_modify_changed(struct phy_device *phydev, ...@@ -117,6 +187,15 @@ static int access_ereg_modify_changed(struct phy_device *phydev,
return rc; return rc;
} }
static int access_smi_poll_timeout(struct phy_device *phydev,
u8 offset, u16 mask, u16 clr)
{
int val;
return phy_read_poll_timeout(phydev, offset, val, (val & mask) == clr,
150, 30000, true);
}
static int lan87xx_config_rgmii_delay(struct phy_device *phydev) static int lan87xx_config_rgmii_delay(struct phy_device *phydev)
{ {
int rc; int rc;
...@@ -157,68 +236,159 @@ static int lan87xx_config_rgmii_delay(struct phy_device *phydev) ...@@ -157,68 +236,159 @@ static int lan87xx_config_rgmii_delay(struct phy_device *phydev)
static int lan87xx_phy_init(struct phy_device *phydev) static int lan87xx_phy_init(struct phy_device *phydev)
{ {
static const struct access_ereg_val init[] = { static const struct access_ereg_val init[] = {
/* TX Amplitude = 5 */ /* TXPD/TXAMP6 Configs */
{PHYACC_ATTR_MODE_MODIFY, PHYACC_ATTR_BANK_AFE, 0x0B, { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_AFE,
0x000A, 0x001E}, T1_AFE_PORT_CFG1_REG, 0x002D, 0 },
/* Clear SMI interrupts */ /* HW_Init Hi and Force_ED */
{PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_SMI, 0x18, { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_SMI,
0, 0}, T1_POWER_DOWN_CONTROL_REG, 0x0308, 0 },
/* Clear MISC interrupts */ /* Equalizer Full Duplex Freeze - T1 Slave */
{PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_MISC, 0x08, { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0, 0}, T1_EQ_FD_STG1_FRZ_CFG, 0x0002, 0 },
/* Turn on TC10 Ring Oscillator (ROSC) */ { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
{PHYACC_ATTR_MODE_MODIFY, PHYACC_ATTR_BANK_MISC, 0x20, T1_EQ_FD_STG2_FRZ_CFG, 0x0002, 0 },
0x0020, 0x0020}, { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
/* WUR Detect Length to 1.2uS, LPC Detect Length to 1.09uS */ T1_EQ_FD_STG3_FRZ_CFG, 0x0002, 0 },
{PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_PCS, 0x20, { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
0x283C, 0}, T1_EQ_FD_STG4_FRZ_CFG, 0x0002, 0 },
/* Wake_In Debounce Length to 39uS, Wake_Out Length to 79uS */ { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
{PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_MISC, 0x21, T1_EQ_WT_FD_LCK_FRZ_CFG, 0x0002, 0 },
0x274F, 0}, { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
/* Enable Auto Wake Forward to Wake_Out, ROSC on, Sleep, T1_PST_EQ_LCK_STG1_FRZ_CFG, 0x0002, 0 },
* and Wake_In to wake PHY /* Slave Full Duplex Multi Configs */
*/ { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
{PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_MISC, 0x20, T1_SLV_FD_MULT_CFG_REG, 0x0D53, 0 },
0x80A7, 0}, /* CDR Pre and Post Lock Configs */
/* Enable WUP Auto Fwd, Enable Wake on MDI, Wakeup Debouncer { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
* to 128 uS T1_CDR_CFG_PRE_LOCK_REG, 0x0AB2, 0 },
*/ { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
{PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_MISC, 0x24, T1_CDR_CFG_POST_LOCK_REG, 0x0AB3, 0 },
0xF110, 0}, /* Lock Stage 2-3 Multi Factor Config */
/* Enable HW Init */ { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
{PHYACC_ATTR_MODE_MODIFY, PHYACC_ATTR_BANK_SMI, 0x1A, T1_LCK_STG2_MUFACT_CFG_REG, 0x0AEA, 0 },
0x0100, 0x0100}, { PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_LCK_STG3_MUFACT_CFG_REG, 0x0AEB, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_POST_LCK_MUFACT_CFG_REG, 0x0AEB, 0 },
/* Pointer delay */
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_RX_FIFO_CFG_REG, 0x1C00, 0 },
/* Tx iir edits */
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x1000, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x1861, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x1061, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x1922, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x1122, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x1983, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x1183, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x1944, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x1144, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x18c5, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x10c5, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x1846, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x1046, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x1807, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x1007, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x1808, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x1008, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x1809, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x1009, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x180A, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x100A, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x180B, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x100B, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x180C, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x100C, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x180D, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x100D, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x180E, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x100E, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x180F, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x100F, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x1810, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x1010, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x1811, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x1011, 0 },
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_TX_LPF_FIR_CFG_REG, 0x1000, 0 },
/* SQI enable */
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_DSP,
T1_SQI_CONFIG_REG, 0x9572, 0 },
/* Flag LPS and WUR as idle errors */
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_SMI,
T1_MDIO_CONTROL2_REG, 0x0014, 0 },
/* HW_Init toggle, undo force ED, TXPD off */
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_SMI,
T1_POWER_DOWN_CONTROL_REG, 0x0200, 0 },
/* Reset PCS to trigger hardware initialization */
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_SMI,
T1_MDIO_CONTROL2_REG, 0x0094, 0 },
/* Poll till Hardware is initialized */
{ PHYACC_ATTR_MODE_POLL, PHYACC_ATTR_BANK_SMI,
T1_MDIO_CONTROL2_REG, 0x0080, 0 },
/* Tx AMP - 0x06 */
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_AFE,
T1_AFE_PORT_CFG1_REG, 0x000C, 0 },
/* Read INTERRUPT_SOURCE Register */
{ PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_SMI,
T1_INTERRUPT_SOURCE_REG, 0, 0 },
/* Read INTERRUPT_SOURCE Register */
{ PHYACC_ATTR_MODE_READ, PHYACC_ATTR_BANK_MISC,
T1_INTERRUPT2_SOURCE_REG, 0, 0 },
/* HW_Init Hi */
{ PHYACC_ATTR_MODE_WRITE, PHYACC_ATTR_BANK_SMI,
T1_POWER_DOWN_CONTROL_REG, 0x0300, 0 },
}; };
int rc, i; int rc, i;
/* Start manual initialization procedures in Managed Mode */ /* phy Soft reset */
rc = access_ereg_modify_changed(phydev, PHYACC_ATTR_BANK_SMI, rc = genphy_soft_reset(phydev);
0x1a, 0x0000, 0x0100);
if (rc < 0)
return rc;
/* Soft Reset the SMI block */
rc = access_ereg_modify_changed(phydev, PHYACC_ATTR_BANK_SMI,
0x00, 0x8000, 0x8000);
if (rc < 0)
return rc;
/* Check to see if the self-clearing bit is cleared */
usleep_range(1000, 2000);
rc = access_ereg(phydev, PHYACC_ATTR_MODE_READ,
PHYACC_ATTR_BANK_SMI, 0x00, 0);
if (rc < 0) if (rc < 0)
return rc; return rc;
if ((rc & 0x8000) != 0)
return -ETIMEDOUT;
/* PHY Initialization */ /* PHY Initialization */
for (i = 0; i < ARRAY_SIZE(init); i++) { for (i = 0; i < ARRAY_SIZE(init); i++) {
if (init[i].mode == PHYACC_ATTR_MODE_MODIFY) { if (init[i].mode == PHYACC_ATTR_MODE_POLL &&
rc = access_ereg_modify_changed(phydev, init[i].bank, init[i].bank == PHYACC_ATTR_BANK_SMI) {
init[i].offset, rc = access_smi_poll_timeout(phydev,
init[i].val, init[i].offset,
init[i].mask); init[i].val,
init[i].mask);
} else { } else {
rc = access_ereg(phydev, init[i].mode, init[i].bank, rc = access_ereg(phydev, init[i].mode, init[i].bank,
init[i].offset, init[i].val); init[i].offset, init[i].val);
...@@ -504,22 +674,114 @@ static int lan87xx_cable_test_get_status(struct phy_device *phydev, ...@@ -504,22 +674,114 @@ static int lan87xx_cable_test_get_status(struct phy_device *phydev,
return 0; return 0;
} }
static int lan87xx_read_master_slave(struct phy_device *phydev)
{
int rc = 0;
phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN;
phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN;
rc = phy_read(phydev, MII_CTRL1000);
if (rc < 0)
return rc;
if (rc & CTL1000_AS_MASTER)
phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE;
else
phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE;
rc = phy_read(phydev, MII_STAT1000);
if (rc < 0)
return rc;
if (rc & LPA_1000MSRES)
phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER;
else
phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE;
return rc;
}
static int lan87xx_read_status(struct phy_device *phydev)
{
int rc = 0;
rc = phy_read(phydev, T1_MODE_STAT_REG);
if (rc < 0)
return rc;
if (rc & T1_LINK_UP_MSK)
phydev->link = 1;
else
phydev->link = 0;
phydev->speed = SPEED_UNKNOWN;
phydev->duplex = DUPLEX_UNKNOWN;
phydev->pause = 0;
phydev->asym_pause = 0;
rc = lan87xx_read_master_slave(phydev);
if (rc < 0)
return rc;
rc = genphy_read_status_fixed(phydev);
if (rc < 0)
return rc;
return rc;
}
static int lan87xx_config_aneg(struct phy_device *phydev)
{
u16 ctl = 0;
int rc;
switch (phydev->master_slave_set) {
case MASTER_SLAVE_CFG_MASTER_FORCE:
ctl |= CTL1000_AS_MASTER;
break;
case MASTER_SLAVE_CFG_SLAVE_FORCE:
break;
case MASTER_SLAVE_CFG_UNKNOWN:
case MASTER_SLAVE_CFG_UNSUPPORTED:
return 0;
default:
phydev_warn(phydev, "Unsupported Master/Slave mode\n");
return -EOPNOTSUPP;
}
rc = phy_modify_changed(phydev, MII_CTRL1000, CTL1000_AS_MASTER, ctl);
if (rc == 1)
rc = genphy_soft_reset(phydev);
return rc;
}
static struct phy_driver microchip_t1_phy_driver[] = { static struct phy_driver microchip_t1_phy_driver[] = {
{ {
.phy_id = 0x0007c150, PHY_ID_MATCH_MODEL(PHY_ID_LAN87XX),
.phy_id_mask = 0xfffffff0,
.name = "Microchip LAN87xx T1", .name = "Microchip LAN87xx T1",
.flags = PHY_POLL_CABLE_TEST, .flags = PHY_POLL_CABLE_TEST,
.features = PHY_BASIC_T1_FEATURES, .features = PHY_BASIC_T1_FEATURES,
.config_init = lan87xx_config_init, .config_init = lan87xx_config_init,
.config_intr = lan87xx_phy_config_intr, .config_intr = lan87xx_phy_config_intr,
.handle_interrupt = lan87xx_handle_interrupt, .handle_interrupt = lan87xx_handle_interrupt,
.suspend = genphy_suspend, .suspend = genphy_suspend,
.resume = genphy_resume, .resume = genphy_resume,
.config_aneg = lan87xx_config_aneg,
.read_status = lan87xx_read_status,
.cable_test_start = lan87xx_cable_test_start,
.cable_test_get_status = lan87xx_cable_test_get_status,
},
{
PHY_ID_MATCH_MODEL(PHY_ID_LAN937X),
.name = "Microchip LAN937x T1",
.features = PHY_BASIC_T1_FEATURES,
.config_init = lan87xx_config_init,
.suspend = genphy_suspend,
.resume = genphy_resume,
.config_aneg = lan87xx_config_aneg,
.read_status = lan87xx_read_status,
.cable_test_start = lan87xx_cable_test_start, .cable_test_start = lan87xx_cable_test_start,
.cable_test_get_status = lan87xx_cable_test_get_status, .cable_test_get_status = lan87xx_cable_test_get_status,
} }
...@@ -528,7 +790,8 @@ static struct phy_driver microchip_t1_phy_driver[] = { ...@@ -528,7 +790,8 @@ static struct phy_driver microchip_t1_phy_driver[] = {
module_phy_driver(microchip_t1_phy_driver); module_phy_driver(microchip_t1_phy_driver);
static struct mdio_device_id __maybe_unused microchip_t1_tbl[] = { static struct mdio_device_id __maybe_unused microchip_t1_tbl[] = {
{ 0x0007c150, 0xfffffff0 }, { PHY_ID_MATCH_MODEL(PHY_ID_LAN87XX) },
{ PHY_ID_MATCH_MODEL(PHY_ID_LAN937X) },
{ } { }
}; };
......
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