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" |
10 | #include <linux/slab.h> |
11 | #include <linux/module.h> |
12 | #include <linux/of_address.h> |
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(addr: core->io_addr + offset); |
19 | } |
20 | |
21 | static u16 bcma_host_soc_read16(struct bcma_device *core, u16 offset) |
22 | { |
23 | return readw(addr: core->io_addr + offset); |
24 | } |
25 | |
26 | static u32 bcma_host_soc_read32(struct bcma_device *core, u16 offset) |
27 | { |
28 | return readl(addr: 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(val: value, addr: 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(val: value, addr: 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(val: value, addr: 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(val: *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(val: (__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(val: (__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 | { |
140 | if (WARN_ONCE(!core->io_wrap, "Accessed core has no wrapper/agent\n" )) |
141 | return ~0; |
142 | return readl(addr: core->io_wrap + offset); |
143 | } |
144 | |
145 | static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset, |
146 | u32 value) |
147 | { |
148 | if (WARN_ONCE(!core->io_wrap, "Accessed core has no wrapper/agent\n" )) |
149 | return; |
150 | writel(val: value, addr: core->io_wrap + offset); |
151 | } |
152 | |
153 | static const struct bcma_host_ops bcma_host_soc_ops = { |
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; |
171 | |
172 | /* iomap only first core. We have to read some register on this core |
173 | * to scan the bus. |
174 | */ |
175 | bus->mmio = ioremap(BCMA_ADDR_BASE, BCMA_CORE_SIZE * 1); |
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 | |
183 | /* Initialize struct, detect chip */ |
184 | bcma_init_bus(bus); |
185 | |
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 */ |
195 | err = bcma_bus_early_register(bus); |
196 | if (err) |
197 | iounmap(addr: bus->mmio); |
198 | |
199 | return err; |
200 | } |
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, size: sizeof(*bus), GFP_KERNEL); |
212 | if (!bus) |
213 | return -ENOMEM; |
214 | |
215 | bus->dev = dev; |
216 | |
217 | /* Map MMIO */ |
218 | bus->mmio = of_iomap(node: np, index: 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; |
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, data: bus); |
235 | |
236 | return err; |
237 | |
238 | err_unmap_mmio: |
239 | iounmap(addr: 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(addr: 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 */ |
279 | |