[PATCH 00/14] Add support for Ethernet interfaces on RZ/G2L

This patch series enables the usage of both Ethernet interfaces on the Renesas RZ/G2L SMARC EVK board. This requires changes to the RZ/G2L clock driver, RZ/G2L pinctrl driver, ksz9131 phy driver and ravb network driver. Once all drivers have the required support, we enable the relevant options in the RZ/G2L defconfig and cherry-pick required devicetree changes from Linux v6.12-rc4.
Paul Barker (14): clk: rzg2l: Ignore enable for core clocks pinctrl: rzg2l: Support 2.5V PVDD for Ethernet interfaces pinctrl: rzg2l: Support Ethernet TXC output enable pinctrl: rzg2l: Drop unnecessary scope net: phy: Port set/clear bits from Linux net: phy: ksz90x1: Handle ksz9131 LED errata net: phy: ksz90x1: Load skew values from device tree net: phy: ksz90x1: Simplify ksz9131_config_rgmii_delay net: ravb: Support up to two instances net: ravb: Simplify max-speed handling in ravb_of_to_plat net: ravb: Add RZ/G2L Support renesas_rzg2l_smarc_defconfig: Enable networking support arm64: dts: renesas: rzg2l: Enable Ethernet TXC output arm64: dts: renesas: rzg2l: Set Ethernet PVDD to 1.8V
arch/arm/mach-renesas/Kconfig | 1 + configs/renesas_rzg2l_smarc_defconfig | 6 + drivers/clk/renesas/rzg2l-cpg.c | 8 + drivers/net/Kconfig | 2 + drivers/net/phy/micrel_ksz90x1.c | 161 +++++++++++-- drivers/net/ravb.c | 216 ++++++++++++++++-- drivers/pinctrl/renesas/rzg2l-pfc.c | 83 +++++-- .../src/arm64/renesas/rzg2l-smarc-som.dtsi | 86 ++++--- include/phy.h | 22 ++ include/renesas/rzg2l-pfc.h | 4 + 10 files changed, 505 insertions(+), 84 deletions(-)

In the RZ/G2L family, core clocks are always on and can't be disabled. However, drivers which are shared with other SoCs may call clk_enable() or clk_enable_bulk() for a clock referenced in the device tree which happens to be a core clock on the RZ/G2L. To avoid the need for conditionals in these drivers, simply ignore attempts to enable a core clock.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com --- drivers/clk/renesas/rzg2l-cpg.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index c8735d869cf9..3c5340df8eed 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -69,7 +69,15 @@ static int rzg2l_cpg_clk_set(struct clk *clk, bool enable)
dev_dbg(clk->dev, "%s %s clock %u\n", enable ? "enable" : "disable", is_mod_clk(clk->id) ? "module" : "core", cpg_clk_id); + if (!is_mod_clk(clk->id)) { + /* + * Non-module clocks are always on. Ignore attempts to enable + * them and reject attempts to disable them. + */ + if (enable) + return 0; + dev_err(clk->dev, "ID %lu is not a module clock\n", clk->id); return -EINVAL; }

On 10/24/24 5:24 PM, Paul Barker wrote:
In the RZ/G2L family, core clocks are always on and can't be disabled. However, drivers which are shared with other SoCs may call clk_enable() or clk_enable_bulk() for a clock referenced in the device tree which happens to be a core clock on the RZ/G2L. To avoid the need for conditionals in these drivers, simply ignore attempts to enable a core clock.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com
Reviewed-by: Marek Vasut marek.vasut+renesas@mailbox.org

The Ethenet interfaces on the Renesas RZ/G2L SoC family can operate at multiple power supply voltages: 3.3V (default value), 2.5V and 1.8V.
rzg2l_pinconf_set() is extended to support the 2.5V setting, with a check to ensure this is only used on Ethernet interfaces as it is not supported on the SD & QSPI interfaces.
While we're modifying rzg2l_pinconf_set(), drop the unnecessary default value for pwr_reg as it is set in every branch of the following if condition.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com --- drivers/pinctrl/renesas/rzg2l-pfc.c | 49 ++++++++++++++++++++--------- include/renesas/rzg2l-pfc.h | 2 ++ 2 files changed, 37 insertions(+), 14 deletions(-)
diff --git a/drivers/pinctrl/renesas/rzg2l-pfc.c b/drivers/pinctrl/renesas/rzg2l-pfc.c index e88ec1c18373..0098e2d52d57 100644 --- a/drivers/pinctrl/renesas/rzg2l-pfc.c +++ b/drivers/pinctrl/renesas/rzg2l-pfc.c @@ -394,18 +394,10 @@ static int rzg2l_pinconf_set(struct udevice *dev, unsigned int pin_selector, }
case PIN_CONFIG_POWER_SOURCE: { - u32 pwr_reg = 0x0; + bool support_2500 = false; + u32 pwr_reg; + u32 value;
- /* argument is in mV */ - if (argument != 1800 && argument != 3300) { - dev_err(dev, "Invalid mV %u\n", argument); - return -EINVAL; - } - - /* - * TODO: PIN_CFG_IO_VMC_ETH0 & PIN_CFG_IO_VMC_ETH1 will be - * handled when the RZ/G2L Ethernet driver is added. - */ if (cfg & PIN_CFG_IO_VMC_SD0) { dev_dbg(dev, "port off %u:%u set SD_CH 0 PVDD=%u\n", port_offset, pin, argument); @@ -418,13 +410,42 @@ static int rzg2l_pinconf_set(struct udevice *dev, unsigned int pin_selector, dev_dbg(dev, "port off %u:%u set QSPI PVDD=%u\n", port_offset, pin, argument); pwr_reg = QSPI; + } else if (cfg & PIN_CFG_IO_VMC_ETH0) { + dev_dbg(dev, "port off %u:%u set ETH0 PVDD=%u\n", + port_offset, pin, argument); + pwr_reg = ETH_POC(0); + support_2500 = true; + } else if (cfg & PIN_CFG_IO_VMC_ETH1) { + dev_dbg(dev, "port off %u:%u set ETH1 PVDD=%u\n", + port_offset, pin, argument); + pwr_reg = ETH_POC(1); + support_2500 = true; } else { - dev_dbg(dev, "pin power source is not selectable\n"); + dev_dbg(dev, "port off %u:%u PVDD is not selectable\n", + port_offset, pin); + return -EINVAL; + } + + /* argument is in mV */ + switch (argument) { + case 1800: + value = PVDD_1800; + break; + case 3300: + value = PVDD_3300; + break; + case 2500: + if (support_2500) { + value = PVDD_2500; + break; + } + fallthrough; + default: + dev_err(dev, "Invalid mV %u\n", argument); return -EINVAL; }
- writel((argument == 1800) ? PVDD_1800 : PVDD_3300, - data->base + pwr_reg); + writel(value, data->base + pwr_reg); break; }
diff --git a/include/renesas/rzg2l-pfc.h b/include/renesas/rzg2l-pfc.h index 2df17ece2a31..d1015b1d2ac1 100644 --- a/include/renesas/rzg2l-pfc.h +++ b/include/renesas/rzg2l-pfc.h @@ -77,9 +77,11 @@ #define IEN(n) (0x1800 + (n) * 8) #define PWPR 0x3014 #define SD_CH(n) (0x3000 + (n) * 4) +#define ETH_POC(ch) (0x300c + (ch) * 4) #define QSPI 0x3008
#define PVDD_1800 1 /* I/O domain voltage <= 1.8V */ +#define PVDD_2500 2 /* I/O domain voltage 2.5V */ #define PVDD_3300 0 /* I/O domain voltage >= 3.3V */
#define PWPR_B0WI BIT(7) /* Bit Write Disable */

On 10/24/24 5:24 PM, Paul Barker wrote:
The Ethenet interfaces on the Renesas RZ/G2L SoC family can operate at multiple power supply voltages: 3.3V (default value), 2.5V and 1.8V.
rzg2l_pinconf_set() is extended to support the 2.5V setting, with a check to ensure this is only used on Ethernet interfaces as it is not supported on the SD & QSPI interfaces.
While we're modifying rzg2l_pinconf_set(), drop the unnecessary default value for pwr_reg as it is set in every branch of the following if condition.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com
Is this ported from Linux ? If so, please include the Linux kernel commit in the commit message, else ignore this comment.

On 27/10/2024 16:14, Marek Vasut wrote:
On 10/24/24 5:24 PM, Paul Barker wrote:
The Ethenet interfaces on the Renesas RZ/G2L SoC family can operate at multiple power supply voltages: 3.3V (default value), 2.5V and 1.8V.
rzg2l_pinconf_set() is extended to support the 2.5V setting, with a check to ensure this is only used on Ethernet interfaces as it is not supported on the SD & QSPI interfaces.
While we're modifying rzg2l_pinconf_set(), drop the unnecessary default value for pwr_reg as it is set in every branch of the following if condition.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com
Is this ported from Linux ? If so, please include the Linux kernel commit in the commit message, else ignore this comment.
This was re-implemented in U-Boot instead of porting Linux commits (51996952b8b50 and cd27553b0dee6) due to differences between the existing RZ/G2L pinctrl code in Linux and U-Boot.
Thanks,

On the RZ/G2L SoC family, the direction of the Ethernet TXC/TX_CLK signal is selectable to support an Ethernet PHY operating in either MII or RGMII mode. By default, the signal is configured as an input and MII mode is supported. The ETH_MODE register can be modified to configure this signal as an output to support RGMII mode.
As this signal is be default an input, and can optionally be switched to an output, it maps neatly onto an `output-enable` property in the device tree.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com --- drivers/pinctrl/renesas/rzg2l-pfc.c | 31 +++++++++++++++++++++++++++-- include/renesas/rzg2l-pfc.h | 2 ++ 2 files changed, 31 insertions(+), 2 deletions(-)
diff --git a/drivers/pinctrl/renesas/rzg2l-pfc.c b/drivers/pinctrl/renesas/rzg2l-pfc.c index 0098e2d52d57..af371bd0ff1e 100644 --- a/drivers/pinctrl/renesas/rzg2l-pfc.c +++ b/drivers/pinctrl/renesas/rzg2l-pfc.c @@ -180,7 +180,7 @@ static const u32 r9a07g044_gpio_configs[] = { RZG2L_GPIO_PORT_PACK(3, 0x21, RZG2L_MPXED_PIN_FUNCS), RZG2L_GPIO_PORT_PACK(2, 0x22, RZG2L_MPXED_PIN_FUNCS), RZG2L_GPIO_PORT_PACK(2, 0x23, RZG2L_MPXED_PIN_FUNCS), - RZG2L_GPIO_PORT_PACK(3, 0x24, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)), + RZG2L_GPIO_PORT_PACK(3, 0x24, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0) | PIN_CFG_OEN), RZG2L_GPIO_PORT_PACK(2, 0x25, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)), RZG2L_GPIO_PORT_PACK(2, 0x26, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)), RZG2L_GPIO_PORT_PACK(2, 0x27, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)), @@ -189,7 +189,7 @@ static const u32 r9a07g044_gpio_configs[] = { RZG2L_GPIO_PORT_PACK(2, 0x2a, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)), RZG2L_GPIO_PORT_PACK(2, 0x2b, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)), RZG2L_GPIO_PORT_PACK(2, 0x2c, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH0)), - RZG2L_GPIO_PORT_PACK(2, 0x2d, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1)), + RZG2L_GPIO_PORT_PACK(2, 0x2d, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1) | PIN_CFG_OEN), RZG2L_GPIO_PORT_PACK(2, 0x2e, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1)), RZG2L_GPIO_PORT_PACK(2, 0x2f, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1)), RZG2L_GPIO_PORT_PACK(2, 0x30, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IO_VMC_ETH1)), @@ -449,6 +449,32 @@ static int rzg2l_pinconf_set(struct udevice *dev, unsigned int pin_selector, break; }
+ case PIN_CONFIG_OUTPUT_ENABLE: { + u8 ch; + + if (!(cfg & PIN_CFG_OEN)) { + dev_err(dev, "pin does not support OEN\n"); + return -EINVAL; + } + + /* + * We can determine which Ethernet interface we're dealing with from + * the caps. + */ + if (cfg & PIN_CFG_IO_VMC_ETH0) + ch = 0; + else /* PIN_CFG_IO_VMC_ETH1 */ + ch = 1; + + dev_dbg(dev, "set ETH%u TXC OEN=%u\n", ch, argument); + if (argument) + clrbits_8(data->base + ETH_MODE, BIT(ch)); + else + setbits_8(data->base + ETH_MODE, BIT(ch)); + + break; + } + default: dev_err(dev, "Invalid pinconf parameter\n"); return -EOPNOTSUPP; @@ -542,6 +568,7 @@ static int rzg2l_get_pin_muxing(struct udevice *dev, unsigned int selector,
static const struct pinconf_param rzg2l_pinconf_params[] = { { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 }, + { "output-enable", PIN_CONFIG_OUTPUT_ENABLE, 1 }, { "power-source", PIN_CONFIG_POWER_SOURCE, 3300 /* mV */ }, };
diff --git a/include/renesas/rzg2l-pfc.h b/include/renesas/rzg2l-pfc.h index d1015b1d2ac1..36fa8da8e2e4 100644 --- a/include/renesas/rzg2l-pfc.h +++ b/include/renesas/rzg2l-pfc.h @@ -22,6 +22,7 @@ #define PIN_CFG_FILONOFF BIT(10) #define PIN_CFG_FILNUM BIT(11) #define PIN_CFG_FILCLKSEL BIT(12) +#define PIN_CFG_OEN BIT(13)
#define RZG2L_MPXED_PIN_FUNCS (PIN_CFG_IOLH_A | \ PIN_CFG_SR | \ @@ -79,6 +80,7 @@ #define SD_CH(n) (0x3000 + (n) * 4) #define ETH_POC(ch) (0x300c + (ch) * 4) #define QSPI 0x3008 +#define ETH_MODE (0x3018)
#define PVDD_1800 1 /* I/O domain voltage <= 1.8V */ #define PVDD_2500 2 /* I/O domain voltage 2.5V */

On 10/24/24 5:24 PM, Paul Barker wrote:
On the RZ/G2L SoC family, the direction of the Ethernet TXC/TX_CLK signal is selectable to support an Ethernet PHY operating in either MII or RGMII mode. By default, the signal is configured as an input and MII mode is supported. The ETH_MODE register can be modified to configure this signal as an output to support RGMII mode.
As this signal is be default an input, and can optionally be switched to an output, it maps neatly onto an `output-enable` property in the device tree.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com
Same comment as on 2/14 regarding kernel commits.
Is this something which should be configured in DT instead ?

On 27/10/2024 16:15, Marek Vasut wrote:
On 10/24/24 5:24 PM, Paul Barker wrote:
On the RZ/G2L SoC family, the direction of the Ethernet TXC/TX_CLK signal is selectable to support an Ethernet PHY operating in either MII or RGMII mode. By default, the signal is configured as an input and MII mode is supported. The ETH_MODE register can be modified to configure this signal as an output to support RGMII mode.
As this signal is be default an input, and can optionally be switched to an output, it maps neatly onto an `output-enable` property in the device tree.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com
Same comment as on 2/14 regarding kernel commits.
This was re-implemented in U-Boot due to differences between the existing RZ/G2L pinctrl code in Linux and U-Boot.
Is this something which should be configured in DT instead ?
This patch adds support for configuring it in the DT, using the 'output-enable' property. You can see this used later in this series in the device tree patch to enable Ethernet TXC output [1].
[1]: https://msgid.link/20241024152448.102-14-paul.barker.ct@bp.renesas.com
Thanks,

In rzg2l_pinconf_set(), there are no new variables defined in the case statement for PIN_CONFIG_INPUT_ENABLE so no additional scope is needed.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com --- drivers/pinctrl/renesas/rzg2l-pfc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/pinctrl/renesas/rzg2l-pfc.c b/drivers/pinctrl/renesas/rzg2l-pfc.c index af371bd0ff1e..3c751e9473a5 100644 --- a/drivers/pinctrl/renesas/rzg2l-pfc.c +++ b/drivers/pinctrl/renesas/rzg2l-pfc.c @@ -381,7 +381,7 @@ static int rzg2l_pinconf_set(struct udevice *dev, unsigned int pin_selector, }
switch (param) { - case PIN_CONFIG_INPUT_ENABLE: { + case PIN_CONFIG_INPUT_ENABLE: if (!(cfg & PIN_CFG_IEN)) { dev_err(dev, "pin does not support IEN\n"); return -EINVAL; @@ -391,7 +391,6 @@ static int rzg2l_pinconf_set(struct udevice *dev, unsigned int pin_selector, port_offset, pin, argument); rzg2l_rmw_pin_config(data, IEN(port_offset), pin, IEN_MASK, !!argument); break; - }
case PIN_CONFIG_POWER_SOURCE: { bool support_2500 = false;

On 10/24/24 5:24 PM, Paul Barker wrote:
In rzg2l_pinconf_set(), there are no new variables defined in the case statement for PIN_CONFIG_INPUT_ENABLE so no additional scope is needed.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com
Reviewed-by: Marek Vasut marek.vasut+renesas@mailbox.org
btw. it might make sense to split the series per subsystem so it can go in piece by piece.

On 27/10/2024 16:16, Marek Vasut wrote:
On 10/24/24 5:24 PM, Paul Barker wrote:
In rzg2l_pinconf_set(), there are no new variables defined in the case statement for PIN_CONFIG_INPUT_ENABLE so no additional scope is needed.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com
Reviewed-by: Marek Vasut marek.vasut+renesas@mailbox.org
btw. it might make sense to split the series per subsystem so it can go in piece by piece.
I could split this into clk (patch 1), pinctrl (patch 2-4), Ethernet phy (patch 5-8) and ravb prep patches (9-10), sent as independent series. The support for RZ/G2L Ethernet (patches 11 & 12) would have to wait until all those series are merged. The devicetree changes (patches 13 & 14) could be sent once the pinctrl patches are merged.
I think that this would delay things and prevent RZ/G2L Ethernet support from landing in v2024.01, so I sent this as one series. I can break it up if needed though. Let me know what you would prefer.
Thanks,

On 10/28/24 9:27 AM, Paul Barker wrote:
On 27/10/2024 16:16, Marek Vasut wrote:
On 10/24/24 5:24 PM, Paul Barker wrote:
In rzg2l_pinconf_set(), there are no new variables defined in the case statement for PIN_CONFIG_INPUT_ENABLE so no additional scope is needed.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com
Reviewed-by: Marek Vasut marek.vasut+renesas@mailbox.org
btw. it might make sense to split the series per subsystem so it can go in piece by piece.
I could split this into clk (patch 1), pinctrl (patch 2-4), Ethernet phy (patch 5-8) and ravb prep patches (9-10), sent as independent series.
Yes please.
The support for RZ/G2L Ethernet (patches 11 & 12) would have to wait until all those series are merged. The devicetree changes (patches 13 & 14) could be sent once the pinctrl patches are merged.
Or just include a patchwork links to the dependencies.
I think that this would delay things and prevent RZ/G2L Ethernet support from landing in v2024.01, so I sent this as one series. I can break it up if needed though. Let me know what you would prefer.
Please break it up, I'll try to pick it into 2025.01 still. It is easier to pick it in more manageable chunks.

To simply porting phy drivers from Linux to U-Boot, define phy_set_bits() and phy_clear_bits() functions with a similar API to those used in Linux.
The U-Boot versions of these functions include the `devad` argument which is not present in the Linux versions, to keep them aligned with the other phy functions in U-Boot.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com --- include/phy.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
diff --git a/include/phy.h b/include/phy.h index 36785031eeb0..510b0a21831b 100644 --- a/include/phy.h +++ b/include/phy.h @@ -333,6 +333,28 @@ int gen10g_startup(struct phy_device *phydev); int gen10g_shutdown(struct phy_device *phydev); int gen10g_discover_mmds(struct phy_device *phydev);
+/** + * phy_set_bits - Convenience function for setting bits in a PHY register + * @phydev: the phy_device struct + * @regnum: register number to write + * @val: bits to set + */ +static inline int phy_set_bits(struct phy_device *phydev, int devad, u32 regnum, u16 val) +{ + return phy_modify(phydev, devad, regnum, 0, val); +} + +/** + * phy_clear_bits - Convenience function for clearing bits in a PHY register + * @phydev: the phy_device struct + * @regnum: register number to write + * @val: bits to clear + */ +static inline int phy_clear_bits(struct phy_device *phydev, int devad, u32 regnum, u16 val) +{ + return phy_modify(phydev, devad, regnum, val, 0); +} + /** * U_BOOT_PHY_DRIVER() - Declare a new U-Boot driver * @__name: name of the driver

On 10/24/24 5:24 PM, Paul Barker wrote:
To simply porting phy drivers from Linux to U-Boot, define phy_set_bits() and phy_clear_bits() functions with a similar API to those used in Linux.
The U-Boot versions of these functions include the `devad` argument which is not present in the Linux versions, to keep them aligned with the other phy functions in U-Boot.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com
Reviewed-by: Marek Vasut marek.vasut+renesas@mailbox.org

Micrel KSZ9131 PHY LED behavior is not correct when configured in Individual Mode, LED1 (Activity LED) is in the ON state when there is no-link.
Workaround this by setting bit 9 of register 0x1e after verifying that the LED configuration is Individual Mode.
This issue is described in KSZ9131RNX Silicon Errata DS80000693B [*] and according to that it will not be corrected in a future silicon revision.
[*] https://ww1.microchip.com/downloads/en/DeviceDoc/KSZ9131RNX-Silicon-Errata-a...
Based on commit 0316c7e66bbd in the Linux kernel.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com --- drivers/net/phy/micrel_ksz90x1.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
diff --git a/drivers/net/phy/micrel_ksz90x1.c b/drivers/net/phy/micrel_ksz90x1.c index c48ae6e88f30..4f99b115a3c7 100644 --- a/drivers/net/phy/micrel_ksz90x1.c +++ b/drivers/net/phy/micrel_ksz90x1.c @@ -436,6 +436,26 @@ static int ksz9131_config_rgmii_delay(struct phy_device *phydev) return ret; }
+/* Silicon Errata DS80000693B + * + * When LEDs are configured in Individual Mode, LED1 is ON in a no-link + * condition. Workaround is to set register 0x1e, bit 9, this way LED1 behaves + * according to the datasheet (off if there is no link). + */ +static int ksz9131_led_errata(struct phy_device *phydev) +{ + int reg; + + reg = phy_read_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG, 0); + if (reg < 0) + return reg; + + if (!(reg & BIT(4))) + return 0; + + return phy_set_bits(phydev, MDIO_DEVAD_NONE, 0x1e, BIT(9)); +} + static int ksz9131_config(struct phy_device *phydev) { int ret; @@ -446,6 +466,10 @@ static int ksz9131_config(struct phy_device *phydev) return ret; }
+ ret = ksz9131_led_errata(phydev); + if (ret < 0) + return ret; + /* add an option to disable the gigabit feature of this PHY */ if (env_get("disable_giga")) { unsigned features;

On 10/24/24 5:24 PM, Paul Barker wrote:
Micrel KSZ9131 PHY LED behavior is not correct when configured in Individual Mode, LED1 (Activity LED) is in the ON state when there is no-link.
Workaround this by setting bit 9 of register 0x1e after verifying that the LED configuration is Individual Mode.
This issue is described in KSZ9131RNX Silicon Errata DS80000693B [*] and according to that it will not be corrected in a future silicon revision.
[*] https://ww1.microchip.com/downloads/en/DeviceDoc/KSZ9131RNX-Silicon-Errata-a...
Based on commit 0316c7e66bbd in the Linux kernel.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com
drivers/net/phy/micrel_ksz90x1.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
diff --git a/drivers/net/phy/micrel_ksz90x1.c b/drivers/net/phy/micrel_ksz90x1.c index c48ae6e88f30..4f99b115a3c7 100644 --- a/drivers/net/phy/micrel_ksz90x1.c +++ b/drivers/net/phy/micrel_ksz90x1.c @@ -436,6 +436,26 @@ static int ksz9131_config_rgmii_delay(struct phy_device *phydev) return ret; }
+/* Silicon Errata DS80000693B
- When LEDs are configured in Individual Mode, LED1 is ON in a no-link
- condition. Workaround is to set register 0x1e, bit 9, this way LED1 behaves
- according to the datasheet (off if there is no link).
- */
+static int ksz9131_led_errata(struct phy_device *phydev) +{
- int reg;
- reg = phy_read_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG, 0);
- if (reg < 0)
return reg;
- if (!(reg & BIT(4)))
It would be good to have symbolic names for these BIT()s , please add some #define ... macros .

On 27/10/2024 16:18, Marek Vasut wrote:
On 10/24/24 5:24 PM, Paul Barker wrote:
Micrel KSZ9131 PHY LED behavior is not correct when configured in Individual Mode, LED1 (Activity LED) is in the ON state when there is no-link.
Workaround this by setting bit 9 of register 0x1e after verifying that the LED configuration is Individual Mode.
This issue is described in KSZ9131RNX Silicon Errata DS80000693B [*] and according to that it will not be corrected in a future silicon revision.
[*] https://ww1.microchip.com/downloads/en/DeviceDoc/KSZ9131RNX-Silicon-Errata-a...
Based on commit 0316c7e66bbd in the Linux kernel.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com
drivers/net/phy/micrel_ksz90x1.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
diff --git a/drivers/net/phy/micrel_ksz90x1.c b/drivers/net/phy/micrel_ksz90x1.c index c48ae6e88f30..4f99b115a3c7 100644 --- a/drivers/net/phy/micrel_ksz90x1.c +++ b/drivers/net/phy/micrel_ksz90x1.c @@ -436,6 +436,26 @@ static int ksz9131_config_rgmii_delay(struct phy_device *phydev) return ret; }
+/* Silicon Errata DS80000693B
- When LEDs are configured in Individual Mode, LED1 is ON in a no-link
- condition. Workaround is to set register 0x1e, bit 9, this way LED1 behaves
- according to the datasheet (off if there is no link).
- */
+static int ksz9131_led_errata(struct phy_device *phydev) +{
- int reg;
- reg = phy_read_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG, 0);
- if (reg < 0)
return reg;
- if (!(reg & BIT(4)))
It would be good to have symbolic names for these BIT()s , please add some #define ... macros .
I can add symbolic names for the values used above (KSZ9131RN_COMMON_CTRL=0 and KSZ9131RN_COMMON_CTRL_LED_MODE=BIT(4)).
The arguments used in the following phy_set_bits() call are a bit trickier - all the errata document says is "Register 0x1E (30d), bit 9 must be set to 1". The Linux kernel commit adding this workaround doesn't have any symbolic names either.
Thanks,

On 10/28/24 9:47 AM, Paul Barker wrote:
On 27/10/2024 16:18, Marek Vasut wrote:
On 10/24/24 5:24 PM, Paul Barker wrote:
Micrel KSZ9131 PHY LED behavior is not correct when configured in Individual Mode, LED1 (Activity LED) is in the ON state when there is no-link.
Workaround this by setting bit 9 of register 0x1e after verifying that the LED configuration is Individual Mode.
This issue is described in KSZ9131RNX Silicon Errata DS80000693B [*] and according to that it will not be corrected in a future silicon revision.
[*] https://ww1.microchip.com/downloads/en/DeviceDoc/KSZ9131RNX-Silicon-Errata-a...
Based on commit 0316c7e66bbd in the Linux kernel.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com
drivers/net/phy/micrel_ksz90x1.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
diff --git a/drivers/net/phy/micrel_ksz90x1.c b/drivers/net/phy/micrel_ksz90x1.c index c48ae6e88f30..4f99b115a3c7 100644 --- a/drivers/net/phy/micrel_ksz90x1.c +++ b/drivers/net/phy/micrel_ksz90x1.c @@ -436,6 +436,26 @@ static int ksz9131_config_rgmii_delay(struct phy_device *phydev) return ret; }
+/* Silicon Errata DS80000693B
- When LEDs are configured in Individual Mode, LED1 is ON in a no-link
- condition. Workaround is to set register 0x1e, bit 9, this way LED1 behaves
- according to the datasheet (off if there is no link).
- */
+static int ksz9131_led_errata(struct phy_device *phydev) +{
- int reg;
- reg = phy_read_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG, 0);
- if (reg < 0)
return reg;
- if (!(reg & BIT(4)))
It would be good to have symbolic names for these BIT()s , please add some #define ... macros .
I can add symbolic names for the values used above (KSZ9131RN_COMMON_CTRL=0 and KSZ9131RN_COMMON_CTRL_LED_MODE=BIT(4)).
The arguments used in the following phy_set_bits() call are a bit trickier - all the errata document says is "Register 0x1E (30d), bit 9 must be set to 1". The Linux kernel commit adding this workaround doesn't have any symbolic names either.
Maybe also send a kernel patch ?

Various signal skew values may be set in the device tree for the ksz9131 Ethernet PHY. For example, the RZ/G2L board requires non-default values for rxc-skew-psec & txc-skew-psec.
This is based on the ksz9131 phy driver in Linux v6.11.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com --- drivers/net/phy/micrel_ksz90x1.c | 115 +++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+)
diff --git a/drivers/net/phy/micrel_ksz90x1.c b/drivers/net/phy/micrel_ksz90x1.c index 4f99b115a3c7..b64046e0bc72 100644 --- a/drivers/net/phy/micrel_ksz90x1.c +++ b/drivers/net/phy/micrel_ksz90x1.c @@ -389,6 +389,117 @@ U_BOOT_PHY_DRIVER(ksz9031) = { #define KSZ9131RN_DLL_ENABLE_DELAY 0 #define KSZ9131RN_DLL_DISABLE_DELAY BIT(12)
+#define KSZ9131RN_CONTROL_PAD_SKEW 4 +#define KSZ9131RN_RX_DATA_PAD_SKEW 5 +#define KSZ9131RN_TX_DATA_PAD_SKEW 6 +#define KSZ9131RN_CLK_PAD_SKEW 8 + +#define KSZ9131RN_SKEW_5BIT_MAX 2400 +#define KSZ9131RN_SKEW_4BIT_MAX 800 +#define KSZ9131RN_OFFSET 700 +#define KSZ9131RN_STEP 100 + +static int ksz9131_of_load_skew_values(struct phy_device *phydev, + ofnode of_node, + u16 reg, size_t field_sz, + const char *field[], u8 numfields) +{ + int val[4] = {-(1 + KSZ9131RN_OFFSET), -(2 + KSZ9131RN_OFFSET), + -(3 + KSZ9131RN_OFFSET), -(4 + KSZ9131RN_OFFSET)}; + int skewval, skewmax = 0; + int matches = 0; + u16 maxval; + u16 newval; + u16 mask; + int i; + + /* psec properties in dts should mean x pico seconds */ + if (field_sz == 5) + skewmax = KSZ9131RN_SKEW_5BIT_MAX; + else + skewmax = KSZ9131RN_SKEW_4BIT_MAX; + + for (i = 0; i < numfields; i++) + if (!ofnode_read_s32(of_node, field[i], &skewval)) { + if (skewval < -KSZ9131RN_OFFSET) + skewval = -KSZ9131RN_OFFSET; + else if (skewval > skewmax) + skewval = skewmax; + + val[i] = skewval + KSZ9131RN_OFFSET; + matches++; + } + + if (!matches) + return 0; + + if (matches < numfields) + newval = phy_read_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG, reg); + else + newval = 0; + + maxval = (field_sz == 4) ? 0xf : 0x1f; + for (i = 0; i < numfields; i++) + if (val[i] != -(i + 1 + KSZ9131RN_OFFSET)) { + mask = 0xffff; + mask ^= maxval << (field_sz * i); + newval = (newval & mask) | + (((val[i] / KSZ9131RN_STEP) & maxval) + << (field_sz * i)); + } + + return phy_write_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG, reg, newval); +} + +static int ksz9131_of_load_all_skew_values(struct phy_device *phydev) +{ + const char *control_skews[2] = { "txen-skew-psec", "rxdv-skew-psec" }; + const char *clk_skews[2] = { "rxc-skew-psec", "txc-skew-psec" }; + const char *rx_data_skews[4] = { + "rxd0-skew-psec", "rxd1-skew-psec", + "rxd2-skew-psec", "rxd3-skew-psec" + }; + const char *tx_data_skews[4] = { + "txd0-skew-psec", "txd1-skew-psec", + "txd2-skew-psec", "txd3-skew-psec" + }; + struct ofnode_phandle_args phandle_args; + int ret; + + /* + * Silently ignore failure here as the device tree is not required to + * contain a phy node. + */ + if (dev_read_phandle_with_args(phydev->dev, "phy-handle", NULL, 0, 0, + &phandle_args)) + return 0; + + if (!ofnode_valid(phandle_args.node)) + return 0; + + ret = ksz9131_of_load_skew_values(phydev, phandle_args.node, + KSZ9131RN_CLK_PAD_SKEW, 5, + clk_skews, 2); + if (ret < 0) + return ret; + + ret = ksz9131_of_load_skew_values(phydev, phandle_args.node, + KSZ9131RN_CONTROL_PAD_SKEW, 4, + control_skews, 2); + if (ret < 0) + return ret; + + ret = ksz9131_of_load_skew_values(phydev, phandle_args.node, + KSZ9131RN_RX_DATA_PAD_SKEW, 4, + rx_data_skews, 4); + if (ret < 0) + return ret; + + return ksz9131_of_load_skew_values(phydev, phandle_args.node, + KSZ9131RN_TX_DATA_PAD_SKEW, 4, + tx_data_skews, 4); +} + static int ksz9131_config_rgmii_delay(struct phy_device *phydev) { struct phy_driver *drv = phydev->drv; @@ -466,6 +577,10 @@ static int ksz9131_config(struct phy_device *phydev) return ret; }
+ ret = ksz9131_of_load_all_skew_values(phydev); + if (ret < 0) + return ret; + ret = ksz9131_led_errata(phydev); if (ret < 0) return ret;

On 10/24/24 5:24 PM, Paul Barker wrote:
Various signal skew values may be set in the device tree for the ksz9131 Ethernet PHY. For example, the RZ/G2L board requires non-default values for rxc-skew-psec & txc-skew-psec.
This is based on the ksz9131 phy driver in Linux v6.11.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com
Reviewed-by: Marek Vasut marek.vasut+renesas@mailbox.org

We can call phy_modify_mmd() instead of manually calling drv->readext() and drv->writeext().
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com --- drivers/net/phy/micrel_ksz90x1.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-)
diff --git a/drivers/net/phy/micrel_ksz90x1.c b/drivers/net/phy/micrel_ksz90x1.c index b64046e0bc72..6515d8feb9be 100644 --- a/drivers/net/phy/micrel_ksz90x1.c +++ b/drivers/net/phy/micrel_ksz90x1.c @@ -502,8 +502,7 @@ static int ksz9131_of_load_all_skew_values(struct phy_device *phydev)
static int ksz9131_config_rgmii_delay(struct phy_device *phydev) { - struct phy_driver *drv = phydev->drv; - u16 rxcdll_val, txcdll_val, val; + u16 rxcdll_val, txcdll_val; int ret;
switch (phydev->interface) { @@ -527,24 +526,15 @@ static int ksz9131_config_rgmii_delay(struct phy_device *phydev) return 0; }
- val = drv->readext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG, - KSZ9131RN_RXC_DLL_CTRL); - val &= ~KSZ9131RN_DLL_CTRL_BYPASS; - val |= rxcdll_val; - ret = drv->writeext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG, - KSZ9131RN_RXC_DLL_CTRL, val); - if (ret) + ret = phy_modify_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG, + KSZ9131RN_RXC_DLL_CTRL, KSZ9131RN_DLL_CTRL_BYPASS, + rxcdll_val); + if (ret < 0) return ret;
- val = drv->readext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG, - KSZ9131RN_TXC_DLL_CTRL); - - val &= ~KSZ9131RN_DLL_CTRL_BYPASS; - val |= txcdll_val; - ret = drv->writeext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG, - KSZ9131RN_TXC_DLL_CTRL, val); - - return ret; + return phy_modify_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG, + KSZ9131RN_TXC_DLL_CTRL, KSZ9131RN_DLL_CTRL_BYPASS, + txcdll_val); }
/* Silicon Errata DS80000693B

On 10/24/24 5:24 PM, Paul Barker wrote:
We can call phy_modify_mmd() instead of manually calling drv->readext() and drv->writeext().
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com
drivers/net/phy/micrel_ksz90x1.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-)
diff --git a/drivers/net/phy/micrel_ksz90x1.c b/drivers/net/phy/micrel_ksz90x1.c index b64046e0bc72..6515d8feb9be 100644 --- a/drivers/net/phy/micrel_ksz90x1.c +++ b/drivers/net/phy/micrel_ksz90x1.c @@ -502,8 +502,7 @@ static int ksz9131_of_load_all_skew_values(struct phy_device *phydev)
static int ksz9131_config_rgmii_delay(struct phy_device *phydev) {
- struct phy_driver *drv = phydev->drv;
- u16 rxcdll_val, txcdll_val, val;
u16 rxcdll_val, txcdll_val; int ret;
switch (phydev->interface) {
@@ -527,24 +526,15 @@ static int ksz9131_config_rgmii_delay(struct phy_device *phydev) return 0; }
- val = drv->readext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG,
KSZ9131RN_RXC_DLL_CTRL);
- val &= ~KSZ9131RN_DLL_CTRL_BYPASS;
- val |= rxcdll_val;
- ret = drv->writeext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG,
KSZ9131RN_RXC_DLL_CTRL, val);
- if (ret)
- ret = phy_modify_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
KSZ9131RN_RXC_DLL_CTRL, KSZ9131RN_DLL_CTRL_BYPASS,
rxcdll_val);
- if (ret < 0) return ret;
- val = drv->readext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG,
KSZ9131RN_TXC_DLL_CTRL);
- val &= ~KSZ9131RN_DLL_CTRL_BYPASS;
- val |= txcdll_val;
- ret = drv->writeext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG,
KSZ9131RN_TXC_DLL_CTRL, val);
- return ret;
- return phy_modify_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
KSZ9131RN_TXC_DLL_CTRL, KSZ9131RN_DLL_CTRL_BYPASS,
}txcdll_val);
Can't you set both bitfields at the same time ? They seem to be in the same register.

On 27/10/2024 16:20, Marek Vasut wrote:
On 10/24/24 5:24 PM, Paul Barker wrote:
We can call phy_modify_mmd() instead of manually calling drv->readext() and drv->writeext().
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com
drivers/net/phy/micrel_ksz90x1.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-)
diff --git a/drivers/net/phy/micrel_ksz90x1.c b/drivers/net/phy/micrel_ksz90x1.c index b64046e0bc72..6515d8feb9be 100644 --- a/drivers/net/phy/micrel_ksz90x1.c +++ b/drivers/net/phy/micrel_ksz90x1.c @@ -502,8 +502,7 @@ static int ksz9131_of_load_all_skew_values(struct phy_device *phydev)
static int ksz9131_config_rgmii_delay(struct phy_device *phydev) {
- struct phy_driver *drv = phydev->drv;
- u16 rxcdll_val, txcdll_val, val;
u16 rxcdll_val, txcdll_val; int ret;
switch (phydev->interface) {
@@ -527,24 +526,15 @@ static int ksz9131_config_rgmii_delay(struct phy_device *phydev) return 0; }
- val = drv->readext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG,
KSZ9131RN_RXC_DLL_CTRL);
- val &= ~KSZ9131RN_DLL_CTRL_BYPASS;
- val |= rxcdll_val;
- ret = drv->writeext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG,
KSZ9131RN_RXC_DLL_CTRL, val);
- if (ret)
- ret = phy_modify_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
KSZ9131RN_RXC_DLL_CTRL, KSZ9131RN_DLL_CTRL_BYPASS,
rxcdll_val);
- if (ret < 0) return ret;
- val = drv->readext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG,
KSZ9131RN_TXC_DLL_CTRL);
- val &= ~KSZ9131RN_DLL_CTRL_BYPASS;
- val |= txcdll_val;
- ret = drv->writeext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG,
KSZ9131RN_TXC_DLL_CTRL, val);
- return ret;
- return phy_modify_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
KSZ9131RN_TXC_DLL_CTRL, KSZ9131RN_DLL_CTRL_BYPASS,
}txcdll_val);
Can't you set both bitfields at the same time ? They seem to be in the same register.
These writes are to two different registers (KSZ9131RN_RXC_DLL_CTRL and KSZ9131RN_TXC_DLL_CTRL), using the same bitmask in both cases (KSZ9131RN_DLL_CTRL_BYPASS).
Thanks,

On 10/28/24 9:50 AM, Paul Barker wrote:
On 27/10/2024 16:20, Marek Vasut wrote:
On 10/24/24 5:24 PM, Paul Barker wrote:
We can call phy_modify_mmd() instead of manually calling drv->readext() and drv->writeext().
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com
drivers/net/phy/micrel_ksz90x1.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-)
diff --git a/drivers/net/phy/micrel_ksz90x1.c b/drivers/net/phy/micrel_ksz90x1.c index b64046e0bc72..6515d8feb9be 100644 --- a/drivers/net/phy/micrel_ksz90x1.c +++ b/drivers/net/phy/micrel_ksz90x1.c @@ -502,8 +502,7 @@ static int ksz9131_of_load_all_skew_values(struct phy_device *phydev)
static int ksz9131_config_rgmii_delay(struct phy_device *phydev) {
- struct phy_driver *drv = phydev->drv;
- u16 rxcdll_val, txcdll_val, val;
u16 rxcdll_val, txcdll_val; int ret;
switch (phydev->interface) {
@@ -527,24 +526,15 @@ static int ksz9131_config_rgmii_delay(struct phy_device *phydev) return 0; }
- val = drv->readext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG,
KSZ9131RN_RXC_DLL_CTRL);
- val &= ~KSZ9131RN_DLL_CTRL_BYPASS;
- val |= rxcdll_val;
- ret = drv->writeext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG,
KSZ9131RN_RXC_DLL_CTRL, val);
- if (ret)
- ret = phy_modify_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
KSZ9131RN_RXC_DLL_CTRL, KSZ9131RN_DLL_CTRL_BYPASS,
rxcdll_val);
- if (ret < 0) return ret;
- val = drv->readext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG,
KSZ9131RN_TXC_DLL_CTRL);
- val &= ~KSZ9131RN_DLL_CTRL_BYPASS;
- val |= txcdll_val;
- ret = drv->writeext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG,
KSZ9131RN_TXC_DLL_CTRL, val);
- return ret;
- return phy_modify_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
KSZ9131RN_TXC_DLL_CTRL, KSZ9131RN_DLL_CTRL_BYPASS,
}txcdll_val);
Can't you set both bitfields at the same time ? They seem to be in the same register.
These writes are to two different registers (KSZ9131RN_RXC_DLL_CTRL and KSZ9131RN_TXC_DLL_CTRL), using the same bitmask in both cases (KSZ9131RN_DLL_CTRL_BYPASS).
Uh, right, thanks for clarifying.

Several Renesas SoCs in the RZ/G2L family have two Ethernet interfaces. To support this second interface, we extend the bb_miiphy_buses[] array and keep track of the current bus index in ravb_of_to_plat().
Support for an arbitrary number of instances is not implemented - it is expected that bb_miiphy_buses will be replaced with a proper device model/uclass implementation before that is needed.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com --- drivers/net/ravb.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ravb.c b/drivers/net/ravb.c index f1401d2f6ed2..9b33ce929618 100644 --- a/drivers/net/ravb.c +++ b/drivers/net/ravb.c @@ -11,6 +11,7 @@ #include <clk.h> #include <cpu_func.h> #include <dm.h> +#include <dm/device_compat.h> #include <errno.h> #include <log.h> #include <miiphy.h> @@ -494,6 +495,7 @@ static int ravb_probe(struct udevice *dev) { struct eth_pdata *pdata = dev_get_plat(dev); struct ravb_priv *eth = dev_get_priv(dev); + struct bb_miiphy_bus *phybus; struct mii_dev *mdiodev; void __iomem *iobase; int ret; @@ -513,7 +515,8 @@ static int ravb_probe(struct udevice *dev)
mdiodev->read = bb_miiphy_read; mdiodev->write = bb_miiphy_write; - bb_miiphy_buses[0].priv = eth; + phybus = (struct bb_miiphy_bus *)pdata->priv_pdata; + phybus->priv = eth; snprintf(mdiodev->name, sizeof(mdiodev->name), dev->name);
ret = mdio_register(mdiodev); @@ -625,7 +628,17 @@ int ravb_bb_delay(struct bb_miiphy_bus *bus)
struct bb_miiphy_bus bb_miiphy_buses[] = { { - .name = "ravb", + .name = "ravb0", + .init = ravb_bb_init, + .mdio_active = ravb_bb_mdio_active, + .mdio_tristate = ravb_bb_mdio_tristate, + .set_mdio = ravb_bb_set_mdio, + .get_mdio = ravb_bb_get_mdio, + .set_mdc = ravb_bb_set_mdc, + .delay = ravb_bb_delay, + }, + { + .name = "ravb1", .init = ravb_bb_init, .mdio_active = ravb_bb_mdio_active, .mdio_tristate = ravb_bb_mdio_tristate, @@ -646,10 +659,16 @@ static const struct eth_ops ravb_ops = { .write_hwaddr = ravb_write_hwaddr, };
+static int bb_miiphy_index; + int ravb_of_to_plat(struct udevice *dev) { struct eth_pdata *pdata = dev_get_plat(dev); - const fdt32_t *cell; + + if (bb_miiphy_index >= bb_miiphy_buses_num) { + dev_err(dev, "ravb driver supports only 1 or 2 devices!\n"); + return -EOVERFLOW; + }
pdata->iobase = dev_read_addr(dev);
@@ -662,7 +681,8 @@ int ravb_of_to_plat(struct udevice *dev) if (cell) pdata->max_speed = fdt32_to_cpu(*cell);
- sprintf(bb_miiphy_buses[0].name, dev->name); + pdata->priv_pdata = &bb_miiphy_buses[bb_miiphy_index]; + sprintf(bb_miiphy_buses[bb_miiphy_index++].name, dev->name);
return 0; }

On 10/24/24 5:24 PM, Paul Barker wrote:
Several Renesas SoCs in the RZ/G2L family have two Ethernet interfaces. To support this second interface, we extend the bb_miiphy_buses[] array and keep track of the current bus index in ravb_of_to_plat().
Support for an arbitrary number of instances is not implemented - it is expected that bb_miiphy_buses will be replaced with a proper device model/uclass implementation before that is needed.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com
drivers/net/ravb.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ravb.c b/drivers/net/ravb.c index f1401d2f6ed2..9b33ce929618 100644 --- a/drivers/net/ravb.c +++ b/drivers/net/ravb.c @@ -11,6 +11,7 @@ #include <clk.h> #include <cpu_func.h> #include <dm.h> +#include <dm/device_compat.h> #include <errno.h> #include <log.h> #include <miiphy.h> @@ -494,6 +495,7 @@ static int ravb_probe(struct udevice *dev) { struct eth_pdata *pdata = dev_get_plat(dev); struct ravb_priv *eth = dev_get_priv(dev);
- struct bb_miiphy_bus *phybus; struct mii_dev *mdiodev; void __iomem *iobase; int ret;
@@ -513,7 +515,8 @@ static int ravb_probe(struct udevice *dev)
mdiodev->read = bb_miiphy_read; mdiodev->write = bb_miiphy_write;
- bb_miiphy_buses[0].priv = eth;
phybus = (struct bb_miiphy_bus *)pdata->priv_pdata;
phybus->priv = eth; snprintf(mdiodev->name, sizeof(mdiodev->name), dev->name);
ret = mdio_register(mdiodev);
@@ -625,7 +628,17 @@ int ravb_bb_delay(struct bb_miiphy_bus *bus)
struct bb_miiphy_bus bb_miiphy_buses[] = { {
.name = "ravb",
.name = "ravb0",
.init = ravb_bb_init,
.mdio_active = ravb_bb_mdio_active,
.mdio_tristate = ravb_bb_mdio_tristate,
.set_mdio = ravb_bb_set_mdio,
.get_mdio = ravb_bb_get_mdio,
.set_mdc = ravb_bb_set_mdc,
.delay = ravb_bb_delay,
- },
- {
.init = ravb_bb_init, .mdio_active = ravb_bb_mdio_active, .mdio_tristate = ravb_bb_mdio_tristate,.name = "ravb1",
@@ -646,10 +659,16 @@ static const struct eth_ops ravb_ops = { .write_hwaddr = ravb_write_hwaddr, };
+static int bb_miiphy_index;
- int ravb_of_to_plat(struct udevice *dev) { struct eth_pdata *pdata = dev_get_plat(dev);
- const fdt32_t *cell;
- if (bb_miiphy_index >= bb_miiphy_buses_num) {
dev_err(dev, "ravb driver supports only 1 or 2 devices!\n");
Hmmmm, I really do not like this, can we make this dynamic ?
Unless you want to take a look at this yourself, I can add it into my todo ?

On 27/10/2024 16:25, Marek Vasut wrote:
On 10/24/24 5:24 PM, Paul Barker wrote:
Several Renesas SoCs in the RZ/G2L family have two Ethernet interfaces. To support this second interface, we extend the bb_miiphy_buses[] array and keep track of the current bus index in ravb_of_to_plat().
Support for an arbitrary number of instances is not implemented - it is expected that bb_miiphy_buses will be replaced with a proper device model/uclass implementation before that is needed.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com
drivers/net/ravb.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ravb.c b/drivers/net/ravb.c index f1401d2f6ed2..9b33ce929618 100644 --- a/drivers/net/ravb.c +++ b/drivers/net/ravb.c @@ -11,6 +11,7 @@ #include <clk.h> #include <cpu_func.h> #include <dm.h> +#include <dm/device_compat.h> #include <errno.h> #include <log.h> #include <miiphy.h> @@ -494,6 +495,7 @@ static int ravb_probe(struct udevice *dev) { struct eth_pdata *pdata = dev_get_plat(dev); struct ravb_priv *eth = dev_get_priv(dev);
- struct bb_miiphy_bus *phybus; struct mii_dev *mdiodev; void __iomem *iobase; int ret;
@@ -513,7 +515,8 @@ static int ravb_probe(struct udevice *dev)
mdiodev->read = bb_miiphy_read; mdiodev->write = bb_miiphy_write;
- bb_miiphy_buses[0].priv = eth;
phybus = (struct bb_miiphy_bus *)pdata->priv_pdata;
phybus->priv = eth; snprintf(mdiodev->name, sizeof(mdiodev->name), dev->name);
ret = mdio_register(mdiodev);
@@ -625,7 +628,17 @@ int ravb_bb_delay(struct bb_miiphy_bus *bus)
struct bb_miiphy_bus bb_miiphy_buses[] = { {
.name = "ravb",
.name = "ravb0",
.init = ravb_bb_init,
.mdio_active = ravb_bb_mdio_active,
.mdio_tristate = ravb_bb_mdio_tristate,
.set_mdio = ravb_bb_set_mdio,
.get_mdio = ravb_bb_get_mdio,
.set_mdc = ravb_bb_set_mdc,
.delay = ravb_bb_delay,
- },
- {
.init = ravb_bb_init, .mdio_active = ravb_bb_mdio_active, .mdio_tristate = ravb_bb_mdio_tristate,.name = "ravb1",
@@ -646,10 +659,16 @@ static const struct eth_ops ravb_ops = { .write_hwaddr = ravb_write_hwaddr, };
+static int bb_miiphy_index;
- int ravb_of_to_plat(struct udevice *dev) { struct eth_pdata *pdata = dev_get_plat(dev);
- const fdt32_t *cell;
- if (bb_miiphy_index >= bb_miiphy_buses_num) {
dev_err(dev, "ravb driver supports only 1 or 2 devices!\n");
Hmmmm, I really do not like this, can we make this dynamic ?
Unless you want to take a look at this yourself, I can add it into my todo ?
I think the real solution here would be to separate the bb_miiphy operations from the bus instance, so we would have something like:
struct bb_miiphy_bus { struct bb_miiphy_ops *ops; void *priv; };
struct bb_miiphy_ops { int (*init)(struct bb_miiphy_bus *bus); int (*mdio_active)(struct bb_miiphy_bus *bus); int (*mdio_tristate)(struct bb_miiphy_bus *bus); int (*set_mdio)(struct bb_miiphy_bus *bus, int v); int (*get_mdio)(struct bb_miiphy_bus *bus, int *v); int (*set_mdc)(struct bb_miiphy_bus *bus, int v); int (*delay)(struct bb_miiphy_bus *bus); };
int bb_miiphy_bus_register(const char *name, struct bb_miiphy_ops *ops, void *priv);
Where drivers will call `bb_miiphy_bus_register()` from the probe function, it will create a `struct bb_miiphy_bus` instance and a `struct mii_dev` instance then call `mdio_register()`. The driver can then support an arbitrary number of MDIO busses from a single constant `struct bb_miiphy_ops` instance.
The bb_miiphy_getbus() function should be dropped from miiphy.c. Instead, the priv pointer in the `struct mii_dev` instance can point to the appropriate `struct bb_miiphy_bus` instance.
It looks like all users of CONFIG_BITBANGMII also set CONFIG_BITBANGMII_MULTI, and there don't seem to be any targets that define the macros documented in README.bitbangMII (lines 15-22). So, we can drop the non-BITBANGMII_MULTI code from miiphybb.c and simplify things a lot.
That's non-trivial but it's not a huge set of changes, maybe something we could target for v2024.04?
Thanks,

Hi Marek,
On 28/10/2024 09:50, Paul Barker wrote:
On 27/10/2024 16:25, Marek Vasut wrote:
On 10/24/24 5:24 PM, Paul Barker wrote:
int ravb_of_to_plat(struct udevice *dev) { struct eth_pdata *pdata = dev_get_plat(dev);
- const fdt32_t *cell;
- if (bb_miiphy_index >= bb_miiphy_buses_num) {
dev_err(dev, "ravb driver supports only 1 or 2 devices!\n");
Hmmmm, I really do not like this, can we make this dynamic ?
Unless you want to take a look at this yourself, I can add it into my todo ?
I think the real solution here would be to separate the bb_miiphy operations from the bus instance, so we would have something like:
struct bb_miiphy_bus { struct bb_miiphy_ops *ops; void *priv; }; struct bb_miiphy_ops { int (*init)(struct bb_miiphy_bus *bus); int (*mdio_active)(struct bb_miiphy_bus *bus); int (*mdio_tristate)(struct bb_miiphy_bus *bus); int (*set_mdio)(struct bb_miiphy_bus *bus, int v); int (*get_mdio)(struct bb_miiphy_bus *bus, int *v); int (*set_mdc)(struct bb_miiphy_bus *bus, int v); int (*delay)(struct bb_miiphy_bus *bus); }; int bb_miiphy_bus_register(const char *name, struct bb_miiphy_ops *ops, void *priv);
Where drivers will call `bb_miiphy_bus_register()` from the probe function, it will create a `struct bb_miiphy_bus` instance and a `struct mii_dev` instance then call `mdio_register()`. The driver can then support an arbitrary number of MDIO busses from a single constant `struct bb_miiphy_ops` instance.
The bb_miiphy_getbus() function should be dropped from miiphy.c. Instead, the priv pointer in the `struct mii_dev` instance can point to the appropriate `struct bb_miiphy_bus` instance.
It looks like all users of CONFIG_BITBANGMII also set CONFIG_BITBANGMII_MULTI, and there don't seem to be any targets that define the macros documented in README.bitbangMII (lines 15-22). So, we can drop the non-BITBANGMII_MULTI code from miiphybb.c and simplify things a lot.
That's non-trivial but it's not a huge set of changes, maybe something we could target for v2024.04?
We've got several of the other patches from this series merged now after v2 so I'm coming back to this one. I think we should take this patch as-is and then follow up with general improvements to the bb_miiphy support. Are you happy with that? If so I will re-send it along with a re-worked version of patch 11 from this series (net: ravb: Add RZ/G2L Support).
Thanks,

On 12/5/24 8:12 PM, Paul Barker wrote:
Hi Marek,
On 28/10/2024 09:50, Paul Barker wrote:
On 27/10/2024 16:25, Marek Vasut wrote:
On 10/24/24 5:24 PM, Paul Barker wrote:
int ravb_of_to_plat(struct udevice *dev) { struct eth_pdata *pdata = dev_get_plat(dev);
- const fdt32_t *cell;
- if (bb_miiphy_index >= bb_miiphy_buses_num) {
dev_err(dev, "ravb driver supports only 1 or 2 devices!\n");
Hmmmm, I really do not like this, can we make this dynamic ?
Unless you want to take a look at this yourself, I can add it into my todo ?
I think the real solution here would be to separate the bb_miiphy operations from the bus instance, so we would have something like:
struct bb_miiphy_bus { struct bb_miiphy_ops *ops; void *priv; }; struct bb_miiphy_ops { int (*init)(struct bb_miiphy_bus *bus); int (*mdio_active)(struct bb_miiphy_bus *bus); int (*mdio_tristate)(struct bb_miiphy_bus *bus); int (*set_mdio)(struct bb_miiphy_bus *bus, int v); int (*get_mdio)(struct bb_miiphy_bus *bus, int *v); int (*set_mdc)(struct bb_miiphy_bus *bus, int v); int (*delay)(struct bb_miiphy_bus *bus); }; int bb_miiphy_bus_register(const char *name, struct bb_miiphy_ops *ops, void *priv);
Where drivers will call `bb_miiphy_bus_register()` from the probe function, it will create a `struct bb_miiphy_bus` instance and a `struct mii_dev` instance then call `mdio_register()`. The driver can then support an arbitrary number of MDIO busses from a single constant `struct bb_miiphy_ops` instance.
The bb_miiphy_getbus() function should be dropped from miiphy.c. Instead, the priv pointer in the `struct mii_dev` instance can point to the appropriate `struct bb_miiphy_bus` instance.
It looks like all users of CONFIG_BITBANGMII also set CONFIG_BITBANGMII_MULTI, and there don't seem to be any targets that define the macros documented in README.bitbangMII (lines 15-22). So, we can drop the non-BITBANGMII_MULTI code from miiphybb.c and simplify things a lot.
That's non-trivial but it's not a huge set of changes, maybe something we could target for v2024.04?
We've got several of the other patches from this series merged now after v2 so I'm coming back to this one. I think we should take this patch as-is and then follow up with general improvements to the bb_miiphy support. Are you happy with that? If so I will re-send it along with a re-worked version of patch 11 from this series (net: ravb: Add RZ/G2L Support).
I apologize for the horrible delay.
I just posted the bb_miiphy patches so maybe we can do it properly right from the start ?

On 10/28/24 10:50 AM, Paul Barker wrote:
On 27/10/2024 16:25, Marek Vasut wrote:
On 10/24/24 5:24 PM, Paul Barker wrote:
Several Renesas SoCs in the RZ/G2L family have two Ethernet interfaces. To support this second interface, we extend the bb_miiphy_buses[] array and keep track of the current bus index in ravb_of_to_plat().
Support for an arbitrary number of instances is not implemented - it is expected that bb_miiphy_buses will be replaced with a proper device model/uclass implementation before that is needed.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com
drivers/net/ravb.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ravb.c b/drivers/net/ravb.c index f1401d2f6ed2..9b33ce929618 100644 --- a/drivers/net/ravb.c +++ b/drivers/net/ravb.c @@ -11,6 +11,7 @@ #include <clk.h> #include <cpu_func.h> #include <dm.h> +#include <dm/device_compat.h> #include <errno.h> #include <log.h> #include <miiphy.h> @@ -494,6 +495,7 @@ static int ravb_probe(struct udevice *dev) { struct eth_pdata *pdata = dev_get_plat(dev); struct ravb_priv *eth = dev_get_priv(dev);
- struct bb_miiphy_bus *phybus; struct mii_dev *mdiodev; void __iomem *iobase; int ret;
@@ -513,7 +515,8 @@ static int ravb_probe(struct udevice *dev)
mdiodev->read = bb_miiphy_read; mdiodev->write = bb_miiphy_write;
- bb_miiphy_buses[0].priv = eth;
phybus = (struct bb_miiphy_bus *)pdata->priv_pdata;
phybus->priv = eth; snprintf(mdiodev->name, sizeof(mdiodev->name), dev->name);
ret = mdio_register(mdiodev);
@@ -625,7 +628,17 @@ int ravb_bb_delay(struct bb_miiphy_bus *bus)
struct bb_miiphy_bus bb_miiphy_buses[] = { {
.name = "ravb",
.name = "ravb0",
.init = ravb_bb_init,
.mdio_active = ravb_bb_mdio_active,
.mdio_tristate = ravb_bb_mdio_tristate,
.set_mdio = ravb_bb_set_mdio,
.get_mdio = ravb_bb_get_mdio,
.set_mdc = ravb_bb_set_mdc,
.delay = ravb_bb_delay,
- },
- {
.name = "ravb1", .init = ravb_bb_init, .mdio_active = ravb_bb_mdio_active, .mdio_tristate = ravb_bb_mdio_tristate,
@@ -646,10 +659,16 @@ static const struct eth_ops ravb_ops = { .write_hwaddr = ravb_write_hwaddr, };
+static int bb_miiphy_index;
- int ravb_of_to_plat(struct udevice *dev) { struct eth_pdata *pdata = dev_get_plat(dev);
- const fdt32_t *cell;
- if (bb_miiphy_index >= bb_miiphy_buses_num) {
dev_err(dev, "ravb driver supports only 1 or 2 devices!\n");
Hmmmm, I really do not like this, can we make this dynamic ?
Unless you want to take a look at this yourself, I can add it into my todo ?
I think the real solution here would be to separate the bb_miiphy operations from the bus instance, so we would have something like:
struct bb_miiphy_bus { struct bb_miiphy_ops *ops; void *priv; }; struct bb_miiphy_ops { int (*init)(struct bb_miiphy_bus *bus); int (*mdio_active)(struct bb_miiphy_bus *bus); int (*mdio_tristate)(struct bb_miiphy_bus *bus); int (*set_mdio)(struct bb_miiphy_bus *bus, int v); int (*get_mdio)(struct bb_miiphy_bus *bus, int *v); int (*set_mdc)(struct bb_miiphy_bus *bus, int v); int (*delay)(struct bb_miiphy_bus *bus); }; int bb_miiphy_bus_register(const char *name, struct bb_miiphy_ops *ops, void *priv);
Where drivers will call `bb_miiphy_bus_register()` from the probe function, it will create a `struct bb_miiphy_bus` instance and a `struct mii_dev` instance then call `mdio_register()`. The driver can then support an arbitrary number of MDIO busses from a single constant `struct bb_miiphy_ops` instance.
The bb_miiphy_getbus() function should be dropped from miiphy.c. Instead, the priv pointer in the `struct mii_dev` instance can point to the appropriate `struct bb_miiphy_bus` instance.
It looks like all users of CONFIG_BITBANGMII also set CONFIG_BITBANGMII_MULTI, and there don't seem to be any targets that define the macros documented in README.bitbangMII (lines 15-22). So, we can drop the non-BITBANGMII_MULTI code from miiphybb.c and simplify things a lot.
That's non-trivial but it's not a huge set of changes, maybe something we could target for v2024.04?
Patches posted somewhat inline with what you suggested:
https://patchwork.ozlabs.org/project/uboot/patch/20250118061304.124807-1-mar... https://patchwork.ozlabs.org/project/uboot/patch/20250118061445.124932-1-mar... https://patchwork.ozlabs.org/project/uboot/patch/20250118061558.124963-1-mar... https://patchwork.ozlabs.org/project/uboot/patch/20250118061629.125005-1-mar... https://patchwork.ozlabs.org/project/uboot/patch/20250118063458.137258-1-mar... https://patchwork.ozlabs.org/project/uboot/patch/20250118065402.172253-1-mar...

We can call dev_read_u32_default() instead of calling fdt_getprop() then fdt32_to_cpu().
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com --- drivers/net/ravb.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/drivers/net/ravb.c b/drivers/net/ravb.c index 9b33ce929618..fb869cd0872e 100644 --- a/drivers/net/ravb.c +++ b/drivers/net/ravb.c @@ -676,10 +676,7 @@ int ravb_of_to_plat(struct udevice *dev) if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) return -EINVAL;
- pdata->max_speed = 1000; - cell = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "max-speed", NULL); - if (cell) - pdata->max_speed = fdt32_to_cpu(*cell); + pdata->max_speed = dev_read_u32_default(dev, "max-speed", 1000);
pdata->priv_pdata = &bb_miiphy_buses[bb_miiphy_index]; sprintf(bb_miiphy_buses[bb_miiphy_index++].name, dev->name);

On 10/24/24 5:24 PM, Paul Barker wrote:
We can call dev_read_u32_default() instead of calling fdt_getprop() then fdt32_to_cpu().
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com
drivers/net/ravb.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/drivers/net/ravb.c b/drivers/net/ravb.c index 9b33ce929618..fb869cd0872e 100644 --- a/drivers/net/ravb.c +++ b/drivers/net/ravb.c @@ -676,10 +676,7 @@ int ravb_of_to_plat(struct udevice *dev) if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) return -EINVAL;
- pdata->max_speed = 1000;
- cell = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "max-speed", NULL);
- if (cell)
pdata->max_speed = fdt32_to_cpu(*cell);
- pdata->max_speed = dev_read_u32_default(dev, "max-speed", 1000);
Reviewed-by: Marek Vasut marek.vasut+renesas@mailbox.org

The Renesas R9A07G044L (RZ/G2L) SoC includes two Gigabit Ethernet interfaces which can be supported using the ravb driver. Some RZ/G2L specific steps need to be taken during initialization due to differences between this SoC and previously supported SoCs. We also need to ensure that the module reset is de-asserted after the module clock is enabled but before any Ethernet register reads/writes take place.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com --- arch/arm/mach-renesas/Kconfig | 1 + drivers/net/Kconfig | 2 + drivers/net/ravb.c | 183 ++++++++++++++++++++++++++++++++-- 3 files changed, 176 insertions(+), 10 deletions(-)
diff --git a/arch/arm/mach-renesas/Kconfig b/arch/arm/mach-renesas/Kconfig index aeb55da609bd..d373ab56ce91 100644 --- a/arch/arm/mach-renesas/Kconfig +++ b/arch/arm/mach-renesas/Kconfig @@ -76,6 +76,7 @@ config RZG2L imply MULTI_DTB_FIT imply MULTI_DTB_FIT_USER_DEFINED_AREA imply PINCTRL_RZG2L + imply RENESAS_RAVB imply RENESAS_SDHI imply RZG2L_GPIO imply SCIF_CONSOLE diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 89f7411bdf33..d009acdcd94f 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -822,6 +822,8 @@ config RENESAS_RAVB depends on RCAR_64 select PHYLIB select PHY_ETHERNET_ID + select BITBANGMII + select BITBANGMII_MULTI help This driver implements support for the Ethernet AVB block in Renesas M3 and H3 SoCs. diff --git a/drivers/net/ravb.c b/drivers/net/ravb.c index fb869cd0872e..e2ab929858c8 100644 --- a/drivers/net/ravb.c +++ b/drivers/net/ravb.c @@ -24,6 +24,7 @@ #include <asm/io.h> #include <asm/global_data.h> #include <asm/gpio.h> +#include <reset.h>
/* Registers */ #define RAVB_REG_CCC 0x000 @@ -31,12 +32,14 @@ #define RAVB_REG_CSR 0x00C #define RAVB_REG_APSR 0x08C #define RAVB_REG_RCR 0x090 +#define RAVB_REG_RTC 0x0B4 #define RAVB_REG_TGC 0x300 #define RAVB_REG_TCCR 0x304 #define RAVB_REG_RIC0 0x360 #define RAVB_REG_RIC1 0x368 #define RAVB_REG_RIC2 0x370 #define RAVB_REG_TIC 0x378 +#define RAVB_REG_RIC3 0x388 #define RAVB_REG_ECMR 0x500 #define RAVB_REG_RFLR 0x508 #define RAVB_REG_ECSIPR 0x518 @@ -44,6 +47,7 @@ #define RAVB_REG_GECMR 0x5b0 #define RAVB_REG_MAHR 0x5c0 #define RAVB_REG_MALR 0x5c8 +#define RAVB_REG_CSR0 0x800
#define CCC_OPC_CONFIG BIT(0) #define CCC_OPC_OPERATION BIT(1) @@ -65,14 +69,24 @@ #define PIR_MDC BIT(0)
#define ECMR_TRCCM BIT(26) +#define ECMR_RCPT BIT(25) #define ECMR_RZPF BIT(20) #define ECMR_PFR BIT(18) #define ECMR_RXF BIT(17) +#define ECMR_TXF BIT(16) #define ECMR_RE BIT(6) #define ECMR_TE BIT(5) #define ECMR_DM BIT(1) +#define ECMR_PRM BIT(0) #define ECMR_CHG_DM (ECMR_TRCCM | ECMR_RZPF | ECMR_PFR | ECMR_RXF)
+#define CSR0_RPE BIT(5) +#define CSR0_TPE BIT(4) + +#define GECMR_SPEED_10M (0 << 4) +#define GECMR_SPEED_100M (1 << 4) +#define GECMR_SPEED_1G (2 << 4) + /* DMA Descriptors */ #define RAVB_NUM_BASE_DESC 16 #define RAVB_NUM_TX_DESC 8 @@ -108,6 +122,16 @@
#define RAVB_TX_TIMEOUT_MS 1000
+#define RAVB_RCV_BUFF_MAX 8192 + +struct ravb_device_ops { + int (*mac_init)(struct udevice *dev); + int (*dmac_init)(struct udevice *dev); + int (*config)(struct udevice *dev); + int (*reset_deassert)(struct udevice *dev); + void (*reset_assert)(struct udevice *dev); +}; + struct ravb_desc { u32 ctrl; u32 dptr; @@ -131,6 +155,7 @@ struct ravb_priv { struct mii_dev *bus; void __iomem *iobase; struct clk_bulk clks; + struct reset_ctl rst; };
static inline void ravb_flush_dcache(u32 addr, u32 len) @@ -350,8 +375,25 @@ static int ravb_write_hwaddr(struct udevice *dev) }
/* E-MAC init function */ -static int ravb_mac_init(struct ravb_priv *eth) +static int ravb_mac_init_rzg2l(struct udevice *dev) { + struct ravb_priv *eth = dev_get_priv(dev); + + setbits_32(eth->iobase + RAVB_REG_ECMR, + ECMR_PRM | ECMR_RXF | ECMR_TXF | ECMR_RCPT | + ECMR_TE | ECMR_RE | ECMR_RZPF | + (eth->phydev->duplex ? ECMR_DM : 0)); + + /* Recv frame limit set register */ + writel(RAVB_RCV_BUFF_MAX + ETH_FCS_LEN, eth->iobase + RAVB_REG_RFLR); + + return 0; +} + +static int ravb_mac_init_rcar(struct udevice *dev) +{ + struct ravb_priv *eth = dev_get_priv(dev); + /* Disable MAC Interrupt */ writel(0, eth->iobase + RAVB_REG_ECSIPR);
@@ -364,12 +406,10 @@ static int ravb_mac_init(struct ravb_priv *eth) /* AVB-DMAC init function */ static int ravb_dmac_init(struct udevice *dev) { + struct ravb_device_ops *device_ops = + (struct ravb_device_ops *)dev_get_driver_data(dev); struct ravb_priv *eth = dev_get_priv(dev); - struct eth_pdata *pdata = dev_get_plat(dev); - int ret = 0; - int mode = 0; - unsigned int delay; - bool explicit_delay = false; + int ret;
/* Set CONFIG mode */ ret = ravb_reset(dev); @@ -385,6 +425,27 @@ static int ravb_dmac_init(struct udevice *dev) /* Set little endian */ clrbits_le32(eth->iobase + RAVB_REG_CCC, CCC_BOC);
+ return device_ops->dmac_init(dev); +} + +static int ravb_dmac_init_rzg2l(struct udevice *dev) +{ + struct ravb_priv *eth = dev_get_priv(dev); + + /* Set Max Frame Length (RTC) */ + writel(RAVB_RCV_BUFF_MAX, eth->iobase + RAVB_REG_RTC); + + return 0; +} + +static int ravb_dmac_init_rcar(struct udevice *dev) +{ + struct ravb_priv *eth = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_plat(dev); + int mode = 0; + unsigned int delay; + bool explicit_delay = false; + /* AVB rx set */ writel(0x18000001, eth->iobase + RAVB_REG_RCR);
@@ -429,22 +490,50 @@ static int ravb_dmac_init(struct udevice *dev)
static int ravb_config(struct udevice *dev) { + struct ravb_device_ops *device_ops = + (struct ravb_device_ops *)dev_get_driver_data(dev); struct ravb_priv *eth = dev_get_priv(dev); struct phy_device *phy = eth->phydev; - u32 mask = ECMR_CHG_DM | ECMR_RE | ECMR_TE; int ret;
/* Configure AVB-DMAC register */ ravb_dmac_init(dev);
/* Configure E-MAC registers */ - ravb_mac_init(eth); + device_ops->mac_init(dev); ravb_write_hwaddr(dev);
ret = phy_startup(phy); if (ret) return ret;
+ return device_ops->config(dev); +} + +static int ravb_config_rzg2l(struct udevice *dev) +{ + struct ravb_priv *eth = dev_get_priv(dev); + struct phy_device *phy = eth->phydev; + + writel(CSR0_TPE | CSR0_RPE, eth->iobase + RAVB_REG_CSR0); + + /* Set the transfer speed */ + if (phy->speed == 10) + writel(GECMR_SPEED_10M, eth->iobase + RAVB_REG_GECMR); + else if (phy->speed == 100) + writel(GECMR_SPEED_100M, eth->iobase + RAVB_REG_GECMR); + else if (phy->speed == 1000) + writel(GECMR_SPEED_1G, eth->iobase + RAVB_REG_GECMR); + + return 0; +} + +static int ravb_config_rcar(struct udevice *dev) +{ + struct ravb_priv *eth = dev_get_priv(dev); + struct phy_device *phy = eth->phydev; + u32 mask = ECMR_CHG_DM | ECMR_RE | ECMR_TE; + /* Set the transfer speed */ if (phy->speed == 100) writel(0, eth->iobase + RAVB_REG_GECMR); @@ -491,8 +580,47 @@ static void ravb_stop(struct udevice *dev) ravb_reset(dev); }
+static int ravb_reset_deassert_rzg2l(struct udevice *dev) +{ + struct ravb_priv *eth = dev_get_priv(dev); + int ret; + + ret = reset_get_by_index(dev, 0, ð->rst); + if (ret < 0) { + dev_err(dev, "failed to get reset line\n"); + return ret; + } + + ret = reset_deassert(ð->rst); + if (ret < 0) { + dev_err(dev, "failed to de-assert reset line\n"); + reset_free(ð->rst); + } + + return ret; +} + +static int ravb_reset_deassert_rcar(struct udevice *dev) +{ + return 0; +} + +static void ravb_reset_assert_rzg2l(struct udevice *dev) +{ + struct ravb_priv *eth = dev_get_priv(dev); + + reset_assert(ð->rst); + reset_free(ð->rst); +} + +static void ravb_reset_assert_rcar(struct udevice *dev) +{ +} + static int ravb_probe(struct udevice *dev) { + struct ravb_device_ops *device_ops = + (struct ravb_device_ops *)dev_get_driver_data(dev); struct eth_pdata *pdata = dev_get_plat(dev); struct ravb_priv *eth = dev_get_priv(dev); struct bb_miiphy_bus *phybus; @@ -530,6 +658,10 @@ static int ravb_probe(struct udevice *dev) if (ret) goto err_mdio_register;
+ ret = device_ops->reset_deassert(dev); + if (ret) + goto err_reset_deassert; + ret = ravb_reset(dev); if (ret) goto err_mdio_reset; @@ -541,6 +673,8 @@ static int ravb_probe(struct udevice *dev) return 0;
err_mdio_reset: + device_ops->reset_assert(dev); +err_reset_deassert: clk_release_bulk(ð->clks); err_mdio_register: mdio_free(mdiodev); @@ -551,8 +685,11 @@ err_mdio_alloc:
static int ravb_remove(struct udevice *dev) { + struct ravb_device_ops *device_ops = + (struct ravb_device_ops *)dev_get_driver_data(dev); struct ravb_priv *eth = dev_get_priv(dev);
+ device_ops->reset_assert(dev); clk_release_bulk(ð->clks);
free(eth->phydev); @@ -684,9 +821,35 @@ int ravb_of_to_plat(struct udevice *dev) return 0; }
+static const struct ravb_device_ops ravb_device_ops_rzg2l = { + .mac_init = ravb_mac_init_rzg2l, + .dmac_init = ravb_dmac_init_rzg2l, + .config = ravb_config_rzg2l, + .reset_deassert = ravb_reset_deassert_rzg2l, + .reset_assert = ravb_reset_assert_rzg2l, +}; + +static const struct ravb_device_ops ravb_device_ops_rcar = { + .mac_init = ravb_mac_init_rcar, + .dmac_init = ravb_dmac_init_rcar, + .config = ravb_config_rcar, + .reset_deassert = ravb_reset_deassert_rcar, + .reset_assert = ravb_reset_assert_rcar, +}; + static const struct udevice_id ravb_ids[] = { - { .compatible = "renesas,etheravb-rcar-gen3" }, - { .compatible = "renesas,etheravb-rcar-gen4" }, + { + .compatible = "renesas,etheravb-rcar-gen3", + .data = (ulong)&ravb_device_ops_rcar, + }, + { + .compatible = "renesas,etheravb-rcar-gen4", + .data = (ulong)&ravb_device_ops_rcar, + }, + { + .compatible = "renesas,rzg2l-gbeth", + .data = (ulong)&ravb_device_ops_rzg2l, + }, { } };

On 10/24/24 5:24 PM, Paul Barker wrote:
The Renesas R9A07G044L (RZ/G2L) SoC includes two Gigabit Ethernet interfaces which can be supported using the ravb driver. Some RZ/G2L specific steps need to be taken during initialization due to differences between this SoC and previously supported SoCs. We also need to ensure that the module reset is de-asserted after the module clock is enabled but before any Ethernet register reads/writes take place.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com
arch/arm/mach-renesas/Kconfig | 1 + drivers/net/Kconfig | 2 + drivers/net/ravb.c | 183 ++++++++++++++++++++++++++++++++-- 3 files changed, 176 insertions(+), 10 deletions(-)
diff --git a/arch/arm/mach-renesas/Kconfig b/arch/arm/mach-renesas/Kconfig index aeb55da609bd..d373ab56ce91 100644 --- a/arch/arm/mach-renesas/Kconfig +++ b/arch/arm/mach-renesas/Kconfig @@ -76,6 +76,7 @@ config RZG2L imply MULTI_DTB_FIT imply MULTI_DTB_FIT_USER_DEFINED_AREA imply PINCTRL_RZG2L
- imply RENESAS_RAVB imply RENESAS_SDHI imply RZG2L_GPIO imply SCIF_CONSOLE
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 89f7411bdf33..d009acdcd94f 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -822,6 +822,8 @@ config RENESAS_RAVB depends on RCAR_64 select PHYLIB select PHY_ETHERNET_ID
- select BITBANGMII
- select BITBANGMII_MULTI
Keep the list sorted.
help This driver implements support for the Ethernet AVB block in Renesas M3 and H3 SoCs. diff --git a/drivers/net/ravb.c b/drivers/net/ravb.c index fb869cd0872e..e2ab929858c8 100644 --- a/drivers/net/ravb.c +++ b/drivers/net/ravb.c
[...]
@@ -108,6 +122,16 @@
#define RAVB_TX_TIMEOUT_MS 1000
+#define RAVB_RCV_BUFF_MAX 8192
+struct ravb_device_ops {
- int (*mac_init)(struct udevice *dev);
- int (*dmac_init)(struct udevice *dev);
- int (*config)(struct udevice *dev);
- int (*reset_deassert)(struct udevice *dev);
- void (*reset_assert)(struct udevice *dev);
+};
[...]
+static int ravb_reset_deassert_rcar(struct udevice *dev) +{
The callsites should check if a callback is assigned or NULL and only call the callback if it is assigned. Then you won't need empty callbacks like this.
Basically add if (ops->reset_deassert) ops->reset_deassert() and remove this empty function.
- return 0;
+}
+static void ravb_reset_assert_rzg2l(struct udevice *dev) +{
- struct ravb_priv *eth = dev_get_priv(dev);
- reset_assert(ð->rst);
- reset_free(ð->rst);
+}
A bit of a design question -- would it make sense to have ravb-rcar.c and ravb-rzg2l.c to contain the differences between the ravb variants, and keep common code only in ravb.c ?
[...]
@@ -684,9 +821,35 @@ int ravb_of_to_plat(struct udevice *dev) return 0; }
+static const struct ravb_device_ops ravb_device_ops_rzg2l = {
Keep the list sorted, rzg is below rcar (Z is after C) .
- .mac_init = ravb_mac_init_rzg2l,
- .dmac_init = ravb_dmac_init_rzg2l,
- .config = ravb_config_rzg2l,
- .reset_deassert = ravb_reset_deassert_rzg2l,
- .reset_assert = ravb_reset_assert_rzg2l,
+};
+static const struct ravb_device_ops ravb_device_ops_rcar = {
- .mac_init = ravb_mac_init_rcar,
- .dmac_init = ravb_dmac_init_rcar,
- .config = ravb_config_rcar,
- .reset_deassert = ravb_reset_deassert_rcar,
- .reset_assert = ravb_reset_assert_rcar,
+};
[...]

On 27/10/2024 16:29, Marek Vasut wrote:
On 10/24/24 5:24 PM, Paul Barker wrote:
The Renesas R9A07G044L (RZ/G2L) SoC includes two Gigabit Ethernet interfaces which can be supported using the ravb driver. Some RZ/G2L specific steps need to be taken during initialization due to differences between this SoC and previously supported SoCs. We also need to ensure that the module reset is de-asserted after the module clock is enabled but before any Ethernet register reads/writes take place.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com
arch/arm/mach-renesas/Kconfig | 1 + drivers/net/Kconfig | 2 + drivers/net/ravb.c | 183 ++++++++++++++++++++++++++++++++-- 3 files changed, 176 insertions(+), 10 deletions(-)
diff --git a/arch/arm/mach-renesas/Kconfig b/arch/arm/mach-renesas/Kconfig index aeb55da609bd..d373ab56ce91 100644 --- a/arch/arm/mach-renesas/Kconfig +++ b/arch/arm/mach-renesas/Kconfig @@ -76,6 +76,7 @@ config RZG2L imply MULTI_DTB_FIT imply MULTI_DTB_FIT_USER_DEFINED_AREA imply PINCTRL_RZG2L
- imply RENESAS_RAVB imply RENESAS_SDHI imply RZG2L_GPIO imply SCIF_CONSOLE
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 89f7411bdf33..d009acdcd94f 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -822,6 +822,8 @@ config RENESAS_RAVB depends on RCAR_64 select PHYLIB select PHY_ETHERNET_ID
- select BITBANGMII
- select BITBANGMII_MULTI
Keep the list sorted.
Will fix in v2.
help This driver implements support for the Ethernet AVB block in Renesas M3 and H3 SoCs. diff --git a/drivers/net/ravb.c b/drivers/net/ravb.c index fb869cd0872e..e2ab929858c8 100644 --- a/drivers/net/ravb.c +++ b/drivers/net/ravb.c
[...]
@@ -108,6 +122,16 @@
#define RAVB_TX_TIMEOUT_MS 1000
+#define RAVB_RCV_BUFF_MAX 8192
+struct ravb_device_ops {
- int (*mac_init)(struct udevice *dev);
- int (*dmac_init)(struct udevice *dev);
- int (*config)(struct udevice *dev);
- int (*reset_deassert)(struct udevice *dev);
- void (*reset_assert)(struct udevice *dev);
+};
[...]
+static int ravb_reset_deassert_rcar(struct udevice *dev) +{
The callsites should check if a callback is assigned or NULL and only call the callback if it is assigned. Then you won't need empty callbacks like this.
Basically add if (ops->reset_deassert) ops->reset_deassert() and remove this empty function.
Will fix in v2.
- return 0;
+}
+static void ravb_reset_assert_rzg2l(struct udevice *dev) +{
- struct ravb_priv *eth = dev_get_priv(dev);
- reset_assert(ð->rst);
- reset_free(ð->rst);
+}
A bit of a design question -- would it make sense to have ravb-rcar.c and ravb-rzg2l.c to contain the differences between the ravb variants, and keep common code only in ravb.c ?
That would probably be an improvement. I'll do that for v2.
Thanks,

For Ethernet to work on the RZ/G2L board, we need to enable support for the ksz9131 PHY and enable random MAC address generation (as no MAC address is programmed into the board).
We also enable the `dhcp`, `mii` and `ping` commands so that Ethernet functionality can be tested and used to boot Linux.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com --- configs/renesas_rzg2l_smarc_defconfig | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/configs/renesas_rzg2l_smarc_defconfig b/configs/renesas_rzg2l_smarc_defconfig index 7a1224b3f07a..991818e797ea 100644 --- a/configs/renesas_rzg2l_smarc_defconfig +++ b/configs/renesas_rzg2l_smarc_defconfig @@ -26,6 +26,9 @@ CONFIG_CMD_GPIO=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y CONFIG_CMD_PART=y +CONFIG_CMD_DHCP=y +CONFIG_CMD_MII=y +CONFIG_CMD_PING=y CONFIG_CMD_PMIC=y CONFIG_CMD_EXT2=y CONFIG_CMD_EXT4=y @@ -40,6 +43,7 @@ CONFIG_ENV_IS_IN_MMC=y CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_SYS_MMC_ENV_PART=2 CONFIG_VERSION_VARIABLE=y +CONFIG_NET_RANDOM_ETHADDR=y CONFIG_REGMAP=y CONFIG_CLK=y CONFIG_CLK_RENESAS=y @@ -49,6 +53,8 @@ CONFIG_DM_I2C=y CONFIG_MMC_IO_VOLTAGE=y CONFIG_MMC_UHS_SUPPORT=y CONFIG_MMC_HS400_SUPPORT=y +CONFIG_PHY_MICREL=y +CONFIG_PHY_MICREL_KSZ90X1=y CONFIG_DM_PMIC=y CONFIG_PMIC_RAA215300=y CONFIG_DM_REGULATOR=y

Configure ET0_TXC and ET1_TXC as outputs on the Renesas RZ/[GV]2L SMARC SoMs, as per RGMII specification.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com Reviewed-by: Geert Uytterhoeven geert+renesas@glider.be Acked-by: Linus Walleij linus.walleij@linaro.org Link: https://lore.kernel.org/20240625200316.4282-5-paul.barker.ct@bp.renesas.com Signed-off-by: Geert Uytterhoeven geert+renesas@glider.be
[ upstream commit: 41c934da488d3a5a79148ead3b5c5eecac1b1d5d ]
(cherry picked from commit 11cbf7bc3124f3d5267ea6aef8e4ba6d6b4f589e) --- .../src/arm64/renesas/rzg2l-smarc-som.dtsi | 76 +++++++++++-------- 1 file changed, 44 insertions(+), 32 deletions(-)
diff --git a/dts/upstream/src/arm64/renesas/rzg2l-smarc-som.dtsi b/dts/upstream/src/arm64/renesas/rzg2l-smarc-som.dtsi index 4409c47239b9..2b5e037ea9fa 100644 --- a/dts/upstream/src/arm64/renesas/rzg2l-smarc-som.dtsi +++ b/dts/upstream/src/arm64/renesas/rzg2l-smarc-som.dtsi @@ -180,41 +180,53 @@ };
eth0_pins: eth0 { - pinmux = <RZG2L_PORT_PINMUX(28, 1, 1)>, /* ET0_LINKSTA */ - <RZG2L_PORT_PINMUX(27, 1, 1)>, /* ET0_MDC */ - <RZG2L_PORT_PINMUX(28, 0, 1)>, /* ET0_MDIO */ - <RZG2L_PORT_PINMUX(20, 0, 1)>, /* ET0_TXC */ - <RZG2L_PORT_PINMUX(20, 1, 1)>, /* ET0_TX_CTL */ - <RZG2L_PORT_PINMUX(20, 2, 1)>, /* ET0_TXD0 */ - <RZG2L_PORT_PINMUX(21, 0, 1)>, /* ET0_TXD1 */ - <RZG2L_PORT_PINMUX(21, 1, 1)>, /* ET0_TXD2 */ - <RZG2L_PORT_PINMUX(22, 0, 1)>, /* ET0_TXD3 */ - <RZG2L_PORT_PINMUX(24, 0, 1)>, /* ET0_RXC */ - <RZG2L_PORT_PINMUX(24, 1, 1)>, /* ET0_RX_CTL */ - <RZG2L_PORT_PINMUX(25, 0, 1)>, /* ET0_RXD0 */ - <RZG2L_PORT_PINMUX(25, 1, 1)>, /* ET0_RXD1 */ - <RZG2L_PORT_PINMUX(26, 0, 1)>, /* ET0_RXD2 */ - <RZG2L_PORT_PINMUX(26, 1, 1)>, /* ET0_RXD3 */ - <RZG2L_PORT_PINMUX(1, 0, 1)>; /* IRQ2 */ + txc { + pinmux = <RZG2L_PORT_PINMUX(20, 0, 1)>; /* ET0_TXC */ + output-enable; + }; + + mux { + pinmux = <RZG2L_PORT_PINMUX(28, 1, 1)>, /* ET0_LINKSTA */ + <RZG2L_PORT_PINMUX(27, 1, 1)>, /* ET0_MDC */ + <RZG2L_PORT_PINMUX(28, 0, 1)>, /* ET0_MDIO */ + <RZG2L_PORT_PINMUX(20, 1, 1)>, /* ET0_TX_CTL */ + <RZG2L_PORT_PINMUX(20, 2, 1)>, /* ET0_TXD0 */ + <RZG2L_PORT_PINMUX(21, 0, 1)>, /* ET0_TXD1 */ + <RZG2L_PORT_PINMUX(21, 1, 1)>, /* ET0_TXD2 */ + <RZG2L_PORT_PINMUX(22, 0, 1)>, /* ET0_TXD3 */ + <RZG2L_PORT_PINMUX(24, 0, 1)>, /* ET0_RXC */ + <RZG2L_PORT_PINMUX(24, 1, 1)>, /* ET0_RX_CTL */ + <RZG2L_PORT_PINMUX(25, 0, 1)>, /* ET0_RXD0 */ + <RZG2L_PORT_PINMUX(25, 1, 1)>, /* ET0_RXD1 */ + <RZG2L_PORT_PINMUX(26, 0, 1)>, /* ET0_RXD2 */ + <RZG2L_PORT_PINMUX(26, 1, 1)>, /* ET0_RXD3 */ + <RZG2L_PORT_PINMUX(1, 0, 1)>; /* IRQ2 */ + }; };
eth1_pins: eth1 { - pinmux = <RZG2L_PORT_PINMUX(37, 2, 1)>, /* ET1_LINKSTA */ - <RZG2L_PORT_PINMUX(37, 0, 1)>, /* ET1_MDC */ - <RZG2L_PORT_PINMUX(37, 1, 1)>, /* ET1_MDIO */ - <RZG2L_PORT_PINMUX(29, 0, 1)>, /* ET1_TXC */ - <RZG2L_PORT_PINMUX(29, 1, 1)>, /* ET1_TX_CTL */ - <RZG2L_PORT_PINMUX(30, 0, 1)>, /* ET1_TXD0 */ - <RZG2L_PORT_PINMUX(30, 1, 1)>, /* ET1_TXD1 */ - <RZG2L_PORT_PINMUX(31, 0, 1)>, /* ET1_TXD2 */ - <RZG2L_PORT_PINMUX(31, 1, 1)>, /* ET1_TXD3 */ - <RZG2L_PORT_PINMUX(33, 1, 1)>, /* ET1_RXC */ - <RZG2L_PORT_PINMUX(34, 0, 1)>, /* ET1_RX_CTL */ - <RZG2L_PORT_PINMUX(34, 1, 1)>, /* ET1_RXD0 */ - <RZG2L_PORT_PINMUX(35, 0, 1)>, /* ET1_RXD1 */ - <RZG2L_PORT_PINMUX(35, 1, 1)>, /* ET1_RXD2 */ - <RZG2L_PORT_PINMUX(36, 0, 1)>, /* ET1_RXD3 */ - <RZG2L_PORT_PINMUX(1, 1, 1)>; /* IRQ3 */ + txc { + pinmux = <RZG2L_PORT_PINMUX(29, 0, 1)>; /* ET1_TXC */ + output-enable; + }; + + mux { + pinmux = <RZG2L_PORT_PINMUX(37, 2, 1)>, /* ET1_LINKSTA */ + <RZG2L_PORT_PINMUX(37, 0, 1)>, /* ET1_MDC */ + <RZG2L_PORT_PINMUX(37, 1, 1)>, /* ET1_MDIO */ + <RZG2L_PORT_PINMUX(29, 1, 1)>, /* ET1_TX_CTL */ + <RZG2L_PORT_PINMUX(30, 0, 1)>, /* ET1_TXD0 */ + <RZG2L_PORT_PINMUX(30, 1, 1)>, /* ET1_TXD1 */ + <RZG2L_PORT_PINMUX(31, 0, 1)>, /* ET1_TXD2 */ + <RZG2L_PORT_PINMUX(31, 1, 1)>, /* ET1_TXD3 */ + <RZG2L_PORT_PINMUX(33, 1, 1)>, /* ET1_RXC */ + <RZG2L_PORT_PINMUX(34, 0, 1)>, /* ET1_RX_CTL */ + <RZG2L_PORT_PINMUX(34, 1, 1)>, /* ET1_RXD0 */ + <RZG2L_PORT_PINMUX(35, 0, 1)>, /* ET1_RXD1 */ + <RZG2L_PORT_PINMUX(35, 1, 1)>, /* ET1_RXD2 */ + <RZG2L_PORT_PINMUX(36, 0, 1)>, /* ET1_RXD3 */ + <RZG2L_PORT_PINMUX(1, 1, 1)>; /* IRQ3 */ + }; };
gpio-sd0-pwr-en-hog {

On 24/10/2024 16:24, Paul Barker wrote:
Configure ET0_TXC and ET1_TXC as outputs on the Renesas RZ/[GV]2L SMARC SoMs, as per RGMII specification.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com Reviewed-by: Geert Uytterhoeven geert+renesas@glider.be Acked-by: Linus Walleij linus.walleij@linaro.org Link: https://lore.kernel.org/20240625200316.4282-5-paul.barker.ct@bp.renesas.com Signed-off-by: Geert Uytterhoeven geert+renesas@glider.be
[ upstream commit: 41c934da488d3a5a79148ead3b5c5eecac1b1d5d ]
(cherry picked from commit 11cbf7bc3124f3d5267ea6aef8e4ba6d6b4f589e)
Apologies Geert and Linus W, this and the following patch are for U-Boot. `git send-email` Cc'd you based on the Reviewed-by & Acked-by tags. You can safely ignore these :)
I'll see if I can add some notes to the relevant U-Boot docs [1] [2] to use the `--no-signed-off-cc` argument to `git send-email` for such patches, so that myself and others hopefully don't make the same mistake in the future.
[1]: https://docs.u-boot.org/en/latest/develop/process.html#resyncing-of-the-devi... [2]: https://docs.u-boot.org/en/latest/develop/devicetree/control.html#resyncing-...
Thanks,

On Thu, 24 Oct 2024 at 20:55, Paul Barker paul.barker.ct@bp.renesas.com wrote:
Configure ET0_TXC and ET1_TXC as outputs on the Renesas RZ/[GV]2L SMARC SoMs, as per RGMII specification.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com Reviewed-by: Geert Uytterhoeven geert+renesas@glider.be Acked-by: Linus Walleij linus.walleij@linaro.org Link: https://lore.kernel.org/20240625200316.4282-5-paul.barker.ct@bp.renesas.com Signed-off-by: Geert Uytterhoeven geert+renesas@glider.be
[ upstream commit: 41c934da488d3a5a79148ead3b5c5eecac1b1d5d ]
(cherry picked from commit 11cbf7bc3124f3d5267ea6aef8e4ba6d6b4f589e)
.../src/arm64/renesas/rzg2l-smarc-som.dtsi | 76 +++++++++++-------- 1 file changed, 44 insertions(+), 32 deletions(-)
Acked-by: Sumit Garg sumit.garg@linaro.org
-Sumit
diff --git a/dts/upstream/src/arm64/renesas/rzg2l-smarc-som.dtsi b/dts/upstream/src/arm64/renesas/rzg2l-smarc-som.dtsi index 4409c47239b9..2b5e037ea9fa 100644 --- a/dts/upstream/src/arm64/renesas/rzg2l-smarc-som.dtsi +++ b/dts/upstream/src/arm64/renesas/rzg2l-smarc-som.dtsi @@ -180,41 +180,53 @@ };
eth0_pins: eth0 {
pinmux = <RZG2L_PORT_PINMUX(28, 1, 1)>, /* ET0_LINKSTA */
<RZG2L_PORT_PINMUX(27, 1, 1)>, /* ET0_MDC */
<RZG2L_PORT_PINMUX(28, 0, 1)>, /* ET0_MDIO */
<RZG2L_PORT_PINMUX(20, 0, 1)>, /* ET0_TXC */
<RZG2L_PORT_PINMUX(20, 1, 1)>, /* ET0_TX_CTL */
<RZG2L_PORT_PINMUX(20, 2, 1)>, /* ET0_TXD0 */
<RZG2L_PORT_PINMUX(21, 0, 1)>, /* ET0_TXD1 */
<RZG2L_PORT_PINMUX(21, 1, 1)>, /* ET0_TXD2 */
<RZG2L_PORT_PINMUX(22, 0, 1)>, /* ET0_TXD3 */
<RZG2L_PORT_PINMUX(24, 0, 1)>, /* ET0_RXC */
<RZG2L_PORT_PINMUX(24, 1, 1)>, /* ET0_RX_CTL */
<RZG2L_PORT_PINMUX(25, 0, 1)>, /* ET0_RXD0 */
<RZG2L_PORT_PINMUX(25, 1, 1)>, /* ET0_RXD1 */
<RZG2L_PORT_PINMUX(26, 0, 1)>, /* ET0_RXD2 */
<RZG2L_PORT_PINMUX(26, 1, 1)>, /* ET0_RXD3 */
<RZG2L_PORT_PINMUX(1, 0, 1)>; /* IRQ2 */
txc {
pinmux = <RZG2L_PORT_PINMUX(20, 0, 1)>; /* ET0_TXC */
output-enable;
};
mux {
pinmux = <RZG2L_PORT_PINMUX(28, 1, 1)>, /* ET0_LINKSTA */
<RZG2L_PORT_PINMUX(27, 1, 1)>, /* ET0_MDC */
<RZG2L_PORT_PINMUX(28, 0, 1)>, /* ET0_MDIO */
<RZG2L_PORT_PINMUX(20, 1, 1)>, /* ET0_TX_CTL */
<RZG2L_PORT_PINMUX(20, 2, 1)>, /* ET0_TXD0 */
<RZG2L_PORT_PINMUX(21, 0, 1)>, /* ET0_TXD1 */
<RZG2L_PORT_PINMUX(21, 1, 1)>, /* ET0_TXD2 */
<RZG2L_PORT_PINMUX(22, 0, 1)>, /* ET0_TXD3 */
<RZG2L_PORT_PINMUX(24, 0, 1)>, /* ET0_RXC */
<RZG2L_PORT_PINMUX(24, 1, 1)>, /* ET0_RX_CTL */
<RZG2L_PORT_PINMUX(25, 0, 1)>, /* ET0_RXD0 */
<RZG2L_PORT_PINMUX(25, 1, 1)>, /* ET0_RXD1 */
<RZG2L_PORT_PINMUX(26, 0, 1)>, /* ET0_RXD2 */
<RZG2L_PORT_PINMUX(26, 1, 1)>, /* ET0_RXD3 */
<RZG2L_PORT_PINMUX(1, 0, 1)>; /* IRQ2 */
}; }; eth1_pins: eth1 {
pinmux = <RZG2L_PORT_PINMUX(37, 2, 1)>, /* ET1_LINKSTA */
<RZG2L_PORT_PINMUX(37, 0, 1)>, /* ET1_MDC */
<RZG2L_PORT_PINMUX(37, 1, 1)>, /* ET1_MDIO */
<RZG2L_PORT_PINMUX(29, 0, 1)>, /* ET1_TXC */
<RZG2L_PORT_PINMUX(29, 1, 1)>, /* ET1_TX_CTL */
<RZG2L_PORT_PINMUX(30, 0, 1)>, /* ET1_TXD0 */
<RZG2L_PORT_PINMUX(30, 1, 1)>, /* ET1_TXD1 */
<RZG2L_PORT_PINMUX(31, 0, 1)>, /* ET1_TXD2 */
<RZG2L_PORT_PINMUX(31, 1, 1)>, /* ET1_TXD3 */
<RZG2L_PORT_PINMUX(33, 1, 1)>, /* ET1_RXC */
<RZG2L_PORT_PINMUX(34, 0, 1)>, /* ET1_RX_CTL */
<RZG2L_PORT_PINMUX(34, 1, 1)>, /* ET1_RXD0 */
<RZG2L_PORT_PINMUX(35, 0, 1)>, /* ET1_RXD1 */
<RZG2L_PORT_PINMUX(35, 1, 1)>, /* ET1_RXD2 */
<RZG2L_PORT_PINMUX(36, 0, 1)>, /* ET1_RXD3 */
<RZG2L_PORT_PINMUX(1, 1, 1)>; /* IRQ3 */
txc {
pinmux = <RZG2L_PORT_PINMUX(29, 0, 1)>; /* ET1_TXC */
output-enable;
};
mux {
pinmux = <RZG2L_PORT_PINMUX(37, 2, 1)>, /* ET1_LINKSTA */
<RZG2L_PORT_PINMUX(37, 0, 1)>, /* ET1_MDC */
<RZG2L_PORT_PINMUX(37, 1, 1)>, /* ET1_MDIO */
<RZG2L_PORT_PINMUX(29, 1, 1)>, /* ET1_TX_CTL */
<RZG2L_PORT_PINMUX(30, 0, 1)>, /* ET1_TXD0 */
<RZG2L_PORT_PINMUX(30, 1, 1)>, /* ET1_TXD1 */
<RZG2L_PORT_PINMUX(31, 0, 1)>, /* ET1_TXD2 */
<RZG2L_PORT_PINMUX(31, 1, 1)>, /* ET1_TXD3 */
<RZG2L_PORT_PINMUX(33, 1, 1)>, /* ET1_RXC */
<RZG2L_PORT_PINMUX(34, 0, 1)>, /* ET1_RX_CTL */
<RZG2L_PORT_PINMUX(34, 1, 1)>, /* ET1_RXD0 */
<RZG2L_PORT_PINMUX(35, 0, 1)>, /* ET1_RXD1 */
<RZG2L_PORT_PINMUX(35, 1, 1)>, /* ET1_RXD2 */
<RZG2L_PORT_PINMUX(36, 0, 1)>, /* ET1_RXD3 */
<RZG2L_PORT_PINMUX(1, 1, 1)>; /* IRQ3 */
}; }; gpio-sd0-pwr-en-hog {
-- 2.43.0

On the RZ/G2L & RZ/V2L SMARC SOMs, the RGMII interface between the SoC and the Ethernet PHY operates at 1.8V.
The power supply for this interface may be correctly configured in u-boot, but the kernel should not be relying on this. Now that the RZ/G2L pinctrl driver supports configuring the Ethernet power supply voltage, we can simply specify the desired voltage in the device tree.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com Reviewed-by: Geert Uytterhoeven geert+renesas@glider.be Acked-by: Linus Walleij linus.walleij@linaro.org Link: https://lore.kernel.org/20240625200316.4282-8-paul.barker.ct@bp.renesas.com Signed-off-by: Geert Uytterhoeven geert+renesas@glider.be
[ upstream commit: 96a3f525708120379013d9d3265663c07ceb38d5 ]
(cherry picked from commit c535103b52a1edf50309dcbd1948d56520e84a1e) --- .../src/arm64/renesas/rzg2l-smarc-som.dtsi | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/dts/upstream/src/arm64/renesas/rzg2l-smarc-som.dtsi b/dts/upstream/src/arm64/renesas/rzg2l-smarc-som.dtsi index 2b5e037ea9fa..83f5642d0d35 100644 --- a/dts/upstream/src/arm64/renesas/rzg2l-smarc-som.dtsi +++ b/dts/upstream/src/arm64/renesas/rzg2l-smarc-som.dtsi @@ -182,6 +182,7 @@ eth0_pins: eth0 { txc { pinmux = <RZG2L_PORT_PINMUX(20, 0, 1)>; /* ET0_TXC */ + power-source = <1800>; output-enable; };
@@ -199,14 +200,19 @@ <RZG2L_PORT_PINMUX(25, 0, 1)>, /* ET0_RXD0 */ <RZG2L_PORT_PINMUX(25, 1, 1)>, /* ET0_RXD1 */ <RZG2L_PORT_PINMUX(26, 0, 1)>, /* ET0_RXD2 */ - <RZG2L_PORT_PINMUX(26, 1, 1)>, /* ET0_RXD3 */ - <RZG2L_PORT_PINMUX(1, 0, 1)>; /* IRQ2 */ + <RZG2L_PORT_PINMUX(26, 1, 1)>; /* ET0_RXD3 */ + power-source = <1800>; + }; + + irq { + pinmux = <RZG2L_PORT_PINMUX(1, 0, 1)>; /* IRQ2 */ }; };
eth1_pins: eth1 { txc { pinmux = <RZG2L_PORT_PINMUX(29, 0, 1)>; /* ET1_TXC */ + power-source = <1800>; output-enable; };
@@ -224,8 +230,12 @@ <RZG2L_PORT_PINMUX(34, 1, 1)>, /* ET1_RXD0 */ <RZG2L_PORT_PINMUX(35, 0, 1)>, /* ET1_RXD1 */ <RZG2L_PORT_PINMUX(35, 1, 1)>, /* ET1_RXD2 */ - <RZG2L_PORT_PINMUX(36, 0, 1)>, /* ET1_RXD3 */ - <RZG2L_PORT_PINMUX(1, 1, 1)>; /* IRQ3 */ + <RZG2L_PORT_PINMUX(36, 0, 1)>; /* ET1_RXD3 */ + power-source = <1800>; + }; + + irq { + pinmux = <RZG2L_PORT_PINMUX(1, 1, 1)>; /* IRQ3 */ }; };

On Thu, 24 Oct 2024 at 20:56, Paul Barker paul.barker.ct@bp.renesas.com wrote:
On the RZ/G2L & RZ/V2L SMARC SOMs, the RGMII interface between the SoC and the Ethernet PHY operates at 1.8V.
The power supply for this interface may be correctly configured in u-boot, but the kernel should not be relying on this. Now that the RZ/G2L pinctrl driver supports configuring the Ethernet power supply voltage, we can simply specify the desired voltage in the device tree.
Signed-off-by: Paul Barker paul.barker.ct@bp.renesas.com Reviewed-by: Geert Uytterhoeven geert+renesas@glider.be Acked-by: Linus Walleij linus.walleij@linaro.org Link: https://lore.kernel.org/20240625200316.4282-8-paul.barker.ct@bp.renesas.com Signed-off-by: Geert Uytterhoeven geert+renesas@glider.be
[ upstream commit: 96a3f525708120379013d9d3265663c07ceb38d5 ]
(cherry picked from commit c535103b52a1edf50309dcbd1948d56520e84a1e)
.../src/arm64/renesas/rzg2l-smarc-som.dtsi | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
Acked-by: Sumit Garg sumit.garg@linaro.org
-Sumit
diff --git a/dts/upstream/src/arm64/renesas/rzg2l-smarc-som.dtsi b/dts/upstream/src/arm64/renesas/rzg2l-smarc-som.dtsi index 2b5e037ea9fa..83f5642d0d35 100644 --- a/dts/upstream/src/arm64/renesas/rzg2l-smarc-som.dtsi +++ b/dts/upstream/src/arm64/renesas/rzg2l-smarc-som.dtsi @@ -182,6 +182,7 @@ eth0_pins: eth0 { txc { pinmux = <RZG2L_PORT_PINMUX(20, 0, 1)>; /* ET0_TXC */
power-source = <1800>; output-enable; };
@@ -199,14 +200,19 @@ <RZG2L_PORT_PINMUX(25, 0, 1)>, /* ET0_RXD0 */ <RZG2L_PORT_PINMUX(25, 1, 1)>, /* ET0_RXD1 */ <RZG2L_PORT_PINMUX(26, 0, 1)>, /* ET0_RXD2 */
<RZG2L_PORT_PINMUX(26, 1, 1)>, /* ET0_RXD3 */
<RZG2L_PORT_PINMUX(1, 0, 1)>; /* IRQ2 */
<RZG2L_PORT_PINMUX(26, 1, 1)>; /* ET0_RXD3 */
power-source = <1800>;
};
irq {
pinmux = <RZG2L_PORT_PINMUX(1, 0, 1)>; /* IRQ2 */ }; }; eth1_pins: eth1 { txc { pinmux = <RZG2L_PORT_PINMUX(29, 0, 1)>; /* ET1_TXC */
power-source = <1800>; output-enable; };
@@ -224,8 +230,12 @@ <RZG2L_PORT_PINMUX(34, 1, 1)>, /* ET1_RXD0 */ <RZG2L_PORT_PINMUX(35, 0, 1)>, /* ET1_RXD1 */ <RZG2L_PORT_PINMUX(35, 1, 1)>, /* ET1_RXD2 */
<RZG2L_PORT_PINMUX(36, 0, 1)>, /* ET1_RXD3 */
<RZG2L_PORT_PINMUX(1, 1, 1)>; /* IRQ3 */
<RZG2L_PORT_PINMUX(36, 0, 1)>; /* ET1_RXD3 */
power-source = <1800>;
};
irq {
pinmux = <RZG2L_PORT_PINMUX(1, 1, 1)>; /* IRQ3 */ }; };
-- 2.43.0
participants (3)
-
Marek Vasut
-
Paul Barker
-
Sumit Garg