xref: /linux/drivers/net/dsa/b53/b53_mmap.c (revision cd2a9e62c8a3c5cae7691982667d79a0edc65283)
1 /*
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 
28 struct b53_mmap_priv {
29 	void __iomem *regs;
30 };
31 
32 static 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 
41 static 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 
57 static 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 
73 static 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 
99 static 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 
114 static 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 
123 static 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 
140 static 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 
157 static 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 
180 static 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 
197 static 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 
210 static 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 
230 static 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 
240 static 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 
248 static 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 
257 module_platform_driver(b53_mmap_driver);
258 MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
259 MODULE_DESCRIPTION("B53 MMAP access driver");
260 MODULE_LICENSE("Dual BSD/GPL");
261