diff mbox series

[RFC,net-next,v3,13/20] net: dsa: qca8k: make rgmii delay configurable

Message ID 20210504222915.17206-13-ansuelsmth@gmail.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series [RFC,net-next,v3,01/20] net: mdio: ipq8064: clean whitespaces in define | expand

Checks

Context Check Description
netdev/apply fail Patch does not apply to net-next
netdev/tree_selection success Clearly marked for net-next

Commit Message

Christian Marangi May 4, 2021, 10:29 p.m. UTC
The legacy qsdk code used a different delay instead of the max value.
Qsdk use 1 ps for rx and 2 ps for tx. Make these values configurable
using the standard rx/tx-internal-delay-ps ethernet binding and apply
qsdk values by default. The connected gmac doesn't add any delay so no
additional delay is added to tx/rx.

Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
---
 drivers/net/dsa/qca8k.c | 51 +++++++++++++++++++++++++++++++++++++++--
 drivers/net/dsa/qca8k.h | 11 +++++----
 2 files changed, 55 insertions(+), 7 deletions(-)

Comments

Andrew Lunn May 5, 2021, 1 a.m. UTC | #1
On Wed, May 05, 2021 at 12:29:07AM +0200, Ansuel Smith wrote:
> The legacy qsdk code used a different delay instead of the max value.
> Qsdk use 1 ps for rx and 2 ps for tx. Make these values configurable
> using the standard rx/tx-internal-delay-ps ethernet binding and apply
> qsdk values by default. The connected gmac doesn't add any delay so no
> additional delay is added to tx/rx.
> 
> Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
> ---
>  drivers/net/dsa/qca8k.c | 51 +++++++++++++++++++++++++++++++++++++++--
>  drivers/net/dsa/qca8k.h | 11 +++++----
>  2 files changed, 55 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
> index 22334d416f53..cb9b44769e92 100644
> --- a/drivers/net/dsa/qca8k.c
> +++ b/drivers/net/dsa/qca8k.c
> @@ -779,6 +779,47 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv)
>  	return 0;
>  }
>  
> +static int
> +qca8k_setup_of_rgmii_delay(struct qca8k_priv *priv)
> +{
> +	struct device_node *ports, *port;
> +	u32 val;
> +
> +	ports = of_get_child_by_name(priv->dev->of_node, "ports");
> +	if (!ports)
> +		return -EINVAL;
> +
> +	/* Assume only one port with rgmii-id mode */
> +	for_each_available_child_of_node(ports, port) {

Are delays global? Or per port? They really should be per port.  If it
is global, one value that applies to all ports, i would not use
it. Have the PHY apply the delay, not the MAC.

    Andrew
Christian Marangi May 5, 2021, 1:07 a.m. UTC | #2
On Wed, May 05, 2021 at 03:00:45AM +0200, Andrew Lunn wrote:
> On Wed, May 05, 2021 at 12:29:07AM +0200, Ansuel Smith wrote:
> > The legacy qsdk code used a different delay instead of the max value.
> > Qsdk use 1 ps for rx and 2 ps for tx. Make these values configurable
> > using the standard rx/tx-internal-delay-ps ethernet binding and apply
> > qsdk values by default. The connected gmac doesn't add any delay so no
> > additional delay is added to tx/rx.
> > 
> > Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
> > ---
> >  drivers/net/dsa/qca8k.c | 51 +++++++++++++++++++++++++++++++++++++++--
> >  drivers/net/dsa/qca8k.h | 11 +++++----
> >  2 files changed, 55 insertions(+), 7 deletions(-)
> > 
> > diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
> > index 22334d416f53..cb9b44769e92 100644
> > --- a/drivers/net/dsa/qca8k.c
> > +++ b/drivers/net/dsa/qca8k.c
> > @@ -779,6 +779,47 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv)
> >  	return 0;
> >  }
> >  
> > +static int
> > +qca8k_setup_of_rgmii_delay(struct qca8k_priv *priv)
> > +{
> > +	struct device_node *ports, *port;
> > +	u32 val;
> > +
> > +	ports = of_get_child_by_name(priv->dev->of_node, "ports");
> > +	if (!ports)
> > +		return -EINVAL;
> > +
> > +	/* Assume only one port with rgmii-id mode */
> > +	for_each_available_child_of_node(ports, port) {
> 
> Are delays global? Or per port? They really should be per port.  If it
> is global, one value that applies to all ports, i would not use
> it. Have the PHY apply the delay, not the MAC.
> 
>     Andrew

It's expected to set the delay in the port node. But yes the value is
global and assigned to every port (in reality this is only assigned to
the unique rgmii cpu port). The switch has only one rgmii port
and one sgmii, that's why I skipped any logic about handling more than
one case with internal delay. If you want I can try to add some logic to
handle this value per port. But again on the switch there is only one
reg to set the delay and the qca8k_phylink_mac_config function use this
only for the rgmii cpu port.
Vladimir Oltean May 6, 2021, 11:10 a.m. UTC | #3
On Wed, May 05, 2021 at 12:29:07AM +0200, Ansuel Smith wrote:
> The legacy qsdk code used a different delay instead of the max value.
> Qsdk use 1 ps for rx and 2 ps for tx. Make these values configurable
> using the standard rx/tx-internal-delay-ps ethernet binding and apply
> qsdk values by default. The connected gmac doesn't add any delay so no
> additional delay is added to tx/rx.
> 
> Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
> ---
>  drivers/net/dsa/qca8k.c | 51 +++++++++++++++++++++++++++++++++++++++--
>  drivers/net/dsa/qca8k.h | 11 +++++----
>  2 files changed, 55 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
> index 22334d416f53..cb9b44769e92 100644
> --- a/drivers/net/dsa/qca8k.c
> +++ b/drivers/net/dsa/qca8k.c
> @@ -779,6 +779,47 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv)
>  	return 0;
>  }
>  
> +static int
> +qca8k_setup_of_rgmii_delay(struct qca8k_priv *priv)
> +{
> +	struct device_node *ports, *port;
> +	u32 val;
> +
> +	ports = of_get_child_by_name(priv->dev->of_node, "ports");

Consider falling back to searching for the "ethernet-ports" name too,
DSA should now support both.

> +	if (!ports)
> +		return -EINVAL;
> +
> +	/* Assume only one port with rgmii-id mode */
> +	for_each_available_child_of_node(ports, port) {
> +		if (!of_property_match_string(port, "phy-mode", "rgmii-id"))
> +			continue;
> +
> +		if (of_property_read_u32(port, "rx-internal-delay-ps", &val))
> +			val = 2;
> +
> +		if (val > QCA8K_MAX_DELAY) {
> +			dev_err(priv->dev, "rgmii rx delay is limited to more than 3ps, setting to the max value");
> +			priv->rgmii_rx_delay = 3;

?!
3 picoseconds is not a lot of clock skew for a 125/25/2.5 MHz clock. 3 nanoseconds maybe?

> +		} else {
> +			priv->rgmii_rx_delay = val;
> +		}
> +
> +		if (of_property_read_u32(port, "rx-internal-delay-ps", &val))
> +			val = 1;
> +
> +		if (val > QCA8K_MAX_DELAY) {
> +			dev_err(priv->dev, "rgmii tx delay is limited to more than 3ps, setting to the max value");
> +			priv->rgmii_tx_delay = 3;
> +		} else {
> +			priv->rgmii_rx_delay = val;
> +		}
> +	}
> +
> +	of_node_put(ports);
> +
> +	return 0;
> +}
> +
>  static int
>  qca8k_setup(struct dsa_switch *ds)
>  {
> @@ -808,6 +849,10 @@ qca8k_setup(struct dsa_switch *ds)
>  	if (ret)
>  		return ret;
>  
> +	ret = qca8k_setup_of_rgmii_delay(priv);
> +	if (ret)
> +		return ret;
> +
>  	/* Enable CPU Port */
>  	ret = qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0,
>  			    QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);
> @@ -1018,8 +1063,10 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
>  		 */
>  		qca8k_write(priv, reg,
>  			    QCA8K_PORT_PAD_RGMII_EN |
> -			    QCA8K_PORT_PAD_RGMII_TX_DELAY(QCA8K_MAX_DELAY) |
> -			    QCA8K_PORT_PAD_RGMII_RX_DELAY(QCA8K_MAX_DELAY));
> +			    QCA8K_PORT_PAD_RGMII_TX_DELAY(priv->rgmii_tx_delay) |
> +			    QCA8K_PORT_PAD_RGMII_RX_DELAY(priv->rgmii_rx_delay) |
> +			    QCA8K_PORT_PAD_RGMII_TX_DELAY_EN |
> +			    QCA8K_PORT_PAD_RGMII_RX_DELAY_EN);
>  		/* QCA8337 requires to set rgmii rx delay */
>  		if (data->id == QCA8K_ID_QCA8337)
>  			qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL,
> diff --git a/drivers/net/dsa/qca8k.h b/drivers/net/dsa/qca8k.h
> index 0b503f78bf92..80830bb42736 100644
> --- a/drivers/net/dsa/qca8k.h
> +++ b/drivers/net/dsa/qca8k.h
> @@ -36,12 +36,11 @@
>  #define QCA8K_REG_PORT5_PAD_CTRL			0x008
>  #define QCA8K_REG_PORT6_PAD_CTRL			0x00c
>  #define   QCA8K_PORT_PAD_RGMII_EN			BIT(26)
> -#define   QCA8K_PORT_PAD_RGMII_TX_DELAY(x)		\
> -						((0x8 + (x & 0x3)) << 22)
> -#define   QCA8K_PORT_PAD_RGMII_RX_DELAY(x)		\
> -						((0x10 + (x & 0x3)) << 20)
> -#define   QCA8K_MAX_DELAY				3
> +#define   QCA8K_PORT_PAD_RGMII_TX_DELAY(x)		((x) << 22)
> +#define   QCA8K_PORT_PAD_RGMII_RX_DELAY(x)		((x) << 20)
> +#define	  QCA8K_PORT_PAD_RGMII_TX_DELAY_EN		BIT(25)
>  #define   QCA8K_PORT_PAD_RGMII_RX_DELAY_EN		BIT(24)
> +#define   QCA8K_MAX_DELAY				3
>  #define   QCA8K_PORT_PAD_SGMII_EN			BIT(7)
>  #define QCA8K_REG_PWS					0x010
>  #define   QCA8K_PWS_SERDES_AEN_DIS			BIT(7)
> @@ -251,6 +250,8 @@ struct qca8k_match_data {
>  
>  struct qca8k_priv {
>  	u8 switch_revision;
> +	u8 rgmii_tx_delay;
> +	u8 rgmii_rx_delay;
>  	struct regmap *regmap;
>  	struct mii_bus *bus;
>  	struct ar8xxx_port_status port_sts[QCA8K_NUM_PORTS];
> -- 
> 2.30.2
>
Christian Marangi May 6, 2021, 9:53 p.m. UTC | #4
On Thu, May 06, 2021 at 02:10:33PM +0300, Vladimir Oltean wrote:
> On Wed, May 05, 2021 at 12:29:07AM +0200, Ansuel Smith wrote:
> > The legacy qsdk code used a different delay instead of the max value.
> > Qsdk use 1 ps for rx and 2 ps for tx. Make these values configurable
> > using the standard rx/tx-internal-delay-ps ethernet binding and apply
> > qsdk values by default. The connected gmac doesn't add any delay so no
> > additional delay is added to tx/rx.
> > 
> > Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
> > ---
> >  drivers/net/dsa/qca8k.c | 51 +++++++++++++++++++++++++++++++++++++++--
> >  drivers/net/dsa/qca8k.h | 11 +++++----
> >  2 files changed, 55 insertions(+), 7 deletions(-)
> > 
> > diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
> > index 22334d416f53..cb9b44769e92 100644
> > --- a/drivers/net/dsa/qca8k.c
> > +++ b/drivers/net/dsa/qca8k.c
> > @@ -779,6 +779,47 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv)
> >  	return 0;
> >  }
> >  
> > +static int
> > +qca8k_setup_of_rgmii_delay(struct qca8k_priv *priv)
> > +{
> > +	struct device_node *ports, *port;
> > +	u32 val;
> > +
> > +	ports = of_get_child_by_name(priv->dev->of_node, "ports");
> 
> Consider falling back to searching for the "ethernet-ports" name too,
> DSA should now support both.
>

The function qca8k_setup_mdio_bus also checks for ports node. Should I
also there the fallback correct?

> > +	if (!ports)
> > +		return -EINVAL;
> > +
> > +	/* Assume only one port with rgmii-id mode */
> > +	for_each_available_child_of_node(ports, port) {
> > +		if (!of_property_match_string(port, "phy-mode", "rgmii-id"))
> > +			continue;
> > +
> > +		if (of_property_read_u32(port, "rx-internal-delay-ps", &val))
> > +			val = 2;
> > +
> > +		if (val > QCA8K_MAX_DELAY) {
> > +			dev_err(priv->dev, "rgmii rx delay is limited to more than 3ps, setting to the max value");
> > +			priv->rgmii_rx_delay = 3;
> 
> ?!
> 3 picoseconds is not a lot of clock skew for a 125/25/2.5 MHz clock. 3 nanoseconds maybe?
> 
> > +		} else {
> > +			priv->rgmii_rx_delay = val;
> > +		}
> > +
> > +		if (of_property_read_u32(port, "rx-internal-delay-ps", &val))
> > +			val = 1;
> > +
> > +		if (val > QCA8K_MAX_DELAY) {
> > +			dev_err(priv->dev, "rgmii tx delay is limited to more than 3ps, setting to the max value");
> > +			priv->rgmii_tx_delay = 3;
> > +		} else {
> > +			priv->rgmii_rx_delay = val;
> > +		}
> > +	}
> > +
> > +	of_node_put(ports);
> > +
> > +	return 0;
> > +}
> > +
> >  static int
> >  qca8k_setup(struct dsa_switch *ds)
> >  {
> > @@ -808,6 +849,10 @@ qca8k_setup(struct dsa_switch *ds)
> >  	if (ret)
> >  		return ret;
> >  
> > +	ret = qca8k_setup_of_rgmii_delay(priv);
> > +	if (ret)
> > +		return ret;
> > +
> >  	/* Enable CPU Port */
> >  	ret = qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0,
> >  			    QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);
> > @@ -1018,8 +1063,10 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
> >  		 */
> >  		qca8k_write(priv, reg,
> >  			    QCA8K_PORT_PAD_RGMII_EN |
> > -			    QCA8K_PORT_PAD_RGMII_TX_DELAY(QCA8K_MAX_DELAY) |
> > -			    QCA8K_PORT_PAD_RGMII_RX_DELAY(QCA8K_MAX_DELAY));
> > +			    QCA8K_PORT_PAD_RGMII_TX_DELAY(priv->rgmii_tx_delay) |
> > +			    QCA8K_PORT_PAD_RGMII_RX_DELAY(priv->rgmii_rx_delay) |
> > +			    QCA8K_PORT_PAD_RGMII_TX_DELAY_EN |
> > +			    QCA8K_PORT_PAD_RGMII_RX_DELAY_EN);
> >  		/* QCA8337 requires to set rgmii rx delay */
> >  		if (data->id == QCA8K_ID_QCA8337)
> >  			qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL,
> > diff --git a/drivers/net/dsa/qca8k.h b/drivers/net/dsa/qca8k.h
> > index 0b503f78bf92..80830bb42736 100644
> > --- a/drivers/net/dsa/qca8k.h
> > +++ b/drivers/net/dsa/qca8k.h
> > @@ -36,12 +36,11 @@
> >  #define QCA8K_REG_PORT5_PAD_CTRL			0x008
> >  #define QCA8K_REG_PORT6_PAD_CTRL			0x00c
> >  #define   QCA8K_PORT_PAD_RGMII_EN			BIT(26)
> > -#define   QCA8K_PORT_PAD_RGMII_TX_DELAY(x)		\
> > -						((0x8 + (x & 0x3)) << 22)
> > -#define   QCA8K_PORT_PAD_RGMII_RX_DELAY(x)		\
> > -						((0x10 + (x & 0x3)) << 20)
> > -#define   QCA8K_MAX_DELAY				3
> > +#define   QCA8K_PORT_PAD_RGMII_TX_DELAY(x)		((x) << 22)
> > +#define   QCA8K_PORT_PAD_RGMII_RX_DELAY(x)		((x) << 20)
> > +#define	  QCA8K_PORT_PAD_RGMII_TX_DELAY_EN		BIT(25)
> >  #define   QCA8K_PORT_PAD_RGMII_RX_DELAY_EN		BIT(24)
> > +#define   QCA8K_MAX_DELAY				3
> >  #define   QCA8K_PORT_PAD_SGMII_EN			BIT(7)
> >  #define QCA8K_REG_PWS					0x010
> >  #define   QCA8K_PWS_SERDES_AEN_DIS			BIT(7)
> > @@ -251,6 +250,8 @@ struct qca8k_match_data {
> >  
> >  struct qca8k_priv {
> >  	u8 switch_revision;
> > +	u8 rgmii_tx_delay;
> > +	u8 rgmii_rx_delay;
> >  	struct regmap *regmap;
> >  	struct mii_bus *bus;
> >  	struct ar8xxx_port_status port_sts[QCA8K_NUM_PORTS];
> > -- 
> > 2.30.2
> >
Vladimir Oltean May 7, 2021, 8:51 a.m. UTC | #5
On Thu, May 06, 2021 at 11:53:36PM +0200, Ansuel Smith wrote:
> On Thu, May 06, 2021 at 02:10:33PM +0300, Vladimir Oltean wrote:
> > On Wed, May 05, 2021 at 12:29:07AM +0200, Ansuel Smith wrote:
> > > The legacy qsdk code used a different delay instead of the max value.
> > > Qsdk use 1 ps for rx and 2 ps for tx. Make these values configurable
> > > using the standard rx/tx-internal-delay-ps ethernet binding and apply
> > > qsdk values by default. The connected gmac doesn't add any delay so no
> > > additional delay is added to tx/rx.
> > > 
> > > Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
> > > ---
> > >  drivers/net/dsa/qca8k.c | 51 +++++++++++++++++++++++++++++++++++++++--
> > >  drivers/net/dsa/qca8k.h | 11 +++++----
> > >  2 files changed, 55 insertions(+), 7 deletions(-)
> > > 
> > > diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
> > > index 22334d416f53..cb9b44769e92 100644
> > > --- a/drivers/net/dsa/qca8k.c
> > > +++ b/drivers/net/dsa/qca8k.c
> > > @@ -779,6 +779,47 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv)
> > >  	return 0;
> > >  }
> > >  
> > > +static int
> > > +qca8k_setup_of_rgmii_delay(struct qca8k_priv *priv)
> > > +{
> > > +	struct device_node *ports, *port;
> > > +	u32 val;
> > > +
> > > +	ports = of_get_child_by_name(priv->dev->of_node, "ports");
> > 
> > Consider falling back to searching for the "ethernet-ports" name too,
> > DSA should now support both.
> >
> 
> The function qca8k_setup_mdio_bus also checks for ports node. Should I
> also there the fallback correct?

Yes, ideally the entire driver should work fine with "ethernet-ports"
and not just pieces of it.
diff mbox series

Patch

diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c
index 22334d416f53..cb9b44769e92 100644
--- a/drivers/net/dsa/qca8k.c
+++ b/drivers/net/dsa/qca8k.c
@@ -779,6 +779,47 @@  qca8k_setup_mdio_bus(struct qca8k_priv *priv)
 	return 0;
 }
 
+static int
+qca8k_setup_of_rgmii_delay(struct qca8k_priv *priv)
+{
+	struct device_node *ports, *port;
+	u32 val;
+
+	ports = of_get_child_by_name(priv->dev->of_node, "ports");
+	if (!ports)
+		return -EINVAL;
+
+	/* Assume only one port with rgmii-id mode */
+	for_each_available_child_of_node(ports, port) {
+		if (!of_property_match_string(port, "phy-mode", "rgmii-id"))
+			continue;
+
+		if (of_property_read_u32(port, "rx-internal-delay-ps", &val))
+			val = 2;
+
+		if (val > QCA8K_MAX_DELAY) {
+			dev_err(priv->dev, "rgmii rx delay is limited to more than 3ps, setting to the max value");
+			priv->rgmii_rx_delay = 3;
+		} else {
+			priv->rgmii_rx_delay = val;
+		}
+
+		if (of_property_read_u32(port, "rx-internal-delay-ps", &val))
+			val = 1;
+
+		if (val > QCA8K_MAX_DELAY) {
+			dev_err(priv->dev, "rgmii tx delay is limited to more than 3ps, setting to the max value");
+			priv->rgmii_tx_delay = 3;
+		} else {
+			priv->rgmii_rx_delay = val;
+		}
+	}
+
+	of_node_put(ports);
+
+	return 0;
+}
+
 static int
 qca8k_setup(struct dsa_switch *ds)
 {
@@ -808,6 +849,10 @@  qca8k_setup(struct dsa_switch *ds)
 	if (ret)
 		return ret;
 
+	ret = qca8k_setup_of_rgmii_delay(priv);
+	if (ret)
+		return ret;
+
 	/* Enable CPU Port */
 	ret = qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0,
 			    QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);
@@ -1018,8 +1063,10 @@  qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
 		 */
 		qca8k_write(priv, reg,
 			    QCA8K_PORT_PAD_RGMII_EN |
-			    QCA8K_PORT_PAD_RGMII_TX_DELAY(QCA8K_MAX_DELAY) |
-			    QCA8K_PORT_PAD_RGMII_RX_DELAY(QCA8K_MAX_DELAY));
+			    QCA8K_PORT_PAD_RGMII_TX_DELAY(priv->rgmii_tx_delay) |
+			    QCA8K_PORT_PAD_RGMII_RX_DELAY(priv->rgmii_rx_delay) |
+			    QCA8K_PORT_PAD_RGMII_TX_DELAY_EN |
+			    QCA8K_PORT_PAD_RGMII_RX_DELAY_EN);
 		/* QCA8337 requires to set rgmii rx delay */
 		if (data->id == QCA8K_ID_QCA8337)
 			qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL,
diff --git a/drivers/net/dsa/qca8k.h b/drivers/net/dsa/qca8k.h
index 0b503f78bf92..80830bb42736 100644
--- a/drivers/net/dsa/qca8k.h
+++ b/drivers/net/dsa/qca8k.h
@@ -36,12 +36,11 @@ 
 #define QCA8K_REG_PORT5_PAD_CTRL			0x008
 #define QCA8K_REG_PORT6_PAD_CTRL			0x00c
 #define   QCA8K_PORT_PAD_RGMII_EN			BIT(26)
-#define   QCA8K_PORT_PAD_RGMII_TX_DELAY(x)		\
-						((0x8 + (x & 0x3)) << 22)
-#define   QCA8K_PORT_PAD_RGMII_RX_DELAY(x)		\
-						((0x10 + (x & 0x3)) << 20)
-#define   QCA8K_MAX_DELAY				3
+#define   QCA8K_PORT_PAD_RGMII_TX_DELAY(x)		((x) << 22)
+#define   QCA8K_PORT_PAD_RGMII_RX_DELAY(x)		((x) << 20)
+#define	  QCA8K_PORT_PAD_RGMII_TX_DELAY_EN		BIT(25)
 #define   QCA8K_PORT_PAD_RGMII_RX_DELAY_EN		BIT(24)
+#define   QCA8K_MAX_DELAY				3
 #define   QCA8K_PORT_PAD_SGMII_EN			BIT(7)
 #define QCA8K_REG_PWS					0x010
 #define   QCA8K_PWS_SERDES_AEN_DIS			BIT(7)
@@ -251,6 +250,8 @@  struct qca8k_match_data {
 
 struct qca8k_priv {
 	u8 switch_revision;
+	u8 rgmii_tx_delay;
+	u8 rgmii_rx_delay;
 	struct regmap *regmap;
 	struct mii_bus *bus;
 	struct ar8xxx_port_status port_sts[QCA8K_NUM_PORTS];