diff mbox series

[v3,6/7] net: enetc: force the RGMII MAC speed/duplex instead of using in-band signaling

Message ID 20210629175317.2607470-7-vladimir.oltean@nxp.com
State Accepted
Commit 71346a84860c67827ef4852bc1c0ad31ac3f46ed
Delegated to: Ramon Fried
Headers show
Series Fixes for the NXP LS1028A-QDS boards | expand

Commit Message

Vladimir Oltean June 29, 2021, 5:53 p.m. UTC
The RGMII spec supports optional in-band status reporting for the speed
and duplex negotiated on the copper side, and the ENETC driver enables
this feature by default.

However, this does not work when the PHY does not implement the in-band
reporting, or when there is a MAC-to-MAC connection described using a
fixed-link. In that case, it would be better to disable the feature in
the ENETC MAC and always force the speed and duplex to the values that
were negotiated and retrieved over MDIO once the autoneg is finished.
Since this works always, we just do it unconditionally and drop the
in-band code.

Note that because we need to wait for the autoneg to complete, we need
to move enetc_setup_mac_iface() after phy_startup() returns, and then
pass the phydev pointer all the way to enetc_init_rgmii().

The same considerations have led to a similar Linux driver patch as well:
https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit/?id=c76a97218dcbb2cb7cec1404ace43ef96c87d874

Copyright updated according to corporate requirements.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v2->v3: update copyright
v1->v2: none

 drivers/net/fsl_enetc.c | 44 ++++++++++++++++++++++++++++++-----------
 drivers/net/fsl_enetc.h |  7 ++++++-
 2 files changed, 39 insertions(+), 12 deletions(-)

Comments

Ramon Fried June 29, 2021, 11:07 p.m. UTC | #1
On Tue, Jun 29, 2021 at 8:55 PM Vladimir Oltean <vladimir.oltean@nxp.com> wrote:
>
> The RGMII spec supports optional in-band status reporting for the speed
> and duplex negotiated on the copper side, and the ENETC driver enables
> this feature by default.
>
> However, this does not work when the PHY does not implement the in-band
> reporting, or when there is a MAC-to-MAC connection described using a
> fixed-link. In that case, it would be better to disable the feature in
> the ENETC MAC and always force the speed and duplex to the values that
> were negotiated and retrieved over MDIO once the autoneg is finished.
> Since this works always, we just do it unconditionally and drop the
> in-band code.
>
> Note that because we need to wait for the autoneg to complete, we need
> to move enetc_setup_mac_iface() after phy_startup() returns, and then
> pass the phydev pointer all the way to enetc_init_rgmii().
>
> The same considerations have led to a similar Linux driver patch as well:
> https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit/?id=c76a97218dcbb2cb7cec1404ace43ef96c87d874
>
> Copyright updated according to corporate requirements.
>
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> ---
> v2->v3: update copyright
> v1->v2: none
>
>  drivers/net/fsl_enetc.c | 44 ++++++++++++++++++++++++++++++-----------
>  drivers/net/fsl_enetc.h |  7 ++++++-
>  2 files changed, 39 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c
> index 9c198a1039d2..6a5a38c1ffe2 100644
> --- a/drivers/net/fsl_enetc.c
> +++ b/drivers/net/fsl_enetc.c
> @@ -178,21 +178,43 @@ static int enetc_init_sgmii(struct udevice *dev)
>  }
>
>  /* set up MAC for RGMII */
> -static int enetc_init_rgmii(struct udevice *dev)
> +static void enetc_init_rgmii(struct udevice *dev, struct phy_device *phydev)
>  {
>         struct enetc_priv *priv = dev_get_priv(dev);
> -       u32 if_mode;
> +       u32 old_val, val;
>
> -       /* enable RGMII AN */
> -       if_mode = enetc_read_port(priv, ENETC_PM_IF_MODE);
> -       if_mode |= ENETC_PM_IF_MODE_AN_ENA;
> -       enetc_write_port(priv, ENETC_PM_IF_MODE, if_mode);
> +       old_val = val = enetc_read_port(priv, ENETC_PM_IF_MODE);
>
> -       return 0;
> +       /* disable unreliable RGMII in-band signaling and force the MAC into
> +        * the speed negotiated by the PHY.
> +        */
> +       val &= ~ENETC_PM_IF_MODE_AN_ENA;
> +
> +       if (phydev->speed == SPEED_1000) {
> +               val &= ~ENETC_PM_IFM_SSP_MASK;
> +               val |= ENETC_PM_IFM_SSP_1000;
> +       } else if (phydev->speed == SPEED_100) {
> +               val &= ~ENETC_PM_IFM_SSP_MASK;
> +               val |= ENETC_PM_IFM_SSP_100;
> +       } else if (phydev->speed == SPEED_10) {
> +               val &= ~ENETC_PM_IFM_SSP_MASK;
> +               val |= ENETC_PM_IFM_SSP_10;
> +       }
> +
> +       if (phydev->duplex == DUPLEX_FULL)
> +               val |= ENETC_PM_IFM_FULL_DPX;
> +       else
> +               val &= ~ENETC_PM_IFM_FULL_DPX;
> +
> +       if (val == old_val)
> +               return;
> +
> +       enetc_write_port(priv, ENETC_PM_IF_MODE, val);
>  }
>
>  /* set up MAC configuration for the given interface type */
> -static void enetc_setup_mac_iface(struct udevice *dev)
> +static void enetc_setup_mac_iface(struct udevice *dev,
> +                                 struct phy_device *phydev)
>  {
>         struct enetc_priv *priv = dev_get_priv(dev);
>         u32 if_mode;
> @@ -202,7 +224,7 @@ static void enetc_setup_mac_iface(struct udevice *dev)
>         case PHY_INTERFACE_MODE_RGMII_ID:
>         case PHY_INTERFACE_MODE_RGMII_RXID:
>         case PHY_INTERFACE_MODE_RGMII_TXID:
> -               enetc_init_rgmii(dev);
> +               enetc_init_rgmii(dev, phydev);
>                 break;
>         case PHY_INTERFACE_MODE_XGMII:
>         case PHY_INTERFACE_MODE_USXGMII:
> @@ -546,10 +568,10 @@ static int enetc_start(struct udevice *dev)
>         enetc_setup_tx_bdr(dev);
>         enetc_setup_rx_bdr(dev);
>
> -       enetc_setup_mac_iface(dev);
> -
>         phy_startup(priv->phy);
>
> +       enetc_setup_mac_iface(dev, priv->phy);
> +
>         return 0;
>  }
>
> diff --git a/drivers/net/fsl_enetc.h b/drivers/net/fsl_enetc.h
> index 110c1d78fbc6..69f2f4aaff1e 100644
> --- a/drivers/net/fsl_enetc.h
> +++ b/drivers/net/fsl_enetc.h
> @@ -1,7 +1,7 @@
>  /* SPDX-License-Identifier: GPL-2.0+ */
>  /*
>   * ENETC ethernet controller driver
> - * Copyright 2017-2019 NXP
> + * Copyright 2017-2021 NXP
>   */
>
>  #ifndef _ENETC_H
> @@ -77,6 +77,11 @@ enum enetc_bdr_type {TX, RX};
>  #define ENETC_PM_IF_MODE               0x8300
>  #define  ENETC_PM_IF_MODE_RG           BIT(2)
>  #define  ENETC_PM_IF_MODE_AN_ENA       BIT(15)
> +#define  ENETC_PM_IFM_SSP_MASK         GENMASK(14, 13)
> +#define  ENETC_PM_IFM_SSP_1000         (2 << 13)
> +#define  ENETC_PM_IFM_SSP_100          (0 << 13)
> +#define  ENETC_PM_IFM_SSP_10           (1 << 13)
> +#define  ENETC_PM_IFM_FULL_DPX         BIT(12)
>  #define  ENETC_PM_IF_IFMODE_MASK       GENMASK(1, 0)
>
>  /* buffer descriptors count must be multiple of 8 and aligned to 128 bytes */
> --
> 2.25.1
>
Applied to u-boot-net/master, Thanks !
Ramon
diff mbox series

Patch

diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c
index 9c198a1039d2..6a5a38c1ffe2 100644
--- a/drivers/net/fsl_enetc.c
+++ b/drivers/net/fsl_enetc.c
@@ -178,21 +178,43 @@  static int enetc_init_sgmii(struct udevice *dev)
 }
 
 /* set up MAC for RGMII */
-static int enetc_init_rgmii(struct udevice *dev)
+static void enetc_init_rgmii(struct udevice *dev, struct phy_device *phydev)
 {
 	struct enetc_priv *priv = dev_get_priv(dev);
-	u32 if_mode;
+	u32 old_val, val;
 
-	/* enable RGMII AN */
-	if_mode = enetc_read_port(priv, ENETC_PM_IF_MODE);
-	if_mode |= ENETC_PM_IF_MODE_AN_ENA;
-	enetc_write_port(priv, ENETC_PM_IF_MODE, if_mode);
+	old_val = val = enetc_read_port(priv, ENETC_PM_IF_MODE);
 
-	return 0;
+	/* disable unreliable RGMII in-band signaling and force the MAC into
+	 * the speed negotiated by the PHY.
+	 */
+	val &= ~ENETC_PM_IF_MODE_AN_ENA;
+
+	if (phydev->speed == SPEED_1000) {
+		val &= ~ENETC_PM_IFM_SSP_MASK;
+		val |= ENETC_PM_IFM_SSP_1000;
+	} else if (phydev->speed == SPEED_100) {
+		val &= ~ENETC_PM_IFM_SSP_MASK;
+		val |= ENETC_PM_IFM_SSP_100;
+	} else if (phydev->speed == SPEED_10) {
+		val &= ~ENETC_PM_IFM_SSP_MASK;
+		val |= ENETC_PM_IFM_SSP_10;
+	}
+
+	if (phydev->duplex == DUPLEX_FULL)
+		val |= ENETC_PM_IFM_FULL_DPX;
+	else
+		val &= ~ENETC_PM_IFM_FULL_DPX;
+
+	if (val == old_val)
+		return;
+
+	enetc_write_port(priv, ENETC_PM_IF_MODE, val);
 }
 
 /* set up MAC configuration for the given interface type */
-static void enetc_setup_mac_iface(struct udevice *dev)
+static void enetc_setup_mac_iface(struct udevice *dev,
+				  struct phy_device *phydev)
 {
 	struct enetc_priv *priv = dev_get_priv(dev);
 	u32 if_mode;
@@ -202,7 +224,7 @@  static void enetc_setup_mac_iface(struct udevice *dev)
 	case PHY_INTERFACE_MODE_RGMII_ID:
 	case PHY_INTERFACE_MODE_RGMII_RXID:
 	case PHY_INTERFACE_MODE_RGMII_TXID:
-		enetc_init_rgmii(dev);
+		enetc_init_rgmii(dev, phydev);
 		break;
 	case PHY_INTERFACE_MODE_XGMII:
 	case PHY_INTERFACE_MODE_USXGMII:
@@ -546,10 +568,10 @@  static int enetc_start(struct udevice *dev)
 	enetc_setup_tx_bdr(dev);
 	enetc_setup_rx_bdr(dev);
 
-	enetc_setup_mac_iface(dev);
-
 	phy_startup(priv->phy);
 
+	enetc_setup_mac_iface(dev, priv->phy);
+
 	return 0;
 }
 
diff --git a/drivers/net/fsl_enetc.h b/drivers/net/fsl_enetc.h
index 110c1d78fbc6..69f2f4aaff1e 100644
--- a/drivers/net/fsl_enetc.h
+++ b/drivers/net/fsl_enetc.h
@@ -1,7 +1,7 @@ 
 /* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * ENETC ethernet controller driver
- * Copyright 2017-2019 NXP
+ * Copyright 2017-2021 NXP
  */
 
 #ifndef _ENETC_H
@@ -77,6 +77,11 @@  enum enetc_bdr_type {TX, RX};
 #define ENETC_PM_IF_MODE		0x8300
 #define  ENETC_PM_IF_MODE_RG		BIT(2)
 #define  ENETC_PM_IF_MODE_AN_ENA	BIT(15)
+#define  ENETC_PM_IFM_SSP_MASK		GENMASK(14, 13)
+#define  ENETC_PM_IFM_SSP_1000		(2 << 13)
+#define  ENETC_PM_IFM_SSP_100		(0 << 13)
+#define  ENETC_PM_IFM_SSP_10		(1 << 13)
+#define  ENETC_PM_IFM_FULL_DPX		BIT(12)
 #define  ENETC_PM_IF_IFMODE_MASK	GENMASK(1, 0)
 
 /* buffer descriptors count must be multiple of 8 and aligned to 128 bytes */