blob: f115ee25c0e83716bb43d6d7b46c51fd1b86ec13 [file] [log] [blame]
Florian Fainelli967dd822016-06-09 18:23:53 -07001/*
2 * B53 register access through memory mapped registers
3 *
4 * Copyright (C) 2012-2013 Jonas Gorski <jogo@openwrt.org>
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/kconfig.h>
21#include <linux/module.h>
22#include <linux/io.h>
23#include <linux/platform_device.h>
24#include <linux/platform_data/b53.h>
25
26#include "b53_priv.h"
27
28struct b53_mmap_priv {
29 void __iomem *regs;
30};
31
32static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
33{
34 u8 __iomem *regs = dev->priv;
35
36 *val = readb(regs + (page << 8) + reg);
37
38 return 0;
39}
40
41static int b53_mmap_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
42{
43 u8 __iomem *regs = dev->priv;
44
45 if (WARN_ON(reg % 2))
46 return -EINVAL;
47
48 if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && dev->pdata &&
49 dev->pdata->big_endian)
50 *val = __raw_readw(regs + (page << 8) + reg);
51 else
52 *val = readw(regs + (page << 8) + reg);
53
54 return 0;
55}
56
57static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
58{
59 u8 __iomem *regs = dev->priv;
60
61 if (WARN_ON(reg % 4))
62 return -EINVAL;
63
64 if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && dev->pdata &&
65 dev->pdata->big_endian)
66 *val = __raw_readl(regs + (page << 8) + reg);
67 else
68 *val = readl(regs + (page << 8) + reg);
69
70 return 0;
71}
72
73static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
74{
75 if (WARN_ON(reg % 2))
76 return -EINVAL;
77
78 if (reg % 4) {
79 u16 lo;
80 u32 hi;
81
82 b53_mmap_read16(dev, page, reg, &lo);
83 b53_mmap_read32(dev, page, reg + 2, &hi);
84
85 *val = ((u64)hi << 16) | lo;
86 } else {
87 u32 lo;
88 u16 hi;
89
90 b53_mmap_read32(dev, page, reg, &lo);
91 b53_mmap_read16(dev, page, reg + 4, &hi);
92
93 *val = ((u64)hi << 32) | lo;
94 }
95
96 return 0;
97}
98
99static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
100{
101 u32 hi, lo;
102
103 if (WARN_ON(reg % 4))
104 return -EINVAL;
105
106 b53_mmap_read32(dev, page, reg, &lo);
107 b53_mmap_read32(dev, page, reg + 4, &hi);
108
109 *val = ((u64)hi << 32) | lo;
110
111 return 0;
112}
113
114static int b53_mmap_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
115{
116 u8 __iomem *regs = dev->priv;
117
118 writeb(value, regs + (page << 8) + reg);
119
120 return 0;
121}
122
123static int b53_mmap_write16(struct b53_device *dev, u8 page, u8 reg,
124 u16 value)
125{
126 u8 __iomem *regs = dev->priv;
127
128 if (WARN_ON(reg % 2))
129 return -EINVAL;
130
131 if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && dev->pdata &&
132 dev->pdata->big_endian)
133 __raw_writew(value, regs + (page << 8) + reg);
134 else
135 writew(value, regs + (page << 8) + reg);
136
137 return 0;
138}
139
140static int b53_mmap_write32(struct b53_device *dev, u8 page, u8 reg,
141 u32 value)
142{
143 u8 __iomem *regs = dev->priv;
144
145 if (WARN_ON(reg % 4))
146 return -EINVAL;
147
148 if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && dev->pdata &&
149 dev->pdata->big_endian)
150 __raw_writel(value, regs + (page << 8) + reg);
151 else
152 writel(value, regs + (page << 8) + reg);
153
154 return 0;
155}
156
157static int b53_mmap_write48(struct b53_device *dev, u8 page, u8 reg,
158 u64 value)
159{
160 if (WARN_ON(reg % 2))
161 return -EINVAL;
162
163 if (reg % 4) {
164 u32 hi = (u32)(value >> 16);
165 u16 lo = (u16)value;
166
167 b53_mmap_write16(dev, page, reg, lo);
168 b53_mmap_write32(dev, page, reg + 2, hi);
169 } else {
170 u16 hi = (u16)(value >> 32);
171 u32 lo = (u32)value;
172
173 b53_mmap_write32(dev, page, reg, lo);
174 b53_mmap_write16(dev, page, reg + 4, hi);
175 }
176
177 return 0;
178}
179
180static int b53_mmap_write64(struct b53_device *dev, u8 page, u8 reg,
181 u64 value)
182{
183 u32 hi, lo;
184
185 hi = upper_32_bits(value);
186 lo = lower_32_bits(value);
187
188 if (WARN_ON(reg % 4))
189 return -EINVAL;
190
191 b53_mmap_write32(dev, page, reg, lo);
192 b53_mmap_write32(dev, page, reg + 4, hi);
193
194 return 0;
195}
196
197static struct b53_io_ops b53_mmap_ops = {
198 .read8 = b53_mmap_read8,
199 .read16 = b53_mmap_read16,
200 .read32 = b53_mmap_read32,
201 .read48 = b53_mmap_read48,
202 .read64 = b53_mmap_read64,
203 .write8 = b53_mmap_write8,
204 .write16 = b53_mmap_write16,
205 .write32 = b53_mmap_write32,
206 .write48 = b53_mmap_write48,
207 .write64 = b53_mmap_write64,
208};
209
210static int b53_mmap_probe(struct platform_device *pdev)
211{
212 struct b53_platform_data *pdata = pdev->dev.platform_data;
213 struct b53_device *dev;
214
215 if (!pdata)
216 return -EINVAL;
217
218 dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, pdata->regs);
219 if (!dev)
220 return -ENOMEM;
221
222 if (pdata)
223 dev->pdata = pdata;
224
225 platform_set_drvdata(pdev, dev);
226
227 return b53_switch_register(dev);
228}
229
230static int b53_mmap_remove(struct platform_device *pdev)
231{
232 struct b53_device *dev = platform_get_drvdata(pdev);
233
234 if (dev)
235 b53_switch_remove(dev);
236
237 return 0;
238}
239
240static const struct of_device_id b53_mmap_of_table[] = {
241 { .compatible = "brcm,bcm3384-switch" },
242 { .compatible = "brcm,bcm6328-switch" },
243 { .compatible = "brcm,bcm6368-switch" },
244 { .compatible = "brcm,bcm63xx-switch" },
245 { /* sentinel */ },
246};
247
248static struct platform_driver b53_mmap_driver = {
249 .probe = b53_mmap_probe,
250 .remove = b53_mmap_remove,
251 .driver = {
252 .name = "b53-switch",
253 .of_match_table = b53_mmap_of_table,
254 },
255};
256
257module_platform_driver(b53_mmap_driver);
258MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
259MODULE_DESCRIPTION("B53 MMAP access driver");
260MODULE_LICENSE("Dual BSD/GPL");