2021-04-01 18:17:39

by Sit, Michael Wei Hong

[permalink] [raw]
Subject: [PATCH net-next 1/2] net: stmmac: enable 2.5Gbps link speed

From: Voon Weifeng <[email protected]>

Intel mgbe supports 2.5G mode operation when PCS is in 1000BASE-X mode.
The 2.5G mode of operation is functionally same as 1000BASE-X mode,
except that the clock rate is 2.5 times the original rate. In 2.5G mode,
the link will operate as 2500Mbps/250Mbps/25Mbps. Hence, 2.5Gbps
link speed will be mutually exclusive with 1000Mbps/100Mbps/10Mbps.

Signed-off-by: Voon Weifeng <[email protected]>
Signed-off-by: Michael Sit Wei Hong <[email protected]>
---
.../net/ethernet/stmicro/stmmac/dwmac-intel.c | 44 ++++++++++++++++++-
.../net/ethernet/stmicro/stmmac/dwmac-intel.h | 13 ++++++
.../net/ethernet/stmicro/stmmac/dwmac4_core.c | 1 +
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 26 ++++++++++-
include/linux/stmmac.h | 2 +
5 files changed, 83 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
index 3d9a57043af2..4f70a12b42f9 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
@@ -102,6 +102,22 @@ static int intel_serdes_powerup(struct net_device *ndev, void *priv_data)

serdes_phy_addr = intel_priv->mdio_adhoc_addr;

+ /* Set the serdes rate and the PCLK rate */
+ data = mdiobus_read(priv->mii, serdes_phy_addr,
+ SERDES_GCR0);
+
+ data &= ~SERDES_RATE_MASK;
+ data &= ~SERDES_PCLK_MASK;
+
+ if (priv->plat->speed_2500_en)
+ data |= SERDES_RATE_PCIE_GEN2 << SERDES_RATE_PCIE_SHIFT |
+ SERDES_PCLK_37p5MHZ << SERDES_PCLK_SHIFT;
+ else
+ data |= SERDES_RATE_PCIE_GEN1 << SERDES_RATE_PCIE_SHIFT |
+ SERDES_PCLK_70MHZ << SERDES_PCLK_SHIFT;
+
+ mdiobus_write(priv->mii, serdes_phy_addr, SERDES_GCR0, data);
+
/* assert clk_req */
data = mdiobus_read(priv->mii, serdes_phy_addr, SERDES_GCR0);
data |= SERDES_PLL_CLK;
@@ -220,6 +236,28 @@ static void intel_serdes_powerdown(struct net_device *ndev, void *intel_data)
}
}

+static bool intel_speed_mode_2500(struct net_device *ndev, void *intel_data)
+{
+ struct intel_priv_data *intel_priv = intel_data;
+ struct stmmac_priv *priv = netdev_priv(ndev);
+ int serdes_phy_addr = 0;
+ u32 data = 0;
+
+ serdes_phy_addr = intel_priv->mdio_adhoc_addr;
+
+ /* Determine the link speed mode: 2.5Gbps/1Gbps */
+ data = mdiobus_read(priv->mii, serdes_phy_addr,
+ SERDES_GCR);
+
+ if (((data & SERDES_LINK_MODE_MASK) >> SERDES_LINK_MODE_SHIFT) ==
+ SERDES_LINK_MODE_2G5) {
+ dev_info(priv->device, "Link Speed Mode: 2.5Gbps\n");
+ return true;
+ } else {
+ return false;
+ }
+}
+
/* Program PTP Clock Frequency for different variant of
* Intel mGBE that has slightly different GPO mapping
*/
@@ -540,7 +578,7 @@ static int ehl_sgmii_data(struct pci_dev *pdev,
{
plat->bus_id = 1;
plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
-
+ plat->speed_mode_2500 = intel_speed_mode_2500;
plat->serdes_powerup = intel_serdes_powerup;
plat->serdes_powerdown = intel_serdes_powerdown;

@@ -593,6 +631,7 @@ static int ehl_pse0_sgmii1g_data(struct pci_dev *pdev,
struct plat_stmmacenet_data *plat)
{
plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
+ plat->speed_mode_2500 = intel_speed_mode_2500;
plat->serdes_powerup = intel_serdes_powerup;
plat->serdes_powerdown = intel_serdes_powerdown;
return ehl_pse0_common_data(pdev, plat);
@@ -631,6 +670,7 @@ static int ehl_pse1_sgmii1g_data(struct pci_dev *pdev,
struct plat_stmmacenet_data *plat)
{
plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
+ plat->speed_mode_2500 = intel_speed_mode_2500;
plat->serdes_powerup = intel_serdes_powerup;
plat->serdes_powerdown = intel_serdes_powerdown;
return ehl_pse1_common_data(pdev, plat);
@@ -655,6 +695,7 @@ static int tgl_sgmii_phy0_data(struct pci_dev *pdev,
{
plat->bus_id = 1;
plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
+ plat->speed_mode_2500 = intel_speed_mode_2500;
plat->serdes_powerup = intel_serdes_powerup;
plat->serdes_powerdown = intel_serdes_powerdown;
return tgl_common_data(pdev, plat);
@@ -669,6 +710,7 @@ static int tgl_sgmii_phy1_data(struct pci_dev *pdev,
{
plat->bus_id = 2;
plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
+ plat->speed_mode_2500 = intel_speed_mode_2500;
plat->serdes_powerup = intel_serdes_powerup;
plat->serdes_powerdown = intel_serdes_powerdown;
return tgl_common_data(pdev, plat);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h
index e723096c0b15..021a5c178d97 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h
@@ -9,6 +9,7 @@
#define POLL_DELAY_US 8

/* SERDES Register */
+#define SERDES_GCR 0x0 /* Global Conguration */
#define SERDES_GSR0 0x5 /* Global Status Reg0 */
#define SERDES_GCR0 0xb /* Global Configuration Reg0 */

@@ -16,8 +17,20 @@
#define SERDES_PLL_CLK BIT(0) /* PLL clk valid signal */
#define SERDES_RST BIT(2) /* Serdes Reset */
#define SERDES_PWR_ST_MASK GENMASK(6, 4) /* Serdes Power state*/
+#define SERDES_RATE_MASK GENMASK(9, 8)
+#define SERDES_PCLK_MASK GENMASK(14, 12) /* PCLK rate to PHY */
+#define SERDES_LINK_MODE_MASK GENMASK(2, 1)
+#define SERDES_LINK_MODE_SHIFT 1
#define SERDES_PWR_ST_SHIFT 4
#define SERDES_PWR_ST_P0 0x0
#define SERDES_PWR_ST_P3 0x3
+#define SERDES_LINK_MODE_2G5 0x3
+#define SERSED_LINK_MODE_1G 0x2
+#define SERDES_PCLK_37p5MHZ 0x0
+#define SERDES_PCLK_70MHZ 0x1
+#define SERDES_RATE_PCIE_GEN1 0x0
+#define SERDES_RATE_PCIE_GEN2 0x1
+#define SERDES_RATE_PCIE_SHIFT 8
+#define SERDES_PCLK_SHIFT 12

#endif /* __DWMAC_INTEL_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index 95864f014ffa..4c3f27a9e8b2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -1357,6 +1357,7 @@ int dwmac4_setup(struct stmmac_priv *priv)
mac->link.speed10 = GMAC_CONFIG_PS;
mac->link.speed100 = GMAC_CONFIG_FES | GMAC_CONFIG_PS;
mac->link.speed1000 = 0;
+ mac->link.speed2500 = GMAC_CONFIG_FES;
mac->link.speed_mask = GMAC_CONFIG_FES | GMAC_CONFIG_PS;
mac->mii.addr = GMAC_MDIO_ADDR;
mac->mii.data = GMAC_MDIO_DATA;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index d34388b1ffcc..e182f9be4247 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -882,6 +882,18 @@ static void stmmac_validate(struct phylink_config *config,
phylink_set(mac_supported, Asym_Pause);
phylink_set_port_modes(mac_supported);

+ /* 2.5G mode only support 2500baseT full duplex only */
+ if (priv->plat->has_gmac4 && priv->plat->speed_2500_en) {
+ phylink_set(mac_supported, 2500baseT_Full);
+ phylink_set(mask, 10baseT_Half);
+ phylink_set(mask, 10baseT_Full);
+ phylink_set(mask, 100baseT_Half);
+ phylink_set(mask, 100baseT_Full);
+ phylink_set(mask, 1000baseT_Half);
+ phylink_set(mask, 1000baseT_Full);
+ phylink_set(mask, 1000baseKX_Full);
+ }
+
/* Cut down 1G if asked to */
if ((max_speed > 0) && (max_speed < 1000)) {
phylink_set(mask, 1000baseT_Full);
@@ -1192,8 +1204,13 @@ static int stmmac_phy_setup(struct stmmac_priv *priv)
priv->phylink_config.dev = &priv->dev->dev;
priv->phylink_config.type = PHYLINK_NETDEV;
priv->phylink_config.pcs_poll = true;
- priv->phylink_config.ovr_an_inband =
- priv->plat->mdio_bus_data->xpcs_an_inband;
+ /* For 2.5G, we do not use SGMII in-band AN */
+ if (priv->plat->speed_2500_en) {
+ priv->phylink_config.ovr_an_inband = false;
+ } else {
+ priv->phylink_config.ovr_an_inband =
+ priv->plat->mdio_bus_data->xpcs_an_inband;
+ }

if (!fwnode)
fwnode = dev_fwnode(priv->device);
@@ -5815,6 +5832,11 @@ int stmmac_dvr_probe(struct device *device,
}
}

+ if (priv->plat->speed_mode_2500) {
+ priv->plat->speed_2500_en = priv->plat->speed_mode_2500(ndev,
+ priv->plat->bsp_priv);
+ }
+
ret = stmmac_phy_setup(priv);
if (ret) {
netdev_err(ndev, "failed to setup phy (%d)\n", ret);
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index e338ef7abc00..a43ce24d2a42 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -209,6 +209,7 @@ struct plat_stmmacenet_data {
void (*fix_mac_speed)(void *priv, unsigned int speed);
int (*serdes_powerup)(struct net_device *ndev, void *priv);
void (*serdes_powerdown)(struct net_device *ndev, void *priv);
+ bool (*speed_mode_2500)(struct net_device *ndev, void *priv);
void (*ptp_clk_freq_config)(void *priv);
int (*init)(struct platform_device *pdev, void *priv);
void (*exit)(struct platform_device *pdev, void *priv);
@@ -234,6 +235,7 @@ struct plat_stmmacenet_data {
int has_xgmac;
bool vlan_fail_q_en;
u8 vlan_fail_q;
+ bool speed_2500_en;
unsigned int eee_usecs_rate;
struct pci_dev *pdev;
bool has_crossts;
--
2.17.1


2021-04-01 18:46:24

by Russell King (Oracle)

[permalink] [raw]
Subject: Re: [PATCH net-next 1/2] net: stmmac: enable 2.5Gbps link speed

On Thu, Apr 01, 2021 at 11:01:51PM +0800, Michael Sit Wei Hong wrote:
> + /* 2.5G mode only support 2500baseT full duplex only */
> + if (priv->plat->has_gmac4 && priv->plat->speed_2500_en) {
> + phylink_set(mac_supported, 2500baseT_Full);
> + phylink_set(mask, 10baseT_Half);
> + phylink_set(mask, 10baseT_Full);
> + phylink_set(mask, 100baseT_Half);
> + phylink_set(mask, 100baseT_Full);
> + phylink_set(mask, 1000baseT_Half);
> + phylink_set(mask, 1000baseT_Full);
> + phylink_set(mask, 1000baseKX_Full);

Why? This seems at odds to the comment above?

What about 2500baseX_Full ?

--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!

2021-04-02 07:45:54

by Voon, Weifeng

[permalink] [raw]
Subject: RE: [PATCH net-next 1/2] net: stmmac: enable 2.5Gbps link speed

> > + /* 2.5G mode only support 2500baseT full duplex only */
> > + if (priv->plat->has_gmac4 && priv->plat->speed_2500_en) {
> > + phylink_set(mac_supported, 2500baseT_Full);
> > + phylink_set(mask, 10baseT_Half);
> > + phylink_set(mask, 10baseT_Full);
> > + phylink_set(mask, 100baseT_Half);
> > + phylink_set(mask, 100baseT_Full);
> > + phylink_set(mask, 1000baseT_Half);
> > + phylink_set(mask, 1000baseT_Full);
> > + phylink_set(mask, 1000baseKX_Full);
>
> Why? This seems at odds to the comment above?

> What about 2500baseX_Full ?

The comments explain that the PCS<->PHY link is in 2500BASE-X
and why 10/100/1000 link speed is mutually exclusive with 2500.
But the connected external PHY are twisted pair cable which only
supports 2500baseT_full.

Weifeng

2021-04-02 12:36:10

by Andrew Lunn

[permalink] [raw]
Subject: Re: [PATCH net-next 1/2] net: stmmac: enable 2.5Gbps link speed

On Fri, Apr 02, 2021 at 07:45:04AM +0000, Voon, Weifeng wrote:
> > > + /* 2.5G mode only support 2500baseT full duplex only */
> > > + if (priv->plat->has_gmac4 && priv->plat->speed_2500_en) {
> > > + phylink_set(mac_supported, 2500baseT_Full);
> > > + phylink_set(mask, 10baseT_Half);
> > > + phylink_set(mask, 10baseT_Full);
> > > + phylink_set(mask, 100baseT_Half);
> > > + phylink_set(mask, 100baseT_Full);
> > > + phylink_set(mask, 1000baseT_Half);
> > > + phylink_set(mask, 1000baseT_Full);
> > > + phylink_set(mask, 1000baseKX_Full);
> >
> > Why? This seems at odds to the comment above?
>
> > What about 2500baseX_Full ?
>
> The comments explain that the PCS<->PHY link is in 2500BASE-X
> and why 10/100/1000 link speed is mutually exclusive with 2500.
> But the connected external PHY are twisted pair cable which only
> supports 2500baseT_full.

The PHY should indicate what modes its supports. The PHY drivers
get_features() call should set supported to only 2500baseT_Full, if
that is all it supports.

What modes are actually used should then be the intersect of what both
the MAC and the PHY indicate they can do.

Andrew

2021-04-05 16:05:16

by Voon, Weifeng

[permalink] [raw]
Subject: RE: [PATCH net-next 1/2] net: stmmac: enable 2.5Gbps link speed

> On Fri, Apr 02, 2021 at 07:45:04AM +0000, Voon, Weifeng wrote:
> > > > + /* 2.5G mode only support 2500baseT full duplex only */
> > > > + if (priv->plat->has_gmac4 && priv->plat->speed_2500_en) {
> > > > + phylink_set(mac_supported, 2500baseT_Full);
> > > > + phylink_set(mask, 10baseT_Half);
> > > > + phylink_set(mask, 10baseT_Full);
> > > > + phylink_set(mask, 100baseT_Half);
> > > > + phylink_set(mask, 100baseT_Full);
> > > > + phylink_set(mask, 1000baseT_Half);
> > > > + phylink_set(mask, 1000baseT_Full);
> > > > + phylink_set(mask, 1000baseKX_Full);
> > >
> > > Why? This seems at odds to the comment above?
> >
> > > What about 2500baseX_Full ?
> >
> > The comments explain that the PCS<->PHY link is in 2500BASE-X and why
> > 10/100/1000 link speed is mutually exclusive with 2500.
> > But the connected external PHY are twisted pair cable which only
> > supports 2500baseT_full.
>
> The PHY should indicate what modes its supports. The PHY drivers
> get_features() call should set supported to only 2500baseT_Full, if that is
> all it supports.
>
> What modes are actually used should then be the intersect of what both the
> MAC and the PHY indicate they can do.

Noted Andrew. Instead of masking the 10/100/1000 mode support in the MAC, we will
set the supported modes in the PCS.

2021-04-05 20:41:12

by Andrew Lunn

[permalink] [raw]
Subject: Re: [PATCH net-next 1/2] net: stmmac: enable 2.5Gbps link speed

On Mon, Apr 05, 2021 at 09:07:34AM +0000, Voon, Weifeng wrote:
> > On Fri, Apr 02, 2021 at 07:45:04AM +0000, Voon, Weifeng wrote:
> > > > > + /* 2.5G mode only support 2500baseT full duplex only */
> > > > > + if (priv->plat->has_gmac4 && priv->plat->speed_2500_en) {
> > > > > + phylink_set(mac_supported, 2500baseT_Full);
> > > > > + phylink_set(mask, 10baseT_Half);
> > > > > + phylink_set(mask, 10baseT_Full);
> > > > > + phylink_set(mask, 100baseT_Half);
> > > > > + phylink_set(mask, 100baseT_Full);
> > > > > + phylink_set(mask, 1000baseT_Half);
> > > > > + phylink_set(mask, 1000baseT_Full);
> > > > > + phylink_set(mask, 1000baseKX_Full);
> > > >
> > > > Why? This seems at odds to the comment above?
> > >
> > > > What about 2500baseX_Full ?
> > >
> > > The comments explain that the PCS<->PHY link is in 2500BASE-X and why
> > > 10/100/1000 link speed is mutually exclusive with 2500.
> > > But the connected external PHY are twisted pair cable which only
> > > supports 2500baseT_full.
> >
> > The PHY should indicate what modes its supports. The PHY drivers
> > get_features() call should set supported to only 2500baseT_Full, if that is
> > all it supports.
> >
> > What modes are actually used should then be the intersect of what both the
> > MAC and the PHY indicate they can do.
>
> Noted Andrew. Instead of masking the 10/100/1000 mode support in the MAC, we will
> set the supported modes in the PCS.

PCS?

You said:

> > > But the connected external PHY are twisted pair cable which only
> > > supports 2500baseT_full.

So it should be the PHY, not the PCS, which indicates it only supports
2500baseT_full.

Andrew