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...@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, + }, { } }; -- 2.43.0