blob: 6e8f6520118f65c3c7d0e7d42fb5183ce8ae18da [file] [log] [blame]
Grygorii Strashko6c4bbcc2018-10-31 16:21:43 -05001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * CPSW MDIO generic driver for TI AMxx/K2x/EMAC devices.
4 *
5 * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
6 */
7
8#include <common.h>
9#include <asm/io.h>
10#include <miiphy.h>
11#include <wait_bit.h>
12
13struct cpsw_mdio_regs {
14 u32 version;
15 u32 control;
16#define CONTROL_IDLE BIT(31)
17#define CONTROL_ENABLE BIT(30)
18#define CONTROL_FAULT BIT(19)
19#define CONTROL_FAULT_ENABLE BIT(18)
20#define CONTROL_DIV_MASK GENMASK(15, 0)
21
22 u32 alive;
23 u32 link;
24 u32 linkintraw;
25 u32 linkintmasked;
26 u32 __reserved_0[2];
27 u32 userintraw;
28 u32 userintmasked;
29 u32 userintmaskset;
30 u32 userintmaskclr;
31 u32 __reserved_1[20];
32
33 struct {
34 u32 access;
35 u32 physel;
36#define USERACCESS_GO BIT(31)
37#define USERACCESS_WRITE BIT(30)
38#define USERACCESS_ACK BIT(29)
39#define USERACCESS_READ (0)
40#define USERACCESS_PHY_REG_SHIFT (21)
41#define USERACCESS_PHY_ADDR_SHIFT (16)
42#define USERACCESS_DATA GENMASK(15, 0)
43 } user[0];
44};
45
46#define CPSW_MDIO_DIV_DEF 0xff
47#define PHY_REG_MASK 0x1f
48#define PHY_ID_MASK 0x1f
49
50/*
51 * This timeout definition is a worst-case ultra defensive measure against
52 * unexpected controller lock ups. Ideally, we should never ever hit this
53 * scenario in practice.
54 */
55#define CPSW_MDIO_TIMEOUT 100 /* msecs */
56
57struct cpsw_mdio {
58 struct cpsw_mdio_regs *regs;
59 struct mii_dev *bus;
60 int div;
61};
62
63/* wait until hardware is ready for another user access */
64static int cpsw_mdio_wait_for_user_access(struct cpsw_mdio *mdio)
65{
66 return wait_for_bit_le32(&mdio->regs->user[0].access,
67 USERACCESS_GO, false,
68 CPSW_MDIO_TIMEOUT, false);
69}
70
71static int cpsw_mdio_read(struct mii_dev *bus, int phy_id,
72 int dev_addr, int phy_reg)
73{
74 struct cpsw_mdio *mdio = bus->priv;
75 int data, ret;
76 u32 reg;
77
78 if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
79 return -EINVAL;
80
81 ret = cpsw_mdio_wait_for_user_access(mdio);
82 if (ret)
83 return ret;
84 reg = (USERACCESS_GO | USERACCESS_READ |
85 (phy_reg << USERACCESS_PHY_REG_SHIFT) |
86 (phy_id << USERACCESS_PHY_ADDR_SHIFT));
87 writel(reg, &mdio->regs->user[0].access);
88 ret = cpsw_mdio_wait_for_user_access(mdio);
89 if (ret)
90 return ret;
91
92 reg = readl(&mdio->regs->user[0].access);
93 data = (reg & USERACCESS_ACK) ? (reg & USERACCESS_DATA) : -1;
94 return data;
95}
96
97static int cpsw_mdio_write(struct mii_dev *bus, int phy_id, int dev_addr,
98 int phy_reg, u16 data)
99{
100 struct cpsw_mdio *mdio = bus->priv;
101 u32 reg;
102 int ret;
103
104 if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
105 return -EINVAL;
106
107 ret = cpsw_mdio_wait_for_user_access(mdio);
108 if (ret)
109 return ret;
110 reg = (USERACCESS_GO | USERACCESS_WRITE |
111 (phy_reg << USERACCESS_PHY_REG_SHIFT) |
112 (phy_id << USERACCESS_PHY_ADDR_SHIFT) |
113 (data & USERACCESS_DATA));
114 writel(reg, &mdio->regs->user[0].access);
115
116 return cpsw_mdio_wait_for_user_access(mdio);
117}
118
119u32 cpsw_mdio_get_alive(struct mii_dev *bus)
120{
121 struct cpsw_mdio *mdio = bus->priv;
122 u32 val;
123
124 val = readl(&mdio->regs->control);
125 return val & GENMASK(15, 0);
126}
127
Keerthy45e8c052019-07-09 10:30:33 +0530128struct mii_dev *cpsw_mdio_init(const char *name, phys_addr_t mdio_base,
Grygorii Strashko6c4bbcc2018-10-31 16:21:43 -0500129 u32 bus_freq, int fck_freq)
130{
131 struct cpsw_mdio *cpsw_mdio;
132 int ret;
133
134 cpsw_mdio = calloc(1, sizeof(*cpsw_mdio));
135 if (!cpsw_mdio) {
136 debug("failed to alloc cpsw_mdio\n");
137 return NULL;
138 }
139
140 cpsw_mdio->bus = mdio_alloc();
141 if (!cpsw_mdio->bus) {
142 debug("failed to alloc mii bus\n");
143 free(cpsw_mdio);
144 return NULL;
145 }
146
Keerthy45e8c052019-07-09 10:30:33 +0530147 cpsw_mdio->regs = (struct cpsw_mdio_regs *)(uintptr_t)mdio_base;
Grygorii Strashko6c4bbcc2018-10-31 16:21:43 -0500148
149 if (!bus_freq || !fck_freq)
150 cpsw_mdio->div = CPSW_MDIO_DIV_DEF;
151 else
152 cpsw_mdio->div = (fck_freq / bus_freq) - 1;
153 cpsw_mdio->div &= CONTROL_DIV_MASK;
154
155 /* set enable and clock divider */
156 writel(cpsw_mdio->div | CONTROL_ENABLE | CONTROL_FAULT |
157 CONTROL_FAULT_ENABLE, &cpsw_mdio->regs->control);
158 wait_for_bit_le32(&cpsw_mdio->regs->control,
159 CONTROL_IDLE, false, CPSW_MDIO_TIMEOUT, true);
160
161 /*
162 * wait for scan logic to settle:
163 * the scan time consists of (a) a large fixed component, and (b) a
164 * small component that varies with the mii bus frequency. These
165 * were estimated using measurements at 1.1 and 2.2 MHz on tnetv107x
166 * silicon. Since the effect of (b) was found to be largely
167 * negligible, we keep things simple here.
168 */
169 mdelay(1);
170
171 cpsw_mdio->bus->read = cpsw_mdio_read;
172 cpsw_mdio->bus->write = cpsw_mdio_write;
173 cpsw_mdio->bus->priv = cpsw_mdio;
174 snprintf(cpsw_mdio->bus->name, sizeof(cpsw_mdio->bus->name), name);
175
176 ret = mdio_register(cpsw_mdio->bus);
177 if (ret < 0) {
178 debug("failed to register mii bus\n");
179 goto free_bus;
180 }
181
182 return cpsw_mdio->bus;
183
184free_bus:
185 mdio_free(cpsw_mdio->bus);
186 free(cpsw_mdio);
187 return NULL;
188}
189
190void cpsw_mdio_free(struct mii_dev *bus)
191{
192 struct cpsw_mdio *mdio = bus->priv;
193 u32 reg;
194
195 /* disable mdio */
196 reg = readl(&mdio->regs->control);
197 reg &= ~CONTROL_ENABLE;
198 writel(reg, &mdio->regs->control);
199
200 mdio_unregister(bus);
201 mdio_free(bus);
202 free(mdio);
203}