1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * B53 register access through memory mapped registers
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2012-2013 Jonas Gorski <jogo@openwrt.org>
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Permission to use, copy, modify, and/or distribute this software for any
7*4882a593Smuzhiyun * purpose with or without fee is hereby granted, provided that the above
8*4882a593Smuzhiyun * copyright notice and this permission notice appear in all copies.
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*4882a593Smuzhiyun * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*4882a593Smuzhiyun * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*4882a593Smuzhiyun * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*4882a593Smuzhiyun * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15*4882a593Smuzhiyun * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16*4882a593Smuzhiyun * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*4882a593Smuzhiyun */
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #include <linux/kernel.h>
20*4882a593Smuzhiyun #include <linux/module.h>
21*4882a593Smuzhiyun #include <linux/io.h>
22*4882a593Smuzhiyun #include <linux/platform_device.h>
23*4882a593Smuzhiyun #include <linux/platform_data/b53.h>
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #include "b53_priv.h"
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun struct b53_mmap_priv {
28*4882a593Smuzhiyun void __iomem *regs;
29*4882a593Smuzhiyun };
30*4882a593Smuzhiyun
b53_mmap_read8(struct b53_device * dev,u8 page,u8 reg,u8 * val)31*4882a593Smuzhiyun static int b53_mmap_read8(struct b53_device *dev, u8 page, u8 reg, u8 *val)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun struct b53_mmap_priv *priv = dev->priv;
34*4882a593Smuzhiyun void __iomem *regs = priv->regs;
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun *val = readb(regs + (page << 8) + reg);
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun return 0;
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun
b53_mmap_read16(struct b53_device * dev,u8 page,u8 reg,u16 * val)41*4882a593Smuzhiyun static int b53_mmap_read16(struct b53_device *dev, u8 page, u8 reg, u16 *val)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun struct b53_mmap_priv *priv = dev->priv;
44*4882a593Smuzhiyun void __iomem *regs = priv->regs;
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun if (WARN_ON(reg % 2))
47*4882a593Smuzhiyun return -EINVAL;
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun if (dev->pdata && dev->pdata->big_endian)
50*4882a593Smuzhiyun *val = ioread16be(regs + (page << 8) + reg);
51*4882a593Smuzhiyun else
52*4882a593Smuzhiyun *val = readw(regs + (page << 8) + reg);
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun return 0;
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun
b53_mmap_read32(struct b53_device * dev,u8 page,u8 reg,u32 * val)57*4882a593Smuzhiyun static int b53_mmap_read32(struct b53_device *dev, u8 page, u8 reg, u32 *val)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun struct b53_mmap_priv *priv = dev->priv;
60*4882a593Smuzhiyun void __iomem *regs = priv->regs;
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun if (WARN_ON(reg % 4))
63*4882a593Smuzhiyun return -EINVAL;
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun if (dev->pdata && dev->pdata->big_endian)
66*4882a593Smuzhiyun *val = ioread32be(regs + (page << 8) + reg);
67*4882a593Smuzhiyun else
68*4882a593Smuzhiyun *val = readl(regs + (page << 8) + reg);
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun return 0;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun
b53_mmap_read48(struct b53_device * dev,u8 page,u8 reg,u64 * val)73*4882a593Smuzhiyun static int b53_mmap_read48(struct b53_device *dev, u8 page, u8 reg, u64 *val)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun struct b53_mmap_priv *priv = dev->priv;
76*4882a593Smuzhiyun void __iomem *regs = priv->regs;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun if (WARN_ON(reg % 2))
79*4882a593Smuzhiyun return -EINVAL;
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun if (reg % 4) {
82*4882a593Smuzhiyun u16 lo;
83*4882a593Smuzhiyun u32 hi;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun if (dev->pdata && dev->pdata->big_endian) {
86*4882a593Smuzhiyun lo = ioread16be(regs + (page << 8) + reg);
87*4882a593Smuzhiyun hi = ioread32be(regs + (page << 8) + reg + 2);
88*4882a593Smuzhiyun } else {
89*4882a593Smuzhiyun lo = readw(regs + (page << 8) + reg);
90*4882a593Smuzhiyun hi = readl(regs + (page << 8) + reg + 2);
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun *val = ((u64)hi << 16) | lo;
94*4882a593Smuzhiyun } else {
95*4882a593Smuzhiyun u32 lo;
96*4882a593Smuzhiyun u16 hi;
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun if (dev->pdata && dev->pdata->big_endian) {
99*4882a593Smuzhiyun lo = ioread32be(regs + (page << 8) + reg);
100*4882a593Smuzhiyun hi = ioread16be(regs + (page << 8) + reg + 4);
101*4882a593Smuzhiyun } else {
102*4882a593Smuzhiyun lo = readl(regs + (page << 8) + reg);
103*4882a593Smuzhiyun hi = readw(regs + (page << 8) + reg + 4);
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun *val = ((u64)hi << 32) | lo;
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun return 0;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun
b53_mmap_read64(struct b53_device * dev,u8 page,u8 reg,u64 * val)112*4882a593Smuzhiyun static int b53_mmap_read64(struct b53_device *dev, u8 page, u8 reg, u64 *val)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun struct b53_mmap_priv *priv = dev->priv;
115*4882a593Smuzhiyun void __iomem *regs = priv->regs;
116*4882a593Smuzhiyun u32 hi, lo;
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun if (WARN_ON(reg % 4))
119*4882a593Smuzhiyun return -EINVAL;
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun if (dev->pdata && dev->pdata->big_endian) {
122*4882a593Smuzhiyun lo = ioread32be(regs + (page << 8) + reg);
123*4882a593Smuzhiyun hi = ioread32be(regs + (page << 8) + reg + 4);
124*4882a593Smuzhiyun } else {
125*4882a593Smuzhiyun lo = readl(regs + (page << 8) + reg);
126*4882a593Smuzhiyun hi = readl(regs + (page << 8) + reg + 4);
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun *val = ((u64)hi << 32) | lo;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun return 0;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
b53_mmap_write8(struct b53_device * dev,u8 page,u8 reg,u8 value)134*4882a593Smuzhiyun static int b53_mmap_write8(struct b53_device *dev, u8 page, u8 reg, u8 value)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun struct b53_mmap_priv *priv = dev->priv;
137*4882a593Smuzhiyun void __iomem *regs = priv->regs;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun writeb(value, regs + (page << 8) + reg);
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun return 0;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
b53_mmap_write16(struct b53_device * dev,u8 page,u8 reg,u16 value)144*4882a593Smuzhiyun static int b53_mmap_write16(struct b53_device *dev, u8 page, u8 reg,
145*4882a593Smuzhiyun u16 value)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun struct b53_mmap_priv *priv = dev->priv;
148*4882a593Smuzhiyun void __iomem *regs = priv->regs;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun if (WARN_ON(reg % 2))
151*4882a593Smuzhiyun return -EINVAL;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun if (dev->pdata && dev->pdata->big_endian)
154*4882a593Smuzhiyun iowrite16be(value, regs + (page << 8) + reg);
155*4882a593Smuzhiyun else
156*4882a593Smuzhiyun writew(value, regs + (page << 8) + reg);
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun return 0;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
b53_mmap_write32(struct b53_device * dev,u8 page,u8 reg,u32 value)161*4882a593Smuzhiyun static int b53_mmap_write32(struct b53_device *dev, u8 page, u8 reg,
162*4882a593Smuzhiyun u32 value)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun struct b53_mmap_priv *priv = dev->priv;
165*4882a593Smuzhiyun void __iomem *regs = priv->regs;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun if (WARN_ON(reg % 4))
168*4882a593Smuzhiyun return -EINVAL;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun if (dev->pdata && dev->pdata->big_endian)
171*4882a593Smuzhiyun iowrite32be(value, regs + (page << 8) + reg);
172*4882a593Smuzhiyun else
173*4882a593Smuzhiyun writel(value, regs + (page << 8) + reg);
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun return 0;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun
b53_mmap_write48(struct b53_device * dev,u8 page,u8 reg,u64 value)178*4882a593Smuzhiyun static int b53_mmap_write48(struct b53_device *dev, u8 page, u8 reg,
179*4882a593Smuzhiyun u64 value)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun if (WARN_ON(reg % 2))
182*4882a593Smuzhiyun return -EINVAL;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun if (reg % 4) {
185*4882a593Smuzhiyun u32 hi = (u32)(value >> 16);
186*4882a593Smuzhiyun u16 lo = (u16)value;
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun b53_mmap_write16(dev, page, reg, lo);
189*4882a593Smuzhiyun b53_mmap_write32(dev, page, reg + 2, hi);
190*4882a593Smuzhiyun } else {
191*4882a593Smuzhiyun u16 hi = (u16)(value >> 32);
192*4882a593Smuzhiyun u32 lo = (u32)value;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun b53_mmap_write32(dev, page, reg, lo);
195*4882a593Smuzhiyun b53_mmap_write16(dev, page, reg + 4, hi);
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun return 0;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun
b53_mmap_write64(struct b53_device * dev,u8 page,u8 reg,u64 value)201*4882a593Smuzhiyun static int b53_mmap_write64(struct b53_device *dev, u8 page, u8 reg,
202*4882a593Smuzhiyun u64 value)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun u32 hi, lo;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun hi = upper_32_bits(value);
207*4882a593Smuzhiyun lo = lower_32_bits(value);
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun if (WARN_ON(reg % 4))
210*4882a593Smuzhiyun return -EINVAL;
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun b53_mmap_write32(dev, page, reg, lo);
213*4882a593Smuzhiyun b53_mmap_write32(dev, page, reg + 4, hi);
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun return 0;
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun static const struct b53_io_ops b53_mmap_ops = {
219*4882a593Smuzhiyun .read8 = b53_mmap_read8,
220*4882a593Smuzhiyun .read16 = b53_mmap_read16,
221*4882a593Smuzhiyun .read32 = b53_mmap_read32,
222*4882a593Smuzhiyun .read48 = b53_mmap_read48,
223*4882a593Smuzhiyun .read64 = b53_mmap_read64,
224*4882a593Smuzhiyun .write8 = b53_mmap_write8,
225*4882a593Smuzhiyun .write16 = b53_mmap_write16,
226*4882a593Smuzhiyun .write32 = b53_mmap_write32,
227*4882a593Smuzhiyun .write48 = b53_mmap_write48,
228*4882a593Smuzhiyun .write64 = b53_mmap_write64,
229*4882a593Smuzhiyun };
230*4882a593Smuzhiyun
b53_mmap_probe(struct platform_device * pdev)231*4882a593Smuzhiyun static int b53_mmap_probe(struct platform_device *pdev)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun struct b53_platform_data *pdata = pdev->dev.platform_data;
234*4882a593Smuzhiyun struct b53_mmap_priv *priv;
235*4882a593Smuzhiyun struct b53_device *dev;
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun if (!pdata)
238*4882a593Smuzhiyun return -EINVAL;
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
241*4882a593Smuzhiyun if (!priv)
242*4882a593Smuzhiyun return -ENOMEM;
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun priv->regs = pdata->regs;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun dev = b53_switch_alloc(&pdev->dev, &b53_mmap_ops, priv);
247*4882a593Smuzhiyun if (!dev)
248*4882a593Smuzhiyun return -ENOMEM;
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun dev->pdata = pdata;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun platform_set_drvdata(pdev, dev);
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun return b53_switch_register(dev);
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun
b53_mmap_remove(struct platform_device * pdev)257*4882a593Smuzhiyun static int b53_mmap_remove(struct platform_device *pdev)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun struct b53_device *dev = platform_get_drvdata(pdev);
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun if (dev)
262*4882a593Smuzhiyun b53_switch_remove(dev);
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun return 0;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun static const struct of_device_id b53_mmap_of_table[] = {
268*4882a593Smuzhiyun { .compatible = "brcm,bcm3384-switch" },
269*4882a593Smuzhiyun { .compatible = "brcm,bcm6328-switch" },
270*4882a593Smuzhiyun { .compatible = "brcm,bcm6368-switch" },
271*4882a593Smuzhiyun { .compatible = "brcm,bcm63xx-switch" },
272*4882a593Smuzhiyun { /* sentinel */ },
273*4882a593Smuzhiyun };
274*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, b53_mmap_of_table);
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun static struct platform_driver b53_mmap_driver = {
277*4882a593Smuzhiyun .probe = b53_mmap_probe,
278*4882a593Smuzhiyun .remove = b53_mmap_remove,
279*4882a593Smuzhiyun .driver = {
280*4882a593Smuzhiyun .name = "b53-switch",
281*4882a593Smuzhiyun .of_match_table = b53_mmap_of_table,
282*4882a593Smuzhiyun },
283*4882a593Smuzhiyun };
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun module_platform_driver(b53_mmap_driver);
286*4882a593Smuzhiyun MODULE_AUTHOR("Jonas Gorski <jogo@openwrt.org>");
287*4882a593Smuzhiyun MODULE_DESCRIPTION("B53 MMAP access driver");
288*4882a593Smuzhiyun MODULE_LICENSE("Dual BSD/GPL");
289