#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>
#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>
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)
{
}
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);
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,
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);
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);
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);
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);
.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,