summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerge Semin <fancer.lancer@gmail.com>2026-08-08 02:05:36 +0300
committerSerge Semin <fancer.lancer@gmail.com>2026-08-13 20:37:18 +0300
commitcf39f0286dee2cae124b8d34c6b5336954cffa22 (patch)
tree61a3877282b5bb9a04551b72544e3ca2d99da7f2
parente480f0e6acb66a987cd77e72615f9bdd000e56b4 (diff)
downloadlinux-gmac/ext5/pcs.tar.gz
linux-gmac/ext5/pcs.zip
net: stmmac: Add Inband/PCS support for RGMIIgmac/ext5/pcs
The PCS module currently supports in-band getting the PHY link status for the SGMII interface only. But the DW GMAC and DW QoS Ether controllers are also capable to use in-band signals of RGMII. Let's convert the STMMAC PCS module to supporting it. Basically it means to permit the integrated PCS initialization in case if the RGMII interface is enabled. That's done by checking the ActPhyIF capability detected from the GMAC. Note the link status is now determined irrespective to the PCS negotiation mode. It's fine since in case or SGMII the AN mode is always enabled so the PHY link status will be always reported in-band-ly. In case of RGMII there is no MAC-PHY negotiation and the PHY link status will be delivered for as long as the PHY supports reporting it (MLO_AN_INBAND mode is on). Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/common.h1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c3
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c3
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c13
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c21
5 files changed, 27 insertions, 14 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index ce383f012220..489c06488133 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -277,6 +277,7 @@ struct stmmac_safety_stats {
#define FLOW_AUTO (FLOW_TX | FLOW_RX)
/* PCS defines */
+#define STMMAC_PCS_RGMII (1 << 0)
#define STMMAC_PCS_SGMII (1 << 1)
#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
index 3714b98cd8c7..323f4c958846 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
@@ -35,9 +35,6 @@ static const struct stmmac_pcs_info dwmac1000_pcs_info = {
static int dwmac1000_pcs_init(struct stmmac_priv *priv)
{
- if (!priv->dma_cap.pcs)
- return 0;
-
return stmmac_integrated_pcs_init(priv, &dwmac1000_pcs_info);
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index 369bc2535e92..9e1a116a17ee 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -31,9 +31,6 @@ static const struct stmmac_pcs_info dwmac4_pcs_info = {
static int dwmac4_pcs_init(struct stmmac_priv *priv)
{
- if (!priv->dma_cap.pcs)
- return 0;
-
return stmmac_integrated_pcs_init(priv, &dwmac4_pcs_info);
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index fd8bffe9e7d1..44a40ff66ced 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1029,11 +1029,13 @@ static struct phylink_pcs *stmmac_mac_select_pcs(struct phylink_config *config,
return pcs;
}
- /* The PCS control register is only relevant for SGMII, TBI and RTBI
- * modes. We no longer support TBI or RTBI, so only configure this
- * register when operating in SGMII mode with the integrated PCS.
+ /* The PCS AN CSRs are only relevant for SGMII, TBI and RTBI modes.
+ * The in-band link status is available for RGMII and SGMII interfaces.
+ * We no longer support TBI or RTBI, so use the feature when operating
+ * in RGMII or SGMII mode with the integrated PCS.
*/
- if (priv->hw->pcs & STMMAC_PCS_SGMII && priv->integrated_pcs)
+ if (priv->hw->pcs & (STMMAC_PCS_SGMII | STMMAC_PCS_RGMII) &&
+ priv->integrated_pcs)
return &priv->integrated_pcs->pcs;
return NULL;
@@ -1306,6 +1308,9 @@ static void stmmac_check_pcs_mode(struct stmmac_priv *priv)
priv->hw->reverse_sgmii_enable = false;
break;
}
+ } else if (phy_interface_mode_is_rgmii(interface)) {
+ netdev_dbg(priv->dev, "PCS RGMII support enabled\n");
+ priv->hw->pcs = STMMAC_PCS_RGMII;
}
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c
index 23b56a7ae221..8fd6905a6831 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c
@@ -57,10 +57,11 @@ static void dwmac_integrated_pcs_get_state(struct phylink_pcs *pcs,
rgsmii = field_get(spcs->rgsmii_status_mask,
readl(spcs->rgsmii));
- state->link = status & BMSR_LSTATUS &&
- rgsmii & GMAC_RGSMII_LNKSTS;
+ state->link = !!(rgsmii & GMAC_RGSMII_LNKSTS);
+ if (state->interface == PHY_INTERFACE_MODE_SGMII)
+ state->link = state->link && status & BMSR_LSTATUS;
- if (state->link && neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) {
+ if (state->link) {
state->duplex = rgsmii & GMAC_RGSMII_LNKMOD ?
DUPLEX_FULL : DUPLEX_HALF;
switch (FIELD_GET(GMAC_RGSMII_SPEED_MASK, rgsmii)) {
@@ -92,6 +93,10 @@ static int dwmac_integrated_pcs_config(struct phylink_pcs *pcs,
{
struct stmmac_pcs *spcs = phylink_pcs_to_stmmac_pcs(pcs);
+ /* PCS AN capability isn't applicable for RGMII interface */
+ if (phy_interface_mode_is_rgmii(interface))
+ return 0;
+
dwmac_ctrl_ane(spcs->base, 0, 1, spcs->priv->hw->reverse_sgmii_enable);
return 0;
@@ -146,6 +151,8 @@ int stmmac_integrated_pcs_get_phy_intf_sel(struct phylink_pcs *pcs,
{
if (interface == PHY_INTERFACE_MODE_SGMII)
return PHY_INTF_SEL_SGMII;
+ else if (phy_interface_mode_is_rgmii(interface))
+ return PHY_INTF_SEL_RGMII;
return -EINVAL;
}
@@ -155,6 +162,9 @@ int stmmac_integrated_pcs_init(struct stmmac_priv *priv,
{
struct stmmac_pcs *spcs;
+ if (!priv->dma_cap.pcs && priv->dma_cap.actphyif != PHY_INTF_SEL_RGMII)
+ return 0;
+
spcs = devm_kzalloc(priv->device, sizeof(*spcs), GFP_KERNEL);
if (!spcs)
return -ENOMEM;
@@ -166,7 +176,10 @@ int stmmac_integrated_pcs_init(struct stmmac_priv *priv,
spcs->int_mask = pcs_info->int_mask;
spcs->pcs.ops = &dwmac_integrated_pcs_ops;
- __set_bit(PHY_INTERFACE_MODE_SGMII, spcs->pcs.supported_interfaces);
+ if (priv->dma_cap.pcs)
+ __set_bit(PHY_INTERFACE_MODE_SGMII, spcs->pcs.supported_interfaces);
+ if (priv->dma_cap.actphyif == PHY_INTF_SEL_RGMII)
+ phy_interface_set_rgmii(spcs->pcs.supported_interfaces);
priv->integrated_pcs = spcs;