summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/net/marvell-orion-mdio.txt10
-rw-r--r--drivers/net/ethernet/marvell/mvmdio.c214
2 files changed, 164 insertions, 60 deletions
diff --git a/Documentation/devicetree/bindings/net/marvell-orion-mdio.txt b/Documentation/devicetree/bindings/net/marvell-orion-mdio.txt
index ccdabdcc8618..42cd81090a2c 100644
--- a/Documentation/devicetree/bindings/net/marvell-orion-mdio.txt
+++ b/Documentation/devicetree/bindings/net/marvell-orion-mdio.txt
@@ -1,12 +1,14 @@
1* Marvell MDIO Ethernet Controller interface 1* Marvell MDIO Ethernet Controller interface
2 2
3The Ethernet controllers of the Marvel Kirkwood, Dove, Orion5x, 3The Ethernet controllers of the Marvel Kirkwood, Dove, Orion5x,
4MV78xx0, Armada 370 and Armada XP have an identical unit that provides 4MV78xx0, Armada 370, Armada XP, Armada 7k and Armada 8k have an
5an interface with the MDIO bus. This driver handles this MDIO 5identical unit that provides an interface with the MDIO bus.
6interface. 6Additionally, Armada 7k and Armada 8k has a second unit which
7provides an interface with the xMDIO bus. This driver handles
8these interfaces.
7 9
8Required properties: 10Required properties:
9- compatible: "marvell,orion-mdio" 11- compatible: "marvell,orion-mdio" or "marvell,xmdio"
10- reg: address and length of the MDIO registers. When an interrupt is 12- reg: address and length of the MDIO registers. When an interrupt is
11 not present, the length is the size of the SMI register (4 bytes) 13 not present, the length is the size of the SMI register (4 bytes)
12 otherwise it must be 0x84 bytes to cover the interrupt control 14 otherwise it must be 0x84 bytes to cover the interrupt control
diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c
index 90a60b98c28e..c9798210fa0f 100644
--- a/drivers/net/ethernet/marvell/mvmdio.c
+++ b/drivers/net/ethernet/marvell/mvmdio.c
@@ -17,41 +17,52 @@
17 * warranty of any kind, whether express or implied. 17 * warranty of any kind, whether express or implied.
18 */ 18 */
19 19
20#include <linux/clk.h>
21#include <linux/delay.h>
22#include <linux/interrupt.h>
23#include <linux/io.h>
20#include <linux/kernel.h> 24#include <linux/kernel.h>
21#include <linux/module.h> 25#include <linux/module.h>
22#include <linux/mutex.h> 26#include <linux/of_device.h>
27#include <linux/of_mdio.h>
23#include <linux/phy.h> 28#include <linux/phy.h>
24#include <linux/interrupt.h>
25#include <linux/platform_device.h> 29#include <linux/platform_device.h>
26#include <linux/delay.h>
27#include <linux/io.h>
28#include <linux/clk.h>
29#include <linux/of_mdio.h>
30#include <linux/sched.h> 30#include <linux/sched.h>
31#include <linux/wait.h> 31#include <linux/wait.h>
32 32
33#define MVMDIO_SMI_DATA_SHIFT 0 33#define MVMDIO_SMI_DATA_SHIFT 0
34#define MVMDIO_SMI_PHY_ADDR_SHIFT 16 34#define MVMDIO_SMI_PHY_ADDR_SHIFT 16
35#define MVMDIO_SMI_PHY_REG_SHIFT 21 35#define MVMDIO_SMI_PHY_REG_SHIFT 21
36#define MVMDIO_SMI_READ_OPERATION BIT(26) 36#define MVMDIO_SMI_READ_OPERATION BIT(26)
37#define MVMDIO_SMI_WRITE_OPERATION 0 37#define MVMDIO_SMI_WRITE_OPERATION 0
38#define MVMDIO_SMI_READ_VALID BIT(27) 38#define MVMDIO_SMI_READ_VALID BIT(27)
39#define MVMDIO_SMI_BUSY BIT(28) 39#define MVMDIO_SMI_BUSY BIT(28)
40#define MVMDIO_ERR_INT_CAUSE 0x007C 40#define MVMDIO_ERR_INT_CAUSE 0x007C
41#define MVMDIO_ERR_INT_SMI_DONE 0x00000010 41#define MVMDIO_ERR_INT_SMI_DONE 0x00000010
42#define MVMDIO_ERR_INT_MASK 0x0080 42#define MVMDIO_ERR_INT_MASK 0x0080
43
44#define MVMDIO_XSMI_MGNT_REG 0x0
45#define MVMDIO_XSMI_PHYADDR_SHIFT 16
46#define MVMDIO_XSMI_DEVADDR_SHIFT 21
47#define MVMDIO_XSMI_WRITE_OPERATION (0x5 << 26)
48#define MVMDIO_XSMI_READ_OPERATION (0x7 << 26)
49#define MVMDIO_XSMI_READ_VALID BIT(29)
50#define MVMDIO_XSMI_BUSY BIT(30)
51#define MVMDIO_XSMI_ADDR_REG 0x8
43 52
44/* 53/*
45 * SMI Timeout measurements: 54 * SMI Timeout measurements:
46 * - Kirkwood 88F6281 (Globalscale Dreamplug): 45us to 95us (Interrupt) 55 * - Kirkwood 88F6281 (Globalscale Dreamplug): 45us to 95us (Interrupt)
47 * - Armada 370 (Globalscale Mirabox): 41us to 43us (Polled) 56 * - Armada 370 (Globalscale Mirabox): 41us to 43us (Polled)
48 */ 57 */
49#define MVMDIO_SMI_TIMEOUT 1000 /* 1000us = 1ms */ 58#define MVMDIO_SMI_TIMEOUT 1000 /* 1000us = 1ms */
50#define MVMDIO_SMI_POLL_INTERVAL_MIN 45 59#define MVMDIO_SMI_POLL_INTERVAL_MIN 45
51#define MVMDIO_SMI_POLL_INTERVAL_MAX 55 60#define MVMDIO_SMI_POLL_INTERVAL_MAX 55
61
62#define MVMDIO_XSMI_POLL_INTERVAL_MIN 150
63#define MVMDIO_XSMI_POLL_INTERVAL_MAX 160
52 64
53struct orion_mdio_dev { 65struct orion_mdio_dev {
54 struct mutex lock;
55 void __iomem *regs; 66 void __iomem *regs;
56 struct clk *clk[3]; 67 struct clk *clk[3];
57 /* 68 /*
@@ -64,14 +75,21 @@ struct orion_mdio_dev {
64 wait_queue_head_t smi_busy_wait; 75 wait_queue_head_t smi_busy_wait;
65}; 76};
66 77
67static int orion_mdio_smi_is_done(struct orion_mdio_dev *dev) 78enum orion_mdio_bus_type {
68{ 79 BUS_TYPE_SMI,
69 return !(readl(dev->regs) & MVMDIO_SMI_BUSY); 80 BUS_TYPE_XSMI
70} 81};
82
83struct orion_mdio_ops {
84 int (*is_done)(struct orion_mdio_dev *);
85 unsigned int poll_interval_min;
86 unsigned int poll_interval_max;
87};
71 88
72/* Wait for the SMI unit to be ready for another operation 89/* Wait for the SMI unit to be ready for another operation
73 */ 90 */
74static int orion_mdio_wait_ready(struct mii_bus *bus) 91static int orion_mdio_wait_ready(const struct orion_mdio_ops *ops,
92 struct mii_bus *bus)
75{ 93{
76 struct orion_mdio_dev *dev = bus->priv; 94 struct orion_mdio_dev *dev = bus->priv;
77 unsigned long timeout = usecs_to_jiffies(MVMDIO_SMI_TIMEOUT); 95 unsigned long timeout = usecs_to_jiffies(MVMDIO_SMI_TIMEOUT);
@@ -79,14 +97,14 @@ static int orion_mdio_wait_ready(struct mii_bus *bus)
79 int timedout = 0; 97 int timedout = 0;
80 98
81 while (1) { 99 while (1) {
82 if (orion_mdio_smi_is_done(dev)) 100 if (ops->is_done(dev))
83 return 0; 101 return 0;
84 else if (timedout) 102 else if (timedout)
85 break; 103 break;
86 104
87 if (dev->err_interrupt <= 0) { 105 if (dev->err_interrupt <= 0) {
88 usleep_range(MVMDIO_SMI_POLL_INTERVAL_MIN, 106 usleep_range(ops->poll_interval_min,
89 MVMDIO_SMI_POLL_INTERVAL_MAX); 107 ops->poll_interval_max);
90 108
91 if (time_is_before_jiffies(end)) 109 if (time_is_before_jiffies(end))
92 ++timedout; 110 ++timedout;
@@ -98,8 +116,7 @@ static int orion_mdio_wait_ready(struct mii_bus *bus)
98 if (timeout < 2) 116 if (timeout < 2)
99 timeout = 2; 117 timeout = 2;
100 wait_event_timeout(dev->smi_busy_wait, 118 wait_event_timeout(dev->smi_busy_wait,
101 orion_mdio_smi_is_done(dev), 119 ops->is_done(dev), timeout);
102 timeout);
103 120
104 ++timedout; 121 ++timedout;
105 } 122 }
@@ -109,52 +126,61 @@ static int orion_mdio_wait_ready(struct mii_bus *bus)
109 return -ETIMEDOUT; 126 return -ETIMEDOUT;
110} 127}
111 128
112static int orion_mdio_read(struct mii_bus *bus, int mii_id, 129static int orion_mdio_smi_is_done(struct orion_mdio_dev *dev)
113 int regnum) 130{
131 return !(readl(dev->regs) & MVMDIO_SMI_BUSY);
132}
133
134static const struct orion_mdio_ops orion_mdio_smi_ops = {
135 .is_done = orion_mdio_smi_is_done,
136 .poll_interval_min = MVMDIO_SMI_POLL_INTERVAL_MIN,
137 .poll_interval_max = MVMDIO_SMI_POLL_INTERVAL_MAX,
138};
139
140static int orion_mdio_smi_read(struct mii_bus *bus, int mii_id,
141 int regnum)
114{ 142{
115 struct orion_mdio_dev *dev = bus->priv; 143 struct orion_mdio_dev *dev = bus->priv;
116 u32 val; 144 u32 val;
117 int ret; 145 int ret;
118 146
119 mutex_lock(&dev->lock); 147 if (regnum & MII_ADDR_C45)
148 return -EOPNOTSUPP;
120 149
121 ret = orion_mdio_wait_ready(bus); 150 ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus);
122 if (ret < 0) 151 if (ret < 0)
123 goto out; 152 return ret;
124 153
125 writel(((mii_id << MVMDIO_SMI_PHY_ADDR_SHIFT) | 154 writel(((mii_id << MVMDIO_SMI_PHY_ADDR_SHIFT) |
126 (regnum << MVMDIO_SMI_PHY_REG_SHIFT) | 155 (regnum << MVMDIO_SMI_PHY_REG_SHIFT) |
127 MVMDIO_SMI_READ_OPERATION), 156 MVMDIO_SMI_READ_OPERATION),
128 dev->regs); 157 dev->regs);
129 158
130 ret = orion_mdio_wait_ready(bus); 159 ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus);
131 if (ret < 0) 160 if (ret < 0)
132 goto out; 161 return ret;
133 162
134 val = readl(dev->regs); 163 val = readl(dev->regs);
135 if (!(val & MVMDIO_SMI_READ_VALID)) { 164 if (!(val & MVMDIO_SMI_READ_VALID)) {
136 dev_err(bus->parent, "SMI bus read not valid\n"); 165 dev_err(bus->parent, "SMI bus read not valid\n");
137 ret = -ENODEV; 166 return -ENODEV;
138 goto out;
139 } 167 }
140 168
141 ret = val & 0xFFFF; 169 return val & GENMASK(15, 0);
142out:
143 mutex_unlock(&dev->lock);
144 return ret;
145} 170}
146 171
147static int orion_mdio_write(struct mii_bus *bus, int mii_id, 172static int orion_mdio_smi_write(struct mii_bus *bus, int mii_id,
148 int regnum, u16 value) 173 int regnum, u16 value)
149{ 174{
150 struct orion_mdio_dev *dev = bus->priv; 175 struct orion_mdio_dev *dev = bus->priv;
151 int ret; 176 int ret;
152 177
153 mutex_lock(&dev->lock); 178 if (regnum & MII_ADDR_C45)
179 return -EOPNOTSUPP;
154 180
155 ret = orion_mdio_wait_ready(bus); 181 ret = orion_mdio_wait_ready(&orion_mdio_smi_ops, bus);
156 if (ret < 0) 182 if (ret < 0)
157 goto out; 183 return ret;
158 184
159 writel(((mii_id << MVMDIO_SMI_PHY_ADDR_SHIFT) | 185 writel(((mii_id << MVMDIO_SMI_PHY_ADDR_SHIFT) |
160 (regnum << MVMDIO_SMI_PHY_REG_SHIFT) | 186 (regnum << MVMDIO_SMI_PHY_REG_SHIFT) |
@@ -162,9 +188,74 @@ static int orion_mdio_write(struct mii_bus *bus, int mii_id,
162 (value << MVMDIO_SMI_DATA_SHIFT)), 188 (value << MVMDIO_SMI_DATA_SHIFT)),
163 dev->regs); 189 dev->regs);
164 190
165out: 191 return 0;
166 mutex_unlock(&dev->lock); 192}
167 return ret; 193
194static int orion_mdio_xsmi_is_done(struct orion_mdio_dev *dev)
195{
196 return !(readl(dev->regs + MVMDIO_XSMI_MGNT_REG) & MVMDIO_XSMI_BUSY);
197}
198
199static const struct orion_mdio_ops orion_mdio_xsmi_ops = {
200 .is_done = orion_mdio_xsmi_is_done,
201 .poll_interval_min = MVMDIO_XSMI_POLL_INTERVAL_MIN,
202 .poll_interval_max = MVMDIO_XSMI_POLL_INTERVAL_MAX,
203};
204
205static int orion_mdio_xsmi_read(struct mii_bus *bus, int mii_id,
206 int regnum)
207{
208 struct orion_mdio_dev *dev = bus->priv;
209 u16 dev_addr = (regnum >> 16) & GENMASK(4, 0);
210 int ret;
211
212 if (!(regnum & MII_ADDR_C45))
213 return -EOPNOTSUPP;
214
215 ret = orion_mdio_wait_ready(&orion_mdio_xsmi_ops, bus);
216 if (ret < 0)
217 return ret;
218
219 writel(regnum & GENMASK(15, 0), dev->regs + MVMDIO_XSMI_ADDR_REG);
220 writel((mii_id << MVMDIO_XSMI_PHYADDR_SHIFT) |
221 (dev_addr << MVMDIO_XSMI_DEVADDR_SHIFT) |
222 MVMDIO_XSMI_READ_OPERATION,
223 dev->regs + MVMDIO_XSMI_MGNT_REG);
224
225 ret = orion_mdio_wait_ready(&orion_mdio_xsmi_ops, bus);
226 if (ret < 0)
227 return ret;
228
229 if (!(readl(dev->regs + MVMDIO_XSMI_MGNT_REG) &
230 MVMDIO_XSMI_READ_VALID)) {
231 dev_err(bus->parent, "XSMI bus read not valid\n");
232 return -ENODEV;
233 }
234
235 return readl(dev->regs + MVMDIO_XSMI_MGNT_REG) & GENMASK(15, 0);
236}
237
238static int orion_mdio_xsmi_write(struct mii_bus *bus, int mii_id,
239 int regnum, u16 value)
240{
241 struct orion_mdio_dev *dev = bus->priv;
242 u16 dev_addr = (regnum >> 16) & GENMASK(4, 0);
243 int ret;
244
245 if (!(regnum & MII_ADDR_C45))
246 return -EOPNOTSUPP;
247
248 ret = orion_mdio_wait_ready(&orion_mdio_xsmi_ops, bus);
249 if (ret < 0)
250 return ret;
251
252 writel(regnum & GENMASK(15, 0), dev->regs + MVMDIO_XSMI_ADDR_REG);
253 writel((mii_id << MVMDIO_XSMI_PHYADDR_SHIFT) |
254 (dev_addr << MVMDIO_XSMI_DEVADDR_SHIFT) |
255 MVMDIO_XSMI_WRITE_OPERATION | value,
256 dev->regs + MVMDIO_XSMI_MGNT_REG);
257
258 return 0;
168} 259}
169 260
170static irqreturn_t orion_mdio_err_irq(int irq, void *dev_id) 261static irqreturn_t orion_mdio_err_irq(int irq, void *dev_id)
@@ -184,11 +275,14 @@ static irqreturn_t orion_mdio_err_irq(int irq, void *dev_id)
184 275
185static int orion_mdio_probe(struct platform_device *pdev) 276static int orion_mdio_probe(struct platform_device *pdev)
186{ 277{
278 enum orion_mdio_bus_type type;
187 struct resource *r; 279 struct resource *r;
188 struct mii_bus *bus; 280 struct mii_bus *bus;
189 struct orion_mdio_dev *dev; 281 struct orion_mdio_dev *dev;
190 int i, ret; 282 int i, ret;
191 283
284 type = (enum orion_mdio_bus_type)of_device_get_match_data(&pdev->dev);
285
192 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 286 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
193 if (!r) { 287 if (!r) {
194 dev_err(&pdev->dev, "No SMI register address given\n"); 288 dev_err(&pdev->dev, "No SMI register address given\n");
@@ -200,9 +294,18 @@ static int orion_mdio_probe(struct platform_device *pdev)
200 if (!bus) 294 if (!bus)
201 return -ENOMEM; 295 return -ENOMEM;
202 296
297 switch (type) {
298 case BUS_TYPE_SMI:
299 bus->read = orion_mdio_smi_read;
300 bus->write = orion_mdio_smi_write;
301 break;
302 case BUS_TYPE_XSMI:
303 bus->read = orion_mdio_xsmi_read;
304 bus->write = orion_mdio_xsmi_write;
305 break;
306 }
307
203 bus->name = "orion_mdio_bus"; 308 bus->name = "orion_mdio_bus";
204 bus->read = orion_mdio_read;
205 bus->write = orion_mdio_write;
206 snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", 309 snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii",
207 dev_name(&pdev->dev)); 310 dev_name(&pdev->dev));
208 bus->parent = &pdev->dev; 311 bus->parent = &pdev->dev;
@@ -244,8 +347,6 @@ static int orion_mdio_probe(struct platform_device *pdev)
244 return -EPROBE_DEFER; 347 return -EPROBE_DEFER;
245 } 348 }
246 349
247 mutex_init(&dev->lock);
248
249 if (pdev->dev.of_node) 350 if (pdev->dev.of_node)
250 ret = of_mdiobus_register(bus, pdev->dev.of_node); 351 ret = of_mdiobus_register(bus, pdev->dev.of_node);
251 else 352 else
@@ -294,7 +395,8 @@ static int orion_mdio_remove(struct platform_device *pdev)
294} 395}
295 396
296static const struct of_device_id orion_mdio_match[] = { 397static const struct of_device_id orion_mdio_match[] = {
297 { .compatible = "marvell,orion-mdio" }, 398 { .compatible = "marvell,orion-mdio", .data = (void *)BUS_TYPE_SMI },
399 { .compatible = "marvell,xmdio", .data = (void *)BUS_TYPE_XSMI },
298 { } 400 { }
299}; 401};
300MODULE_DEVICE_TABLE(of, orion_mdio_match); 402MODULE_DEVICE_TABLE(of, orion_mdio_match);