5454#define MII_M1011_PHY_SCR 0x10
5555#define MII_M1011_PHY_SCR_DOWNSHIFT_EN BIT(11)
5656#define MII_M1011_PHY_SCR_DOWNSHIFT_SHIFT 12
57- #define MII_M1011_PHY_SRC_DOWNSHIFT_MASK 0x7800
57+ #define MII_M1011_PHY_SRC_DOWNSHIFT_MASK GENMASK(14, 12)
58+ #define MII_M1011_PHY_SCR_DOWNSHIFT_MAX 8
5859#define MII_M1011_PHY_SCR_MDI (0x0 << 5)
5960#define MII_M1011_PHY_SCR_MDI_X (0x1 << 5)
6061#define MII_M1011_PHY_SCR_AUTO_CROSS (0x3 << 5)
6162
63+ #define MII_M1011_PHY_SSR 0x11
64+ #define MII_M1011_PHY_SSR_DOWNSHIFT BIT(5)
65+
6266#define MII_M1111_PHY_LED_CONTROL 0x18
6367#define MII_M1111_PHY_LED_DIRECT 0x4100
6468#define MII_M1111_PHY_LED_COMBINE 0x411c
@@ -833,6 +837,79 @@ static int m88e1111_config_init(struct phy_device *phydev)
833837 return genphy_soft_reset (phydev );
834838}
835839
840+ static int m88e1111_get_downshift (struct phy_device * phydev , u8 * data )
841+ {
842+ int val , cnt , enable ;
843+
844+ val = phy_read (phydev , MII_M1011_PHY_SCR );
845+ if (val < 0 )
846+ return val ;
847+
848+ enable = FIELD_GET (MII_M1011_PHY_SCR_DOWNSHIFT_EN , val );
849+ cnt = FIELD_GET (MII_M1011_PHY_SRC_DOWNSHIFT_MASK , val ) + 1 ;
850+
851+ * data = enable ? cnt : DOWNSHIFT_DEV_DISABLE ;
852+
853+ return 0 ;
854+ }
855+
856+ static int m88e1111_set_downshift (struct phy_device * phydev , u8 cnt )
857+ {
858+ int val ;
859+
860+ if (cnt > MII_M1011_PHY_SCR_DOWNSHIFT_MAX )
861+ return - E2BIG ;
862+
863+ if (!cnt )
864+ return phy_clear_bits (phydev , MII_M1011_PHY_SCR ,
865+ MII_M1011_PHY_SCR_DOWNSHIFT_EN );
866+
867+ val = MII_M1011_PHY_SCR_DOWNSHIFT_EN ;
868+ val |= FIELD_PREP (MII_M1011_PHY_SRC_DOWNSHIFT_MASK , cnt - 1 );
869+
870+ return phy_modify (phydev , MII_M1011_PHY_SCR ,
871+ MII_M1011_PHY_SCR_DOWNSHIFT_EN |
872+ MII_M1011_PHY_SRC_DOWNSHIFT_MASK ,
873+ val );
874+ }
875+
876+ static int m88e1111_get_tunable (struct phy_device * phydev ,
877+ struct ethtool_tunable * tuna , void * data )
878+ {
879+ switch (tuna -> id ) {
880+ case ETHTOOL_PHY_DOWNSHIFT :
881+ return m88e1111_get_downshift (phydev , data );
882+ default :
883+ return - EOPNOTSUPP ;
884+ }
885+ }
886+
887+ static int m88e1111_set_tunable (struct phy_device * phydev ,
888+ struct ethtool_tunable * tuna , const void * data )
889+ {
890+ switch (tuna -> id ) {
891+ case ETHTOOL_PHY_DOWNSHIFT :
892+ return m88e1111_set_downshift (phydev , * (const u8 * )data );
893+ default :
894+ return - EOPNOTSUPP ;
895+ }
896+ }
897+
898+ static void m88e1111_link_change_notify (struct phy_device * phydev )
899+ {
900+ int status ;
901+
902+ if (phydev -> state != PHY_RUNNING )
903+ return ;
904+
905+ /* we may be on fiber page currently */
906+ status = phy_read_paged (phydev , MII_MARVELL_COPPER_PAGE ,
907+ MII_M1011_PHY_SSR );
908+
909+ if (status > 0 && status & MII_M1011_PHY_SSR_DOWNSHIFT )
910+ phydev_warn (phydev , "Downshift occurred! Cabling may be defective.\n" );
911+ }
912+
836913static int m88e1318_config_init (struct phy_device * phydev )
837914{
838915 if (phy_interrupt_is_valid (phydev )) {
@@ -1117,6 +1194,8 @@ static int m88e1540_get_tunable(struct phy_device *phydev,
11171194 switch (tuna -> id ) {
11181195 case ETHTOOL_PHY_FAST_LINK_DOWN :
11191196 return m88e1540_get_fld (phydev , data );
1197+ case ETHTOOL_PHY_DOWNSHIFT :
1198+ return m88e1111_get_downshift (phydev , data );
11201199 default :
11211200 return - EOPNOTSUPP ;
11221201 }
@@ -1128,6 +1207,8 @@ static int m88e1540_set_tunable(struct phy_device *phydev,
11281207 switch (tuna -> id ) {
11291208 case ETHTOOL_PHY_FAST_LINK_DOWN :
11301209 return m88e1540_set_fld (phydev , data );
1210+ case ETHTOOL_PHY_DOWNSHIFT :
1211+ return m88e1111_set_downshift (phydev , * (const u8 * )data );
11311212 default :
11321213 return - EOPNOTSUPP ;
11331214 }
@@ -2220,6 +2301,9 @@ static struct phy_driver marvell_drivers[] = {
22202301 .get_sset_count = marvell_get_sset_count ,
22212302 .get_strings = marvell_get_strings ,
22222303 .get_stats = marvell_get_stats ,
2304+ .get_tunable = m88e1111_get_tunable ,
2305+ .set_tunable = m88e1111_set_tunable ,
2306+ .link_change_notify = m88e1111_link_change_notify ,
22232307 },
22242308 {
22252309 .phy_id = MARVELL_PHY_ID_88E1318S ,
@@ -2359,6 +2443,7 @@ static struct phy_driver marvell_drivers[] = {
23592443 .get_stats = marvell_get_stats ,
23602444 .get_tunable = m88e1540_get_tunable ,
23612445 .set_tunable = m88e1540_set_tunable ,
2446+ .link_change_notify = m88e1111_link_change_notify ,
23622447 },
23632448 {
23642449 .phy_id = MARVELL_PHY_ID_88E1545 ,
@@ -2421,6 +2506,7 @@ static struct phy_driver marvell_drivers[] = {
24212506 .get_stats = marvell_get_stats ,
24222507 .get_tunable = m88e1540_get_tunable ,
24232508 .set_tunable = m88e1540_set_tunable ,
2509+ .link_change_notify = m88e1111_link_change_notify ,
24242510 },
24252511};
24262512
0 commit comments