diff options
Diffstat (limited to 'drivers/net/dwc_eth_qos.c')
-rw-r--r-- | drivers/net/dwc_eth_qos.c | 150 |
1 files changed, 119 insertions, 31 deletions
diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 32a5d52165a..3415c418a93 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -29,10 +29,10 @@ #define LOG_CATEGORY UCLASS_ETH -#include <common.h> #include <clk.h> #include <cpu_func.h> #include <dm.h> +#include <dm/device_compat.h> #include <errno.h> #include <eth_phy.h> #include <log.h> @@ -51,6 +51,7 @@ #include <asm/arch/clock.h> #include <asm/mach-imx/sys_proto.h> #endif +#include <linux/bitfield.h> #include <linux/delay.h> #include <linux/printk.h> @@ -147,6 +148,25 @@ static int eqos_mdio_wait_idle(struct eqos_priv *eqos) 1000000, true); } +/* Bitmask common for mdio_read and mdio_write */ +#define EQOS_MDIO_BITFIELD(pa, rda, cr) \ + FIELD_PREP(EQOS_MAC_MDIO_ADDRESS_PA_MASK, pa) | \ + FIELD_PREP(EQOS_MAC_MDIO_ADDRESS_RDA_MASK, rda) | \ + FIELD_PREP(EQOS_MAC_MDIO_ADDRESS_CR_MASK, cr) | \ + EQOS_MAC_MDIO_ADDRESS_GB + +static u32 eqos_mdio_bitfield(struct eqos_priv *eqos, int addr, int devad, int reg) +{ + int cr = eqos->config->config_mac_mdio; + bool c22 = devad == MDIO_DEVAD_NONE ? true : false; + + if (c22) + return EQOS_MDIO_BITFIELD(addr, reg, cr); + else + return EQOS_MDIO_BITFIELD(addr, devad, cr) | + EQOS_MAC_MDIO_ADDRESS_C45E; +} + static int eqos_mdio_read(struct mii_dev *bus, int mdio_addr, int mdio_devad, int mdio_reg) { @@ -164,15 +184,17 @@ static int eqos_mdio_read(struct mii_dev *bus, int mdio_addr, int mdio_devad, } val = readl(&eqos->mac_regs->mdio_address); - val &= EQOS_MAC_MDIO_ADDRESS_SKAP | - EQOS_MAC_MDIO_ADDRESS_C45E; - val |= (mdio_addr << EQOS_MAC_MDIO_ADDRESS_PA_SHIFT) | - (mdio_reg << EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT) | - (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; + val &= EQOS_MAC_MDIO_ADDRESS_SKAP; + + val |= eqos_mdio_bitfield(eqos, mdio_addr, mdio_devad, mdio_reg) | + FIELD_PREP(EQOS_MAC_MDIO_ADDRESS_GOC_MASK, + EQOS_MAC_MDIO_ADDRESS_GOC_READ); + + if (val & EQOS_MAC_MDIO_ADDRESS_C45E) { + writel(FIELD_PREP(EQOS_MAC_MDIO_DATA_RA_MASK, mdio_reg), + &eqos->mac_regs->mdio_data); + } + writel(val, &eqos->mac_regs->mdio_address); udelay(eqos->config->mdio_wait); @@ -195,7 +217,8 @@ static int eqos_mdio_write(struct mii_dev *bus, int mdio_addr, int mdio_devad, int mdio_reg, u16 mdio_val) { struct eqos_priv *eqos = bus->priv; - u32 val; + u32 v_addr; + u32 v_data; int ret; debug("%s(dev=%p, addr=%x, reg=%d, val=%x):\n", __func__, eqos->dev, @@ -207,20 +230,19 @@ static int eqos_mdio_write(struct mii_dev *bus, int mdio_addr, int mdio_devad, return ret; } - writel(mdio_val, &eqos->mac_regs->mdio_data); + v_addr = readl(&eqos->mac_regs->mdio_address); + v_addr &= EQOS_MAC_MDIO_ADDRESS_SKAP; - val = readl(&eqos->mac_regs->mdio_address); - val &= EQOS_MAC_MDIO_ADDRESS_SKAP | - EQOS_MAC_MDIO_ADDRESS_C45E; - val |= (mdio_addr << EQOS_MAC_MDIO_ADDRESS_PA_SHIFT) | - (mdio_reg << EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT) | - (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); + v_addr |= eqos_mdio_bitfield(eqos, mdio_addr, mdio_devad, mdio_reg) | + FIELD_PREP(EQOS_MAC_MDIO_ADDRESS_GOC_MASK, + EQOS_MAC_MDIO_ADDRESS_GOC_WRITE); + v_data = mdio_val; + if (v_addr & EQOS_MAC_MDIO_ADDRESS_C45E) + v_data |= FIELD_PREP(EQOS_MAC_MDIO_DATA_RA_MASK, mdio_reg); + + writel(v_data, &eqos->mac_regs->mdio_data); + writel(v_addr, &eqos->mac_regs->mdio_address); udelay(eqos->config->mdio_wait); ret = eqos_mdio_wait_idle(eqos); @@ -1280,6 +1302,13 @@ static int eqos_probe_resources_tegra186(struct udevice *dev) debug("%s(dev=%p):\n", __func__, dev); + ret = eqos_get_base_addr_dt(dev); + if (ret) { + pr_err("eqos_get_base_addr_dt failed: %d\n", ret); + return ret; + } + eqos->tegra186_regs = (void *)(eqos->regs + EQOS_TEGRA186_REGS_BASE); + ret = reset_get_by_name(dev, "eqos", &eqos->reset_ctl); if (ret) { pr_err("reset_get_by_name(rst) failed: %d\n", ret); @@ -1354,6 +1383,69 @@ static int eqos_remove_resources_tegra186(struct udevice *dev) return 0; } +static int eqos_bind(struct udevice *dev) +{ + static int dev_num; + const size_t name_sz = 16; + char name[name_sz]; + + /* Device name defaults to DT node name. */ + if (ofnode_valid(dev_ofnode(dev))) + return 0; + + /* Assign unique names in case there is no DT node. */ + snprintf(name, name_sz, "eth_eqos#%d", dev_num++); + return device_set_name(dev, name); +} + +/* + * Get driver data based on the device tree. Boards not using a device tree can + * overwrite this function. + */ +__weak void *eqos_get_driver_data(struct udevice *dev) +{ + return (void *)dev_get_driver_data(dev); +} + +static fdt_addr_t eqos_get_base_addr_common(struct udevice *dev, fdt_addr_t addr) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + + if (addr == FDT_ADDR_T_NONE) { +#if CONFIG_IS_ENABLED(FDT_64BIT) + dev_err(dev, "addr=0x%llx is invalid.\n", addr); +#else + dev_err(dev, "addr=0x%x is invalid.\n", addr); +#endif + return -EINVAL; + } + + eqos->regs = addr; + eqos->mac_regs = (void *)(addr + EQOS_MAC_REGS_BASE); + eqos->mtl_regs = (void *)(addr + EQOS_MTL_REGS_BASE); + eqos->dma_regs = (void *)(addr + EQOS_DMA_REGS_BASE); + + return 0; +} + +int eqos_get_base_addr_dt(struct udevice *dev) +{ + fdt_addr_t addr = dev_read_addr(dev); + return eqos_get_base_addr_common(dev, addr); +} + +int eqos_get_base_addr_pci(struct udevice *dev) +{ + fdt_addr_t addr; + void *paddr; + + paddr = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE, + PCI_REGION_MEM); + addr = paddr ? (fdt_addr_t)paddr : FDT_ADDR_T_NONE; + + return eqos_get_base_addr_common(dev, addr); +} + static int eqos_probe(struct udevice *dev) { struct eqos_priv *eqos = dev_get_priv(dev); @@ -1362,17 +1454,12 @@ static int eqos_probe(struct udevice *dev) debug("%s(dev=%p):\n", __func__, dev); eqos->dev = dev; - eqos->config = (void *)dev_get_driver_data(dev); - eqos->regs = dev_read_addr(dev); - if (eqos->regs == FDT_ADDR_T_NONE) { - pr_err("dev_read_addr() failed\n"); + eqos->config = eqos_get_driver_data(dev); + if (!eqos->config) { + pr_err("Failed to get driver data.\n"); return -ENODEV; } - eqos->mac_regs = (void *)(eqos->regs + EQOS_MAC_REGS_BASE); - eqos->mtl_regs = (void *)(eqos->regs + EQOS_MTL_REGS_BASE); - eqos->dma_regs = (void *)(eqos->regs + EQOS_DMA_REGS_BASE); - eqos->tegra186_regs = (void *)(eqos->regs + EQOS_TEGRA186_REGS_BASE); eqos->max_speed = dev_read_u32_default(dev, "max-speed", 0); @@ -1553,6 +1640,7 @@ U_BOOT_DRIVER(eth_eqos) = { .name = "eth_eqos", .id = UCLASS_ETH, .of_match = of_match_ptr(eqos_ids), + .bind = eqos_bind, .probe = eqos_probe, .remove = eqos_remove, .ops = &eqos_ops, |