Commit | Line | Data |
---|---|---|
ecd177c2 HM |
1 | /* |
2 | * Broadcom specific AMBA | |
3 | * System on Chip (SoC) Host | |
4 | * | |
5 | * Licensed under the GNU/GPL. See COPYING for details. | |
6 | */ | |
7 | ||
8 | #include "bcma_private.h" | |
9 | #include "scan.h" | |
2101e533 HM |
10 | #include <linux/slab.h> |
11 | #include <linux/module.h> | |
12 | #include <linux/of_address.h> | |
ecd177c2 HM |
13 | #include <linux/bcma/bcma.h> |
14 | #include <linux/bcma/bcma_soc.h> | |
15 | ||
16 | static u8 bcma_host_soc_read8(struct bcma_device *core, u16 offset) | |
17 | { | |
18 | return readb(core->io_addr + offset); | |
19 | } | |
20 | ||
21 | static u16 bcma_host_soc_read16(struct bcma_device *core, u16 offset) | |
22 | { | |
23 | return readw(core->io_addr + offset); | |
24 | } | |
25 | ||
26 | static u32 bcma_host_soc_read32(struct bcma_device *core, u16 offset) | |
27 | { | |
28 | return readl(core->io_addr + offset); | |
29 | } | |
30 | ||
31 | static void bcma_host_soc_write8(struct bcma_device *core, u16 offset, | |
32 | u8 value) | |
33 | { | |
34 | writeb(value, core->io_addr + offset); | |
35 | } | |
36 | ||
37 | static void bcma_host_soc_write16(struct bcma_device *core, u16 offset, | |
38 | u16 value) | |
39 | { | |
40 | writew(value, core->io_addr + offset); | |
41 | } | |
42 | ||
43 | static void bcma_host_soc_write32(struct bcma_device *core, u16 offset, | |
44 | u32 value) | |
45 | { | |
46 | writel(value, core->io_addr + offset); | |
47 | } | |
48 | ||
49 | #ifdef CONFIG_BCMA_BLOCKIO | |
50 | static void bcma_host_soc_block_read(struct bcma_device *core, void *buffer, | |
51 | size_t count, u16 offset, u8 reg_width) | |
52 | { | |
53 | void __iomem *addr = core->io_addr + offset; | |
54 | ||
55 | switch (reg_width) { | |
56 | case sizeof(u8): { | |
57 | u8 *buf = buffer; | |
58 | ||
59 | while (count) { | |
60 | *buf = __raw_readb(addr); | |
61 | buf++; | |
62 | count--; | |
63 | } | |
64 | break; | |
65 | } | |
66 | case sizeof(u16): { | |
67 | __le16 *buf = buffer; | |
68 | ||
69 | WARN_ON(count & 1); | |
70 | while (count) { | |
71 | *buf = (__force __le16)__raw_readw(addr); | |
72 | buf++; | |
73 | count -= 2; | |
74 | } | |
75 | break; | |
76 | } | |
77 | case sizeof(u32): { | |
78 | __le32 *buf = buffer; | |
79 | ||
80 | WARN_ON(count & 3); | |
81 | while (count) { | |
82 | *buf = (__force __le32)__raw_readl(addr); | |
83 | buf++; | |
84 | count -= 4; | |
85 | } | |
86 | break; | |
87 | } | |
88 | default: | |
89 | WARN_ON(1); | |
90 | } | |
91 | } | |
92 | ||
93 | static void bcma_host_soc_block_write(struct bcma_device *core, | |
94 | const void *buffer, | |
95 | size_t count, u16 offset, u8 reg_width) | |
96 | { | |
97 | void __iomem *addr = core->io_addr + offset; | |
98 | ||
99 | switch (reg_width) { | |
100 | case sizeof(u8): { | |
101 | const u8 *buf = buffer; | |
102 | ||
103 | while (count) { | |
104 | __raw_writeb(*buf, addr); | |
105 | buf++; | |
106 | count--; | |
107 | } | |
108 | break; | |
109 | } | |
110 | case sizeof(u16): { | |
111 | const __le16 *buf = buffer; | |
112 | ||
113 | WARN_ON(count & 1); | |
114 | while (count) { | |
115 | __raw_writew((__force u16)(*buf), addr); | |
116 | buf++; | |
117 | count -= 2; | |
118 | } | |
119 | break; | |
120 | } | |
121 | case sizeof(u32): { | |
122 | const __le32 *buf = buffer; | |
123 | ||
124 | WARN_ON(count & 3); | |
125 | while (count) { | |
126 | __raw_writel((__force u32)(*buf), addr); | |
127 | buf++; | |
128 | count -= 4; | |
129 | } | |
130 | break; | |
131 | } | |
132 | default: | |
133 | WARN_ON(1); | |
134 | } | |
135 | } | |
136 | #endif /* CONFIG_BCMA_BLOCKIO */ | |
137 | ||
138 | static u32 bcma_host_soc_aread32(struct bcma_device *core, u16 offset) | |
139 | { | |
ecf47e9b HM |
140 | if (WARN_ONCE(!core->io_wrap, "Accessed core has no wrapper/agent\n")) |
141 | return ~0; | |
ecd177c2 HM |
142 | return readl(core->io_wrap + offset); |
143 | } | |
144 | ||
145 | static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset, | |
146 | u32 value) | |
147 | { | |
ecf47e9b HM |
148 | if (WARN_ONCE(!core->io_wrap, "Accessed core has no wrapper/agent\n")) |
149 | return; | |
ecd177c2 HM |
150 | writel(value, core->io_wrap + offset); |
151 | } | |
152 | ||
94f3457f | 153 | static const struct bcma_host_ops bcma_host_soc_ops = { |
ecd177c2 HM |
154 | .read8 = bcma_host_soc_read8, |
155 | .read16 = bcma_host_soc_read16, | |
156 | .read32 = bcma_host_soc_read32, | |
157 | .write8 = bcma_host_soc_write8, | |
158 | .write16 = bcma_host_soc_write16, | |
159 | .write32 = bcma_host_soc_write32, | |
160 | #ifdef CONFIG_BCMA_BLOCKIO | |
161 | .block_read = bcma_host_soc_block_read, | |
162 | .block_write = bcma_host_soc_block_write, | |
163 | #endif | |
164 | .aread32 = bcma_host_soc_aread32, | |
165 | .awrite32 = bcma_host_soc_awrite32, | |
166 | }; | |
167 | ||
168 | int __init bcma_host_soc_register(struct bcma_soc *soc) | |
169 | { | |
170 | struct bcma_bus *bus = &soc->bus; | |
ecd177c2 HM |
171 | |
172 | /* iomap only first core. We have to read some register on this core | |
173 | * to scan the bus. | |
174 | */ | |
4bdc0d67 | 175 | bus->mmio = ioremap(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1); |
ecd177c2 HM |
176 | if (!bus->mmio) |
177 | return -ENOMEM; | |
178 | ||
179 | /* Host specific */ | |
180 | bus->hosttype = BCMA_HOSTTYPE_SOC; | |
181 | bus->ops = &bcma_host_soc_ops; | |
182 | ||
dc8ecdd3 RM |
183 | /* Initialize struct, detect chip */ |
184 | bcma_init_bus(bus); | |
185 | ||
a395135d RM |
186 | return 0; |
187 | } | |
188 | ||
189 | int __init bcma_host_soc_init(struct bcma_soc *soc) | |
190 | { | |
191 | struct bcma_bus *bus = &soc->bus; | |
192 | int err; | |
193 | ||
194 | /* Scan bus and initialize it */ | |
c5ed1df7 | 195 | err = bcma_bus_early_register(bus); |
ecd177c2 HM |
196 | if (err) |
197 | iounmap(bus->mmio); | |
198 | ||
199 | return err; | |
200 | } | |
2101e533 HM |
201 | |
202 | #ifdef CONFIG_OF | |
203 | static int bcma_host_soc_probe(struct platform_device *pdev) | |
204 | { | |
205 | struct device *dev = &pdev->dev; | |
206 | struct device_node *np = dev->of_node; | |
207 | struct bcma_bus *bus; | |
208 | int err; | |
209 | ||
210 | /* Alloc */ | |
211 | bus = devm_kzalloc(dev, sizeof(*bus), GFP_KERNEL); | |
212 | if (!bus) | |
213 | return -ENOMEM; | |
214 | ||
5a1c18b7 RM |
215 | bus->dev = dev; |
216 | ||
2101e533 HM |
217 | /* Map MMIO */ |
218 | bus->mmio = of_iomap(np, 0); | |
219 | if (!bus->mmio) | |
220 | return -ENOMEM; | |
221 | ||
222 | /* Host specific */ | |
223 | bus->hosttype = BCMA_HOSTTYPE_SOC; | |
224 | bus->ops = &bcma_host_soc_ops; | |
2101e533 HM |
225 | |
226 | /* Initialize struct, detect chip */ | |
227 | bcma_init_bus(bus); | |
228 | ||
229 | /* Register */ | |
230 | err = bcma_bus_register(bus); | |
231 | if (err) | |
232 | goto err_unmap_mmio; | |
233 | ||
234 | platform_set_drvdata(pdev, bus); | |
235 | ||
236 | return err; | |
237 | ||
238 | err_unmap_mmio: | |
239 | iounmap(bus->mmio); | |
240 | return err; | |
241 | } | |
242 | ||
243 | static int bcma_host_soc_remove(struct platform_device *pdev) | |
244 | { | |
245 | struct bcma_bus *bus = platform_get_drvdata(pdev); | |
246 | ||
247 | bcma_bus_unregister(bus); | |
248 | iounmap(bus->mmio); | |
249 | platform_set_drvdata(pdev, NULL); | |
250 | ||
251 | return 0; | |
252 | } | |
253 | ||
254 | static const struct of_device_id bcma_host_soc_of_match[] = { | |
255 | { .compatible = "brcm,bus-axi", }, | |
256 | {}, | |
257 | }; | |
258 | MODULE_DEVICE_TABLE(of, bcma_host_soc_of_match); | |
259 | ||
260 | static struct platform_driver bcma_host_soc_driver = { | |
261 | .driver = { | |
262 | .name = "bcma-host-soc", | |
263 | .of_match_table = bcma_host_soc_of_match, | |
264 | }, | |
265 | .probe = bcma_host_soc_probe, | |
266 | .remove = bcma_host_soc_remove, | |
267 | }; | |
268 | ||
269 | int __init bcma_host_soc_register_driver(void) | |
270 | { | |
271 | return platform_driver_register(&bcma_host_soc_driver); | |
272 | } | |
273 | ||
274 | void __exit bcma_host_soc_unregister_driver(void) | |
275 | { | |
276 | platform_driver_unregister(&bcma_host_soc_driver); | |
277 | } | |
278 | #endif /* CONFIG_OF */ |