mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
net: phy: microchip_t1: Adds support for lan887x phy
The LAN887x is a Single-Port Ethernet Physical Layer Transceiver compliant with the IEEE 802.3bw (100BASE-T1) and IEEE 802.3bp (1000BASE-T1) specifications. The device provides 100/1000 Mbit/s transmit and receive capability over a single Unshielded Twisted Pair (UTP) cable. It supports communication with an Ethernet MAC via standard RGMII/SGMII interfaces. LAN887x supports following features, - Events/Interrupts - LED/GPIO Operation - IEEE 1588 (PTP) - SQI - Sleep and Wakeup (TC10) - Cable Diagnostics First patch only supports 100Mbps and 1000Mbps force-mode. Reviewed-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: Divya Koppera <divya.koppera@microchip.com> Link: https://patch.msgid.link/20240821055906.27717-3-Divya.Koppera@microchip.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
d4c897675a
commit
0941c83282
@ -12,6 +12,7 @@
|
||||
|
||||
#define PHY_ID_LAN87XX 0x0007c150
|
||||
#define PHY_ID_LAN937X 0x0007c180
|
||||
#define PHY_ID_LAN887X 0x0007c1f0
|
||||
|
||||
/* External Register Control Register */
|
||||
#define LAN87XX_EXT_REG_CTL (0x14)
|
||||
@ -94,8 +95,101 @@
|
||||
/* SQI defines */
|
||||
#define LAN87XX_MAX_SQI 0x07
|
||||
|
||||
/* Chiptop registers */
|
||||
#define LAN887X_PMA_EXT_ABILITY_2 0x12
|
||||
#define LAN887X_PMA_EXT_ABILITY_2_1000T1 BIT(1)
|
||||
#define LAN887X_PMA_EXT_ABILITY_2_100T1 BIT(0)
|
||||
|
||||
/* DSP 100M registers */
|
||||
#define LAN887x_CDR_CONFIG1_100 0x0405
|
||||
#define LAN887x_LOCK1_EQLSR_CONFIG_100 0x0411
|
||||
#define LAN887x_SLV_HD_MUFAC_CONFIG_100 0x0417
|
||||
#define LAN887x_PLOCK_MUFAC_CONFIG_100 0x041c
|
||||
#define LAN887x_PROT_DISABLE_100 0x0425
|
||||
#define LAN887x_KF_LOOP_SAT_CONFIG_100 0x0454
|
||||
|
||||
/* DSP 1000M registers */
|
||||
#define LAN887X_LOCK1_EQLSR_CONFIG 0x0811
|
||||
#define LAN887X_LOCK3_EQLSR_CONFIG 0x0813
|
||||
#define LAN887X_PROT_DISABLE 0x0825
|
||||
#define LAN887X_FFE_GAIN6 0x0843
|
||||
#define LAN887X_FFE_GAIN7 0x0844
|
||||
#define LAN887X_FFE_GAIN8 0x0845
|
||||
#define LAN887X_FFE_GAIN9 0x0846
|
||||
#define LAN887X_ECHO_DELAY_CONFIG 0x08ec
|
||||
#define LAN887X_FFE_MAX_CONFIG 0x08ee
|
||||
|
||||
/* PCS 1000M registers */
|
||||
#define LAN887X_SCR_CONFIG_3 0x8043
|
||||
#define LAN887X_INFO_FLD_CONFIG_5 0x8048
|
||||
|
||||
/* T1 afe registers */
|
||||
#define LAN887X_ZQCAL_CONTROL_1 0x8080
|
||||
#define LAN887X_AFE_PORT_TESTBUS_CTRL2 0x8089
|
||||
#define LAN887X_AFE_PORT_TESTBUS_CTRL4 0x808b
|
||||
#define LAN887X_AFE_PORT_TESTBUS_CTRL6 0x808d
|
||||
#define LAN887X_TX_AMPLT_1000T1_REG 0x80b0
|
||||
#define LAN887X_INIT_COEFF_DFE1_100 0x0422
|
||||
|
||||
/* PMA registers */
|
||||
#define LAN887X_DSP_PMA_CONTROL 0x810e
|
||||
#define LAN887X_DSP_PMA_CONTROL_LNK_SYNC BIT(4)
|
||||
|
||||
/* PCS 100M registers */
|
||||
#define LAN887X_IDLE_ERR_TIMER_WIN 0x8204
|
||||
#define LAN887X_IDLE_ERR_CNT_THRESH 0x8213
|
||||
|
||||
/* Misc registers */
|
||||
#define LAN887X_REG_REG26 0x001a
|
||||
#define LAN887X_REG_REG26_HW_INIT_SEQ_EN BIT(8)
|
||||
|
||||
/* Mis registers */
|
||||
#define LAN887X_MIS_CFG_REG0 0xa00
|
||||
#define LAN887X_MIS_CFG_REG0_RCLKOUT_DIS BIT(5)
|
||||
#define LAN887X_MIS_CFG_REG0_MAC_MODE_SEL GENMASK(1, 0)
|
||||
|
||||
#define LAN887X_MAC_MODE_RGMII 0x01
|
||||
#define LAN887X_MAC_MODE_SGMII 0x03
|
||||
|
||||
#define LAN887X_MIS_DLL_CFG_REG0 0xa01
|
||||
#define LAN887X_MIS_DLL_CFG_REG1 0xa02
|
||||
|
||||
#define LAN887X_MIS_DLL_DELAY_EN BIT(15)
|
||||
#define LAN887X_MIS_DLL_EN BIT(0)
|
||||
#define LAN887X_MIS_DLL_CONF (LAN887X_MIS_DLL_DELAY_EN |\
|
||||
LAN887X_MIS_DLL_EN)
|
||||
|
||||
#define LAN887X_MIS_CFG_REG2 0xa03
|
||||
#define LAN887X_MIS_CFG_REG2_FE_LPBK_EN BIT(2)
|
||||
|
||||
#define LAN887X_MIS_PKT_STAT_REG0 0xa06
|
||||
#define LAN887X_MIS_PKT_STAT_REG1 0xa07
|
||||
#define LAN887X_MIS_PKT_STAT_REG3 0xa09
|
||||
#define LAN887X_MIS_PKT_STAT_REG4 0xa0a
|
||||
#define LAN887X_MIS_PKT_STAT_REG5 0xa0b
|
||||
#define LAN887X_MIS_PKT_STAT_REG6 0xa0c
|
||||
|
||||
/* Chiptop common registers */
|
||||
#define LAN887X_COMMON_LED3_LED2 0xc05
|
||||
#define LAN887X_COMMON_LED2_MODE_SEL_MASK GENMASK(4, 0)
|
||||
#define LAN887X_LED_LINK_ACT_ANY_SPEED 0x0
|
||||
|
||||
/* MX chip top registers */
|
||||
#define LAN887X_CHIP_SOFT_RST 0xf03f
|
||||
#define LAN887X_CHIP_SOFT_RST_RESET BIT(0)
|
||||
|
||||
#define LAN887X_SGMII_CTL 0xf01a
|
||||
#define LAN887X_SGMII_CTL_SGMII_MUX_EN BIT(0)
|
||||
|
||||
#define LAN887X_SGMII_PCS_CFG 0xf034
|
||||
#define LAN887X_SGMII_PCS_CFG_PCS_ENA BIT(9)
|
||||
|
||||
#define LAN887X_EFUSE_READ_DAT9 0xf209
|
||||
#define LAN887X_EFUSE_READ_DAT9_SGMII_DIS BIT(9)
|
||||
#define LAN887X_EFUSE_READ_DAT9_MAC_MODE GENMASK(1, 0)
|
||||
|
||||
#define DRIVER_AUTHOR "Nisar Sayed <nisar.sayed@microchip.com>"
|
||||
#define DRIVER_DESC "Microchip LAN87XX/LAN937x T1 PHY driver"
|
||||
#define DRIVER_DESC "Microchip LAN87XX/LAN937x/LAN887x T1 PHY driver"
|
||||
|
||||
struct access_ereg_val {
|
||||
u8 mode;
|
||||
@ -105,6 +199,32 @@ struct access_ereg_val {
|
||||
u16 mask;
|
||||
};
|
||||
|
||||
struct lan887x_hw_stat {
|
||||
const char *string;
|
||||
u8 mmd;
|
||||
u16 reg;
|
||||
u8 bits;
|
||||
};
|
||||
|
||||
static const struct lan887x_hw_stat lan887x_hw_stats[] = {
|
||||
{ "TX Good Count", MDIO_MMD_VEND1, LAN887X_MIS_PKT_STAT_REG0, 14},
|
||||
{ "RX Good Count", MDIO_MMD_VEND1, LAN887X_MIS_PKT_STAT_REG1, 14},
|
||||
{ "RX ERR Count detected by PCS", MDIO_MMD_VEND1, LAN887X_MIS_PKT_STAT_REG3, 16},
|
||||
{ "TX CRC ERR Count", MDIO_MMD_VEND1, LAN887X_MIS_PKT_STAT_REG4, 8},
|
||||
{ "RX CRC ERR Count", MDIO_MMD_VEND1, LAN887X_MIS_PKT_STAT_REG5, 8},
|
||||
{ "RX ERR Count for SGMII MII2GMII", MDIO_MMD_VEND1, LAN887X_MIS_PKT_STAT_REG6, 8},
|
||||
};
|
||||
|
||||
struct lan887x_regwr_map {
|
||||
u8 mmd;
|
||||
u16 reg;
|
||||
u16 val;
|
||||
};
|
||||
|
||||
struct lan887x_priv {
|
||||
u64 stats[ARRAY_SIZE(lan887x_hw_stats)];
|
||||
};
|
||||
|
||||
static int lan937x_dsp_workaround(struct phy_device *phydev, u16 ereg, u8 bank)
|
||||
{
|
||||
u8 prev_bank;
|
||||
@ -860,6 +980,446 @@ static int lan87xx_get_sqi_max(struct phy_device *phydev)
|
||||
return LAN87XX_MAX_SQI;
|
||||
}
|
||||
|
||||
static int lan887x_rgmii_init(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* SGMII mux disable */
|
||||
ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
|
||||
LAN887X_SGMII_CTL,
|
||||
LAN887X_SGMII_CTL_SGMII_MUX_EN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Select MAC_MODE as RGMII */
|
||||
ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, LAN887X_MIS_CFG_REG0,
|
||||
LAN887X_MIS_CFG_REG0_MAC_MODE_SEL,
|
||||
LAN887X_MAC_MODE_RGMII);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Disable PCS */
|
||||
ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
|
||||
LAN887X_SGMII_PCS_CFG,
|
||||
LAN887X_SGMII_PCS_CFG_PCS_ENA);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* LAN887x Errata: RGMII rx clock active in SGMII mode
|
||||
* Disabled it for SGMII mode
|
||||
* Re-enabling it for RGMII mode
|
||||
*/
|
||||
return phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
|
||||
LAN887X_MIS_CFG_REG0,
|
||||
LAN887X_MIS_CFG_REG0_RCLKOUT_DIS);
|
||||
}
|
||||
|
||||
static int lan887x_sgmii_init(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* SGMII mux enable */
|
||||
ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
|
||||
LAN887X_SGMII_CTL,
|
||||
LAN887X_SGMII_CTL_SGMII_MUX_EN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Select MAC_MODE as SGMII */
|
||||
ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, LAN887X_MIS_CFG_REG0,
|
||||
LAN887X_MIS_CFG_REG0_MAC_MODE_SEL,
|
||||
LAN887X_MAC_MODE_SGMII);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* LAN887x Errata: RGMII rx clock active in SGMII mode.
|
||||
* So disabling it for SGMII mode
|
||||
*/
|
||||
ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, LAN887X_MIS_CFG_REG0,
|
||||
LAN887X_MIS_CFG_REG0_RCLKOUT_DIS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Enable PCS */
|
||||
return phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, LAN887X_SGMII_PCS_CFG,
|
||||
LAN887X_SGMII_PCS_CFG_PCS_ENA);
|
||||
}
|
||||
|
||||
static int lan887x_config_rgmii_en(struct phy_device *phydev)
|
||||
{
|
||||
int txc;
|
||||
int rxc;
|
||||
int ret;
|
||||
|
||||
ret = lan887x_rgmii_init(phydev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Control bit to enable/disable TX DLL delay line in signal path */
|
||||
txc = phy_read_mmd(phydev, MDIO_MMD_VEND1, LAN887X_MIS_DLL_CFG_REG0);
|
||||
if (txc < 0)
|
||||
return txc;
|
||||
|
||||
/* Control bit to enable/disable RX DLL delay line in signal path */
|
||||
rxc = phy_read_mmd(phydev, MDIO_MMD_VEND1, LAN887X_MIS_DLL_CFG_REG1);
|
||||
if (rxc < 0)
|
||||
return rxc;
|
||||
|
||||
/* Configures the phy to enable RX/TX delay
|
||||
* RGMII - TX & RX delays are either added by MAC or not needed,
|
||||
* phy should not add
|
||||
* RGMII_ID - Configures phy to enable TX & RX delays, MAC shouldn't add
|
||||
* RGMII_RX_ID - Configures the PHY to enable the RX delay.
|
||||
* The MAC shouldn't add the RX delay
|
||||
* RGMII_TX_ID - Configures the PHY to enable the TX delay.
|
||||
* The MAC shouldn't add the TX delay in this case
|
||||
*/
|
||||
switch (phydev->interface) {
|
||||
case PHY_INTERFACE_MODE_RGMII:
|
||||
txc &= ~LAN887X_MIS_DLL_CONF;
|
||||
rxc &= ~LAN887X_MIS_DLL_CONF;
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_RGMII_ID:
|
||||
txc |= LAN887X_MIS_DLL_CONF;
|
||||
rxc |= LAN887X_MIS_DLL_CONF;
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_RGMII_RXID:
|
||||
txc &= ~LAN887X_MIS_DLL_CONF;
|
||||
rxc |= LAN887X_MIS_DLL_CONF;
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_RGMII_TXID:
|
||||
txc |= LAN887X_MIS_DLL_CONF;
|
||||
rxc &= ~LAN887X_MIS_DLL_CONF;
|
||||
break;
|
||||
default:
|
||||
WARN_ONCE(1, "Invalid phydev interface %d\n", phydev->interface);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Configures the PHY to enable/disable RX delay in signal path */
|
||||
ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, LAN887X_MIS_DLL_CFG_REG1,
|
||||
LAN887X_MIS_DLL_CONF, rxc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configures the PHY to enable/disable the TX delay in signal path */
|
||||
return phy_modify_mmd(phydev, MDIO_MMD_VEND1, LAN887X_MIS_DLL_CFG_REG0,
|
||||
LAN887X_MIS_DLL_CONF, txc);
|
||||
}
|
||||
|
||||
static int lan887x_config_phy_interface(struct phy_device *phydev)
|
||||
{
|
||||
int interface_mode;
|
||||
int sgmii_dis;
|
||||
int ret;
|
||||
|
||||
/* Read sku efuse data for interfaces supported by sku */
|
||||
ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, LAN887X_EFUSE_READ_DAT9);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* If interface_mode is 1 then efuse sets RGMII operations.
|
||||
* If interface mode is 3 then efuse sets SGMII operations.
|
||||
*/
|
||||
interface_mode = ret & LAN887X_EFUSE_READ_DAT9_MAC_MODE;
|
||||
/* SGMII disable is set for RGMII operations */
|
||||
sgmii_dis = ret & LAN887X_EFUSE_READ_DAT9_SGMII_DIS;
|
||||
|
||||
switch (phydev->interface) {
|
||||
case PHY_INTERFACE_MODE_RGMII:
|
||||
case PHY_INTERFACE_MODE_RGMII_ID:
|
||||
case PHY_INTERFACE_MODE_RGMII_RXID:
|
||||
case PHY_INTERFACE_MODE_RGMII_TXID:
|
||||
/* Reject RGMII settings for SGMII only sku */
|
||||
ret = -EOPNOTSUPP;
|
||||
|
||||
if (!((interface_mode & LAN887X_MAC_MODE_SGMII) ==
|
||||
LAN887X_MAC_MODE_SGMII))
|
||||
ret = lan887x_config_rgmii_en(phydev);
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_SGMII:
|
||||
/* Reject SGMII setting for RGMII only sku */
|
||||
ret = -EOPNOTSUPP;
|
||||
|
||||
if (!sgmii_dis)
|
||||
ret = lan887x_sgmii_init(phydev);
|
||||
break;
|
||||
default:
|
||||
/* Reject setting for unsupported interfaces */
|
||||
ret = -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lan887x_get_features(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = genphy_c45_pma_read_abilities(phydev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Enable twisted pair */
|
||||
linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, phydev->supported);
|
||||
|
||||
/* First patch only supports 100Mbps and 1000Mbps force-mode.
|
||||
* T1 Auto-Negotiation (Clause 98 of IEEE 802.3) will be added later.
|
||||
*/
|
||||
linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lan887x_phy_init(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Clear loopback */
|
||||
ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
|
||||
LAN887X_MIS_CFG_REG2,
|
||||
LAN887X_MIS_CFG_REG2_FE_LPBK_EN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure default behavior of led to link and activity for any
|
||||
* speed
|
||||
*/
|
||||
ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1,
|
||||
LAN887X_COMMON_LED3_LED2,
|
||||
LAN887X_COMMON_LED2_MODE_SEL_MASK,
|
||||
LAN887X_LED_LINK_ACT_ANY_SPEED);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* PHY interface setup */
|
||||
return lan887x_config_phy_interface(phydev);
|
||||
}
|
||||
|
||||
static int lan887x_phy_config(struct phy_device *phydev,
|
||||
const struct lan887x_regwr_map *reg_map, int cnt)
|
||||
{
|
||||
int ret;
|
||||
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
ret = phy_write_mmd(phydev, reg_map[i].mmd,
|
||||
reg_map[i].reg, reg_map[i].val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lan887x_phy_setup(struct phy_device *phydev)
|
||||
{
|
||||
static const struct lan887x_regwr_map phy_cfg[] = {
|
||||
/* PORT_AFE writes */
|
||||
{MDIO_MMD_PMAPMD, LAN887X_ZQCAL_CONTROL_1, 0x4008},
|
||||
{MDIO_MMD_PMAPMD, LAN887X_AFE_PORT_TESTBUS_CTRL2, 0x0000},
|
||||
{MDIO_MMD_PMAPMD, LAN887X_AFE_PORT_TESTBUS_CTRL6, 0x0040},
|
||||
/* 100T1_PCS_VENDOR writes */
|
||||
{MDIO_MMD_PCS, LAN887X_IDLE_ERR_CNT_THRESH, 0x0008},
|
||||
{MDIO_MMD_PCS, LAN887X_IDLE_ERR_TIMER_WIN, 0x800d},
|
||||
/* 100T1 DSP writes */
|
||||
{MDIO_MMD_VEND1, LAN887x_CDR_CONFIG1_100, 0x0ab1},
|
||||
{MDIO_MMD_VEND1, LAN887x_LOCK1_EQLSR_CONFIG_100, 0x5274},
|
||||
{MDIO_MMD_VEND1, LAN887x_SLV_HD_MUFAC_CONFIG_100, 0x0d74},
|
||||
{MDIO_MMD_VEND1, LAN887x_PLOCK_MUFAC_CONFIG_100, 0x0aea},
|
||||
{MDIO_MMD_VEND1, LAN887x_PROT_DISABLE_100, 0x0360},
|
||||
{MDIO_MMD_VEND1, LAN887x_KF_LOOP_SAT_CONFIG_100, 0x0c30},
|
||||
/* 1000T1 DSP writes */
|
||||
{MDIO_MMD_VEND1, LAN887X_LOCK1_EQLSR_CONFIG, 0x2a78},
|
||||
{MDIO_MMD_VEND1, LAN887X_LOCK3_EQLSR_CONFIG, 0x1368},
|
||||
{MDIO_MMD_VEND1, LAN887X_PROT_DISABLE, 0x1354},
|
||||
{MDIO_MMD_VEND1, LAN887X_FFE_GAIN6, 0x3C84},
|
||||
{MDIO_MMD_VEND1, LAN887X_FFE_GAIN7, 0x3ca5},
|
||||
{MDIO_MMD_VEND1, LAN887X_FFE_GAIN8, 0x3ca5},
|
||||
{MDIO_MMD_VEND1, LAN887X_FFE_GAIN9, 0x3ca5},
|
||||
{MDIO_MMD_VEND1, LAN887X_ECHO_DELAY_CONFIG, 0x0024},
|
||||
{MDIO_MMD_VEND1, LAN887X_FFE_MAX_CONFIG, 0x227f},
|
||||
/* 1000T1 PCS writes */
|
||||
{MDIO_MMD_PCS, LAN887X_SCR_CONFIG_3, 0x1e00},
|
||||
{MDIO_MMD_PCS, LAN887X_INFO_FLD_CONFIG_5, 0x0fa1},
|
||||
};
|
||||
|
||||
return lan887x_phy_config(phydev, phy_cfg, ARRAY_SIZE(phy_cfg));
|
||||
}
|
||||
|
||||
static int lan887x_100M_setup(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* (Re)configure the speed/mode dependent T1 settings */
|
||||
if (phydev->master_slave_set == MASTER_SLAVE_CFG_MASTER_FORCE ||
|
||||
phydev->master_slave_set == MASTER_SLAVE_CFG_MASTER_PREFERRED){
|
||||
static const struct lan887x_regwr_map phy_cfg[] = {
|
||||
{MDIO_MMD_PMAPMD, LAN887X_AFE_PORT_TESTBUS_CTRL4, 0x00b8},
|
||||
{MDIO_MMD_PMAPMD, LAN887X_TX_AMPLT_1000T1_REG, 0x0038},
|
||||
{MDIO_MMD_VEND1, LAN887X_INIT_COEFF_DFE1_100, 0x000f},
|
||||
};
|
||||
|
||||
ret = lan887x_phy_config(phydev, phy_cfg, ARRAY_SIZE(phy_cfg));
|
||||
} else {
|
||||
static const struct lan887x_regwr_map phy_cfg[] = {
|
||||
{MDIO_MMD_PMAPMD, LAN887X_AFE_PORT_TESTBUS_CTRL4, 0x0038},
|
||||
{MDIO_MMD_VEND1, LAN887X_INIT_COEFF_DFE1_100, 0x0014},
|
||||
};
|
||||
|
||||
ret = lan887x_phy_config(phydev, phy_cfg, ARRAY_SIZE(phy_cfg));
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, LAN887X_REG_REG26,
|
||||
LAN887X_REG_REG26_HW_INIT_SEQ_EN);
|
||||
}
|
||||
|
||||
static int lan887x_1000M_setup(struct phy_device *phydev)
|
||||
{
|
||||
static const struct lan887x_regwr_map phy_cfg[] = {
|
||||
{MDIO_MMD_PMAPMD, LAN887X_TX_AMPLT_1000T1_REG, 0x003f},
|
||||
{MDIO_MMD_PMAPMD, LAN887X_AFE_PORT_TESTBUS_CTRL4, 0x00b8},
|
||||
};
|
||||
int ret;
|
||||
|
||||
/* (Re)configure the speed/mode dependent T1 settings */
|
||||
ret = lan887x_phy_config(phydev, phy_cfg, ARRAY_SIZE(phy_cfg));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return phy_set_bits_mmd(phydev, MDIO_MMD_PMAPMD, LAN887X_DSP_PMA_CONTROL,
|
||||
LAN887X_DSP_PMA_CONTROL_LNK_SYNC);
|
||||
}
|
||||
|
||||
static int lan887x_link_setup(struct phy_device *phydev)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (phydev->speed == SPEED_1000)
|
||||
ret = lan887x_1000M_setup(phydev);
|
||||
else if (phydev->speed == SPEED_100)
|
||||
ret = lan887x_100M_setup(phydev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* LAN887x Errata: speed configuration changes require soft reset
|
||||
* and chip soft reset
|
||||
*/
|
||||
static int lan887x_phy_reset(struct phy_device *phydev)
|
||||
{
|
||||
int ret, val;
|
||||
|
||||
/* Clear 1000M link sync */
|
||||
ret = phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, LAN887X_DSP_PMA_CONTROL,
|
||||
LAN887X_DSP_PMA_CONTROL_LNK_SYNC);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Clear 100M link sync */
|
||||
ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, LAN887X_REG_REG26,
|
||||
LAN887X_REG_REG26_HW_INIT_SEQ_EN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Chiptop soft-reset to allow the speed/mode change */
|
||||
ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, LAN887X_CHIP_SOFT_RST,
|
||||
LAN887X_CHIP_SOFT_RST_RESET);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* CL22 soft-reset to let the link re-train */
|
||||
ret = phy_modify(phydev, MII_BMCR, BMCR_RESET, BMCR_RESET);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Wait for reset complete or timeout if > 10ms */
|
||||
return phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET),
|
||||
5000, 10000, true);
|
||||
}
|
||||
|
||||
static int lan887x_phy_reconfig(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
linkmode_zero(phydev->advertising);
|
||||
|
||||
ret = genphy_c45_pma_setup_forced(phydev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return lan887x_link_setup(phydev);
|
||||
}
|
||||
|
||||
static int lan887x_config_aneg(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* LAN887x Errata: speed configuration changes require soft reset
|
||||
* and chip soft reset
|
||||
*/
|
||||
ret = lan887x_phy_reset(phydev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return lan887x_phy_reconfig(phydev);
|
||||
}
|
||||
|
||||
static int lan887x_probe(struct phy_device *phydev)
|
||||
{
|
||||
struct lan887x_priv *priv;
|
||||
|
||||
priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
phydev->priv = priv;
|
||||
|
||||
return lan887x_phy_setup(phydev);
|
||||
}
|
||||
|
||||
static u64 lan887x_get_stat(struct phy_device *phydev, int i)
|
||||
{
|
||||
struct lan887x_hw_stat stat = lan887x_hw_stats[i];
|
||||
struct lan887x_priv *priv = phydev->priv;
|
||||
int val;
|
||||
u64 ret;
|
||||
|
||||
if (stat.mmd)
|
||||
val = phy_read_mmd(phydev, stat.mmd, stat.reg);
|
||||
else
|
||||
val = phy_read(phydev, stat.reg);
|
||||
|
||||
if (val < 0) {
|
||||
ret = U64_MAX;
|
||||
} else {
|
||||
val = val & ((1 << stat.bits) - 1);
|
||||
priv->stats[i] += val;
|
||||
ret = priv->stats[i];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void lan887x_get_stats(struct phy_device *phydev,
|
||||
struct ethtool_stats *stats, u64 *data)
|
||||
{
|
||||
for (int i = 0; i < ARRAY_SIZE(lan887x_hw_stats); i++)
|
||||
data[i] = lan887x_get_stat(phydev, i);
|
||||
}
|
||||
|
||||
static int lan887x_get_sset_count(struct phy_device *phydev)
|
||||
{
|
||||
return ARRAY_SIZE(lan887x_hw_stats);
|
||||
}
|
||||
|
||||
static void lan887x_get_strings(struct phy_device *phydev, u8 *data)
|
||||
{
|
||||
for (int i = 0; i < ARRAY_SIZE(lan887x_hw_stats); i++)
|
||||
ethtool_puts(&data, lan887x_hw_stats[i].string);
|
||||
}
|
||||
|
||||
static struct phy_driver microchip_t1_phy_driver[] = {
|
||||
{
|
||||
PHY_ID_MATCH_MODEL(PHY_ID_LAN87XX),
|
||||
@ -894,6 +1454,20 @@ static struct phy_driver microchip_t1_phy_driver[] = {
|
||||
.get_sqi_max = lan87xx_get_sqi_max,
|
||||
.cable_test_start = lan87xx_cable_test_start,
|
||||
.cable_test_get_status = lan87xx_cable_test_get_status,
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_MODEL(PHY_ID_LAN887X),
|
||||
.name = "Microchip LAN887x T1 PHY",
|
||||
.probe = lan887x_probe,
|
||||
.get_features = lan887x_get_features,
|
||||
.config_init = lan887x_phy_init,
|
||||
.config_aneg = lan887x_config_aneg,
|
||||
.get_stats = lan887x_get_stats,
|
||||
.get_sset_count = lan887x_get_sset_count,
|
||||
.get_strings = lan887x_get_strings,
|
||||
.suspend = genphy_suspend,
|
||||
.resume = genphy_resume,
|
||||
.read_status = genphy_c45_read_status,
|
||||
}
|
||||
};
|
||||
|
||||
@ -902,6 +1476,7 @@ module_phy_driver(microchip_t1_phy_driver);
|
||||
static struct mdio_device_id __maybe_unused microchip_t1_tbl[] = {
|
||||
{ PHY_ID_MATCH_MODEL(PHY_ID_LAN87XX) },
|
||||
{ PHY_ID_MATCH_MODEL(PHY_ID_LAN937X) },
|
||||
{ PHY_ID_MATCH_MODEL(PHY_ID_LAN887X) },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user