diff options
| author | Serge Semin <fancer.lancer@gmail.com> | 2023-07-06 14:12:32 +0300 |
|---|---|---|
| committer | Serge Semin <fancer.lancer@gmail.com> | 2026-08-13 20:37:50 +0300 |
| commit | e404c5744d212d0a27cf2413297fbcd99f9edd4b (patch) | |
| tree | 8aa3b5636efaec86d2a438ead10a5841bea8957b | |
| parent | 2d2e715278dffa7d4304ec780276761cdda90fea (diff) | |
| download | linux-e404c5744d212d0a27cf2413297fbcd99f9edd4b.tar.gz linux-e404c5744d212d0a27cf2413297fbcd99f9edd4b.zip | |
net: pcs: xpcs: Add 10GBASE-X interface support
DW XPCS can be synthesized with 10GBASE-X/XAUI link support. In that case
xGMAC is still connected to the XPCS device by means of normally
multi-lane high-speed interface (XGMII, USXGMII, etc) meanwhile an
external interface is defined as 10GBASE-X. From the network subsystem
point of view it's as if DW XPCS is fully integrated into the MAC with no
need in setting any intermediate interface up.
Similarly to the 10GBASE-R, in accordance with the IEEE 802.3 standard
10GBASE-X doesn't intent any auto-negotiations but it's defined as also
being utilized by XGXS (Clause 47). Thus a new AN-less mode is defined
DW_10GBASEX in the driver. It implies PCS and PMA setups required for the
device to work in the denoted mode. The respective actions are executed in
the xpcs_do_config() method. At the same time xpcs_link_up() makes sure
that the PCS/PMA<->PHY link actually works and it has compatible speed and
duplex: 10Gbps speed and full-duplex mode.
Note 1. Synopsys 10G Gen5 PMA requires the reference clock switch in case
if the respective flag doesn't correspond to the specified clock sources.
Note 2. XPCS 10GBASE-X interface features list contains all
speed-compatible link modes in order to have the pcs_validate() permitting
these modes for the externally attached PHYs.
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 | ||||
| -rw-r--r-- | drivers/net/pcs/pcs-xpcs-pma.c | 42 | ||||
| -rw-r--r-- | drivers/net/pcs/pcs-xpcs.c | 70 | ||||
| -rw-r--r-- | drivers/net/pcs/pcs-xpcs.h | 1 | ||||
| -rw-r--r-- | include/linux/pcs/pcs-xpcs.h | 1 |
5 files changed, 117 insertions, 1 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index b0826b833e4a..459d40b95ec8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1090,7 +1090,9 @@ static void stmmac_mac_link_up(struct phylink_config *config, ctrl = old_ctrl & ~priv->hw->link.speed_mask; if (interface == PHY_INTERFACE_MODE_XGMII || - interface == PHY_INTERFACE_MODE_10GBASER) { + interface == PHY_INTERFACE_MODE_10GBASER || + interface == PHY_INTERFACE_MODE_10GBASEX || + interface == PHY_INTERFACE_MODE_XAUI) { switch (speed) { case SPEED_10000: ctrl |= priv->hw->link.xgmii.speed10000; diff --git a/drivers/net/pcs/pcs-xpcs-pma.c b/drivers/net/pcs/pcs-xpcs-pma.c index 128ac789cd25..8d9f2e1e8526 100644 --- a/drivers/net/pcs/pcs-xpcs-pma.c +++ b/drivers/net/pcs/pcs-xpcs-pma.c @@ -87,3 +87,45 @@ int xpcs_10gbaser_pma_config(struct dw_xpcs *xpcs) return 0; } } + +static int xpcs_10gbasex_gen5_10g_pma_config(struct dw_xpcs *xpcs) +{ + int ret; + + ret = xpcs_read_vendor(xpcs, MDIO_MMD_PMAPMD, + DW_VR_XS_PMA_GEN5_10G_GEN_CTRL); + if (ret < 0) + return ret; + + /* Select KX4-mode of the PHY lanes */ + ret &= ~DW_VR_XS_PMA_LANE_MODE; + ret |= FIELD_PREP(DW_VR_XS_PMA_LANE_MODE, DW_VR_XS_PMA_LANE_MODE_KX4); + + /* Activate 4 lane per link */ + ret &= ~DW_VR_XS_PMA_LINK_WIDTH; + ret |= FIELD_PREP(DW_VR_XS_PMA_LINK_WIDTH, DW_VR_XS_PMA_LINK_WIDTH_4); + + /* Enable all 4 lanes since it's X4 */ + ret &= ~DW_VR_XS_PMA_LANE_PWR_OFF; + ret |= FIELD_PREP(DW_VR_XS_PMA_LANE_PWR_OFF, 0x0); + + ret = xpcs_write_vendor(xpcs, MDIO_MMD_PMAPMD, + DW_VR_XS_PMA_GEN5_10G_GEN_CTRL, ret); + if (ret < 0) + return ret; + + /* Select PCS/PMA refclk source: Pad or Core. Vendor-reset the device + * to make sure the updates are perceived by the core + */ + return xpcs_gen5_10g_ref_clock_select(xpcs, true); +} + +int xpcs_10gbasex_pma_config(struct dw_xpcs *xpcs) +{ + switch (xpcs->info.pma) { + case DW_XPCS_PMA_GEN5_10G_ID: + return xpcs_10gbasex_gen5_10g_pma_config(xpcs); + default: + return 0; + } +} diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index e746caae64ab..fcf43f2e82c5 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -137,6 +137,22 @@ static const int xpcs_10gbaser_features[] = { __ETHTOOL_LINK_MODE_MASK_NBITS, }; +static const int xpcs_10gbasex_features[] = { + ETHTOOL_LINK_MODE_Pause_BIT, + ETHTOOL_LINK_MODE_Asym_Pause_BIT, + ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, + /* ETHTOOL_LINK_MODE_10000baseCX4_Full_BIT, */ + /* ETHTOOL_LINK_MODE_10000baseLX4_Full_BIT, */ + /* Speed-compatible modes for the link setup in the external PHYs */ + ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, + ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, + ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, + ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, + ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, + ETHTOOL_LINK_MODE_10000baseER_Full_BIT, + __ETHTOOL_LINK_MODE_MASK_NBITS, +}; + static const int xpcs_sgmii_features[] = { ETHTOOL_LINK_MODE_Pause_BIT, ETHTOOL_LINK_MODE_Asym_Pause_BIT, @@ -710,6 +726,7 @@ static unsigned int xpcs_inband_caps(struct phylink_pcs *pcs, return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE; case DW_10GBASER: + case DW_10GBASEX: case DW_2500BASEX: return LINK_INBAND_DISABLE; @@ -943,6 +960,41 @@ static int xpcs_config_10gbaser(struct dw_xpcs *xpcs) return xpcs_vendor_reset(xpcs); } +static int xpcs_config_10gbasex(struct dw_xpcs *xpcs) +{ + int ret; + + /* Disable Clause 73 AN in anyway */ + ret = xpcs_modify(xpcs, MDIO_MMD_AN, MDIO_CTRL1, + MDIO_AN_CTRL1_ENABLE, 0); + if (ret < 0) + return ret; + + /* Disable RXAUI if it's enabled by default */ + ret = xpcs_read_vpcs(xpcs, DW_VR_XS_PCS_XAUI_MODE_CTRL); + if (ret < 0) + return ret; + + ret &= ~DW_VR_XS_PCS_RXAUI_MODE; + ret = xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_XAUI_MODE_CTRL, ret); + if (ret < 0) + return ret; + + /* Set PCS to 10G speed and 10GBASE-X PCS */ + ret = xpcs_modify(xpcs, MDIO_MMD_PCS, MDIO_CTRL1, + MDIO_CTRL1_SPEEDSEL, MDIO_CTRL1_SPEED10G); + if (ret < 0) + return ret; + + ret = xpcs_modify(xpcs, MDIO_MMD_PCS, MDIO_CTRL2, + MDIO_PCS_CTRL2_TYPE, MDIO_PCS_CTRL2_10GBX); + if (ret < 0) + return ret; + + /* Make sure the specified PCS type is perceived by the core */ + return xpcs_vendor_reset(xpcs); +} + static int xpcs_config_2500basex(struct dw_xpcs *xpcs) { int ret; @@ -1004,6 +1056,11 @@ static int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface, if (ret) return ret; break; + case DW_10GBASEX: + ret = xpcs_config_10gbasex(xpcs); + if (ret) + return ret; + break; case DW_2500BASEX: ret = xpcs_config_2500basex(xpcs); if (ret) @@ -1242,6 +1299,7 @@ static void xpcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode, switch (compat->an_mode) { case DW_10GBASER: + case DW_10GBASEX: phylink_mii_c45_pcs_get_state(xpcs->mdiodev, state); break; case DW_AN_C73: @@ -1349,6 +1407,8 @@ static void xpcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode, break; case PHY_INTERFACE_MODE_10GBASER: + case PHY_INTERFACE_MODE_10GBASEX: + case PHY_INTERFACE_MODE_XAUI: xpcs_link_up_check(xpcs, speed, duplex); break; @@ -1532,6 +1592,16 @@ static const struct dw_xpcs_compat synopsys_xpcs_compat[] = { .an_mode = DW_10GBASER, .pma_config = xpcs_10gbaser_pma_config, }, { + .interface = PHY_INTERFACE_MODE_10GBASEX, + .supported = xpcs_10gbasex_features, + .an_mode = DW_10GBASEX, + .pma_config = xpcs_10gbasex_pma_config, + }, { + .interface = PHY_INTERFACE_MODE_XAUI, + .supported = xpcs_10gbasex_features, + .an_mode = DW_10GBASEX, + .pma_config = xpcs_10gbasex_pma_config, + }, { .interface = PHY_INTERFACE_MODE_SGMII, .supported = xpcs_sgmii_features, .an_mode = DW_AN_C37_SGMII, diff --git a/drivers/net/pcs/pcs-xpcs.h b/drivers/net/pcs/pcs-xpcs.h index 40741e158e16..0b3c972c9ee5 100644 --- a/drivers/net/pcs/pcs-xpcs.h +++ b/drivers/net/pcs/pcs-xpcs.h @@ -158,6 +158,7 @@ int xpcs_soft_reset(struct dw_xpcs *xpcs); int xpcs_vendor_reset(struct dw_xpcs *xpcs); int xpcs_10gbaser_pma_config(struct dw_xpcs *xpcs); +int xpcs_10gbasex_pma_config(struct dw_xpcs *xpcs); int nxp_sja1105_sgmii_pma_config(struct dw_xpcs *xpcs); int nxp_sja1110_sgmii_pma_config(struct dw_xpcs *xpcs); int nxp_sja1110_2500basex_pma_config(struct dw_xpcs *xpcs); diff --git a/include/linux/pcs/pcs-xpcs.h b/include/linux/pcs/pcs-xpcs.h index 36073f7b6bb4..67d3d92bc4e0 100644 --- a/include/linux/pcs/pcs-xpcs.h +++ b/include/linux/pcs/pcs-xpcs.h @@ -20,6 +20,7 @@ #define DW_2500BASEX 3 #define DW_AN_C37_1000BASEX 4 #define DW_10GBASER 5 +#define DW_10GBASEX 6 enum dw_xpcs_pcs_id { DW_XPCS_ID_NATIVE = 0, |
