88#include <linux/phy.h>
99#include <linux/ethtool.h>
1010#include <linux/ethtool_netlink.h>
11+ #include <linux/bitfield.h>
1112
1213#define PHY_ID_LAN87XX 0x0007c150
14+ #define PHY_ID_LAN937X 0x0007c180
1315
1416/* External Register Control Register */
1517#define LAN87XX_EXT_REG_CTL (0x14)
1618#define LAN87XX_EXT_REG_CTL_RD_CTL (0x1000)
1719#define LAN87XX_EXT_REG_CTL_WR_CTL (0x0800)
20+ #define LAN87XX_REG_BANK_SEL_MASK GENMASK(10, 8)
21+ #define LAN87XX_REG_ADDR_MASK GENMASK(7, 0)
1822
1923/* External Register Read Data Register */
2024#define LAN87XX_EXT_REG_RD_DATA (0x15)
7680#define T1_PST_EQ_LCK_STG1_FRZ_CFG 0x6E
7781
7882#define DRIVER_AUTHOR "Nisar Sayed <
[email protected] >"
79- #define DRIVER_DESC "Microchip LAN87XX T1 PHY driver"
83+ #define DRIVER_DESC "Microchip LAN87XX/LAN937x T1 PHY driver"
8084
8185struct access_ereg_val {
8286 u8 mode ;
@@ -86,6 +90,37 @@ struct access_ereg_val {
8690 u16 mask ;
8791};
8892
93+ static int lan937x_dsp_workaround (struct phy_device * phydev , u16 ereg , u8 bank )
94+ {
95+ u8 prev_bank ;
96+ int rc = 0 ;
97+ u16 val ;
98+
99+ mutex_lock (& phydev -> lock );
100+ /* Read previous selected bank */
101+ rc = phy_read (phydev , LAN87XX_EXT_REG_CTL );
102+ if (rc < 0 )
103+ goto out_unlock ;
104+
105+ /* store the prev_bank */
106+ prev_bank = FIELD_GET (LAN87XX_REG_BANK_SEL_MASK , rc );
107+
108+ if (bank != prev_bank && bank == PHYACC_ATTR_BANK_DSP ) {
109+ val = ereg & ~LAN87XX_REG_ADDR_MASK ;
110+
111+ val &= ~LAN87XX_EXT_REG_CTL_WR_CTL ;
112+ val |= LAN87XX_EXT_REG_CTL_RD_CTL ;
113+
114+ /* access twice for DSP bank change,dummy access */
115+ rc = phy_write (phydev , LAN87XX_EXT_REG_CTL , val );
116+ }
117+
118+ out_unlock :
119+ mutex_unlock (& phydev -> lock );
120+
121+ return rc ;
122+ }
123+
89124static int access_ereg (struct phy_device * phydev , u8 mode , u8 bank ,
90125 u8 offset , u16 val )
91126{
@@ -114,6 +149,13 @@ static int access_ereg(struct phy_device *phydev, u8 mode, u8 bank,
114149
115150 ereg |= (bank << 8 ) | offset ;
116151
152+ /* DSP bank access workaround for lan937x */
153+ if (phydev -> phy_id == PHY_ID_LAN937X ) {
154+ rc = lan937x_dsp_workaround (phydev , ereg , bank );
155+ if (rc < 0 )
156+ return rc ;
157+ }
158+
117159 rc = phy_write (phydev , LAN87XX_EXT_REG_CTL , ereg );
118160 if (rc < 0 )
119161 return rc ;
@@ -642,13 +684,24 @@ static struct phy_driver microchip_t1_phy_driver[] = {
642684 .resume = genphy_resume ,
643685 .cable_test_start = lan87xx_cable_test_start ,
644686 .cable_test_get_status = lan87xx_cable_test_get_status ,
687+ },
688+ {
689+ PHY_ID_MATCH_MODEL (PHY_ID_LAN937X ),
690+ .name = "Microchip LAN937x T1" ,
691+ .features = PHY_BASIC_T1_FEATURES ,
692+ .config_init = lan87xx_config_init ,
693+ .suspend = genphy_suspend ,
694+ .resume = genphy_resume ,
695+ .cable_test_start = lan87xx_cable_test_start ,
696+ .cable_test_get_status = lan87xx_cable_test_get_status ,
645697 }
646698};
647699
648700module_phy_driver (microchip_t1_phy_driver );
649701
650702static struct mdio_device_id __maybe_unused microchip_t1_tbl [] = {
651703 { PHY_ID_MATCH_MODEL (PHY_ID_LAN87XX ) },
704+ { PHY_ID_MATCH_MODEL (PHY_ID_LAN937X ) },
652705 { }
653706};
654707
0 commit comments