diff mbox series

[net-next,1/2] net: stmmac: enable 2.5Gbps link speed

Message ID 20210401150152.22444-2-michael.wei.hong.sit@intel.com
State Superseded
Headers show
Series Enable 2.5Gbps speed for stmmac | expand

Commit Message

Michael Sit Wei Hong April 1, 2021, 3:01 p.m. UTC
From: Voon Weifeng <weifeng.voon@intel.com>

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 <weifeng.voon@intel.com>
Signed-off-by: Michael Sit Wei Hong <michael.wei.hong.sit@intel.com>
---
 .../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(-)

Comments

Russell King (Oracle) April 1, 2021, 3:10 p.m. UTC | #1
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 ?
Voon, Weifeng April 2, 2021, 7:45 a.m. UTC | #2
> > +	/* 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
Andrew Lunn April 2, 2021, 12:34 p.m. UTC | #3
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
Voon, Weifeng April 5, 2021, 9:07 a.m. UTC | #4
> 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.
Andrew Lunn April 5, 2021, 12:43 p.m. UTC | #5
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
diff mbox series

Patch

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;