xref: /linux/drivers/net/dsa/b53/b53_srab.c (revision cd2a9e62c8a3c5cae7691982667d79a0edc65283)
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 
62 struct b53_srab_priv {
63 	void __iomem *regs;
64 };
65 
66 static 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 
89 static 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 
100 static 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 
128 static 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 
144 err:
145 	b53_srab_release_grant(dev);
146 
147 	return ret;
148 }
149 
150 static 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 
166 err:
167 	b53_srab_release_grant(dev);
168 
169 	return ret;
170 }
171 
172 static 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 
188 err:
189 	b53_srab_release_grant(dev);
190 
191 	return ret;
192 }
193 
194 static 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 
211 err:
212 	b53_srab_release_grant(dev);
213 
214 	return ret;
215 }
216 
217 static 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 
234 err:
235 	b53_srab_release_grant(dev);
236 
237 	return ret;
238 }
239 
240 static 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 
254 err:
255 	b53_srab_release_grant(dev);
256 
257 	return ret;
258 }
259 
260 static 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 
275 err:
276 	b53_srab_release_grant(dev);
277 
278 	return ret;
279 }
280 
281 static 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 
296 err:
297 	b53_srab_release_grant(dev);
298 
299 	return ret;
300 }
301 
302 static 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 
318 err:
319 	b53_srab_release_grant(dev);
320 
321 	return ret;
322 }
323 
324 static 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 
340 err:
341 	b53_srab_release_grant(dev);
342 
343 	return ret;
344 }
345 
346 static 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 
359 static 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 
383 static 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 
393 static 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 
403 static 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 
412 module_platform_driver(b53_srab_driver);
413 MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
414 MODULE_DESCRIPTION("B53 Switch Register Access Bridge Registers (SRAB) access driver");
415 MODULE_LICENSE("Dual BSD/GPL");
416