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  */
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 
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 
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 
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 
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 
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 
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 
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 
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 
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