@@ -77,6 +77,14 @@ static const int xpcs_sgmii_features[] = {
7777 __ETHTOOL_LINK_MODE_MASK_NBITS ,
7878};
7979
80+ static const int xpcs_1000basex_features [] = {
81+ ETHTOOL_LINK_MODE_Pause_BIT ,
82+ ETHTOOL_LINK_MODE_Asym_Pause_BIT ,
83+ ETHTOOL_LINK_MODE_Autoneg_BIT ,
84+ ETHTOOL_LINK_MODE_1000baseX_Full_BIT ,
85+ __ETHTOOL_LINK_MODE_MASK_NBITS ,
86+ };
87+
8088static const int xpcs_2500basex_features [] = {
8189 ETHTOOL_LINK_MODE_Pause_BIT ,
8290 ETHTOOL_LINK_MODE_Asym_Pause_BIT ,
@@ -102,6 +110,10 @@ static const phy_interface_t xpcs_sgmii_interfaces[] = {
102110 PHY_INTERFACE_MODE_SGMII ,
103111};
104112
113+ static const phy_interface_t xpcs_1000basex_interfaces [] = {
114+ PHY_INTERFACE_MODE_1000BASEX ,
115+ };
116+
105117static const phy_interface_t xpcs_2500basex_interfaces [] = {
106118 PHY_INTERFACE_MODE_2500BASEX ,
107119 PHY_INTERFACE_MODE_MAX ,
@@ -112,6 +124,7 @@ enum {
112124 DW_XPCS_10GKR ,
113125 DW_XPCS_XLGMII ,
114126 DW_XPCS_SGMII ,
127+ DW_XPCS_1000BASEX ,
115128 DW_XPCS_2500BASEX ,
116129 DW_XPCS_INTERFACE_MAX ,
117130};
@@ -189,6 +202,14 @@ int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val)
189202 return mdiobus_c45_write (bus , addr , dev , reg , val );
190203}
191204
205+ static int xpcs_modify_changed (struct dw_xpcs * xpcs , int dev , u32 reg ,
206+ u16 mask , u16 set )
207+ {
208+ u32 reg_addr = mdiobus_c45_addr (dev , reg );
209+
210+ return mdiodev_modify_changed (xpcs -> mdiodev , reg_addr , mask , set );
211+ }
212+
192213static int xpcs_read_vendor (struct dw_xpcs * xpcs , int dev , u32 reg )
193214{
194215 return xpcs_read (xpcs , dev , DW_VENDOR | reg );
@@ -237,6 +258,7 @@ static int xpcs_soft_reset(struct dw_xpcs *xpcs,
237258 break ;
238259 case DW_AN_C37_SGMII :
239260 case DW_2500BASEX :
261+ case DW_AN_C37_1000BASEX :
240262 dev = MDIO_MMD_VEND2 ;
241263 break ;
242264 default :
@@ -772,6 +794,68 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs, unsigned int mode)
772794 return ret ;
773795}
774796
797+ static int xpcs_config_aneg_c37_1000basex (struct dw_xpcs * xpcs , unsigned int mode ,
798+ const unsigned long * advertising )
799+ {
800+ phy_interface_t interface = PHY_INTERFACE_MODE_1000BASEX ;
801+ int ret , mdio_ctrl , adv ;
802+ bool changed = 0 ;
803+
804+ /* According to Chap 7.12, to set 1000BASE-X C37 AN, AN must
805+ * be disabled first:-
806+ * 1) VR_MII_MMD_CTRL Bit(12)[AN_ENABLE] = 0b
807+ * 2) VR_MII_AN_CTRL Bit(2:1)[PCS_MODE] = 00b (1000BASE-X C37)
808+ */
809+ mdio_ctrl = xpcs_read (xpcs , MDIO_MMD_VEND2 , DW_VR_MII_MMD_CTRL );
810+ if (mdio_ctrl < 0 )
811+ return mdio_ctrl ;
812+
813+ if (mdio_ctrl & AN_CL37_EN ) {
814+ ret = xpcs_write (xpcs , MDIO_MMD_VEND2 , DW_VR_MII_MMD_CTRL ,
815+ mdio_ctrl & ~AN_CL37_EN );
816+ if (ret < 0 )
817+ return ret ;
818+ }
819+
820+ ret = xpcs_read (xpcs , MDIO_MMD_VEND2 , DW_VR_MII_AN_CTRL );
821+ if (ret < 0 )
822+ return ret ;
823+
824+ ret &= ~DW_VR_MII_PCS_MODE_MASK ;
825+ ret = xpcs_write (xpcs , MDIO_MMD_VEND2 , DW_VR_MII_AN_CTRL , ret );
826+ if (ret < 0 )
827+ return ret ;
828+
829+ /* Check for advertising changes and update the C45 MII ADV
830+ * register accordingly.
831+ */
832+ adv = phylink_mii_c22_pcs_encode_advertisement (interface ,
833+ advertising );
834+ if (adv >= 0 ) {
835+ ret = xpcs_modify_changed (xpcs , MDIO_MMD_VEND2 ,
836+ MII_ADVERTISE , 0xffff , adv );
837+ if (ret < 0 )
838+ return ret ;
839+
840+ changed = ret ;
841+ }
842+
843+ /* Clear CL37 AN complete status */
844+ ret = xpcs_write (xpcs , MDIO_MMD_VEND2 , DW_VR_MII_AN_INTR_STS , 0 );
845+ if (ret < 0 )
846+ return ret ;
847+
848+ if (phylink_autoneg_inband (mode ) &&
849+ linkmode_test_bit (ETHTOOL_LINK_MODE_Autoneg_BIT , advertising )) {
850+ ret = xpcs_write (xpcs , MDIO_MMD_VEND2 , DW_VR_MII_MMD_CTRL ,
851+ mdio_ctrl | AN_CL37_EN );
852+ if (ret < 0 )
853+ return ret ;
854+ }
855+
856+ return changed ;
857+ }
858+
775859static int xpcs_config_2500basex (struct dw_xpcs * xpcs )
776860{
777861 int ret ;
@@ -817,6 +901,12 @@ int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
817901 if (ret )
818902 return ret ;
819903 break ;
904+ case DW_AN_C37_1000BASEX :
905+ ret = xpcs_config_aneg_c37_1000basex (xpcs , mode ,
906+ advertising );
907+ if (ret )
908+ return ret ;
909+ break ;
820910 case DW_2500BASEX :
821911 ret = xpcs_config_2500basex (xpcs );
822912 if (ret )
@@ -921,6 +1011,29 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
9211011 return 0 ;
9221012}
9231013
1014+ static int xpcs_get_state_c37_1000basex (struct dw_xpcs * xpcs ,
1015+ struct phylink_link_state * state )
1016+ {
1017+ int lpa , bmsr ;
1018+
1019+ if (state -> an_enabled ) {
1020+ /* Reset link state */
1021+ state -> link = false;
1022+
1023+ lpa = xpcs_read (xpcs , MDIO_MMD_VEND2 , MII_LPA );
1024+ if (lpa < 0 || lpa & LPA_RFAULT )
1025+ return lpa ;
1026+
1027+ bmsr = xpcs_read (xpcs , MDIO_MMD_VEND2 , MII_BMSR );
1028+ if (bmsr < 0 )
1029+ return bmsr ;
1030+
1031+ phylink_mii_c22_pcs_decode_state (state , bmsr , lpa );
1032+ }
1033+
1034+ return 0 ;
1035+ }
1036+
9241037static void xpcs_get_state (struct phylink_pcs * pcs ,
9251038 struct phylink_link_state * state )
9261039{
@@ -948,6 +1061,13 @@ static void xpcs_get_state(struct phylink_pcs *pcs,
9481061 ERR_PTR (ret ));
9491062 }
9501063 break ;
1064+ case DW_AN_C37_1000BASEX :
1065+ ret = xpcs_get_state_c37_1000basex (xpcs , state );
1066+ if (ret ) {
1067+ pr_err ("xpcs_get_state_c37_1000basex returned %pe\n" ,
1068+ ERR_PTR (ret ));
1069+ }
1070+ break ;
9511071 default :
9521072 return ;
9531073 }
@@ -983,6 +1103,35 @@ static void xpcs_link_up_sgmii(struct dw_xpcs *xpcs, unsigned int mode,
9831103 pr_err ("%s: xpcs_write returned %pe\n" , __func__ , ERR_PTR (ret ));
9841104}
9851105
1106+ static void xpcs_link_up_1000basex (struct dw_xpcs * xpcs , unsigned int mode ,
1107+ int speed , int duplex )
1108+ {
1109+ int val , ret ;
1110+
1111+ if (phylink_autoneg_inband (mode ))
1112+ return ;
1113+
1114+ switch (speed ) {
1115+ case SPEED_1000 :
1116+ val = BMCR_SPEED1000 ;
1117+ break ;
1118+ case SPEED_100 :
1119+ case SPEED_10 :
1120+ default :
1121+ pr_err ("%s: speed = %d\n" , __func__ , speed );
1122+ return ;
1123+ }
1124+
1125+ if (duplex == DUPLEX_FULL )
1126+ val |= BMCR_FULLDPLX ;
1127+ else
1128+ pr_err ("%s: half duplex not supported\n" , __func__ );
1129+
1130+ ret = xpcs_write (xpcs , MDIO_MMD_VEND2 , MDIO_CTRL1 , val );
1131+ if (ret )
1132+ pr_err ("%s: xpcs_write returned %pe\n" , __func__ , ERR_PTR (ret ));
1133+ }
1134+
9861135void xpcs_link_up (struct phylink_pcs * pcs , unsigned int mode ,
9871136 phy_interface_t interface , int speed , int duplex )
9881137{
@@ -992,9 +1141,23 @@ void xpcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
9921141 return xpcs_config_usxgmii (xpcs , speed );
9931142 if (interface == PHY_INTERFACE_MODE_SGMII )
9941143 return xpcs_link_up_sgmii (xpcs , mode , speed , duplex );
1144+ if (interface == PHY_INTERFACE_MODE_1000BASEX )
1145+ return xpcs_link_up_1000basex (xpcs , mode , speed , duplex );
9951146}
9961147EXPORT_SYMBOL_GPL (xpcs_link_up );
9971148
1149+ static void xpcs_an_restart (struct phylink_pcs * pcs )
1150+ {
1151+ struct dw_xpcs * xpcs = phylink_pcs_to_xpcs (pcs );
1152+ int ret ;
1153+
1154+ ret = xpcs_read (xpcs , MDIO_MMD_VEND2 , MDIO_CTRL1 );
1155+ if (ret >= 0 ) {
1156+ ret |= BMCR_ANRESTART ;
1157+ xpcs_write (xpcs , MDIO_MMD_VEND2 , MDIO_CTRL1 , ret );
1158+ }
1159+ }
1160+
9981161static u32 xpcs_get_id (struct dw_xpcs * xpcs )
9991162{
10001163 int ret ;
@@ -1060,6 +1223,12 @@ static const struct xpcs_compat synopsys_xpcs_compat[DW_XPCS_INTERFACE_MAX] = {
10601223 .num_interfaces = ARRAY_SIZE (xpcs_sgmii_interfaces ),
10611224 .an_mode = DW_AN_C37_SGMII ,
10621225 },
1226+ [DW_XPCS_1000BASEX ] = {
1227+ .supported = xpcs_1000basex_features ,
1228+ .interface = xpcs_1000basex_interfaces ,
1229+ .num_interfaces = ARRAY_SIZE (xpcs_1000basex_interfaces ),
1230+ .an_mode = DW_AN_C37_1000BASEX ,
1231+ },
10631232 [DW_XPCS_2500BASEX ] = {
10641233 .supported = xpcs_2500basex_features ,
10651234 .interface = xpcs_2500basex_interfaces ,
@@ -1115,6 +1284,7 @@ static const struct phylink_pcs_ops xpcs_phylink_ops = {
11151284 .pcs_validate = xpcs_validate ,
11161285 .pcs_config = xpcs_config ,
11171286 .pcs_get_state = xpcs_get_state ,
1287+ .pcs_an_restart = xpcs_an_restart ,
11181288 .pcs_link_up = xpcs_link_up ,
11191289};
11201290
0 commit comments