diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/Kconfig | 2 | ||||
-rw-r--r-- | drivers/net/ravb.c | 173 |
2 files changed, 151 insertions, 24 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 4434d364777..950ed0f25a9 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -860,7 +860,7 @@ config RENESAS_RAVB select PHY_ETHERNET_ID help This driver implements support for the Ethernet AVB block in - Renesas M3 and H3 SoCs. + several Renesas R-Car and RZ SoCs. config MPC8XX_FEC bool "Fast Ethernet Controller on MPC8XX" diff --git a/drivers/net/ravb.c b/drivers/net/ravb.c index 539fd37ee59..68528864ac6 100644 --- a/drivers/net/ravb.c +++ b/drivers/net/ravb.c @@ -23,6 +23,7 @@ #include <asm/io.h> #include <asm/global_data.h> #include <asm/gpio.h> +#include <reset.h> /* Registers */ #define RAVB_REG_CCC 0x000 @@ -30,6 +31,7 @@ #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 @@ -43,6 +45,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) @@ -64,14 +67,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 @@ -107,6 +120,13 @@ #define RAVB_TX_TIMEOUT_MS 1000 +struct ravb_device_ops { + void (*mac_init)(struct udevice *dev); + void (*dmac_init)(struct udevice *dev); + void (*config)(struct udevice *dev); + bool has_reset; +}; + struct ravb_desc { u32 ctrl; u32 dptr; @@ -130,6 +150,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) @@ -181,7 +202,7 @@ static int ravb_recv(struct udevice *dev, int flags, uchar **packetp) { struct ravb_priv *eth = dev_get_priv(dev); struct ravb_rxdesc *desc = ð->rx_desc[eth->rx_desc_idx]; - int len; + int len = 0; u8 *packet; /* Check if the rx descriptor is ready */ @@ -190,12 +211,11 @@ static int ravb_recv(struct udevice *dev, int flags, uchar **packetp) return -EAGAIN; /* Check for errors */ - if (desc->data.ctrl & RAVB_RX_DESC_MSC_RX_ERR_MASK) { + if (desc->data.ctrl & RAVB_RX_DESC_MSC_RX_ERR_MASK) desc->data.ctrl &= ~RAVB_RX_DESC_MSC_MASK; - return -EAGAIN; - } + else + len = desc->data.ctrl & RAVB_DESC_DS_MASK; - len = desc->data.ctrl & RAVB_DESC_DS_MASK; packet = (u8 *)(uintptr_t)desc->data.dptr; ravb_invalidate_dcache((uintptr_t)packet, len); @@ -349,10 +369,13 @@ static int ravb_write_hwaddr(struct udevice *dev) } /* E-MAC init function */ -static int ravb_mac_init(struct ravb_priv *eth) +static void ravb_mac_init(struct udevice *dev) { - /* Disable MAC Interrupt */ - writel(0, eth->iobase + RAVB_REG_ECSIPR); + 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->mac_init(dev); /* * Set receive frame length @@ -363,19 +386,33 @@ static int ravb_mac_init(struct ravb_priv *eth) * largest frames add the CRC length to the maximum Rx descriptor size. */ writel(RFLR_RFL_MIN + ETH_FCS_LEN, eth->iobase + RAVB_REG_RFLR); +} - return 0; +static void 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); +} + +static void 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)); } /* 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); @@ -391,6 +428,18 @@ static int ravb_dmac_init(struct udevice *dev) /* Set little endian */ clrbits_le32(eth->iobase + RAVB_REG_CCC, CCC_BOC); + device_ops->dmac_init(dev); + return 0; +} + +static void 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); @@ -400,7 +449,7 @@ static int ravb_dmac_init(struct udevice *dev) /* Delay CLK: 2ns (not applicable on R-Car E3/D3) */ if ((renesas_get_cpu_type() == RENESAS_CPU_TYPE_R8A77990) || (renesas_get_cpu_type() == RENESAS_CPU_TYPE_R8A77995)) - return 0; + return; if (!dev_read_u32(dev, "rx-internal-delay-ps", &delay)) { /* Valid values are 0 and 1800, according to DT bindings */ @@ -429,28 +478,45 @@ static int ravb_dmac_init(struct udevice *dev) } writel(mode, eth->iobase + RAVB_REG_APSR); +} - return 0; +static void ravb_dmac_init_rzg2l(struct udevice *dev) +{ + struct ravb_priv *eth = dev_get_priv(dev); + + /* Set Max Frame Length (RTC) */ + writel(0x7ffc0000 | RFLR_RFL_MIN, eth->iobase + RAVB_REG_RTC); } 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); + ravb_mac_init(dev); ravb_write_hwaddr(dev); ret = phy_startup(phy); if (ret) return ret; + device_ops->config(dev); + return 0; +} + +static void 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); @@ -462,8 +528,22 @@ static int ravb_config(struct udevice *dev) mask |= ECMR_DM; writel(mask, eth->iobase + RAVB_REG_ECMR); +} - return 0; +static void 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); } static int ravb_start(struct udevice *dev) @@ -581,6 +661,8 @@ static int ravb_bb_miiphy_write(struct mii_dev *miidev, int addr, 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 mii_dev *mdiodev; @@ -616,16 +698,32 @@ static int ravb_probe(struct udevice *dev) if (ret) goto err_clk_enable; + if (device_ops->has_reset) { + ret = reset_get_by_index(dev, 0, ð->rst); + if (ret < 0) + goto err_clk_enable; + + ret = reset_deassert(ð->rst); + if (ret < 0) + goto err_reset_deassert; + } + ret = ravb_reset(dev); if (ret) - goto err_clk_enable; + goto err_ravb_reset; ret = ravb_phy_config(dev); if (ret) - goto err_clk_enable; + goto err_ravb_reset; return 0; +err_ravb_reset: + if (device_ops->has_reset) + reset_assert(ð->rst); +err_reset_deassert: + if (device_ops->has_reset) + reset_free(ð->rst); err_clk_enable: mdio_unregister(mdiodev); err_mdio_register: @@ -639,8 +737,14 @@ err_clk_get: 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); + if (device_ops->has_reset) { + reset_assert(ð->rst); + reset_free(ð->rst); + } clk_release_bulk(ð->clks); free(eth->phydev); @@ -675,9 +779,32 @@ int ravb_of_to_plat(struct udevice *dev) return 0; } +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, +}; + +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, + .has_reset = true, +}; + 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, + }, { } }; |