GNU Linux-libre 4.19.286-gnu1
[releases.git] / drivers / net / dsa / b53 / b53_srab.c
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 #include <linux/of.h>
25
26 #include "b53_priv.h"
27
28 /* command and status register of the SRAB */
29 #define B53_SRAB_CMDSTAT                0x2c
30 #define  B53_SRAB_CMDSTAT_RST           BIT(2)
31 #define  B53_SRAB_CMDSTAT_WRITE         BIT(1)
32 #define  B53_SRAB_CMDSTAT_GORDYN        BIT(0)
33 #define  B53_SRAB_CMDSTAT_PAGE          24
34 #define  B53_SRAB_CMDSTAT_REG           16
35
36 /* high order word of write data to switch registe */
37 #define B53_SRAB_WD_H                   0x30
38
39 /* low order word of write data to switch registe */
40 #define B53_SRAB_WD_L                   0x34
41
42 /* high order word of read data from switch register */
43 #define B53_SRAB_RD_H                   0x38
44
45 /* low order word of read data from switch register */
46 #define B53_SRAB_RD_L                   0x3c
47
48 /* command and status register of the SRAB */
49 #define B53_SRAB_CTRLS                  0x40
50 #define  B53_SRAB_CTRLS_RCAREQ          BIT(3)
51 #define  B53_SRAB_CTRLS_RCAGNT          BIT(4)
52 #define  B53_SRAB_CTRLS_SW_INIT_DONE    BIT(6)
53
54 /* the register captures interrupt pulses from the switch */
55 #define B53_SRAB_INTR                   0x44
56 #define  B53_SRAB_INTR_P(x)             BIT(x)
57 #define  B53_SRAB_SWITCH_PHY            BIT(8)
58 #define  B53_SRAB_1588_SYNC             BIT(9)
59 #define  B53_SRAB_IMP1_SLEEP_TIMER      BIT(10)
60 #define  B53_SRAB_P7_SLEEP_TIMER        BIT(11)
61 #define  B53_SRAB_IMP0_SLEEP_TIMER      BIT(12)
62
63 struct b53_srab_priv {
64         void __iomem *regs;
65 };
66
67 static int b53_srab_request_grant(struct b53_device *dev)
68 {
69         struct b53_srab_priv *priv = dev->priv;
70         u8 __iomem *regs = priv->regs;
71         u32 ctrls;
72         int i;
73
74         ctrls = readl(regs + B53_SRAB_CTRLS);
75         ctrls |= B53_SRAB_CTRLS_RCAREQ;
76         writel(ctrls, regs + B53_SRAB_CTRLS);
77
78         for (i = 0; i < 20; i++) {
79                 ctrls = readl(regs + B53_SRAB_CTRLS);
80                 if (ctrls & B53_SRAB_CTRLS_RCAGNT)
81                         break;
82                 usleep_range(10, 100);
83         }
84         if (WARN_ON(i == 5))
85                 return -EIO;
86
87         return 0;
88 }
89
90 static void b53_srab_release_grant(struct b53_device *dev)
91 {
92         struct b53_srab_priv *priv = dev->priv;
93         u8 __iomem *regs = priv->regs;
94         u32 ctrls;
95
96         ctrls = readl(regs + B53_SRAB_CTRLS);
97         ctrls &= ~B53_SRAB_CTRLS_RCAREQ;
98         writel(ctrls, regs + B53_SRAB_CTRLS);
99 }
100
101 static int b53_srab_op(struct b53_device *dev, u8 page, u8 reg, u32 op)
102 {
103         struct b53_srab_priv *priv = dev->priv;
104         u8 __iomem *regs = priv->regs;
105         int i;
106         u32 cmdstat;
107
108         /* set register address */
109         cmdstat = (page << B53_SRAB_CMDSTAT_PAGE) |
110                   (reg << B53_SRAB_CMDSTAT_REG) |
111                   B53_SRAB_CMDSTAT_GORDYN |
112                   op;
113         writel(cmdstat, regs + B53_SRAB_CMDSTAT);
114
115         /* check if operation completed */
116         for (i = 0; i < 5; ++i) {
117                 cmdstat = readl(regs + B53_SRAB_CMDSTAT);
118                 if (!(cmdstat & B53_SRAB_CMDSTAT_GORDYN))
119                         break;
120                 usleep_range(10, 100);
121         }
122
123         if (WARN_ON(i == 5))
124                 return -EIO;
125
126         return 0;
127 }
128
129 static int b53_srab_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
130 {
131         struct b53_srab_priv *priv = dev->priv;
132         u8 __iomem *regs = priv->regs;
133         int ret = 0;
134
135         ret = b53_srab_request_grant(dev);
136         if (ret)
137                 goto err;
138
139         ret = b53_srab_op(dev, page, reg, 0);
140         if (ret)
141                 goto err;
142
143         *val = readl(regs + B53_SRAB_RD_L) & 0xff;
144
145 err:
146         b53_srab_release_grant(dev);
147
148         return ret;
149 }
150
151 static int b53_srab_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
152 {
153         struct b53_srab_priv *priv = dev->priv;
154         u8 __iomem *regs = priv->regs;
155         int ret = 0;
156
157         ret = b53_srab_request_grant(dev);
158         if (ret)
159                 goto err;
160
161         ret = b53_srab_op(dev, page, reg, 0);
162         if (ret)
163                 goto err;
164
165         *val = readl(regs + B53_SRAB_RD_L) & 0xffff;
166
167 err:
168         b53_srab_release_grant(dev);
169
170         return ret;
171 }
172
173 static int b53_srab_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
174 {
175         struct b53_srab_priv *priv = dev->priv;
176         u8 __iomem *regs = priv->regs;
177         int ret = 0;
178
179         ret = b53_srab_request_grant(dev);
180         if (ret)
181                 goto err;
182
183         ret = b53_srab_op(dev, page, reg, 0);
184         if (ret)
185                 goto err;
186
187         *val = readl(regs + B53_SRAB_RD_L);
188
189 err:
190         b53_srab_release_grant(dev);
191
192         return ret;
193 }
194
195 static int b53_srab_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
196 {
197         struct b53_srab_priv *priv = dev->priv;
198         u8 __iomem *regs = priv->regs;
199         int ret = 0;
200
201         ret = b53_srab_request_grant(dev);
202         if (ret)
203                 goto err;
204
205         ret = b53_srab_op(dev, page, reg, 0);
206         if (ret)
207                 goto err;
208
209         *val = readl(regs + B53_SRAB_RD_L);
210         *val += ((u64)readl(regs + B53_SRAB_RD_H) & 0xffff) << 32;
211
212 err:
213         b53_srab_release_grant(dev);
214
215         return ret;
216 }
217
218 static int b53_srab_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
219 {
220         struct b53_srab_priv *priv = dev->priv;
221         u8 __iomem *regs = priv->regs;
222         int ret = 0;
223
224         ret = b53_srab_request_grant(dev);
225         if (ret)
226                 goto err;
227
228         ret = b53_srab_op(dev, page, reg, 0);
229         if (ret)
230                 goto err;
231
232         *val = readl(regs + B53_SRAB_RD_L);
233         *val += (u64)readl(regs + B53_SRAB_RD_H) << 32;
234
235 err:
236         b53_srab_release_grant(dev);
237
238         return ret;
239 }
240
241 static int b53_srab_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
242 {
243         struct b53_srab_priv *priv = dev->priv;
244         u8 __iomem *regs = priv->regs;
245         int ret = 0;
246
247         ret = b53_srab_request_grant(dev);
248         if (ret)
249                 goto err;
250
251         writel(value, regs + B53_SRAB_WD_L);
252
253         ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
254
255 err:
256         b53_srab_release_grant(dev);
257
258         return ret;
259 }
260
261 static int b53_srab_write16(struct b53_device *dev, u8 page, u8 reg,
262                             u16 value)
263 {
264         struct b53_srab_priv *priv = dev->priv;
265         u8 __iomem *regs = priv->regs;
266         int ret = 0;
267
268         ret = b53_srab_request_grant(dev);
269         if (ret)
270                 goto err;
271
272         writel(value, regs + B53_SRAB_WD_L);
273
274         ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
275
276 err:
277         b53_srab_release_grant(dev);
278
279         return ret;
280 }
281
282 static int b53_srab_write32(struct b53_device *dev, u8 page, u8 reg,
283                             u32 value)
284 {
285         struct b53_srab_priv *priv = dev->priv;
286         u8 __iomem *regs = priv->regs;
287         int ret = 0;
288
289         ret = b53_srab_request_grant(dev);
290         if (ret)
291                 goto err;
292
293         writel(value, regs + B53_SRAB_WD_L);
294
295         ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
296
297 err:
298         b53_srab_release_grant(dev);
299
300         return ret;
301 }
302
303 static int b53_srab_write48(struct b53_device *dev, u8 page, u8 reg,
304                             u64 value)
305 {
306         struct b53_srab_priv *priv = dev->priv;
307         u8 __iomem *regs = priv->regs;
308         int ret = 0;
309
310         ret = b53_srab_request_grant(dev);
311         if (ret)
312                 goto err;
313
314         writel((u32)value, regs + B53_SRAB_WD_L);
315         writel((u16)(value >> 32), regs + B53_SRAB_WD_H);
316
317         ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
318
319 err:
320         b53_srab_release_grant(dev);
321
322         return ret;
323 }
324
325 static int b53_srab_write64(struct b53_device *dev, u8 page, u8 reg,
326                             u64 value)
327 {
328         struct b53_srab_priv *priv = dev->priv;
329         u8 __iomem *regs = priv->regs;
330         int ret = 0;
331
332         ret = b53_srab_request_grant(dev);
333         if (ret)
334                 goto err;
335
336         writel((u32)value, regs + B53_SRAB_WD_L);
337         writel((u32)(value >> 32), regs + B53_SRAB_WD_H);
338
339         ret = b53_srab_op(dev, page, reg, B53_SRAB_CMDSTAT_WRITE);
340
341 err:
342         b53_srab_release_grant(dev);
343
344         return ret;
345 }
346
347 static const struct b53_io_ops b53_srab_ops = {
348         .read8 = b53_srab_read8,
349         .read16 = b53_srab_read16,
350         .read32 = b53_srab_read32,
351         .read48 = b53_srab_read48,
352         .read64 = b53_srab_read64,
353         .write8 = b53_srab_write8,
354         .write16 = b53_srab_write16,
355         .write32 = b53_srab_write32,
356         .write48 = b53_srab_write48,
357         .write64 = b53_srab_write64,
358 };
359
360 static const struct of_device_id b53_srab_of_match[] = {
361         { .compatible = "brcm,bcm53010-srab" },
362         { .compatible = "brcm,bcm53011-srab" },
363         { .compatible = "brcm,bcm53012-srab" },
364         { .compatible = "brcm,bcm53018-srab" },
365         { .compatible = "brcm,bcm53019-srab" },
366         { .compatible = "brcm,bcm5301x-srab" },
367         { .compatible = "brcm,bcm11360-srab", .data = (void *)BCM583XX_DEVICE_ID },
368         { .compatible = "brcm,bcm58522-srab", .data = (void *)BCM58XX_DEVICE_ID },
369         { .compatible = "brcm,bcm58525-srab", .data = (void *)BCM58XX_DEVICE_ID },
370         { .compatible = "brcm,bcm58535-srab", .data = (void *)BCM58XX_DEVICE_ID },
371         { .compatible = "brcm,bcm58622-srab", .data = (void *)BCM58XX_DEVICE_ID },
372         { .compatible = "brcm,bcm58623-srab", .data = (void *)BCM58XX_DEVICE_ID },
373         { .compatible = "brcm,bcm58625-srab", .data = (void *)BCM58XX_DEVICE_ID },
374         { .compatible = "brcm,bcm88312-srab", .data = (void *)BCM58XX_DEVICE_ID },
375         { .compatible = "brcm,cygnus-srab", .data = (void *)BCM583XX_DEVICE_ID },
376         { .compatible = "brcm,nsp-srab", .data = (void *)BCM58XX_DEVICE_ID },
377         { .compatible = "brcm,omega-srab", .data = (void *)BCM583XX_DEVICE_ID },
378         { /* sentinel */ },
379 };
380 MODULE_DEVICE_TABLE(of, b53_srab_of_match);
381
382 static int b53_srab_probe(struct platform_device *pdev)
383 {
384         struct b53_platform_data *pdata = pdev->dev.platform_data;
385         struct device_node *dn = pdev->dev.of_node;
386         const struct of_device_id *of_id = NULL;
387         struct b53_srab_priv *priv;
388         struct b53_device *dev;
389         struct resource *r;
390
391         if (dn)
392                 of_id = of_match_node(b53_srab_of_match, dn);
393
394         if (of_id) {
395                 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
396                 if (!pdata)
397                         return -ENOMEM;
398
399                 pdata->chip_id = (u32)(unsigned long)of_id->data;
400         }
401
402         priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
403         if (!priv)
404                 return -ENOMEM;
405
406         r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
407         priv->regs = devm_ioremap_resource(&pdev->dev, r);
408         if (IS_ERR(priv->regs))
409                 return -ENOMEM;
410
411         dev = b53_switch_alloc(&pdev->dev, &b53_srab_ops, priv);
412         if (!dev)
413                 return -ENOMEM;
414
415         if (pdata)
416                 dev->pdata = pdata;
417
418         platform_set_drvdata(pdev, dev);
419
420         return b53_switch_register(dev);
421 }
422
423 static int b53_srab_remove(struct platform_device *pdev)
424 {
425         struct b53_device *dev = platform_get_drvdata(pdev);
426
427         if (dev)
428                 b53_switch_remove(dev);
429
430         return 0;
431 }
432
433 static struct platform_driver b53_srab_driver = {
434         .probe = b53_srab_probe,
435         .remove = b53_srab_remove,
436         .driver = {
437                 .name = "b53-srab-switch",
438                 .of_match_table = b53_srab_of_match,
439         },
440 };
441
442 module_platform_driver(b53_srab_driver);
443 MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
444 MODULE_DESCRIPTION("B53 Switch Register Access Bridge Registers (SRAB) access driver");
445 MODULE_LICENSE("Dual BSD/GPL");