net: dsa: b53: Add support for Broadcom RoboSwitch
[deliverable/linux.git] / drivers / net / dsa / b53 / b53_srab.c
CommitLineData
967dd82f
FF
1/*
2 * B53 register access through Switch Register Access Bridge Registers
3 *
4 * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/delay.h>
22#include <linux/platform_device.h>
23#include <linux/platform_data/b53.h>
24
25#include "b53_priv.h"
26
27/* command and status register of the SRAB */
28#define B53_SRAB_CMDSTAT 0x2c
29#define B53_SRAB_CMDSTAT_RST BIT(2)
30#define B53_SRAB_CMDSTAT_WRITE BIT(1)
31#define B53_SRAB_CMDSTAT_GORDYN BIT(0)
32#define B53_SRAB_CMDSTAT_PAGE 24
33#define B53_SRAB_CMDSTAT_REG 16
34
35/* high order word of write data to switch registe */
36#define B53_SRAB_WD_H 0x30
37
38/* low order word of write data to switch registe */
39#define B53_SRAB_WD_L 0x34
40
41/* high order word of read data from switch register */
42#define B53_SRAB_RD_H 0x38
43
44/* low order word of read data from switch register */
45#define B53_SRAB_RD_L 0x3c
46
47/* command and status register of the SRAB */
48#define B53_SRAB_CTRLS 0x40
49#define B53_SRAB_CTRLS_RCAREQ BIT(3)
50#define B53_SRAB_CTRLS_RCAGNT BIT(4)
51#define B53_SRAB_CTRLS_SW_INIT_DONE BIT(6)
52
53/* the register captures interrupt pulses from the switch */
54#define B53_SRAB_INTR 0x44
55#define B53_SRAB_INTR_P(x) BIT(x)
56#define B53_SRAB_SWITCH_PHY BIT(8)
57#define B53_SRAB_1588_SYNC BIT(9)
58#define B53_SRAB_IMP1_SLEEP_TIMER BIT(10)
59#define B53_SRAB_P7_SLEEP_TIMER BIT(11)
60#define B53_SRAB_IMP0_SLEEP_TIMER BIT(12)
61
62struct b53_srab_priv {
63 void __iomem *regs;
64};
65
66static int b53_srab_request_grant(struct b53_device *dev)
67{
68 struct b53_srab_priv *priv = dev->priv;
69 u8 __iomem *regs = priv->regs;
70 u32 ctrls;
71 int i;
72
73 ctrls = readl(regs + B53_SRAB_CTRLS);
74 ctrls |= B53_SRAB_CTRLS_RCAREQ;
75 writel(ctrls, regs + B53_SRAB_CTRLS);
76
77 for (i = 0; i < 20; i++) {
78 ctrls = readl(regs + B53_SRAB_CTRLS);
79 if (ctrls & B53_SRAB_CTRLS_RCAGNT)
80 break;
81 usleep_range(10, 100);
82 }
83 if (WARN_ON(i == 5))
84 return -EIO;
85
86 return 0;
87}
88
89static void b53_srab_release_grant(struct b53_device *dev)
90{
91 struct b53_srab_priv *priv = dev->priv;
92 u8 __iomem *regs = priv->regs;
93 u32 ctrls;
94
95 ctrls = readl(regs + B53_SRAB_CTRLS);
96 ctrls &= ~B53_SRAB_CTRLS_RCAREQ;
97 writel(ctrls, regs + B53_SRAB_CTRLS);
98}
99
100static int b53_srab_op(struct b53_device *dev, u8 page, u8 reg, u32 op)
101{
102 struct b53_srab_priv *priv = dev->priv;
103 u8 __iomem *regs = priv->regs;
104 int i;
105 u32 cmdstat;
106
107 /* set register address */
108 cmdstat = (page << B53_SRAB_CMDSTAT_PAGE) |
109 (reg << B53_SRAB_CMDSTAT_REG) |
110 B53_SRAB_CMDSTAT_GORDYN |
111 op;
112 writel(cmdstat, regs + B53_SRAB_CMDSTAT);
113
114 /* check if operation completed */
115 for (i = 0; i < 5; ++i) {
116 cmdstat = readl(regs + B53_SRAB_CMDSTAT);
117 if (!(cmdstat & B53_SRAB_CMDSTAT_GORDYN))
118 break;
119 usleep_range(10, 100);
120 }
121
122 if (WARN_ON(i == 5))
123 return -EIO;
124
125 return 0;
126}
127
128static int b53_srab_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
129{
130 struct b53_srab_priv *priv = dev->priv;
131 u8 __iomem *regs = priv->regs;
132 int ret = 0;
133
134 ret = b53_srab_request_grant(dev);
135 if (ret)
136 goto err;
137
138 ret = b53_srab_op(dev, page, reg, 0);
139 if (ret)
140 goto err;
141
142 *val = readl(regs + B53_SRAB_RD_L) & 0xff;
143
144err:
145 b53_srab_release_grant(dev);
146
147 return ret;
148}
149
150static int b53_srab_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
151{
152 struct b53_srab_priv *priv = dev->priv;
153 u8 __iomem *regs = priv->regs;
154 int ret = 0;
155
156 ret = b53_srab_request_grant(dev);
157 if (ret)
158 goto err;
159
160 ret = b53_srab_op(dev, page, reg, 0);
161 if (ret)
162 goto err;
163
164 *val = readl(regs + B53_SRAB_RD_L) & 0xffff;
165
166err:
167 b53_srab_release_grant(dev);
168
169 return ret;
170}
171
172static int b53_srab_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
173{
174 struct b53_srab_priv *priv = dev->priv;
175 u8 __iomem *regs = priv->regs;
176 int ret = 0;
177
178 ret = b53_srab_request_grant(dev);
179 if (ret)
180 goto err;
181
182 ret = b53_srab_op(dev, page, reg, 0);
183 if (ret)
184 goto err;
185
186 *val = readl(regs + B53_SRAB_RD_L);
187
188err:
189 b53_srab_release_grant(dev);
190
191 return ret;
192}
193
194static int b53_srab_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
195{
196 struct b53_srab_priv *priv = dev->priv;
197 u8 __iomem *regs = priv->regs;
198 int ret = 0;
199
200 ret = b53_srab_request_grant(dev);
201 if (ret)
202 goto err;
203
204 ret = b53_srab_op(dev, page, reg, 0);
205 if (ret)
206 goto err;
207
208 *val = readl(regs + B53_SRAB_RD_L);
209 *val += ((u64)readl(regs + B53_SRAB_RD_H) & 0xffff) << 32;
210
211err:
212 b53_srab_release_grant(dev);
213
214 return ret;
215}
216
217static int b53_srab_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
218{
219 struct b53_srab_priv *priv = dev->priv;
220 u8 __iomem *regs = priv->regs;
221 int ret = 0;
222
223 ret = b53_srab_request_grant(dev);
224 if (ret)
225 goto err;
226
227 ret = b53_srab_op(dev, page, reg, 0);
228 if (ret)
229 goto err;
230
231 *val = readl(regs + B53_SRAB_RD_L);
232 *val += (u64)readl(regs + B53_SRAB_RD_H) << 32;
233
234err:
235 b53_srab_release_grant(dev);
236
237 return ret;
238}
239
240static int b53_srab_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
241{
242 struct b53_srab_priv *priv = dev->priv;
243 u8 __iomem *regs = priv->regs;
244 int ret = 0;
245
246 ret = b53_srab_request_grant(dev);
247 if (ret)
248 goto err;
249
250 writel(value, regs + B53_SRAB_WD_L);
251
252 ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
253
254err:
255 b53_srab_release_grant(dev);
256
257 return ret;
258}
259
260static int b53_srab_write16(struct b53_device *dev, u8 page, u8 reg,
261 u16 value)
262{
263 struct b53_srab_priv *priv = dev->priv;
264 u8 __iomem *regs = priv->regs;
265 int ret = 0;
266
267 ret = b53_srab_request_grant(dev);
268 if (ret)
269 goto err;
270
271 writel(value, regs + B53_SRAB_WD_L);
272
273 ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
274
275err:
276 b53_srab_release_grant(dev);
277
278 return ret;
279}
280
281static int b53_srab_write32(struct b53_device *dev, u8 page, u8 reg,
282 u32 value)
283{
284 struct b53_srab_priv *priv = dev->priv;
285 u8 __iomem *regs = priv->regs;
286 int ret = 0;
287
288 ret = b53_srab_request_grant(dev);
289 if (ret)
290 goto err;
291
292 writel(value, regs + B53_SRAB_WD_L);
293
294 ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
295
296err:
297 b53_srab_release_grant(dev);
298
299 return ret;
300}
301
302static int b53_srab_write48(struct b53_device *dev, u8 page, u8 reg,
303 u64 value)
304{
305 struct b53_srab_priv *priv = dev->priv;
306 u8 __iomem *regs = priv->regs;
307 int ret = 0;
308
309 ret = b53_srab_request_grant(dev);
310 if (ret)
311 goto err;
312
313 writel((u32)value, regs + B53_SRAB_WD_L);
314 writel((u16)(value >> 32), regs + B53_SRAB_WD_H);
315
316 ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
317
318err:
319 b53_srab_release_grant(dev);
320
321 return ret;
322}
323
324static int b53_srab_write64(struct b53_device *dev, u8 page, u8 reg,
325 u64 value)
326{
327 struct b53_srab_priv *priv = dev->priv;
328 u8 __iomem *regs = priv->regs;
329 int ret = 0;
330
331 ret = b53_srab_request_grant(dev);
332 if (ret)
333 goto err;
334
335 writel((u32)value, regs + B53_SRAB_WD_L);
336 writel((u32)(value >> 32), regs + B53_SRAB_WD_H);
337
338 ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
339
340err:
341 b53_srab_release_grant(dev);
342
343 return ret;
344}
345
346static struct b53_io_ops b53_srab_ops = {
347 .read8 = b53_srab_read8,
348 .read16 = b53_srab_read16,
349 .read32 = b53_srab_read32,
350 .read48 = b53_srab_read48,
351 .read64 = b53_srab_read64,
352 .write8 = b53_srab_write8,
353 .write16 = b53_srab_write16,
354 .write32 = b53_srab_write32,
355 .write48 = b53_srab_write48,
356 .write64 = b53_srab_write64,
357};
358
359static int b53_srab_probe(struct platform_device *pdev)
360{
361 struct b53_srab_priv *priv;
362 struct b53_device *dev;
363 struct resource *r;
364
365 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
366 if (!priv)
367 return -ENOMEM;
368
369 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
370 priv->regs = devm_ioremap_resource(&pdev->dev, r);
371 if (IS_ERR(priv->regs))
372 return -ENOMEM;
373
374 dev = b53_switch_alloc(&pdev->dev, &b53_srab_ops, priv);
375 if (!dev)
376 return -ENOMEM;
377
378 platform_set_drvdata(pdev, dev);
379
380 return b53_switch_register(dev);
381}
382
383static int b53_srab_remove(struct platform_device *pdev)
384{
385 struct b53_device *dev = platform_get_drvdata(pdev);
386
387 if (dev)
388 b53_switch_remove(dev);
389
390 return 0;
391}
392
393static const struct of_device_id b53_srab_of_match[] = {
394 { .compatible = "brcm,bcm53010-srab" },
395 { .compatible = "brcm,bcm53011-srab" },
396 { .compatible = "brcm,bcm53012-srab" },
397 { .compatible = "brcm,bcm53018-srab" },
398 { .compatible = "brcm,bcm53019-srab" },
399 { .compatible = "brcm,bcm5301x-srab" },
400 { /* sentinel */ },
401};
402
403static struct platform_driver b53_srab_driver = {
404 .probe = b53_srab_probe,
405 .remove = b53_srab_remove,
406 .driver = {
407 .name = "b53-srab-switch",
408 .of_match_table = b53_srab_of_match,
409 },
410};
411
412module_platform_driver(b53_srab_driver);
413MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
414MODULE_DESCRIPTION("B53 Switch Register Access Bridge Registers (SRAB) access driver");
415MODULE_LICENSE("Dual BSD/GPL");
This page took 0.038949 seconds and 5 git commands to generate.