Commit b97b5331 authored by Ong Boon Leong's avatar Ong Boon Leong Committed by David S. Miller

net: pcs: add C37 SGMII AN support for intel mGbE controller

XPCS IP supports C37 SGMII AN process and it is used in intel multi-GbE
controller as MAC-side SGMII.
Signed-off-by: default avatarOng Boon Leong <boon.leong.ong@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 07a4bc51
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#define SYNOPSYS_XPCS_USXGMII_ID 0x7996ced0 #define SYNOPSYS_XPCS_USXGMII_ID 0x7996ced0
#define SYNOPSYS_XPCS_10GKR_ID 0x7996ced0 #define SYNOPSYS_XPCS_10GKR_ID 0x7996ced0
#define SYNOPSYS_XPCS_XLGMII_ID 0x7996ced0 #define SYNOPSYS_XPCS_XLGMII_ID 0x7996ced0
#define SYNOPSYS_XPCS_SGMII_ID 0x7996ced0
#define SYNOPSYS_XPCS_MASK 0xffffffff #define SYNOPSYS_XPCS_MASK 0xffffffff
/* Vendor regs access */ /* Vendor regs access */
...@@ -57,6 +58,34 @@ ...@@ -57,6 +58,34 @@
#define DW_C73_2500KX BIT(0) #define DW_C73_2500KX BIT(0)
#define DW_C73_5000KR BIT(1) #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[] = { static const int xpcs_usxgmii_features[] = {
ETHTOOL_LINK_MODE_Pause_BIT, ETHTOOL_LINK_MODE_Pause_BIT,
ETHTOOL_LINK_MODE_Asym_Pause_BIT, ETHTOOL_LINK_MODE_Asym_Pause_BIT,
...@@ -105,6 +134,16 @@ static const int xpcs_xlgmii_features[] = { ...@@ -105,6 +134,16 @@ static const int xpcs_xlgmii_features[] = {
__ETHTOOL_LINK_MODE_MASK_NBITS, __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[] = { static const phy_interface_t xpcs_usxgmii_interfaces[] = {
PHY_INTERFACE_MODE_USXGMII, PHY_INTERFACE_MODE_USXGMII,
PHY_INTERFACE_MODE_MAX, PHY_INTERFACE_MODE_MAX,
...@@ -120,6 +159,11 @@ static const phy_interface_t xpcs_xlgmii_interfaces[] = { ...@@ -120,6 +159,11 @@ static const phy_interface_t xpcs_xlgmii_interfaces[] = {
PHY_INTERFACE_MODE_MAX, PHY_INTERFACE_MODE_MAX,
}; };
static const phy_interface_t xpcs_sgmii_interfaces[] = {
PHY_INTERFACE_MODE_SGMII,
PHY_INTERFACE_MODE_MAX,
};
static struct xpcs_id { static struct xpcs_id {
u32 id; u32 id;
u32 mask; u32 mask;
...@@ -145,6 +189,12 @@ static struct xpcs_id { ...@@ -145,6 +189,12 @@ static struct xpcs_id {
.supported = xpcs_xlgmii_features, .supported = xpcs_xlgmii_features,
.interface = xpcs_xlgmii_interfaces, .interface = xpcs_xlgmii_interfaces,
.an_mode = DW_AN_C73, .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,
}, },
}; };
...@@ -207,6 +257,9 @@ static int xpcs_soft_reset(struct mdio_xpcs_args *xpcs) ...@@ -207,6 +257,9 @@ static int xpcs_soft_reset(struct mdio_xpcs_args *xpcs)
case DW_AN_C73: case DW_AN_C73:
dev = MDIO_MMD_PCS; dev = MDIO_MMD_PCS;
break; break;
case DW_AN_C37_SGMII:
dev = MDIO_MMD_VEND2;
break;
default: default:
return -1; return -1;
} }
...@@ -597,6 +650,47 @@ static int xpcs_validate(struct mdio_xpcs_args *xpcs, ...@@ -597,6 +650,47 @@ static int xpcs_validate(struct mdio_xpcs_args *xpcs,
return 0; 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, static int xpcs_config(struct mdio_xpcs_args *xpcs,
const struct phylink_link_state *state) const struct phylink_link_state *state)
{ {
...@@ -610,6 +704,11 @@ static int xpcs_config(struct mdio_xpcs_args *xpcs, ...@@ -610,6 +704,11 @@ static int xpcs_config(struct mdio_xpcs_args *xpcs,
return ret; return ret;
} }
break; break;
case DW_AN_C37_SGMII:
ret = xpcs_config_aneg_c37_sgmii(xpcs);
if (ret)
return ret;
break;
default: default:
return -1; return -1;
} }
...@@ -650,6 +749,47 @@ static int xpcs_get_state_c73(struct mdio_xpcs_args *xpcs, ...@@ -650,6 +749,47 @@ static int xpcs_get_state_c73(struct mdio_xpcs_args *xpcs,
return 0; 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, static int xpcs_get_state(struct mdio_xpcs_args *xpcs,
struct phylink_link_state *state) struct phylink_link_state *state)
{ {
...@@ -661,6 +801,11 @@ static int xpcs_get_state(struct mdio_xpcs_args *xpcs, ...@@ -661,6 +801,11 @@ static int xpcs_get_state(struct mdio_xpcs_args *xpcs,
if (ret) if (ret)
return ret; return ret;
break; break;
case DW_AN_C37_SGMII:
ret = xpcs_get_state_c37_sgmii(xpcs, state);
if (ret)
return ret;
break;
default: default:
return -1; return -1;
} }
...@@ -682,6 +827,7 @@ static u32 xpcs_get_id(struct mdio_xpcs_args *xpcs) ...@@ -682,6 +827,7 @@ static u32 xpcs_get_id(struct mdio_xpcs_args *xpcs)
int ret; int ret;
u32 id; u32 id;
/* First, search C73 PCS using PCS MMD */
ret = xpcs_read(xpcs, MDIO_MMD_PCS, MII_PHYSID1); ret = xpcs_read(xpcs, MDIO_MMD_PCS, MII_PHYSID1);
if (ret < 0) if (ret < 0)
return 0xffffffff; return 0xffffffff;
...@@ -692,7 +838,26 @@ static u32 xpcs_get_id(struct mdio_xpcs_args *xpcs) ...@@ -692,7 +838,26 @@ static u32 xpcs_get_id(struct mdio_xpcs_args *xpcs)
if (ret < 0) if (ret < 0)
return 0xffffffff; return 0xffffffff;
return id | ret; /* 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, static bool xpcs_check_features(struct mdio_xpcs_args *xpcs,
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
/* AN mode */ /* AN mode */
#define DW_AN_C73 1 #define DW_AN_C73 1
#define DW_AN_C37_SGMII 2
struct mdio_xpcs_args { struct mdio_xpcs_args {
__ETHTOOL_DECLARE_LINK_MODE_MASK(supported); __ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment