1 /*
2 * Driver for the MDIO interface of Marvell network interfaces.
3 *
4 * Since the MDIO interface of Marvell network interfaces is shared
5 * between all network interfaces, having a single driver allows to
6 * handle concurrent accesses properly (you may have four Ethernet
7 * ports, but they in fact share the same SMI interface to access
8 * the MDIO bus). This driver is currently used by the mvneta and
9 * mv643xx_eth drivers.
10 *
11 * Copyright (C) 2012 Marvell
12 *
13 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
14 *
15 * This file is licensed under the terms of the GNU General Public
16 * License version 2. This program is licensed "as is" without any
17 * warranty of any kind, whether express or implied.
18 */
19
20 #include <linux/acpi.h>
21 #include <linux/acpi_mdio.h>
22 #include <linux/clk.h>
23 #include <linux/delay.h>
24 #include <linux/interrupt.h>
25 #include <linux/io.h>
26 #include <linux/iopoll.h>
27 #include <linux/kernel.h>
28 #include <linux/mod_devicetable.h>
29 #include <linux/module.h>
30 #include <linux/of_mdio.h>
31 #include <linux/phy.h>
32 #include <linux/platform_device.h>
33 #include <linux/sched.h>
34 #include <linux/wait.h>
35
36 #define MVMDIO_SMI_DATA_SHIFT 0
37 #define MVMDIO_SMI_PHY_ADDR_SHIFT 16
38 #define MVMDIO_SMI_PHY_REG_SHIFT 21
39 #define MVMDIO_SMI_READ_OPERATION BIT(26)
40 #define MVMDIO_SMI_WRITE_OPERATION 0
41 #define MVMDIO_SMI_READ_VALID BIT(27)
42 #define MVMDIO_SMI_BUSY BIT(28)
43 #define MVMDIO_ERR_INT_CAUSE 0x007C
44 #define MVMDIO_ERR_INT_SMI_DONE 0x00000010
45 #define MVMDIO_ERR_INT_MASK 0x0080
46
47 #define MVMDIO_XSMI_MGNT_REG 0x0
48 #define MVMDIO_XSMI_PHYADDR_SHIFT 16
49 #define MVMDIO_XSMI_DEVADDR_SHIFT 21
50 #define MVMDIO_XSMI_WRITE_OPERATION (0x5 << 26)
51 #define MVMDIO_XSMI_READ_OPERATION (0x7 << 26)
52 #define MVMDIO_XSMI_READ_VALID BIT(29)
53 #define MVMDIO_XSMI_BUSY BIT(30)
54 #define MVMDIO_XSMI_ADDR_REG 0x8
55
56 /*
57 * SMI Timeout measurements:
58 * - Kirkwood 88F6281 (Globalscale Dreamplug): 45us to 95us (Interrupt)
59 * - Armada 370 (Globalscale Mirabox): 41us to 43us (Polled)
60 */
61 #define MVMDIO_SMI_TIMEOUT 1000 /* 1000us = 1ms */
62
63 struct orion_mdio_dev {
64 void __iomem *regs;
65 struct clk *clk[4];
66 /*
67 * If we have access to the error interrupt pin (which is
68 * somewhat misnamed as it not only reflects internal errors
69 * but also reflects SMI completion), use that to wait for
70 * SMI access completion instead of polling the SMI busy bit.
71 */
72 int err_interrupt;
73 wait_queue_head_t smi_busy_wait;
74 };
75
76 enum orion_mdio_bus_type {
77 BUS_TYPE_SMI,
78 BUS_TYPE_XSMI
79 };
80
81 struct orion_mdio_ops {
82 int (*is_done)(struct orion_mdio_dev *);
83 };
84
85 /* Wait for the SMI unit to be ready for another operation
86 */
orion_mdio_wait_ready(const struct orion_mdio_ops * ops,struct mii_bus * bus)87 static int orion_mdio_wait_ready(const struct orion_mdio_ops *ops,
88 struct mii_bus *bus)
89 {
90 struct orion_mdio_dev *dev = bus->priv;
91 unsigned long timeout;
92 int done;
93
94 if (dev->err_interrupt <= 0) {
95 if (!read_poll_timeout_atomic(ops->is_done, done, done, 2,
96 MVMDIO_SMI_TIMEOUT, false, dev))
97 return 0;
98 } else {
99 /* wait_event_timeout does not guarantee a delay of at
100 * least one whole jiffie, so timeout must be no less
101 * than two.
102 */
103 timeout = max(usecs_to_jiffies(MVMDIO_SMI_TIMEOUT), 2);
104
105 if (wait_event_timeout(dev->smi_busy_wait,
106 ops->is_done(dev), timeout))
107 return 0;
108 }
109
110 dev_err(bus->parent, "Timeout: SMI busy for too long\n");
111 return -ETIMEDOUT;
112 }
113
orion_mdio_smi_is_done(struct orion_mdio_dev * dev)114 static int orion_mdio_smi_is_done(struct orion_mdio_dev *dev)
115 {
116 return !(readl(dev->regs) & MVMDIO_SMI_BUSY);
117 }
118
119 static const struct orion_mdio_ops orion_mdio_smi_ops = {
120 .is_done = orion_mdio_smi_is_done,
121 };
122
orion_mdio_smi_read(struct mii_bus * bus,int mii_id,int regnum)123 static int orion_mdio_smi_read(struct mii_bus *bus, int mii_id,
124 int regnum)
125 {
126 struct orion_mdio_dev *dev = bus->priv;
127 u32 val;
128 int ret;
129
130 ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus);
131 if (ret < 0)
132 return ret;
133
134 writel(((mii_id << MVMDIO_SMI_PHY_ADDR_SHIFT) |
135 (regnum << MVMDIO_SMI_PHY_REG_SHIFT) |
136 MVMDIO_SMI_READ_OPERATION),
137 dev->regs);
138
139 ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus);
140 if (ret < 0)
141 return ret;
142
143 val = readl(dev->regs);
144 if (!(val & MVMDIO_SMI_READ_VALID)) {
145 dev_err(bus->parent, "SMI bus read not valid\n");
146 return -ENODEV;
147 }
148
149 return val & GENMASK(15, 0);
150 }
151
orion_mdio_smi_write(struct mii_bus * bus,int mii_id,int regnum,u16 value)152 static int orion_mdio_smi_write(struct mii_bus *bus, int mii_id,
153 int regnum, u16 value)
154 {
155 struct orion_mdio_dev *dev = bus->priv;
156 int ret;
157
158 ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus);
159 if (ret < 0)
160 return ret;
161
162 writel(((mii_id << MVMDIO_SMI_PHY_ADDR_SHIFT) |
163 (regnum << MVMDIO_SMI_PHY_REG_SHIFT) |
164 MVMDIO_SMI_WRITE_OPERATION |
165 (value << MVMDIO_SMI_DATA_SHIFT)),
166 dev->regs);
167
168 return 0;
169 }
170
orion_mdio_xsmi_is_done(struct orion_mdio_dev * dev)171 static int orion_mdio_xsmi_is_done(struct orion_mdio_dev *dev)
172 {
173 return !(readl(dev->regs + MVMDIO_XSMI_MGNT_REG) & MVMDIO_XSMI_BUSY);
174 }
175
176 static const struct orion_mdio_ops orion_mdio_xsmi_ops = {
177 .is_done = orion_mdio_xsmi_is_done,
178 };
179
orion_mdio_xsmi_read_c45(struct mii_bus * bus,int mii_id,int dev_addr,int regnum)180 static int orion_mdio_xsmi_read_c45(struct mii_bus *bus, int mii_id,
181 int dev_addr, int regnum)
182 {
183 struct orion_mdio_dev *dev = bus->priv;
184 int ret;
185
186 ret = orion_mdio_wait_ready(&orion_mdio_xsmi_ops, bus);
187 if (ret < 0)
188 return ret;
189
190 writel(regnum, dev->regs + MVMDIO_XSMI_ADDR_REG);
191 writel((mii_id << MVMDIO_XSMI_PHYADDR_SHIFT) |
192 (dev_addr << MVMDIO_XSMI_DEVADDR_SHIFT) |
193 MVMDIO_XSMI_READ_OPERATION,
194 dev->regs + MVMDIO_XSMI_MGNT_REG);
195
196 ret = orion_mdio_wait_ready(&orion_mdio_xsmi_ops, bus);
197 if (ret < 0)
198 return ret;
199
200 if (!(readl(dev->regs + MVMDIO_XSMI_MGNT_REG) &
201 MVMDIO_XSMI_READ_VALID)) {
202 dev_err(bus->parent, "XSMI bus read not valid\n");
203 return -ENODEV;
204 }
205
206 return readl(dev->regs + MVMDIO_XSMI_MGNT_REG) & GENMASK(15, 0);
207 }
208
orion_mdio_xsmi_write_c45(struct mii_bus * bus,int mii_id,int dev_addr,int regnum,u16 value)209 static int orion_mdio_xsmi_write_c45(struct mii_bus *bus, int mii_id,
210 int dev_addr, int regnum, u16 value)
211 {
212 struct orion_mdio_dev *dev = bus->priv;
213 int ret;
214
215 ret = orion_mdio_wait_ready(&orion_mdio_xsmi_ops, bus);
216 if (ret < 0)
217 return ret;
218
219 writel(regnum, dev->regs + MVMDIO_XSMI_ADDR_REG);
220 writel((mii_id << MVMDIO_XSMI_PHYADDR_SHIFT) |
221 (dev_addr << MVMDIO_XSMI_DEVADDR_SHIFT) |
222 MVMDIO_XSMI_WRITE_OPERATION | value,
223 dev->regs + MVMDIO_XSMI_MGNT_REG);
224
225 return 0;
226 }
227
orion_mdio_err_irq(int irq,void * dev_id)228 static irqreturn_t orion_mdio_err_irq(int irq, void *dev_id)
229 {
230 struct orion_mdio_dev *dev = dev_id;
231
232 if (readl(dev->regs + MVMDIO_ERR_INT_CAUSE) &
233 MVMDIO_ERR_INT_SMI_DONE) {
234 writel(~MVMDIO_ERR_INT_SMI_DONE,
235 dev->regs + MVMDIO_ERR_INT_CAUSE);
236 wake_up(&dev->smi_busy_wait);
237 return IRQ_HANDLED;
238 }
239
240 return IRQ_NONE;
241 }
242
orion_mdio_probe(struct platform_device * pdev)243 static int orion_mdio_probe(struct platform_device *pdev)
244 {
245 enum orion_mdio_bus_type type;
246 struct resource *r;
247 struct mii_bus *bus;
248 struct orion_mdio_dev *dev;
249 int i, ret;
250
251 type = (uintptr_t)device_get_match_data(&pdev->dev);
252
253 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
254 if (!r) {
255 dev_err(&pdev->dev, "No SMI register address given\n");
256 return -ENODEV;
257 }
258
259 bus = devm_mdiobus_alloc_size(&pdev->dev,
260 sizeof(struct orion_mdio_dev));
261 if (!bus)
262 return -ENOMEM;
263
264 switch (type) {
265 case BUS_TYPE_SMI:
266 bus->read = orion_mdio_smi_read;
267 bus->write = orion_mdio_smi_write;
268 break;
269 case BUS_TYPE_XSMI:
270 bus->read_c45 = orion_mdio_xsmi_read_c45;
271 bus->write_c45 = orion_mdio_xsmi_write_c45;
272 break;
273 }
274
275 bus->name = "orion_mdio_bus";
276 snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii",
277 dev_name(&pdev->dev));
278 bus->parent = &pdev->dev;
279
280 dev = bus->priv;
281 dev->regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
282 if (!dev->regs) {
283 dev_err(&pdev->dev, "Unable to remap SMI register\n");
284 return -ENODEV;
285 }
286
287 init_waitqueue_head(&dev->smi_busy_wait);
288
289 if (pdev->dev.of_node) {
290 for (i = 0; i < ARRAY_SIZE(dev->clk); i++) {
291 dev->clk[i] = of_clk_get(pdev->dev.of_node, i);
292 if (PTR_ERR(dev->clk[i]) == -EPROBE_DEFER) {
293 ret = -EPROBE_DEFER;
294 goto out_clk;
295 }
296 if (IS_ERR(dev->clk[i]))
297 break;
298 clk_prepare_enable(dev->clk[i]);
299 }
300
301 if (!IS_ERR(of_clk_get(pdev->dev.of_node,
302 ARRAY_SIZE(dev->clk))))
303 dev_warn(&pdev->dev,
304 "unsupported number of clocks, limiting to the first "
305 __stringify(ARRAY_SIZE(dev->clk)) "\n");
306 } else {
307 dev->clk[0] = clk_get(&pdev->dev, NULL);
308 if (PTR_ERR(dev->clk[0]) == -EPROBE_DEFER) {
309 ret = -EPROBE_DEFER;
310 goto out_clk;
311 }
312 if (!IS_ERR(dev->clk[0]))
313 clk_prepare_enable(dev->clk[0]);
314 }
315
316
317 dev->err_interrupt = platform_get_irq_optional(pdev, 0);
318 if (dev->err_interrupt > 0 &&
319 resource_size(r) < MVMDIO_ERR_INT_MASK + 4) {
320 dev_err(&pdev->dev,
321 "disabling interrupt, resource size is too small\n");
322 dev->err_interrupt = 0;
323 }
324 if (dev->err_interrupt > 0) {
325 ret = devm_request_irq(&pdev->dev, dev->err_interrupt,
326 orion_mdio_err_irq,
327 IRQF_SHARED, pdev->name, dev);
328 if (ret)
329 goto out_mdio;
330
331 writel(MVMDIO_ERR_INT_SMI_DONE,
332 dev->regs + MVMDIO_ERR_INT_MASK);
333
334 } else if (dev->err_interrupt == -EPROBE_DEFER) {
335 ret = -EPROBE_DEFER;
336 goto out_mdio;
337 }
338
339 /* For the platforms not supporting DT/ACPI fall-back
340 * to mdiobus_register via of_mdiobus_register.
341 */
342 if (is_acpi_node(pdev->dev.fwnode))
343 ret = acpi_mdiobus_register(bus, pdev->dev.fwnode);
344 else
345 ret = of_mdiobus_register(bus, pdev->dev.of_node);
346 if (ret < 0) {
347 dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret);
348 goto out_mdio;
349 }
350
351 platform_set_drvdata(pdev, bus);
352
353 return 0;
354
355 out_mdio:
356 if (dev->err_interrupt > 0)
357 writel(0, dev->regs + MVMDIO_ERR_INT_MASK);
358
359 out_clk:
360 for (i = 0; i < ARRAY_SIZE(dev->clk); i++) {
361 if (IS_ERR(dev->clk[i]))
362 break;
363 clk_disable_unprepare(dev->clk[i]);
364 clk_put(dev->clk[i]);
365 }
366
367 return ret;
368 }
369
orion_mdio_remove(struct platform_device * pdev)370 static int orion_mdio_remove(struct platform_device *pdev)
371 {
372 struct mii_bus *bus = platform_get_drvdata(pdev);
373 struct orion_mdio_dev *dev = bus->priv;
374 int i;
375
376 if (dev->err_interrupt > 0)
377 writel(0, dev->regs + MVMDIO_ERR_INT_MASK);
378 mdiobus_unregister(bus);
379
380 for (i = 0; i < ARRAY_SIZE(dev->clk); i++) {
381 if (IS_ERR(dev->clk[i]))
382 break;
383 clk_disable_unprepare(dev->clk[i]);
384 clk_put(dev->clk[i]);
385 }
386
387 return 0;
388 }
389
390 static const struct of_device_id orion_mdio_match[] = {
391 { .compatible = "marvell,orion-mdio", .data = (void *)BUS_TYPE_SMI },
392 { .compatible = "marvell,xmdio", .data = (void *)BUS_TYPE_XSMI },
393 { }
394 };
395 MODULE_DEVICE_TABLE(of, orion_mdio_match);
396
397 #ifdef CONFIG_ACPI
398 static const struct acpi_device_id orion_mdio_acpi_match[] = {
399 { "MRVL0100", BUS_TYPE_SMI },
400 { "MRVL0101", BUS_TYPE_XSMI },
401 { },
402 };
403 MODULE_DEVICE_TABLE(acpi, orion_mdio_acpi_match);
404 #endif
405
406 static struct platform_driver orion_mdio_driver = {
407 .probe = orion_mdio_probe,
408 .remove = orion_mdio_remove,
409 .driver = {
410 .name = "orion-mdio",
411 .of_match_table = orion_mdio_match,
412 .acpi_match_table = ACPI_PTR(orion_mdio_acpi_match),
413 },
414 };
415
416 module_platform_driver(orion_mdio_driver);
417
418 MODULE_DESCRIPTION("Marvell MDIO interface driver");
419 MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
420 MODULE_LICENSE("GPL");
421 MODULE_ALIAS("platform:orion-mdio");
422