diff mbox series

[11/14] net: ravb: Add RZ/G2L Support

Message ID 20241024152448.102-12-paul.barker.ct@bp.renesas.com
State New
Delegated to: Marek Vasut
Headers show
Series Add support for Ethernet interfaces on RZ/G2L | expand

Commit Message

Paul Barker Oct. 24, 2024, 3:24 p.m. UTC
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(-)

Comments

Marek Vasut Oct. 27, 2024, 4:29 p.m. UTC | #1
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(&eth->rst);
> +	reset_free(&eth->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,
> +};
[...]
Paul Barker Oct. 28, 2024, 9:52 a.m. UTC | #2
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(&eth->rst);
>> +	reset_free(&eth->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,
diff mbox series

Patch

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, &eth->rst);
+	if (ret < 0) {
+		dev_err(dev, "failed to get reset line\n");
+		return ret;
+	}
+
+	ret = reset_deassert(&eth->rst);
+	if (ret < 0) {
+		dev_err(dev, "failed to de-assert reset line\n");
+		reset_free(&eth->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(&eth->rst);
+	reset_free(&eth->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(&eth->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(&eth->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,
+	},
 	{ }
 };