X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fdwc_eth_qos.c;h=3f4437069babb5669936e8d4ec75203ccdb1ede3;hb=287be3294af6179782f8a561afca427620504581;hp=9f1c5af46e992aec87b4ff826adc68ba27ccf47f;hpb=83d290c56fab2d38cd1ab4c4cc7099559c1d5046;p=oweals%2Fu-boot.git diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 9f1c5af46e..3f4437069b 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -26,11 +26,13 @@ * supports a single RGMII PHY. This configuration also has SW control over * all clock and reset signals to the HW block. */ - #include #include +#include #include #include +#include +#include #include #include #include @@ -38,8 +40,16 @@ #include #include #include +#include #include #include +#include +#ifdef CONFIG_ARCH_IMX8M +#include +#include +#endif +#include +#include /* Core registers */ @@ -79,6 +89,7 @@ struct eqos_mac_regs { #define EQOS_MAC_CONFIGURATION_PS BIT(15) #define EQOS_MAC_CONFIGURATION_FES BIT(14) #define EQOS_MAC_CONFIGURATION_DM BIT(13) +#define EQOS_MAC_CONFIGURATION_LM BIT(12) #define EQOS_MAC_CONFIGURATION_TE BIT(1) #define EQOS_MAC_CONFIGURATION_RE BIT(0) @@ -95,19 +106,29 @@ struct eqos_mac_regs { #define EQOS_MAC_RXQ_CTRL0_RXQ0EN_MASK 3 #define EQOS_MAC_RXQ_CTRL0_RXQ0EN_NOT_ENABLED 0 #define EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB 2 +#define EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_AV 1 #define EQOS_MAC_RXQ_CTRL2_PSRQ0_SHIFT 0 #define EQOS_MAC_RXQ_CTRL2_PSRQ0_MASK 0xff +#define EQOS_MAC_HW_FEATURE0_MMCSEL_SHIFT 8 +#define EQOS_MAC_HW_FEATURE0_HDSEL_SHIFT 2 +#define EQOS_MAC_HW_FEATURE0_GMIISEL_SHIFT 1 +#define EQOS_MAC_HW_FEATURE0_MIISEL_SHIFT 0 + #define EQOS_MAC_HW_FEATURE1_TXFIFOSIZE_SHIFT 6 #define EQOS_MAC_HW_FEATURE1_TXFIFOSIZE_MASK 0x1f #define EQOS_MAC_HW_FEATURE1_RXFIFOSIZE_SHIFT 0 #define EQOS_MAC_HW_FEATURE1_RXFIFOSIZE_MASK 0x1f +#define EQOS_MAC_HW_FEATURE3_ASP_SHIFT 28 +#define EQOS_MAC_HW_FEATURE3_ASP_MASK 0x3 + #define EQOS_MAC_MDIO_ADDRESS_PA_SHIFT 21 #define EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT 16 #define EQOS_MAC_MDIO_ADDRESS_CR_SHIFT 8 #define EQOS_MAC_MDIO_ADDRESS_CR_20_35 2 +#define EQOS_MAC_MDIO_ADDRESS_CR_250_300 5 #define EQOS_MAC_MDIO_ADDRESS_SKAP BIT(4) #define EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT 2 #define EQOS_MAC_MDIO_ADDRESS_GOC_READ 3 @@ -150,6 +171,8 @@ struct eqos_mtl_regs { #define EQOS_MTL_RXQ0_OPERATION_MODE_RFA_MASK 0x3f #define EQOS_MTL_RXQ0_OPERATION_MODE_EHFC BIT(7) #define EQOS_MTL_RXQ0_OPERATION_MODE_RSF BIT(5) +#define EQOS_MTL_RXQ0_OPERATION_MODE_FEP BIT(4) +#define EQOS_MTL_RXQ0_OPERATION_MODE_FUP BIT(3) #define EQOS_MTL_RXQ0_DEBUG_PRXQ_SHIFT 16 #define EQOS_MTL_RXQ0_DEBUG_PRXQ_MASK 0x7fff @@ -241,7 +264,7 @@ struct eqos_tegra186_regs { */ #if EQOS_DESCRIPTOR_SIZE < ARCH_DMA_MINALIGN #if !defined(CONFIG_SYS_NONCACHED_MEMORY) && \ - !defined(CONFIG_SYS_DCACHE_OFF) && !defined(CONFIG_X86) + !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) && !defined(CONFIG_X86) #warning Cache line size is larger than descriptor size #endif #endif @@ -260,6 +283,29 @@ struct eqos_desc { struct eqos_config { bool reg_access_always_ok; + int mdio_wait; + int swr_wait; + int config_mac; + int config_mac_mdio; + phy_interface_t (*interface)(struct udevice *dev); + struct eqos_ops *ops; +}; + +struct eqos_ops { + void (*eqos_inval_desc)(void *desc); + void (*eqos_flush_desc)(void *desc); + void (*eqos_inval_buffer)(void *buf, size_t size); + void (*eqos_flush_buffer)(void *buf, size_t size); + int (*eqos_probe_resources)(struct udevice *dev); + int (*eqos_remove_resources)(struct udevice *dev); + int (*eqos_stop_resets)(struct udevice *dev); + int (*eqos_start_resets)(struct udevice *dev); + void (*eqos_stop_clks)(struct udevice *dev); + int (*eqos_start_clks)(struct udevice *dev); + int (*eqos_calibrate_pads)(struct udevice *dev); + int (*eqos_disable_calibration)(struct udevice *dev); + int (*eqos_set_tx_clk_speed)(struct udevice *dev); + ulong (*eqos_get_tick_clk_rate)(struct udevice *dev); }; struct eqos_priv { @@ -276,9 +322,12 @@ struct eqos_priv { struct clk clk_rx; struct clk clk_ptp_ref; struct clk clk_tx; + struct clk clk_ck; struct clk clk_slave_bus; struct mii_dev *mii; struct phy_device *phy; + int phyaddr; + u32 max_speed; void *descs; struct eqos_desc *tx_descs; struct eqos_desc *rx_descs; @@ -327,7 +376,7 @@ static void eqos_free_descs(void *descs) #endif } -static void eqos_inval_desc(void *desc) +static void eqos_inval_desc_tegra186(void *desc) { #ifndef CONFIG_SYS_NONCACHED_MEMORY unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN - 1); @@ -338,14 +387,36 @@ static void eqos_inval_desc(void *desc) #endif } -static void eqos_flush_desc(void *desc) +static void eqos_inval_desc_generic(void *desc) +{ +#ifndef CONFIG_SYS_NONCACHED_MEMORY + unsigned long start = rounddown((unsigned long)desc, ARCH_DMA_MINALIGN); + unsigned long end = roundup((unsigned long)desc + EQOS_DESCRIPTOR_SIZE, + ARCH_DMA_MINALIGN); + + invalidate_dcache_range(start, end); +#endif +} + +static void eqos_flush_desc_tegra186(void *desc) { #ifndef CONFIG_SYS_NONCACHED_MEMORY flush_cache((unsigned long)desc, EQOS_DESCRIPTOR_SIZE); #endif } -static void eqos_inval_buffer(void *buf, size_t size) +static void eqos_flush_desc_generic(void *desc) +{ +#ifndef CONFIG_SYS_NONCACHED_MEMORY + unsigned long start = rounddown((unsigned long)desc, ARCH_DMA_MINALIGN); + unsigned long end = roundup((unsigned long)desc + EQOS_DESCRIPTOR_SIZE, + ARCH_DMA_MINALIGN); + + flush_dcache_range(start, end); +#endif +} + +static void eqos_inval_buffer_tegra186(void *buf, size_t size) { unsigned long start = (unsigned long)buf & ~(ARCH_DMA_MINALIGN - 1); unsigned long end = ALIGN(start + size, ARCH_DMA_MINALIGN); @@ -353,11 +424,29 @@ static void eqos_inval_buffer(void *buf, size_t size) invalidate_dcache_range(start, end); } -static void eqos_flush_buffer(void *buf, size_t size) +static void eqos_inval_buffer_generic(void *buf, size_t size) +{ + unsigned long start = rounddown((unsigned long)buf, ARCH_DMA_MINALIGN); + unsigned long end = roundup((unsigned long)buf + size, + ARCH_DMA_MINALIGN); + + invalidate_dcache_range(start, end); +} + +static void eqos_flush_buffer_tegra186(void *buf, size_t size) { flush_cache((unsigned long)buf, size); } +static void eqos_flush_buffer_generic(void *buf, size_t size) +{ + unsigned long start = rounddown((unsigned long)buf, ARCH_DMA_MINALIGN); + unsigned long end = roundup((unsigned long)buf + size, + ARCH_DMA_MINALIGN); + + flush_dcache_range(start, end); +} + static int eqos_mdio_wait_idle(struct eqos_priv *eqos) { return wait_for_bit_le32(&eqos->mac_regs->mdio_address, @@ -386,14 +475,14 @@ static int eqos_mdio_read(struct mii_dev *bus, int mdio_addr, int mdio_devad, EQOS_MAC_MDIO_ADDRESS_C45E; val |= (mdio_addr << EQOS_MAC_MDIO_ADDRESS_PA_SHIFT) | (mdio_reg << EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT) | - (EQOS_MAC_MDIO_ADDRESS_CR_20_35 << + (eqos->config->config_mac_mdio << EQOS_MAC_MDIO_ADDRESS_CR_SHIFT) | (EQOS_MAC_MDIO_ADDRESS_GOC_READ << EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT) | EQOS_MAC_MDIO_ADDRESS_GB; writel(val, &eqos->mac_regs->mdio_address); - udelay(10); + udelay(eqos->config->mdio_wait); ret = eqos_mdio_wait_idle(eqos); if (ret) { @@ -432,14 +521,14 @@ static int eqos_mdio_write(struct mii_dev *bus, int mdio_addr, int mdio_devad, EQOS_MAC_MDIO_ADDRESS_C45E; val |= (mdio_addr << EQOS_MAC_MDIO_ADDRESS_PA_SHIFT) | (mdio_reg << EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT) | - (EQOS_MAC_MDIO_ADDRESS_CR_20_35 << + (eqos->config->config_mac_mdio << EQOS_MAC_MDIO_ADDRESS_CR_SHIFT) | (EQOS_MAC_MDIO_ADDRESS_GOC_WRITE << EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT) | EQOS_MAC_MDIO_ADDRESS_GB; writel(val, &eqos->mac_regs->mdio_address); - udelay(10); + udelay(eqos->config->mdio_wait); ret = eqos_mdio_wait_idle(eqos); if (ret) { @@ -452,6 +541,7 @@ static int eqos_mdio_write(struct mii_dev *bus, int mdio_addr, int mdio_devad, static int eqos_start_clks_tegra186(struct udevice *dev) { +#ifdef CONFIG_CLK struct eqos_priv *eqos = dev_get_priv(dev); int ret; @@ -492,10 +582,12 @@ static int eqos_start_clks_tegra186(struct udevice *dev) pr_err("clk_enable(clk_tx) failed: %d", ret); goto err_disable_clk_ptp_ref; } +#endif debug("%s: OK\n", __func__); return 0; +#ifdef CONFIG_CLK err_disable_clk_ptp_ref: clk_disable(&eqos->clk_ptp_ref); err_disable_clk_rx: @@ -507,10 +599,68 @@ err_disable_clk_slave_bus: err: debug("%s: FAILED: %d\n", __func__, ret); return ret; +#endif +} + +static int eqos_start_clks_stm32(struct udevice *dev) +{ +#ifdef CONFIG_CLK + struct eqos_priv *eqos = dev_get_priv(dev); + int ret; + + debug("%s(dev=%p):\n", __func__, dev); + + ret = clk_enable(&eqos->clk_master_bus); + if (ret < 0) { + pr_err("clk_enable(clk_master_bus) failed: %d", ret); + goto err; + } + + ret = clk_enable(&eqos->clk_rx); + if (ret < 0) { + pr_err("clk_enable(clk_rx) failed: %d", ret); + goto err_disable_clk_master_bus; + } + + ret = clk_enable(&eqos->clk_tx); + if (ret < 0) { + pr_err("clk_enable(clk_tx) failed: %d", ret); + goto err_disable_clk_rx; + } + + if (clk_valid(&eqos->clk_ck)) { + ret = clk_enable(&eqos->clk_ck); + if (ret < 0) { + pr_err("clk_enable(clk_ck) failed: %d", ret); + goto err_disable_clk_tx; + } + } +#endif + + debug("%s: OK\n", __func__); + return 0; + +#ifdef CONFIG_CLK +err_disable_clk_tx: + clk_disable(&eqos->clk_tx); +err_disable_clk_rx: + clk_disable(&eqos->clk_rx); +err_disable_clk_master_bus: + clk_disable(&eqos->clk_master_bus); +err: + debug("%s: FAILED: %d\n", __func__, ret); + return ret; +#endif } -void eqos_stop_clks_tegra186(struct udevice *dev) +static int eqos_start_clks_imx(struct udevice *dev) { + return 0; +} + +static void eqos_stop_clks_tegra186(struct udevice *dev) +{ +#ifdef CONFIG_CLK struct eqos_priv *eqos = dev_get_priv(dev); debug("%s(dev=%p):\n", __func__, dev); @@ -520,10 +670,33 @@ void eqos_stop_clks_tegra186(struct udevice *dev) clk_disable(&eqos->clk_rx); clk_disable(&eqos->clk_master_bus); clk_disable(&eqos->clk_slave_bus); +#endif + + debug("%s: OK\n", __func__); +} + +static void eqos_stop_clks_stm32(struct udevice *dev) +{ +#ifdef CONFIG_CLK + struct eqos_priv *eqos = dev_get_priv(dev); + + debug("%s(dev=%p):\n", __func__, dev); + + clk_disable(&eqos->clk_tx); + clk_disable(&eqos->clk_rx); + clk_disable(&eqos->clk_master_bus); + if (clk_valid(&eqos->clk_ck)) + clk_disable(&eqos->clk_ck); +#endif debug("%s: OK\n", __func__); } +static void eqos_stop_clks_imx(struct udevice *dev) +{ + /* empty */ +} + static int eqos_start_resets_tegra186(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -563,6 +736,39 @@ static int eqos_start_resets_tegra186(struct udevice *dev) return 0; } +static int eqos_start_resets_stm32(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + int ret; + + debug("%s(dev=%p):\n", __func__, dev); + if (dm_gpio_is_valid(&eqos->phy_reset_gpio)) { + ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 1); + if (ret < 0) { + pr_err("dm_gpio_set_value(phy_reset, assert) failed: %d", + ret); + return ret; + } + + udelay(2); + + ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 0); + if (ret < 0) { + pr_err("dm_gpio_set_value(phy_reset, deassert) failed: %d", + ret); + return ret; + } + } + debug("%s: OK\n", __func__); + + return 0; +} + +static int eqos_start_resets_imx(struct udevice *dev) +{ + return 0; +} + static int eqos_stop_resets_tegra186(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -573,6 +779,28 @@ static int eqos_stop_resets_tegra186(struct udevice *dev) return 0; } +static int eqos_stop_resets_stm32(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + int ret; + + if (dm_gpio_is_valid(&eqos->phy_reset_gpio)) { + ret = dm_gpio_set_value(&eqos->phy_reset_gpio, 1); + if (ret < 0) { + pr_err("dm_gpio_set_value(phy_reset, assert) failed: %d", + ret); + return ret; + } + } + + return 0; +} + +static int eqos_stop_resets_imx(struct udevice *dev) +{ + return 0; +} + static int eqos_calibrate_pads_tegra186(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -627,9 +855,58 @@ static int eqos_disable_calibration_tegra186(struct udevice *dev) static ulong eqos_get_tick_clk_rate_tegra186(struct udevice *dev) { +#ifdef CONFIG_CLK struct eqos_priv *eqos = dev_get_priv(dev); return clk_get_rate(&eqos->clk_slave_bus); +#else + return 0; +#endif +} + +static ulong eqos_get_tick_clk_rate_stm32(struct udevice *dev) +{ +#ifdef CONFIG_CLK + struct eqos_priv *eqos = dev_get_priv(dev); + + return clk_get_rate(&eqos->clk_master_bus); +#else + return 0; +#endif +} + +__weak u32 imx_get_eqos_csr_clk(void) +{ + return 100 * 1000000; +} +__weak int imx_eqos_txclk_set_rate(unsigned long rate) +{ + return 0; +} + +static ulong eqos_get_tick_clk_rate_imx(struct udevice *dev) +{ + return imx_get_eqos_csr_clk(); +} + +static int eqos_calibrate_pads_stm32(struct udevice *dev) +{ + return 0; +} + +static int eqos_calibrate_pads_imx(struct udevice *dev) +{ + return 0; +} + +static int eqos_disable_calibration_stm32(struct udevice *dev) +{ + return 0; +} + +static int eqos_disable_calibration_imx(struct udevice *dev) +{ + return 0; } static int eqos_set_full_duplex(struct udevice *dev) @@ -696,6 +973,7 @@ static int eqos_set_mii_speed_10(struct udevice *dev) static int eqos_set_tx_clk_speed_tegra186(struct udevice *dev) { +#ifdef CONFIG_CLK struct eqos_priv *eqos = dev_get_priv(dev); ulong rate; int ret; @@ -722,6 +1000,44 @@ static int eqos_set_tx_clk_speed_tegra186(struct udevice *dev) pr_err("clk_set_rate(tx_clk, %lu) failed: %d", rate, ret); return ret; } +#endif + + return 0; +} + +static int eqos_set_tx_clk_speed_stm32(struct udevice *dev) +{ + return 0; +} + +static int eqos_set_tx_clk_speed_imx(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + ulong rate; + int ret; + + debug("%s(dev=%p):\n", __func__, dev); + + switch (eqos->phy->speed) { + case SPEED_1000: + rate = 125 * 1000 * 1000; + break; + case SPEED_100: + rate = 25 * 1000 * 1000; + break; + case SPEED_10: + rate = 2.5 * 1000 * 1000; + break; + default: + pr_err("invalid speed %d", eqos->phy->speed); + return -EINVAL; + } + + ret = imx_eqos_txclk_set_rate(rate); + if (ret < 0) { + pr_err("imx (tx_clk, %lu) failed: %d", rate, ret); + return ret; + } return 0; } @@ -766,23 +1082,23 @@ static int eqos_adjust_link(struct udevice *dev) } if (en_calibration) { - ret = eqos_calibrate_pads_tegra186(dev); + ret = eqos->config->ops->eqos_calibrate_pads(dev); if (ret < 0) { - pr_err("eqos_calibrate_pads_tegra186() failed: %d", ret); + pr_err("eqos_calibrate_pads() failed: %d", + ret); return ret; } } else { - ret = eqos_disable_calibration_tegra186(dev); + ret = eqos->config->ops->eqos_disable_calibration(dev); if (ret < 0) { - pr_err("eqos_disable_calibration_tegra186() failed: %d", - ret); + pr_err("eqos_disable_calibration() failed: %d", + ret); return ret; } } - - ret = eqos_set_tx_clk_speed_tegra186(dev); + ret = eqos->config->ops->eqos_set_tx_clk_speed(dev); if (ret < 0) { - pr_err("eqos_set_tx_clk_speed_tegra186() failed: %d", ret); + pr_err("eqos_set_tx_clk_speed() failed: %d", ret); return ret; } @@ -833,6 +1149,16 @@ static int eqos_write_hwaddr(struct udevice *dev) return 0; } +static int eqos_read_rom_hwaddr(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + +#ifdef CONFIG_ARCH_IMX8M + imx_get_mac_from_fuse(dev->req_seq, pdata->enetaddr); +#endif + return !is_valid_ethaddr(pdata->enetaddr); +} + static int eqos_start(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -846,15 +1172,15 @@ static int eqos_start(struct udevice *dev) eqos->tx_desc_idx = 0; eqos->rx_desc_idx = 0; - ret = eqos_start_clks_tegra186(dev); + ret = eqos->config->ops->eqos_start_clks(dev); if (ret < 0) { - pr_err("eqos_start_clks_tegra186() failed: %d", ret); + pr_err("eqos_start_clks() failed: %d", ret); goto err; } - ret = eqos_start_resets_tegra186(dev); + ret = eqos->config->ops->eqos_start_resets(dev); if (ret < 0) { - pr_err("eqos_start_resets_tegra186() failed: %d", ret); + pr_err("eqos_start_resets() failed: %d", ret); goto err_stop_clks; } @@ -863,32 +1189,57 @@ static int eqos_start(struct udevice *dev) eqos->reg_access_ok = true; ret = wait_for_bit_le32(&eqos->dma_regs->mode, - EQOS_DMA_MODE_SWR, false, 10, false); + EQOS_DMA_MODE_SWR, false, + eqos->config->swr_wait, false); if (ret) { pr_err("EQOS_DMA_MODE_SWR stuck"); goto err_stop_resets; } - ret = eqos_calibrate_pads_tegra186(dev); + ret = eqos->config->ops->eqos_calibrate_pads(dev); if (ret < 0) { - pr_err("eqos_calibrate_pads_tegra186() failed: %d", ret); + pr_err("eqos_calibrate_pads() failed: %d", ret); goto err_stop_resets; } + rate = eqos->config->ops->eqos_get_tick_clk_rate(dev); - rate = eqos_get_tick_clk_rate_tegra186(dev); val = (rate / 1000000) - 1; writel(val, &eqos->mac_regs->us_tic_counter); - eqos->phy = phy_connect(eqos->mii, 0, dev, 0); + /* + * if PHY was already connected and configured, + * don't need to reconnect/reconfigure again + */ if (!eqos->phy) { - pr_err("phy_connect() failed"); - goto err_stop_resets; - } - ret = phy_config(eqos->phy); - if (ret < 0) { - pr_err("phy_config() failed: %d", ret); - goto err_shutdown_phy; + int addr = -1; +#ifdef CONFIG_DM_ETH_PHY + addr = eth_phy_get_addr(dev); +#endif +#ifdef DWC_NET_PHYADDR + addr = DWC_NET_PHYADDR; +#endif + eqos->phy = phy_connect(eqos->mii, addr, dev, + eqos->config->interface(dev)); + if (!eqos->phy) { + pr_err("phy_connect() failed"); + goto err_stop_resets; + } + + if (eqos->max_speed) { + ret = phy_set_supported(eqos->phy, eqos->max_speed); + if (ret) { + pr_err("phy_set_supported() failed: %d", ret); + goto err_shutdown_phy; + } + } + + ret = phy_config(eqos->phy); + if (ret < 0) { + pr_err("phy_config() failed: %d", ret); + goto err_shutdown_phy; + } } + ret = phy_startup(eqos->phy); if (ret < 0) { pr_err("phy_startup() failed: %d", ret); @@ -907,6 +1258,7 @@ static int eqos_start(struct udevice *dev) } /* Configure MTL */ + writel(0x60, &eqos->mtl_regs->txq0_quantum_weight - 0x100); /* Enable Store and Forward mode for TX */ /* Program Tx operating mode */ @@ -920,7 +1272,9 @@ static int eqos_start(struct udevice *dev) /* Enable Store and Forward mode for RX, since no jumbo frame */ setbits_le32(&eqos->mtl_regs->rxq0_operation_mode, - EQOS_MTL_RXQ0_OPERATION_MODE_RSF); + EQOS_MTL_RXQ0_OPERATION_MODE_RSF | + EQOS_MTL_RXQ0_OPERATION_MODE_FEP | + EQOS_MTL_RXQ0_OPERATION_MODE_FUP); /* Transmit/Receive queue fifo size; use all RAM for 1 queue */ val = readl(&eqos->mac_regs->hw_feature1); @@ -993,9 +1347,22 @@ static int eqos_start(struct udevice *dev) clrsetbits_le32(&eqos->mac_regs->rxq_ctrl0, EQOS_MAC_RXQ_CTRL0_RXQ0EN_MASK << EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT, - EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB << + eqos->config->config_mac << + EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT); + + clrsetbits_le32(&eqos->mac_regs->rxq_ctrl0, + EQOS_MAC_RXQ_CTRL0_RXQ0EN_MASK << + EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT, + 0x2 << EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT); + /* Multicast and Broadcast Queue Enable */ + setbits_le32(&eqos->mac_regs->unused_0a4, + 0x00100000); + /* enable promise mode */ + setbits_le32(&eqos->mac_regs->unused_004[1], + 0x1); + /* Set TX flow control parameters */ /* Set Pause Time */ setbits_le32(&eqos->mac_regs->q0_tx_flow_ctrl, @@ -1072,9 +1439,13 @@ static int eqos_start(struct udevice *dev) struct eqos_desc *rx_desc = &(eqos->rx_descs[i]); rx_desc->des0 = (u32)(ulong)(eqos->rx_dma_buf + (i * EQOS_MAX_PACKET_SIZE)); - rx_desc->des3 |= EQOS_DESC3_OWN | EQOS_DESC3_BUF1V; + rx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_BUF1V; + mb(); + eqos->config->ops->eqos_flush_desc(rx_desc); + eqos->config->ops->eqos_inval_buffer(eqos->rx_dma_buf + + (i * EQOS_MAX_PACKET_SIZE), + EQOS_MAX_PACKET_SIZE); } - flush_cache((unsigned long)eqos->descs, EQOS_DESCRIPTORS_SIZE); writel(0, &eqos->dma_regs->ch0_txdesc_list_haddress); writel((ulong)eqos->tx_descs, &eqos->dma_regs->ch0_txdesc_list_address); @@ -1087,14 +1458,12 @@ static int eqos_start(struct udevice *dev) &eqos->dma_regs->ch0_rxdesc_ring_length); /* Enable everything */ - - setbits_le32(&eqos->mac_regs->configuration, - EQOS_MAC_CONFIGURATION_TE | EQOS_MAC_CONFIGURATION_RE); - setbits_le32(&eqos->dma_regs->ch0_tx_control, EQOS_DMA_CH0_TX_CONTROL_ST); setbits_le32(&eqos->dma_regs->ch0_rx_control, EQOS_DMA_CH0_RX_CONTROL_SR); + setbits_le32(&eqos->mac_regs->configuration, + EQOS_MAC_CONFIGURATION_TE | EQOS_MAC_CONFIGURATION_RE); /* TX tail pointer not written until we need to TX a packet */ /* @@ -1113,17 +1482,16 @@ static int eqos_start(struct udevice *dev) err_shutdown_phy: phy_shutdown(eqos->phy); - eqos->phy = NULL; err_stop_resets: - eqos_stop_resets_tegra186(dev); + eqos->config->ops->eqos_stop_resets(dev); err_stop_clks: - eqos_stop_clks_tegra186(dev); + eqos->config->ops->eqos_stop_clks(dev); err: pr_err("FAILED: %d", ret); return ret; } -void eqos_stop(struct udevice *dev) +static void eqos_stop(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); int i; @@ -1170,15 +1538,14 @@ void eqos_stop(struct udevice *dev) if (eqos->phy) { phy_shutdown(eqos->phy); - eqos->phy = NULL; } - eqos_stop_resets_tegra186(dev); - eqos_stop_clks_tegra186(dev); + eqos->config->ops->eqos_stop_resets(dev); + eqos->config->ops->eqos_stop_clks(dev); debug("%s: OK\n", __func__); } -int eqos_send(struct udevice *dev, void *packet, int length) +static int eqos_send(struct udevice *dev, void *packet, int length) { struct eqos_priv *eqos = dev_get_priv(dev); struct eqos_desc *tx_desc; @@ -1188,7 +1555,7 @@ int eqos_send(struct udevice *dev, void *packet, int length) length); memcpy(eqos->tx_dma_buf, packet, length); - eqos_flush_buffer(eqos->tx_dma_buf, length); + eqos->config->ops->eqos_flush_buffer(eqos->tx_dma_buf, length); tx_desc = &(eqos->tx_descs[eqos->tx_desc_idx]); eqos->tx_desc_idx++; @@ -1203,12 +1570,13 @@ int eqos_send(struct udevice *dev, void *packet, int length) */ mb(); tx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_FD | EQOS_DESC3_LD | length; - eqos_flush_desc(tx_desc); + eqos->config->ops->eqos_flush_desc(tx_desc); - writel((ulong)(tx_desc + 1), &eqos->dma_regs->ch0_txdesc_tail_pointer); + writel((ulong)(&(eqos->tx_descs[eqos->tx_desc_idx])), + &eqos->dma_regs->ch0_txdesc_tail_pointer); for (i = 0; i < 1000000; i++) { - eqos_inval_desc(tx_desc); + eqos->config->ops->eqos_inval_desc(tx_desc); if (!(readl(&tx_desc->des3) & EQOS_DESC3_OWN)) return 0; udelay(1); @@ -1219,7 +1587,7 @@ int eqos_send(struct udevice *dev, void *packet, int length) return -ETIMEDOUT; } -int eqos_recv(struct udevice *dev, int flags, uchar **packetp) +static int eqos_recv(struct udevice *dev, int flags, uchar **packetp) { struct eqos_priv *eqos = dev_get_priv(dev); struct eqos_desc *rx_desc; @@ -1228,6 +1596,7 @@ int eqos_recv(struct udevice *dev, int flags, uchar **packetp) debug("%s(dev=%p, flags=%x):\n", __func__, dev, flags); rx_desc = &(eqos->rx_descs[eqos->rx_desc_idx]); + eqos->config->ops->eqos_inval_desc(rx_desc); if (rx_desc->des3 & EQOS_DESC3_OWN) { debug("%s: RX packet not available\n", __func__); return -EAGAIN; @@ -1238,12 +1607,12 @@ int eqos_recv(struct udevice *dev, int flags, uchar **packetp) length = rx_desc->des3 & 0x7fff; debug("%s: *packetp=%p, length=%d\n", __func__, *packetp, length); - eqos_inval_buffer(*packetp, length); + eqos->config->ops->eqos_inval_buffer(*packetp, length); return length; } -int eqos_free_pkt(struct udevice *dev, uchar *packet, int length) +static int eqos_free_pkt(struct udevice *dev, uchar *packet, int length) { struct eqos_priv *eqos = dev_get_priv(dev); uchar *packet_expected; @@ -1259,7 +1628,14 @@ int eqos_free_pkt(struct udevice *dev, uchar *packet, int length) return -EINVAL; } + eqos->config->ops->eqos_inval_buffer(packet, length); + rx_desc = &(eqos->rx_descs[eqos->rx_desc_idx]); + + rx_desc->des0 = 0; + mb(); + eqos->config->ops->eqos_flush_desc(rx_desc); + eqos->config->ops->eqos_inval_buffer(packet, length); rx_desc->des0 = (u32)(ulong)packet; rx_desc->des1 = 0; rx_desc->des2 = 0; @@ -1268,8 +1644,8 @@ int eqos_free_pkt(struct udevice *dev, uchar *packet, int length) * writes to the rest of the descriptor too. */ mb(); - rx_desc->des3 |= EQOS_DESC3_OWN | EQOS_DESC3_BUF1V; - eqos_flush_desc(rx_desc); + rx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_BUF1V; + eqos->config->ops->eqos_flush_desc(rx_desc); writel((ulong)rx_desc, &eqos->dma_regs->ch0_rxdesc_tail_pointer); @@ -1304,7 +1680,7 @@ static int eqos_probe_resources_core(struct udevice *dev) ret = -ENOMEM; goto err_free_descs; } - debug("%s: rx_dma_buf=%p\n", __func__, eqos->rx_dma_buf); + debug("%s: tx_dma_buf=%p\n", __func__, eqos->tx_dma_buf); eqos->rx_dma_buf = memalign(EQOS_BUFFER_ALIGN, EQOS_RX_BUFFER_SIZE); if (!eqos->rx_dma_buf) { @@ -1312,7 +1688,7 @@ static int eqos_probe_resources_core(struct udevice *dev) ret = -ENOMEM; goto err_free_tx_dma_buf; } - debug("%s: tx_dma_buf=%p\n", __func__, eqos->tx_dma_buf); + debug("%s: rx_dma_buf=%p\n", __func__, eqos->rx_dma_buf); eqos->rx_pkt = malloc(EQOS_MAX_PACKET_SIZE); if (!eqos->rx_pkt) { @@ -1322,6 +1698,9 @@ static int eqos_probe_resources_core(struct udevice *dev) } debug("%s: rx_pkt=%p\n", __func__, eqos->rx_pkt); + eqos->config->ops->eqos_inval_buffer(eqos->rx_dma_buf, + EQOS_MAX_PACKET_SIZE * EQOS_DESCRIPTORS_RX); + debug("%s: OK\n", __func__); return 0; @@ -1424,17 +1803,155 @@ err_free_reset_eqos: return ret; } +/* board-specific Ethernet Interface initializations. */ +__weak int board_interface_eth_init(struct udevice *dev, + phy_interface_t interface_type) +{ + return 0; +} + +static int eqos_probe_resources_stm32(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + int ret; + phy_interface_t interface; + struct ofnode_phandle_args phandle_args; + + debug("%s(dev=%p):\n", __func__, dev); + + interface = eqos->config->interface(dev); + + if (interface == PHY_INTERFACE_MODE_NONE) { + pr_err("Invalid PHY interface\n"); + return -EINVAL; + } + + ret = board_interface_eth_init(dev, interface); + if (ret) + return -EINVAL; + + eqos->max_speed = dev_read_u32_default(dev, "max-speed", 0); + + ret = clk_get_by_name(dev, "stmmaceth", &eqos->clk_master_bus); + if (ret) { + pr_err("clk_get_by_name(master_bus) failed: %d", ret); + goto err_probe; + } + + ret = clk_get_by_name(dev, "mac-clk-rx", &eqos->clk_rx); + if (ret) { + pr_err("clk_get_by_name(rx) failed: %d", ret); + goto err_free_clk_master_bus; + } + + ret = clk_get_by_name(dev, "mac-clk-tx", &eqos->clk_tx); + if (ret) { + pr_err("clk_get_by_name(tx) failed: %d", ret); + goto err_free_clk_rx; + } + + /* Get ETH_CLK clocks (optional) */ + ret = clk_get_by_name(dev, "eth-ck", &eqos->clk_ck); + if (ret) + pr_warn("No phy clock provided %d", ret); + + eqos->phyaddr = -1; + ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0, + &phandle_args); + if (!ret) { + /* search "reset-gpios" in phy node */ + ret = gpio_request_by_name_nodev(phandle_args.node, + "reset-gpios", 0, + &eqos->phy_reset_gpio, + GPIOD_IS_OUT | + GPIOD_IS_OUT_ACTIVE); + if (ret) + pr_warn("gpio_request_by_name(phy reset) not provided %d", + ret); + + eqos->phyaddr = ofnode_read_u32_default(phandle_args.node, + "reg", -1); + } + + debug("%s: OK\n", __func__); + return 0; + +err_free_clk_rx: + clk_free(&eqos->clk_rx); +err_free_clk_master_bus: + clk_free(&eqos->clk_master_bus); +err_probe: + + debug("%s: returns %d\n", __func__, ret); + return ret; +} + +static phy_interface_t eqos_get_interface_stm32(struct udevice *dev) +{ + const char *phy_mode; + phy_interface_t interface = PHY_INTERFACE_MODE_NONE; + + debug("%s(dev=%p):\n", __func__, dev); + + phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode", + NULL); + if (phy_mode) + interface = phy_get_interface_by_name(phy_mode); + + return interface; +} + +static phy_interface_t eqos_get_interface_tegra186(struct udevice *dev) +{ + return PHY_INTERFACE_MODE_MII; +} + +static int eqos_probe_resources_imx(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + phy_interface_t interface; + + debug("%s(dev=%p):\n", __func__, dev); + + interface = eqos->config->interface(dev); + + if (interface == PHY_INTERFACE_MODE_NONE) { + pr_err("Invalid PHY interface\n"); + return -EINVAL; + } + + debug("%s: OK\n", __func__); + return 0; +} + +static phy_interface_t eqos_get_interface_imx(struct udevice *dev) +{ + const char *phy_mode; + phy_interface_t interface = PHY_INTERFACE_MODE_NONE; + + debug("%s(dev=%p):\n", __func__, dev); + + phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode", + NULL); + if (phy_mode) + interface = phy_get_interface_by_name(phy_mode); + + return interface; +} + static int eqos_remove_resources_tegra186(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); debug("%s(dev=%p):\n", __func__, dev); +#ifdef CONFIG_CLK clk_free(&eqos->clk_tx); clk_free(&eqos->clk_ptp_ref); clk_free(&eqos->clk_rx); clk_free(&eqos->clk_slave_bus); clk_free(&eqos->clk_master_bus); +#endif dm_gpio_free(dev, &eqos->phy_reset_gpio); reset_free(&eqos->reset_ctl); @@ -1442,6 +1959,32 @@ static int eqos_remove_resources_tegra186(struct udevice *dev) return 0; } +static int eqos_remove_resources_stm32(struct udevice *dev) +{ +#ifdef CONFIG_CLK + struct eqos_priv *eqos = dev_get_priv(dev); + + debug("%s(dev=%p):\n", __func__, dev); + + clk_free(&eqos->clk_tx); + clk_free(&eqos->clk_rx); + clk_free(&eqos->clk_master_bus); + if (clk_valid(&eqos->clk_ck)) + clk_free(&eqos->clk_ck); +#endif + + if (dm_gpio_is_valid(&eqos->phy_reset_gpio)) + dm_gpio_free(dev, &eqos->phy_reset_gpio); + + debug("%s: OK\n", __func__); + return 0; +} + +static int eqos_remove_resources_imx(struct udevice *dev) +{ + return 0; +} + static int eqos_probe(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -1468,35 +2011,45 @@ static int eqos_probe(struct udevice *dev) return ret; } - ret = eqos_probe_resources_tegra186(dev); + ret = eqos->config->ops->eqos_probe_resources(dev); if (ret < 0) { - pr_err("eqos_probe_resources_tegra186() failed: %d", ret); + pr_err("eqos_probe_resources() failed: %d", ret); goto err_remove_resources_core; } - eqos->mii = mdio_alloc(); +#ifdef CONFIG_DM_ETH_PHY + eqos->mii = eth_phy_get_mdio_bus(dev); +#endif if (!eqos->mii) { - pr_err("mdio_alloc() failed"); - goto err_remove_resources_tegra; - } - eqos->mii->read = eqos_mdio_read; - eqos->mii->write = eqos_mdio_write; - eqos->mii->priv = eqos; - strcpy(eqos->mii->name, dev->name); + eqos->mii = mdio_alloc(); + if (!eqos->mii) { + pr_err("mdio_alloc() failed"); + ret = -ENOMEM; + goto err_remove_resources_tegra; + } + eqos->mii->read = eqos_mdio_read; + eqos->mii->write = eqos_mdio_write; + eqos->mii->priv = eqos; + strcpy(eqos->mii->name, dev->name); - ret = mdio_register(eqos->mii); - if (ret < 0) { - pr_err("mdio_register() failed: %d", ret); - goto err_free_mdio; + ret = mdio_register(eqos->mii); + if (ret < 0) { + pr_err("mdio_register() failed: %d", ret); + goto err_free_mdio; + } } +#ifdef CONFIG_DM_ETH_PHY + eth_phy_set_mdio_bus(dev, eqos->mii); +#endif + debug("%s: OK\n", __func__); return 0; err_free_mdio: mdio_free(eqos->mii); err_remove_resources_tegra: - eqos_remove_resources_tegra186(dev); + eqos->config->ops->eqos_remove_resources(dev); err_remove_resources_core: eqos_remove_resources_core(dev); @@ -1512,7 +2065,8 @@ static int eqos_remove(struct udevice *dev) mdio_unregister(eqos->mii); mdio_free(eqos->mii); - eqos_remove_resources_tegra186(dev); + eqos->config->ops->eqos_remove_resources(dev); + eqos_probe_resources_core(dev); debug("%s: OK\n", __func__); @@ -1526,10 +2080,88 @@ static const struct eth_ops eqos_ops = { .recv = eqos_recv, .free_pkt = eqos_free_pkt, .write_hwaddr = eqos_write_hwaddr, + .read_rom_hwaddr = eqos_read_rom_hwaddr, +}; + +static struct eqos_ops eqos_tegra186_ops = { + .eqos_inval_desc = eqos_inval_desc_tegra186, + .eqos_flush_desc = eqos_flush_desc_tegra186, + .eqos_inval_buffer = eqos_inval_buffer_tegra186, + .eqos_flush_buffer = eqos_flush_buffer_tegra186, + .eqos_probe_resources = eqos_probe_resources_tegra186, + .eqos_remove_resources = eqos_remove_resources_tegra186, + .eqos_stop_resets = eqos_stop_resets_tegra186, + .eqos_start_resets = eqos_start_resets_tegra186, + .eqos_stop_clks = eqos_stop_clks_tegra186, + .eqos_start_clks = eqos_start_clks_tegra186, + .eqos_calibrate_pads = eqos_calibrate_pads_tegra186, + .eqos_disable_calibration = eqos_disable_calibration_tegra186, + .eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_tegra186, + .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_tegra186 }; static const struct eqos_config eqos_tegra186_config = { .reg_access_always_ok = false, + .mdio_wait = 10, + .swr_wait = 10, + .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB, + .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_20_35, + .interface = eqos_get_interface_tegra186, + .ops = &eqos_tegra186_ops +}; + +static struct eqos_ops eqos_stm32_ops = { + .eqos_inval_desc = eqos_inval_desc_generic, + .eqos_flush_desc = eqos_flush_desc_generic, + .eqos_inval_buffer = eqos_inval_buffer_generic, + .eqos_flush_buffer = eqos_flush_buffer_generic, + .eqos_probe_resources = eqos_probe_resources_stm32, + .eqos_remove_resources = eqos_remove_resources_stm32, + .eqos_stop_resets = eqos_stop_resets_stm32, + .eqos_start_resets = eqos_start_resets_stm32, + .eqos_stop_clks = eqos_stop_clks_stm32, + .eqos_start_clks = eqos_start_clks_stm32, + .eqos_calibrate_pads = eqos_calibrate_pads_stm32, + .eqos_disable_calibration = eqos_disable_calibration_stm32, + .eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_stm32, + .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_stm32 +}; + +static const struct eqos_config eqos_stm32_config = { + .reg_access_always_ok = false, + .mdio_wait = 10000, + .swr_wait = 50, + .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_AV, + .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300, + .interface = eqos_get_interface_stm32, + .ops = &eqos_stm32_ops +}; + +static struct eqos_ops eqos_imx_ops = { + .eqos_inval_desc = eqos_inval_desc_generic, + .eqos_flush_desc = eqos_flush_desc_generic, + .eqos_inval_buffer = eqos_inval_buffer_generic, + .eqos_flush_buffer = eqos_flush_buffer_generic, + .eqos_probe_resources = eqos_probe_resources_imx, + .eqos_remove_resources = eqos_remove_resources_imx, + .eqos_stop_resets = eqos_stop_resets_imx, + .eqos_start_resets = eqos_start_resets_imx, + .eqos_stop_clks = eqos_stop_clks_imx, + .eqos_start_clks = eqos_start_clks_imx, + .eqos_calibrate_pads = eqos_calibrate_pads_imx, + .eqos_disable_calibration = eqos_disable_calibration_imx, + .eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_imx, + .eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_imx +}; + +struct eqos_config eqos_imx_config = { + .reg_access_always_ok = false, + .mdio_wait = 10000, + .swr_wait = 50, + .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB, + .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300, + .interface = eqos_get_interface_imx, + .ops = &eqos_imx_ops }; static const struct udevice_id eqos_ids[] = { @@ -1537,13 +2169,22 @@ static const struct udevice_id eqos_ids[] = { .compatible = "nvidia,tegra186-eqos", .data = (ulong)&eqos_tegra186_config }, + { + .compatible = "snps,dwmac-4.20a", + .data = (ulong)&eqos_stm32_config + }, + { + .compatible = "fsl,imx-eqos", + .data = (ulong)&eqos_imx_config + }, + { } }; U_BOOT_DRIVER(eth_eqos) = { .name = "eth_eqos", .id = UCLASS_ETH, - .of_match = eqos_ids, + .of_match = of_match_ptr(eqos_ids), .probe = eqos_probe, .remove = eqos_remove, .ops = &eqos_ops,