Loading drivers/net/pcs/pcs-xpcs.c +166 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ #define SYNOPSYS_XPCS_USXGMII_ID 0x7996ced0 #define SYNOPSYS_XPCS_10GKR_ID 0x7996ced0 #define SYNOPSYS_XPCS_XLGMII_ID 0x7996ced0 #define SYNOPSYS_XPCS_SGMII_ID 0x7996ced0 #define SYNOPSYS_XPCS_MASK 0xffffffff /* Vendor regs access */ Loading Loading @@ -57,6 +58,34 @@ #define DW_C73_2500KX BIT(0) #define DW_C73_5000KR BIT(1) /* Clause 37 Defines */ /* VR MII MMD registers offsets */ #define DW_VR_MII_DIG_CTRL1 0x8000 #define DW_VR_MII_AN_CTRL 0x8001 #define DW_VR_MII_AN_INTR_STS 0x8002 /* VR_MII_DIG_CTRL1 */ #define DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW BIT(9) /* VR_MII_AN_CTRL */ #define DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT 3 #define DW_VR_MII_TX_CONFIG_MASK BIT(3) #define DW_VR_MII_TX_CONFIG_PHY_SIDE_SGMII 0x1 #define DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII 0x0 #define DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT 1 #define DW_VR_MII_PCS_MODE_MASK GENMASK(2, 1) #define DW_VR_MII_PCS_MODE_C37_1000BASEX 0x0 #define DW_VR_MII_PCS_MODE_C37_SGMII 0x2 /* VR_MII_AN_INTR_STS */ #define DW_VR_MII_AN_STS_C37_ANSGM_FD BIT(1) #define DW_VR_MII_AN_STS_C37_ANSGM_SP_SHIFT 2 #define DW_VR_MII_AN_STS_C37_ANSGM_SP GENMASK(3, 2) #define DW_VR_MII_C37_ANSGM_SP_10 0x0 #define DW_VR_MII_C37_ANSGM_SP_100 0x1 #define DW_VR_MII_C37_ANSGM_SP_1000 0x2 #define DW_VR_MII_C37_ANSGM_SP_LNKSTS BIT(4) static const int xpcs_usxgmii_features[] = { ETHTOOL_LINK_MODE_Pause_BIT, ETHTOOL_LINK_MODE_Asym_Pause_BIT, Loading Loading @@ -105,6 +134,16 @@ static const int xpcs_xlgmii_features[] = { __ETHTOOL_LINK_MODE_MASK_NBITS, }; static const int xpcs_sgmii_features[] = { ETHTOOL_LINK_MODE_10baseT_Half_BIT, ETHTOOL_LINK_MODE_10baseT_Full_BIT, ETHTOOL_LINK_MODE_100baseT_Half_BIT, ETHTOOL_LINK_MODE_100baseT_Full_BIT, ETHTOOL_LINK_MODE_1000baseT_Half_BIT, ETHTOOL_LINK_MODE_1000baseT_Full_BIT, __ETHTOOL_LINK_MODE_MASK_NBITS, }; static const phy_interface_t xpcs_usxgmii_interfaces[] = { PHY_INTERFACE_MODE_USXGMII, PHY_INTERFACE_MODE_MAX, Loading @@ -120,6 +159,11 @@ static const phy_interface_t xpcs_xlgmii_interfaces[] = { PHY_INTERFACE_MODE_MAX, }; static const phy_interface_t xpcs_sgmii_interfaces[] = { PHY_INTERFACE_MODE_SGMII, PHY_INTERFACE_MODE_MAX, }; static struct xpcs_id { u32 id; u32 mask; Loading @@ -145,6 +189,12 @@ static struct xpcs_id { .supported = xpcs_xlgmii_features, .interface = xpcs_xlgmii_interfaces, .an_mode = DW_AN_C73, }, { .id = SYNOPSYS_XPCS_SGMII_ID, .mask = SYNOPSYS_XPCS_MASK, .supported = xpcs_sgmii_features, .interface = xpcs_sgmii_interfaces, .an_mode = DW_AN_C37_SGMII, }, }; Loading Loading @@ -207,6 +257,9 @@ static int xpcs_soft_reset(struct mdio_xpcs_args *xpcs) case DW_AN_C73: dev = MDIO_MMD_PCS; break; case DW_AN_C37_SGMII: dev = MDIO_MMD_VEND2; break; default: return -1; } Loading Loading @@ -597,6 +650,47 @@ static int xpcs_validate(struct mdio_xpcs_args *xpcs, return 0; } static int xpcs_config_aneg_c37_sgmii(struct mdio_xpcs_args *xpcs) { int ret; /* For AN for C37 SGMII mode, the settings are :- * 1) VR_MII_AN_CTRL Bit(2:1)[PCS_MODE] = 10b (SGMII AN) * 2) VR_MII_AN_CTRL Bit(3) [TX_CONFIG] = 0b (MAC side SGMII) * DW xPCS used with DW EQoS MAC is always MAC side SGMII. * 3) VR_MII_DIG_CTRL1 Bit(9) [MAC_AUTO_SW] = 1b (Automatic * speed/duplex mode change by HW after SGMII AN complete) * * Note: Since it is MAC side SGMII, there is no need to set * SR_MII_AN_ADV. MAC side SGMII receives AN Tx Config from * PHY about the link state change after C28 AN is completed * between PHY and Link Partner. There is also no need to * trigger AN restart for MAC-side SGMII. */ ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL); if (ret < 0) return ret; ret &= ~(DW_VR_MII_PCS_MODE_MASK | DW_VR_MII_TX_CONFIG_MASK); ret |= (DW_VR_MII_PCS_MODE_C37_SGMII << DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT & DW_VR_MII_PCS_MODE_MASK); ret |= (DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII << DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT & DW_VR_MII_TX_CONFIG_MASK); ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, ret); if (ret < 0) return ret; ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1); if (ret < 0) return ret; ret |= DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW; return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret); } static int xpcs_config(struct mdio_xpcs_args *xpcs, const struct phylink_link_state *state) { Loading @@ -610,6 +704,11 @@ static int xpcs_config(struct mdio_xpcs_args *xpcs, return ret; } break; case DW_AN_C37_SGMII: ret = xpcs_config_aneg_c37_sgmii(xpcs); if (ret) return ret; break; default: return -1; } Loading Loading @@ -650,6 +749,47 @@ static int xpcs_get_state_c73(struct mdio_xpcs_args *xpcs, return 0; } static int xpcs_get_state_c37_sgmii(struct mdio_xpcs_args *xpcs, struct phylink_link_state *state) { int ret; /* Reset link_state */ state->link = false; state->speed = SPEED_UNKNOWN; state->duplex = DUPLEX_UNKNOWN; state->pause = 0; /* For C37 SGMII mode, we check DW_VR_MII_AN_INTR_STS for link * status, speed and duplex. */ ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS); if (ret < 0) return false; if (ret & DW_VR_MII_C37_ANSGM_SP_LNKSTS) { int speed_value; state->link = true; speed_value = (ret & DW_VR_MII_AN_STS_C37_ANSGM_SP) >> DW_VR_MII_AN_STS_C37_ANSGM_SP_SHIFT; if (speed_value == DW_VR_MII_C37_ANSGM_SP_1000) state->speed = SPEED_1000; else if (speed_value == DW_VR_MII_C37_ANSGM_SP_100) state->speed = SPEED_100; else state->speed = SPEED_10; if (ret & DW_VR_MII_AN_STS_C37_ANSGM_FD) state->duplex = DUPLEX_FULL; else state->duplex = DUPLEX_HALF; } return 0; } static int xpcs_get_state(struct mdio_xpcs_args *xpcs, struct phylink_link_state *state) { Loading @@ -661,6 +801,11 @@ static int xpcs_get_state(struct mdio_xpcs_args *xpcs, if (ret) return ret; break; case DW_AN_C37_SGMII: ret = xpcs_get_state_c37_sgmii(xpcs, state); if (ret) return ret; break; default: return -1; } Loading @@ -682,6 +827,7 @@ static u32 xpcs_get_id(struct mdio_xpcs_args *xpcs) int ret; u32 id; /* First, search C73 PCS using PCS MMD */ ret = xpcs_read(xpcs, MDIO_MMD_PCS, MII_PHYSID1); if (ret < 0) return 0xffffffff; Loading @@ -692,7 +838,26 @@ static u32 xpcs_get_id(struct mdio_xpcs_args *xpcs) if (ret < 0) return 0xffffffff; /* If Device IDs are not all zeros, we found C73 AN-type device */ if (id | ret) return id | ret; /* Next, search C37 PCS using Vendor-Specific MII MMD */ ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_PHYSID1); if (ret < 0) return 0xffffffff; id = ret << 16; ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_PHYSID2); if (ret < 0) return 0xffffffff; /* If Device IDs are not all zeros, we found C37 AN-type device */ if (id | ret) return id | ret; return 0xffffffff; } static bool xpcs_check_features(struct mdio_xpcs_args *xpcs, Loading include/linux/pcs/pcs-xpcs.h +1 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ /* AN mode */ #define DW_AN_C73 1 #define DW_AN_C37_SGMII 2 struct mdio_xpcs_args { __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); Loading Loading
drivers/net/pcs/pcs-xpcs.c +166 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ #define SYNOPSYS_XPCS_USXGMII_ID 0x7996ced0 #define SYNOPSYS_XPCS_10GKR_ID 0x7996ced0 #define SYNOPSYS_XPCS_XLGMII_ID 0x7996ced0 #define SYNOPSYS_XPCS_SGMII_ID 0x7996ced0 #define SYNOPSYS_XPCS_MASK 0xffffffff /* Vendor regs access */ Loading Loading @@ -57,6 +58,34 @@ #define DW_C73_2500KX BIT(0) #define DW_C73_5000KR BIT(1) /* Clause 37 Defines */ /* VR MII MMD registers offsets */ #define DW_VR_MII_DIG_CTRL1 0x8000 #define DW_VR_MII_AN_CTRL 0x8001 #define DW_VR_MII_AN_INTR_STS 0x8002 /* VR_MII_DIG_CTRL1 */ #define DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW BIT(9) /* VR_MII_AN_CTRL */ #define DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT 3 #define DW_VR_MII_TX_CONFIG_MASK BIT(3) #define DW_VR_MII_TX_CONFIG_PHY_SIDE_SGMII 0x1 #define DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII 0x0 #define DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT 1 #define DW_VR_MII_PCS_MODE_MASK GENMASK(2, 1) #define DW_VR_MII_PCS_MODE_C37_1000BASEX 0x0 #define DW_VR_MII_PCS_MODE_C37_SGMII 0x2 /* VR_MII_AN_INTR_STS */ #define DW_VR_MII_AN_STS_C37_ANSGM_FD BIT(1) #define DW_VR_MII_AN_STS_C37_ANSGM_SP_SHIFT 2 #define DW_VR_MII_AN_STS_C37_ANSGM_SP GENMASK(3, 2) #define DW_VR_MII_C37_ANSGM_SP_10 0x0 #define DW_VR_MII_C37_ANSGM_SP_100 0x1 #define DW_VR_MII_C37_ANSGM_SP_1000 0x2 #define DW_VR_MII_C37_ANSGM_SP_LNKSTS BIT(4) static const int xpcs_usxgmii_features[] = { ETHTOOL_LINK_MODE_Pause_BIT, ETHTOOL_LINK_MODE_Asym_Pause_BIT, Loading Loading @@ -105,6 +134,16 @@ static const int xpcs_xlgmii_features[] = { __ETHTOOL_LINK_MODE_MASK_NBITS, }; static const int xpcs_sgmii_features[] = { ETHTOOL_LINK_MODE_10baseT_Half_BIT, ETHTOOL_LINK_MODE_10baseT_Full_BIT, ETHTOOL_LINK_MODE_100baseT_Half_BIT, ETHTOOL_LINK_MODE_100baseT_Full_BIT, ETHTOOL_LINK_MODE_1000baseT_Half_BIT, ETHTOOL_LINK_MODE_1000baseT_Full_BIT, __ETHTOOL_LINK_MODE_MASK_NBITS, }; static const phy_interface_t xpcs_usxgmii_interfaces[] = { PHY_INTERFACE_MODE_USXGMII, PHY_INTERFACE_MODE_MAX, Loading @@ -120,6 +159,11 @@ static const phy_interface_t xpcs_xlgmii_interfaces[] = { PHY_INTERFACE_MODE_MAX, }; static const phy_interface_t xpcs_sgmii_interfaces[] = { PHY_INTERFACE_MODE_SGMII, PHY_INTERFACE_MODE_MAX, }; static struct xpcs_id { u32 id; u32 mask; Loading @@ -145,6 +189,12 @@ static struct xpcs_id { .supported = xpcs_xlgmii_features, .interface = xpcs_xlgmii_interfaces, .an_mode = DW_AN_C73, }, { .id = SYNOPSYS_XPCS_SGMII_ID, .mask = SYNOPSYS_XPCS_MASK, .supported = xpcs_sgmii_features, .interface = xpcs_sgmii_interfaces, .an_mode = DW_AN_C37_SGMII, }, }; Loading Loading @@ -207,6 +257,9 @@ static int xpcs_soft_reset(struct mdio_xpcs_args *xpcs) case DW_AN_C73: dev = MDIO_MMD_PCS; break; case DW_AN_C37_SGMII: dev = MDIO_MMD_VEND2; break; default: return -1; } Loading Loading @@ -597,6 +650,47 @@ static int xpcs_validate(struct mdio_xpcs_args *xpcs, return 0; } static int xpcs_config_aneg_c37_sgmii(struct mdio_xpcs_args *xpcs) { int ret; /* For AN for C37 SGMII mode, the settings are :- * 1) VR_MII_AN_CTRL Bit(2:1)[PCS_MODE] = 10b (SGMII AN) * 2) VR_MII_AN_CTRL Bit(3) [TX_CONFIG] = 0b (MAC side SGMII) * DW xPCS used with DW EQoS MAC is always MAC side SGMII. * 3) VR_MII_DIG_CTRL1 Bit(9) [MAC_AUTO_SW] = 1b (Automatic * speed/duplex mode change by HW after SGMII AN complete) * * Note: Since it is MAC side SGMII, there is no need to set * SR_MII_AN_ADV. MAC side SGMII receives AN Tx Config from * PHY about the link state change after C28 AN is completed * between PHY and Link Partner. There is also no need to * trigger AN restart for MAC-side SGMII. */ ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL); if (ret < 0) return ret; ret &= ~(DW_VR_MII_PCS_MODE_MASK | DW_VR_MII_TX_CONFIG_MASK); ret |= (DW_VR_MII_PCS_MODE_C37_SGMII << DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT & DW_VR_MII_PCS_MODE_MASK); ret |= (DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII << DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT & DW_VR_MII_TX_CONFIG_MASK); ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, ret); if (ret < 0) return ret; ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1); if (ret < 0) return ret; ret |= DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW; return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret); } static int xpcs_config(struct mdio_xpcs_args *xpcs, const struct phylink_link_state *state) { Loading @@ -610,6 +704,11 @@ static int xpcs_config(struct mdio_xpcs_args *xpcs, return ret; } break; case DW_AN_C37_SGMII: ret = xpcs_config_aneg_c37_sgmii(xpcs); if (ret) return ret; break; default: return -1; } Loading Loading @@ -650,6 +749,47 @@ static int xpcs_get_state_c73(struct mdio_xpcs_args *xpcs, return 0; } static int xpcs_get_state_c37_sgmii(struct mdio_xpcs_args *xpcs, struct phylink_link_state *state) { int ret; /* Reset link_state */ state->link = false; state->speed = SPEED_UNKNOWN; state->duplex = DUPLEX_UNKNOWN; state->pause = 0; /* For C37 SGMII mode, we check DW_VR_MII_AN_INTR_STS for link * status, speed and duplex. */ ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS); if (ret < 0) return false; if (ret & DW_VR_MII_C37_ANSGM_SP_LNKSTS) { int speed_value; state->link = true; speed_value = (ret & DW_VR_MII_AN_STS_C37_ANSGM_SP) >> DW_VR_MII_AN_STS_C37_ANSGM_SP_SHIFT; if (speed_value == DW_VR_MII_C37_ANSGM_SP_1000) state->speed = SPEED_1000; else if (speed_value == DW_VR_MII_C37_ANSGM_SP_100) state->speed = SPEED_100; else state->speed = SPEED_10; if (ret & DW_VR_MII_AN_STS_C37_ANSGM_FD) state->duplex = DUPLEX_FULL; else state->duplex = DUPLEX_HALF; } return 0; } static int xpcs_get_state(struct mdio_xpcs_args *xpcs, struct phylink_link_state *state) { Loading @@ -661,6 +801,11 @@ static int xpcs_get_state(struct mdio_xpcs_args *xpcs, if (ret) return ret; break; case DW_AN_C37_SGMII: ret = xpcs_get_state_c37_sgmii(xpcs, state); if (ret) return ret; break; default: return -1; } Loading @@ -682,6 +827,7 @@ static u32 xpcs_get_id(struct mdio_xpcs_args *xpcs) int ret; u32 id; /* First, search C73 PCS using PCS MMD */ ret = xpcs_read(xpcs, MDIO_MMD_PCS, MII_PHYSID1); if (ret < 0) return 0xffffffff; Loading @@ -692,7 +838,26 @@ static u32 xpcs_get_id(struct mdio_xpcs_args *xpcs) if (ret < 0) return 0xffffffff; /* If Device IDs are not all zeros, we found C73 AN-type device */ if (id | ret) return id | ret; /* Next, search C37 PCS using Vendor-Specific MII MMD */ ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_PHYSID1); if (ret < 0) return 0xffffffff; id = ret << 16; ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_PHYSID2); if (ret < 0) return 0xffffffff; /* If Device IDs are not all zeros, we found C37 AN-type device */ if (id | ret) return id | ret; return 0xffffffff; } static bool xpcs_check_features(struct mdio_xpcs_args *xpcs, Loading
include/linux/pcs/pcs-xpcs.h +1 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ /* AN mode */ #define DW_AN_C73 1 #define DW_AN_C37_SGMII 2 struct mdio_xpcs_args { __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); Loading