1 // SPDX-License-Identifier: GPL-2.0+
3 * CPSW MDIO generic driver for TI AMxx/K2x/EMAC devices.
5 * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
14 #include <linux/delay.h>
16 struct cpsw_mdio_regs {
19 #define CONTROL_IDLE BIT(31)
20 #define CONTROL_ENABLE BIT(30)
21 #define CONTROL_FAULT BIT(19)
22 #define CONTROL_FAULT_ENABLE BIT(18)
23 #define CONTROL_DIV_MASK GENMASK(15, 0)
39 #define USERACCESS_GO BIT(31)
40 #define USERACCESS_WRITE BIT(30)
41 #define USERACCESS_ACK BIT(29)
42 #define USERACCESS_READ (0)
43 #define USERACCESS_PHY_REG_SHIFT (21)
44 #define USERACCESS_PHY_ADDR_SHIFT (16)
45 #define USERACCESS_DATA GENMASK(15, 0)
49 #define CPSW_MDIO_DIV_DEF 0xff
50 #define PHY_REG_MASK 0x1f
51 #define PHY_ID_MASK 0x1f
54 * This timeout definition is a worst-case ultra defensive measure against
55 * unexpected controller lock ups. Ideally, we should never ever hit this
56 * scenario in practice.
58 #define CPSW_MDIO_TIMEOUT 100 /* msecs */
61 struct cpsw_mdio_regs *regs;
66 /* wait until hardware is ready for another user access */
67 static int cpsw_mdio_wait_for_user_access(struct cpsw_mdio *mdio)
69 return wait_for_bit_le32(&mdio->regs->user[0].access,
71 CPSW_MDIO_TIMEOUT, false);
74 static int cpsw_mdio_read(struct mii_dev *bus, int phy_id,
75 int dev_addr, int phy_reg)
77 struct cpsw_mdio *mdio = bus->priv;
81 if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
84 ret = cpsw_mdio_wait_for_user_access(mdio);
87 reg = (USERACCESS_GO | USERACCESS_READ |
88 (phy_reg << USERACCESS_PHY_REG_SHIFT) |
89 (phy_id << USERACCESS_PHY_ADDR_SHIFT));
90 writel(reg, &mdio->regs->user[0].access);
91 ret = cpsw_mdio_wait_for_user_access(mdio);
95 reg = readl(&mdio->regs->user[0].access);
96 data = (reg & USERACCESS_ACK) ? (reg & USERACCESS_DATA) : -1;
100 static int cpsw_mdio_write(struct mii_dev *bus, int phy_id, int dev_addr,
101 int phy_reg, u16 data)
103 struct cpsw_mdio *mdio = bus->priv;
107 if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
110 ret = cpsw_mdio_wait_for_user_access(mdio);
113 reg = (USERACCESS_GO | USERACCESS_WRITE |
114 (phy_reg << USERACCESS_PHY_REG_SHIFT) |
115 (phy_id << USERACCESS_PHY_ADDR_SHIFT) |
116 (data & USERACCESS_DATA));
117 writel(reg, &mdio->regs->user[0].access);
119 return cpsw_mdio_wait_for_user_access(mdio);
122 u32 cpsw_mdio_get_alive(struct mii_dev *bus)
124 struct cpsw_mdio *mdio = bus->priv;
127 val = readl(&mdio->regs->control);
128 return val & GENMASK(15, 0);
131 struct mii_dev *cpsw_mdio_init(const char *name, phys_addr_t mdio_base,
132 u32 bus_freq, int fck_freq)
134 struct cpsw_mdio *cpsw_mdio;
137 cpsw_mdio = calloc(1, sizeof(*cpsw_mdio));
139 debug("failed to alloc cpsw_mdio\n");
143 cpsw_mdio->bus = mdio_alloc();
144 if (!cpsw_mdio->bus) {
145 debug("failed to alloc mii bus\n");
150 cpsw_mdio->regs = (struct cpsw_mdio_regs *)(uintptr_t)mdio_base;
152 if (!bus_freq || !fck_freq)
153 cpsw_mdio->div = CPSW_MDIO_DIV_DEF;
155 cpsw_mdio->div = (fck_freq / bus_freq) - 1;
156 cpsw_mdio->div &= CONTROL_DIV_MASK;
158 /* set enable and clock divider */
159 writel(cpsw_mdio->div | CONTROL_ENABLE | CONTROL_FAULT |
160 CONTROL_FAULT_ENABLE, &cpsw_mdio->regs->control);
161 wait_for_bit_le32(&cpsw_mdio->regs->control,
162 CONTROL_IDLE, false, CPSW_MDIO_TIMEOUT, true);
165 * wait for scan logic to settle:
166 * the scan time consists of (a) a large fixed component, and (b) a
167 * small component that varies with the mii bus frequency. These
168 * were estimated using measurements at 1.1 and 2.2 MHz on tnetv107x
169 * silicon. Since the effect of (b) was found to be largely
170 * negligible, we keep things simple here.
174 cpsw_mdio->bus->read = cpsw_mdio_read;
175 cpsw_mdio->bus->write = cpsw_mdio_write;
176 cpsw_mdio->bus->priv = cpsw_mdio;
177 snprintf(cpsw_mdio->bus->name, sizeof(cpsw_mdio->bus->name), name);
179 ret = mdio_register(cpsw_mdio->bus);
181 debug("failed to register mii bus\n");
185 return cpsw_mdio->bus;
188 mdio_free(cpsw_mdio->bus);
193 void cpsw_mdio_free(struct mii_dev *bus)
195 struct cpsw_mdio *mdio = bus->priv;
199 reg = readl(&mdio->regs->control);
200 reg &= ~CONTROL_ENABLE;
201 writel(reg, &mdio->regs->control);
203 mdio_unregister(bus);