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