diff mbox series

[RFC,net-next,07/10] net: dsa: microchip: apply rgmii tx and rx delay in phylink mac config

Message ID 20220712160308.13253-8-arun.ramadoss@microchip.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series net: dsa: microchip: add support for phylink mac config and link up | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/cc_maintainers success CCed 12 of 12 maintainers
netdev/build_clang success Errors and warnings before: 0 this patch: 0
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 109 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Arun Ramadoss July 12, 2022, 4:03 p.m. UTC
This patch apply the rgmii delay to the xmii tune adjust register based
on the interface selected in phylink mac config. There are two rgmii
port in LAN937x and value to be loaded in the register vary depends on
the port selected.

Signed-off-by: Arun Ramadoss <arun.ramadoss@microchip.com>
---
 drivers/net/dsa/microchip/lan937x_main.c | 61 ++++++++++++++++++++++++
 drivers/net/dsa/microchip/lan937x_reg.h  | 18 +++++++
 2 files changed, 79 insertions(+)

Comments

Vladimir Oltean July 19, 2022, 10:25 a.m. UTC | #1
On Tue, Jul 12, 2022 at 09:33:05PM +0530, Arun Ramadoss wrote:
> This patch apply the rgmii delay to the xmii tune adjust register based
> on the interface selected in phylink mac config. There are two rgmii
> port in LAN937x and value to be loaded in the register vary depends on
> the port selected.
> 
> Signed-off-by: Arun Ramadoss <arun.ramadoss@microchip.com>
> ---
>  drivers/net/dsa/microchip/lan937x_main.c | 61 ++++++++++++++++++++++++
>  drivers/net/dsa/microchip/lan937x_reg.h  | 18 +++++++
>  2 files changed, 79 insertions(+)
> 
> diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c
> index d86ffdf976b0..db88ea567ba6 100644
> --- a/drivers/net/dsa/microchip/lan937x_main.c
> +++ b/drivers/net/dsa/microchip/lan937x_main.c
> @@ -315,6 +315,45 @@ int lan937x_change_mtu(struct ksz_device *dev, int port, int new_mtu)
>  	return 0;
>  }
>  
> +static void lan937x_set_tune_adj(struct ksz_device *dev, int port,
> +				 u16 reg, u8 val)
> +{
> +	u16 data16;
> +
> +	ksz_pread16(dev, port, reg, &data16);
> +
> +	/* Update tune Adjust */
> +	data16 |= FIELD_PREP(PORT_TUNE_ADJ, val);
> +	ksz_pwrite16(dev, port, reg, data16);
> +
> +	/* write DLL reset to take effect */
> +	data16 |= PORT_DLL_RESET;
> +	ksz_pwrite16(dev, port, reg, data16);
> +}
> +
> +static void lan937x_set_rgmii_tx_delay(struct ksz_device *dev, int port)
> +{
> +	u8 val;
> +
> +	/* Apply different codes based on the ports as per characterization
> +	 * results
> +	 */

What characterization result are you referring to? Individual board
designers should do their own characterization, that's why they provide
a p->rgmii_tx_val in the device tree. The value provided there seems to
be ignored and unconditionally replaced with 2 ns here.

> +	val = (port == LAN937X_RGMII_1_PORT) ? RGMII_1_TX_DELAY_2NS :
> +		RGMII_2_TX_DELAY_2NS;
> +
> +	lan937x_set_tune_adj(dev, port, REG_PORT_XMII_CTRL_5, val);
> +}
> +
> +static void lan937x_set_rgmii_rx_delay(struct ksz_device *dev, int port)
> +{
> +	u8 val;
> +
> +	val = (port == LAN937X_RGMII_1_PORT) ? RGMII_1_RX_DELAY_2NS :
> +		RGMII_2_RX_DELAY_2NS;
> +
> +	lan937x_set_tune_adj(dev, port, REG_PORT_XMII_CTRL_4, val);
> +}
> +
>  void lan937x_phylink_get_caps(struct ksz_device *dev, int port,
>  			      struct phylink_config *config)
>  {
> @@ -331,6 +370,9 @@ void lan937x_phylink_mac_config(struct ksz_device *dev, int port,
>  				unsigned int mode,
>  				const struct phylink_link_state *state)
>  {
> +	phy_interface_t interface = state->interface;
> +	struct ksz_port *p = &dev->ports[port];
> +
>  	/* Internal PHYs */
>  	if (dev->info->internal_phy[port])
>  		return;
> @@ -341,6 +383,25 @@ void lan937x_phylink_mac_config(struct ksz_device *dev, int port,
>  	}
>  
>  	ksz_set_xmii(dev, port, state->interface);
> +
> +	/* if the delay is 0, do not enable DLL */
> +	if (interface == PHY_INTERFACE_MODE_RGMII_ID ||
> +	    interface == PHY_INTERFACE_MODE_RGMII_RXID) {

Why not all RGMII modes and only these 2? There was a discussion a long
time ago that the "_*ID" values refer to delays applied by an attached PHY.
Here you are refusing to apply RGMII TX delays in the "rgmii" and "rgmii-txid"
modes.

> +		if (p->rgmii_tx_val) {
> +			lan937x_set_rgmii_tx_delay(dev, port);
> +			dev_info(dev->dev, "Applied rgmii tx delay for the port %d\n",
> +				 port);
> +		}
> +	}
> +
> +	if (interface == PHY_INTERFACE_MODE_RGMII_ID ||
> +	    interface == PHY_INTERFACE_MODE_RGMII_TXID) {
> +		if (p->rgmii_rx_val) {
> +			lan937x_set_rgmii_rx_delay(dev, port);
> +			dev_info(dev->dev, "Applied rgmii rx delay for the port %d\n",
> +				 port);
> +		}
> +	}
>  }
>
Arun Ramadoss July 20, 2022, 2:51 p.m. UTC | #2
On Tue, 2022-07-19 at 13:25 +0300, Vladimir Oltean wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you
> know the content is safe
> 
> On Tue, Jul 12, 2022 at 09:33:05PM +0530, Arun Ramadoss wrote:
> > This patch apply the rgmii delay to the xmii tune adjust register
> > based
> > on the interface selected in phylink mac config. There are two
> > rgmii
> > port in LAN937x and value to be loaded in the register vary depends
> > on
> > the port selected.
> > 
> > Signed-off-by: Arun Ramadoss <arun.ramadoss@microchip.com>
> > ---
> >  drivers/net/dsa/microchip/lan937x_main.c | 61
> > ++++++++++++++++++++++++
> >  drivers/net/dsa/microchip/lan937x_reg.h  | 18 +++++++
> >  2 files changed, 79 insertions(+)
> > 
> > diff --git a/drivers/net/dsa/microchip/lan937x_main.c
> > b/drivers/net/dsa/microchip/lan937x_main.c
> > index d86ffdf976b0..db88ea567ba6 100644
> > --- a/drivers/net/dsa/microchip/lan937x_main.c
> > +++ b/drivers/net/dsa/microchip/lan937x_main.c
> > @@ -315,6 +315,45 @@ int lan937x_change_mtu(struct ksz_device *dev,
> > int port, int new_mtu)
> >       return 0;
> >  }
> > 
> > +
> > +static void lan937x_set_rgmii_tx_delay(struct ksz_device *dev, int
> > port)
> > +{
> > +     u8 val;
> > +
> > +     /* Apply different codes based on the ports as per
> > characterization
> > +      * results
> > +      */
> 
> What characterization result are you referring to? Individual board
> designers should do their own characterization, that's why they
> provide
> a p->rgmii_tx_val in the device tree. The value provided there seems
> to
> be ignored and unconditionally replaced with 2 ns here.

This is the value we got from the post silicon validation team which
has to be programmed to dll register to get the proper delay. The value
is different for rgmii 1 and rgmii2.

> 
> > +     val = (port == LAN937X_RGMII_1_PORT) ? RGMII_1_TX_DELAY_2NS :
> > +             RGMII_2_TX_DELAY_2NS;
> > +
> > +     lan937x_set_tune_adj(dev, port, REG_PORT_XMII_CTRL_5, val);
> > +}
> > +
> > +
> >  @@ -341,6 +383,25 @@ void lan937x_phylink_mac_config(struct
> > ksz_device *dev, int port,
> >       }
> > 
> >       ksz_set_xmii(dev, port, state->interface);
> > +
> > +     /* if the delay is 0, do not enable DLL */
> > +     if (interface == PHY_INTERFACE_MODE_RGMII_ID ||
> > +         interface == PHY_INTERFACE_MODE_RGMII_RXID) {
> 
> Why not all RGMII modes and only these 2? There was a discussion a
> long
> time ago that the "_*ID" values refer to delays applied by an
> attached PHY.
> Here you are refusing to apply RGMII TX delays in the "rgmii" and
> "rgmii-txid"
> modes.

I have reused the code of ksz9477 cpu config function and added the dll
configuration for lan937x family alone. And understood that if device
tree specificies as rgmii_txid then apply the egress delay, for
rgmii_rxid apply ingress delay, for rgmii_id apply both.
From your comment, I am inferring that apply the mac delay for all the
rgmii interface "rgmii*".
Can you correct me if am I wrong and bit elaborate on it.

> 
> > +             if (p->rgmii_tx_val) {
> > +                     lan937x_set_rgmii_tx_delay(dev, port);
> > +                     dev_info(dev->dev, "Applied rgmii tx delay
> > for the port %d\n",
> > +                              port);
> > +             }
> > +     }
> > +
> > +     if (interface == PHY_INTERFACE_MODE_RGMII_ID ||
> > +         interface == PHY_INTERFACE_MODE_RGMII_TXID) {
> > +             if (p->rgmii_rx_val) {
> > +                     lan937x_set_rgmii_rx_delay(dev, port);
> > +                     dev_info(dev->dev, "Applied rgmii rx delay
> > for the port %d\n",
> > +                              port);
> > +             }
> > +     }
> >  }
> >
Vladimir Oltean July 20, 2022, 9:04 p.m. UTC | #3
On Wed, Jul 20, 2022 at 02:51:42PM +0000, Arun.Ramadoss@microchip.com wrote:
> > Why not all RGMII modes and only these 2? There was a discussion a long
> > time ago that the "_*ID" values refer to delays applied by an attached PHY.
> > Here you are refusing to apply RGMII TX delays in the "rgmii" and "rgmii-txid"
> > modes.
> 
> I have reused the code of ksz9477 cpu config function and added the dll
> configuration for lan937x family alone. And understood that if device
> tree specificies as rgmii_txid then apply the egress delay, for
> rgmii_rxid apply ingress delay, for rgmii_id apply both.
> From your comment, I am inferring that apply the mac delay for all the
> rgmii interface "rgmii*".
> Can you correct me if am I wrong and bit elaborate on it.

What we are trying is to interpret what's written in
Documentation/devicetree/bindings/net/ethernet-controller.yaml in a way
that is consistent, even though its wording makes it evident that that
it was written in simpler times.

There it says:

      # RX and TX delays are added by the MAC when required
      - rgmii

      # RGMII with internal RX and TX delays provided by the PHY,
      # the MAC should not add the RX or TX delays in this case
      - rgmii-id

      # RGMII with internal RX delay provided by the PHY, the MAC
      # should not add an RX delay in this case
      - rgmii-rxid

      # RGMII with internal TX delay provided by the PHY, the MAC
      # should not add an TX delay in this case
      - rgmii-txid

The fact that the PHY adds delays in the directions specified by the
phy-mode value is established behavior; yet the MAC's behavior is pretty
much subject to interpretation, and this has resulted in varying
implementations in drivers.

The wise words above say that "RX and TX delays are added by the MAC
when required" - ok but when are they required? Determining this is
impossible based on the phy-mode alone, since there aren't just 2
degrees of freedom who may add delays (the PHY and the MAC). There also
exists the possibility of using serpentine traces (PCB delays), which
practically speaking, can't be described in phy-mode because then, a
potential PHY on the same link would also think they're for itself to
apply.

So the modern interpretation of phy-mode is to say that it simply does
not describe whether a MAC should apply delays in a direction or another.

So a separate set of properties was introduced, "rx-internal-delay-ps"
and "tx-internal-delay-ps". These have the advantage of being located
under the OF node of the MAC, and under the OF node of the PHY respectively.
So it's clearer which side is supposed to configure which delays, and
you also have finer control over the clock skew.

Initially when Prasanna first tried to upstream the lan937x, we discusssed
that since it's a new driver, it should support the modern interpretation
of RGMII delays, and we agreed on that strategy.

Now, with your recent refactoring that makes all switches share the same
probing logic (and OF node parsing), things are in a bit of a greyer area.

For one thing, you seem to have involuntarily inherited support for dubious
legacy bindings, such as the "phy-mode under the switch node" that is
described by commit edecfa98f602 ("net: dsa: microchip: look for
phy-mode in port nodes").

For another, you've inherited the existing interpretation of RGMII
delays from the KSZ9477 driver, which is that the driver interprets the
"phy-mode" as if it's a PHY (when in fact it's a MAC).

The KSZ9477 isn't by far the only MAC driver that applies RGMII delays
based on the phy-mode string, however in the past we made an effort to
update existing DSA drivers to the modern interpretation, see commits:

9ca482a246f0 ("net: dsa: sja1105: parse {rx, tx}-internal-delay-ps properties for RGMII delays")
5654ec78dd7e ("net: dsa: qca8k: rework rgmii delay logic and scan for cpu port 6")

There is a possibility to have a transitioning scheme: if the
"rx-internal-delay-ps" or "tx-internal-delay-ps" properties are present
under the MAC OF node, apply delays based on those. Otherwise, apply
delays based on phy-mode, and warn.

I'd appreciate if you could consider updating the KSZ common driver to
this interpretation of RGMII delays, so that the modern interpretation
becomes more widespread, and there are fewer places from which to copy a
non-standard one.
diff mbox series

Patch

diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c
index d86ffdf976b0..db88ea567ba6 100644
--- a/drivers/net/dsa/microchip/lan937x_main.c
+++ b/drivers/net/dsa/microchip/lan937x_main.c
@@ -315,6 +315,45 @@  int lan937x_change_mtu(struct ksz_device *dev, int port, int new_mtu)
 	return 0;
 }
 
+static void lan937x_set_tune_adj(struct ksz_device *dev, int port,
+				 u16 reg, u8 val)
+{
+	u16 data16;
+
+	ksz_pread16(dev, port, reg, &data16);
+
+	/* Update tune Adjust */
+	data16 |= FIELD_PREP(PORT_TUNE_ADJ, val);
+	ksz_pwrite16(dev, port, reg, data16);
+
+	/* write DLL reset to take effect */
+	data16 |= PORT_DLL_RESET;
+	ksz_pwrite16(dev, port, reg, data16);
+}
+
+static void lan937x_set_rgmii_tx_delay(struct ksz_device *dev, int port)
+{
+	u8 val;
+
+	/* Apply different codes based on the ports as per characterization
+	 * results
+	 */
+	val = (port == LAN937X_RGMII_1_PORT) ? RGMII_1_TX_DELAY_2NS :
+		RGMII_2_TX_DELAY_2NS;
+
+	lan937x_set_tune_adj(dev, port, REG_PORT_XMII_CTRL_5, val);
+}
+
+static void lan937x_set_rgmii_rx_delay(struct ksz_device *dev, int port)
+{
+	u8 val;
+
+	val = (port == LAN937X_RGMII_1_PORT) ? RGMII_1_RX_DELAY_2NS :
+		RGMII_2_RX_DELAY_2NS;
+
+	lan937x_set_tune_adj(dev, port, REG_PORT_XMII_CTRL_4, val);
+}
+
 void lan937x_phylink_get_caps(struct ksz_device *dev, int port,
 			      struct phylink_config *config)
 {
@@ -331,6 +370,9 @@  void lan937x_phylink_mac_config(struct ksz_device *dev, int port,
 				unsigned int mode,
 				const struct phylink_link_state *state)
 {
+	phy_interface_t interface = state->interface;
+	struct ksz_port *p = &dev->ports[port];
+
 	/* Internal PHYs */
 	if (dev->info->internal_phy[port])
 		return;
@@ -341,6 +383,25 @@  void lan937x_phylink_mac_config(struct ksz_device *dev, int port,
 	}
 
 	ksz_set_xmii(dev, port, state->interface);
+
+	/* if the delay is 0, do not enable DLL */
+	if (interface == PHY_INTERFACE_MODE_RGMII_ID ||
+	    interface == PHY_INTERFACE_MODE_RGMII_RXID) {
+		if (p->rgmii_tx_val) {
+			lan937x_set_rgmii_tx_delay(dev, port);
+			dev_info(dev->dev, "Applied rgmii tx delay for the port %d\n",
+				 port);
+		}
+	}
+
+	if (interface == PHY_INTERFACE_MODE_RGMII_ID ||
+	    interface == PHY_INTERFACE_MODE_RGMII_TXID) {
+		if (p->rgmii_rx_val) {
+			lan937x_set_rgmii_rx_delay(dev, port);
+			dev_info(dev->dev, "Applied rgmii rx delay for the port %d\n",
+				 port);
+		}
+	}
 }
 
 int lan937x_setup(struct dsa_switch *ds)
diff --git a/drivers/net/dsa/microchip/lan937x_reg.h b/drivers/net/dsa/microchip/lan937x_reg.h
index a6cb3ca22dc3..ba4adaddb3ec 100644
--- a/drivers/net/dsa/microchip/lan937x_reg.h
+++ b/drivers/net/dsa/microchip/lan937x_reg.h
@@ -136,6 +136,12 @@ 
 
 #define PORT_MII_SEL_EDGE		BIT(5)
 
+#define REG_PORT_XMII_CTRL_4		0x0304
+#define REG_PORT_XMII_CTRL_5		0x0306
+
+#define PORT_DLL_RESET			BIT(15)
+#define PORT_TUNE_ADJ			GENMASK(13, 7)
+
 /* 4 - MAC */
 #define REG_PORT_MAC_CTRL_0		0x0400
 #define PORT_CHECK_LENGTH		BIT(2)
@@ -161,6 +167,18 @@ 
 
 #define P_PRIO_CTRL			REG_PORT_MRI_PRIO_CTRL
 
+/* The port number as per the datasheet */
+#define RGMII_2_PORT_NUM		5
+#define RGMII_1_PORT_NUM		6
+
+#define LAN937X_RGMII_2_PORT		(RGMII_2_PORT_NUM - 1)
+#define LAN937X_RGMII_1_PORT		(RGMII_1_PORT_NUM - 1)
+
+#define RGMII_1_TX_DELAY_2NS		2
+#define RGMII_2_TX_DELAY_2NS		0
+#define RGMII_1_RX_DELAY_2NS		0x1B
+#define RGMII_2_RX_DELAY_2NS		0x14
+
 #define LAN937X_TAG_LEN			2
 
 #endif