1 | #include <machine/rtems-bsd-kernel-space.h> |
---|
2 | |
---|
3 | #include <rtems/bsd/local/opt_dpaa.h> |
---|
4 | |
---|
5 | /* Copyright (c) 2009 - 2016 Freescale Semiconductor, Inc. |
---|
6 | * |
---|
7 | * Redistribution and use in source and binary forms, with or without |
---|
8 | * modification, are permitted provided that the following conditions are met: |
---|
9 | * * Redistributions of source code must retain the above copyright |
---|
10 | * notice, this list of conditions and the following disclaimer. |
---|
11 | * * Redistributions in binary form must reproduce the above copyright |
---|
12 | * notice, this list of conditions and the following disclaimer in the |
---|
13 | * documentation and/or other materials provided with the distribution. |
---|
14 | * * Neither the name of Freescale Semiconductor nor the |
---|
15 | * names of its contributors may be used to endorse or promote products |
---|
16 | * derived from this software without specific prior written permission. |
---|
17 | * |
---|
18 | * ALTERNATIVELY, this software may be distributed under the terms of the |
---|
19 | * GNU General Public License ("GPL") as published by the Free Software |
---|
20 | * Foundation, either version 2 of that License or (at your option) any |
---|
21 | * later version. |
---|
22 | * |
---|
23 | * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY |
---|
24 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
---|
25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
---|
26 | * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY |
---|
27 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
---|
28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
---|
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
---|
30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
---|
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
---|
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
33 | */ |
---|
34 | |
---|
35 | #include "bman_priv.h" |
---|
36 | |
---|
37 | u16 bman_ip_rev; |
---|
38 | EXPORT_SYMBOL(bman_ip_rev); |
---|
39 | |
---|
40 | /* Register offsets */ |
---|
41 | #define REG_FBPR_FPC 0x0800 |
---|
42 | #define REG_ECSR 0x0a00 |
---|
43 | #define REG_ECIR 0x0a04 |
---|
44 | #define REG_EADR 0x0a08 |
---|
45 | #define REG_EDATA(n) (0x0a10 + ((n) * 0x04)) |
---|
46 | #define REG_SBEC(n) (0x0a80 + ((n) * 0x04)) |
---|
47 | #define REG_IP_REV_1 0x0bf8 |
---|
48 | #define REG_IP_REV_2 0x0bfc |
---|
49 | #define REG_FBPR_BARE 0x0c00 |
---|
50 | #define REG_FBPR_BAR 0x0c04 |
---|
51 | #define REG_FBPR_AR 0x0c10 |
---|
52 | #define REG_SRCIDR 0x0d04 |
---|
53 | #define REG_LIODNR 0x0d08 |
---|
54 | #define REG_ERR_ISR 0x0e00 |
---|
55 | #define REG_ERR_IER 0x0e04 |
---|
56 | #define REG_ERR_ISDR 0x0e08 |
---|
57 | |
---|
58 | /* Used by all error interrupt registers except 'inhibit' */ |
---|
59 | #define BM_EIRQ_IVCI 0x00000010 /* Invalid Command Verb */ |
---|
60 | #define BM_EIRQ_FLWI 0x00000008 /* FBPR Low Watermark */ |
---|
61 | #define BM_EIRQ_MBEI 0x00000004 /* Multi-bit ECC Error */ |
---|
62 | #define BM_EIRQ_SBEI 0x00000002 /* Single-bit ECC Error */ |
---|
63 | #define BM_EIRQ_BSCN 0x00000001 /* pool State Change Notification */ |
---|
64 | |
---|
65 | struct bman_hwerr_txt { |
---|
66 | u32 mask; |
---|
67 | const char *txt; |
---|
68 | }; |
---|
69 | |
---|
70 | static const struct bman_hwerr_txt bman_hwerr_txts[] = { |
---|
71 | { BM_EIRQ_IVCI, "Invalid Command Verb" }, |
---|
72 | { BM_EIRQ_FLWI, "FBPR Low Watermark" }, |
---|
73 | { BM_EIRQ_MBEI, "Multi-bit ECC Error" }, |
---|
74 | { BM_EIRQ_SBEI, "Single-bit ECC Error" }, |
---|
75 | { BM_EIRQ_BSCN, "Pool State Change Notification" }, |
---|
76 | }; |
---|
77 | |
---|
78 | /* Only trigger low water mark interrupt once only */ |
---|
79 | #define BMAN_ERRS_TO_DISABLE BM_EIRQ_FLWI |
---|
80 | |
---|
81 | /* Pointer to the start of the BMan's CCSR space */ |
---|
82 | static u32 __iomem *bm_ccsr_start; |
---|
83 | |
---|
84 | static inline u32 bm_ccsr_in(u32 offset) |
---|
85 | { |
---|
86 | return ioread32be(bm_ccsr_start + offset/4); |
---|
87 | } |
---|
88 | static inline void bm_ccsr_out(u32 offset, u32 val) |
---|
89 | { |
---|
90 | iowrite32be(val, bm_ccsr_start + offset/4); |
---|
91 | } |
---|
92 | |
---|
93 | static void bm_get_version(u16 *id, u8 *major, u8 *minor) |
---|
94 | { |
---|
95 | u32 v = bm_ccsr_in(REG_IP_REV_1); |
---|
96 | *id = (v >> 16); |
---|
97 | *major = (v >> 8) & 0xff; |
---|
98 | *minor = v & 0xff; |
---|
99 | } |
---|
100 | |
---|
101 | /* signal transactions for FBPRs with higher priority */ |
---|
102 | #define FBPR_AR_RPRIO_HI BIT(30) |
---|
103 | |
---|
104 | static void bm_set_memory(u64 ba, u32 size) |
---|
105 | { |
---|
106 | u32 exp = ilog2(size); |
---|
107 | /* choke if size isn't within range */ |
---|
108 | DPAA_ASSERT(size >= 4096 && size <= 1024*1024*1024 && |
---|
109 | is_power_of_2(size)); |
---|
110 | /* choke if '[e]ba' has lower-alignment than 'size' */ |
---|
111 | DPAA_ASSERT(!(ba & (size - 1))); |
---|
112 | bm_ccsr_out(REG_FBPR_BARE, upper_32_bits(ba)); |
---|
113 | bm_ccsr_out(REG_FBPR_BAR, lower_32_bits(ba)); |
---|
114 | bm_ccsr_out(REG_FBPR_AR, exp - 1); |
---|
115 | } |
---|
116 | |
---|
117 | /* |
---|
118 | * Location and size of BMan private memory |
---|
119 | * |
---|
120 | * Ideally we would use the DMA API to turn rmem->base into a DMA address |
---|
121 | * (especially if iommu translations ever get involved). Unfortunately, the |
---|
122 | * DMA API currently does not allow mapping anything that is not backed with |
---|
123 | * a struct page. |
---|
124 | */ |
---|
125 | #ifndef __rtems__ |
---|
126 | static dma_addr_t fbpr_a; |
---|
127 | static size_t fbpr_sz; |
---|
128 | |
---|
129 | static int bman_fbpr(struct reserved_mem *rmem) |
---|
130 | { |
---|
131 | fbpr_a = rmem->base; |
---|
132 | fbpr_sz = rmem->size; |
---|
133 | |
---|
134 | WARN_ON(!(fbpr_a && fbpr_sz)); |
---|
135 | |
---|
136 | return 0; |
---|
137 | } |
---|
138 | RESERVEDMEM_OF_DECLARE(bman_fbpr, "fsl,bman-fbpr", bman_fbpr); |
---|
139 | #else /* __rtems__ */ |
---|
140 | static DPAA_NOCACHENOLOAD_ALIGNED_REGION(fbpr, 16777216); |
---|
141 | #define fbpr_a ((uintptr_t)&fbpr[0]) |
---|
142 | #define fbpr_sz sizeof(fbpr) |
---|
143 | #endif /* __rtems__ */ |
---|
144 | |
---|
145 | static irqreturn_t bman_isr(int irq, void *ptr) |
---|
146 | { |
---|
147 | u32 isr_val, ier_val, ecsr_val, isr_mask, i; |
---|
148 | struct device *dev = ptr; |
---|
149 | |
---|
150 | ier_val = bm_ccsr_in(REG_ERR_IER); |
---|
151 | isr_val = bm_ccsr_in(REG_ERR_ISR); |
---|
152 | ecsr_val = bm_ccsr_in(REG_ECSR); |
---|
153 | isr_mask = isr_val & ier_val; |
---|
154 | |
---|
155 | if (!isr_mask) |
---|
156 | return IRQ_NONE; |
---|
157 | |
---|
158 | for (i = 0; i < ARRAY_SIZE(bman_hwerr_txts); i++) { |
---|
159 | if (bman_hwerr_txts[i].mask & isr_mask) { |
---|
160 | #ifndef __rtems__ |
---|
161 | dev_err_ratelimited(dev, "ErrInt: %s\n", |
---|
162 | bman_hwerr_txts[i].txt); |
---|
163 | #endif /* __rtems__ */ |
---|
164 | if (bman_hwerr_txts[i].mask & ecsr_val) { |
---|
165 | /* Re-arm error capture registers */ |
---|
166 | bm_ccsr_out(REG_ECSR, ecsr_val); |
---|
167 | } |
---|
168 | if (bman_hwerr_txts[i].mask & BMAN_ERRS_TO_DISABLE) { |
---|
169 | dev_dbg(dev, "Disabling error 0x%x\n", |
---|
170 | bman_hwerr_txts[i].mask); |
---|
171 | ier_val &= ~bman_hwerr_txts[i].mask; |
---|
172 | bm_ccsr_out(REG_ERR_IER, ier_val); |
---|
173 | } |
---|
174 | } |
---|
175 | } |
---|
176 | bm_ccsr_out(REG_ERR_ISR, isr_val); |
---|
177 | |
---|
178 | return IRQ_HANDLED; |
---|
179 | } |
---|
180 | |
---|
181 | static int fsl_bman_probe(struct platform_device *pdev) |
---|
182 | { |
---|
183 | int ret, err_irq; |
---|
184 | struct device *dev = &pdev->dev; |
---|
185 | struct device_node *node = dev->of_node; |
---|
186 | #ifdef __rtems__ |
---|
187 | struct resource res_storage; |
---|
188 | #endif /* __rtems__ */ |
---|
189 | struct resource *res; |
---|
190 | u16 id, bm_pool_cnt; |
---|
191 | u8 major, minor; |
---|
192 | |
---|
193 | #ifndef __rtems__ |
---|
194 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
195 | #else /* __rtems__ */ |
---|
196 | res = platform_get_resource(&res_storage, pdev, IORESOURCE_MEM, 0); |
---|
197 | #endif /* __rtems__ */ |
---|
198 | if (!res) { |
---|
199 | dev_err(dev, "Can't get %s property 'IORESOURCE_MEM'\n", |
---|
200 | node->full_name); |
---|
201 | return -ENXIO; |
---|
202 | } |
---|
203 | bm_ccsr_start = devm_ioremap(dev, res->start, resource_size(res)); |
---|
204 | if (!bm_ccsr_start) |
---|
205 | return -ENXIO; |
---|
206 | |
---|
207 | bm_get_version(&id, &major, &minor); |
---|
208 | if (major == 1 && minor == 0) { |
---|
209 | bman_ip_rev = BMAN_REV10; |
---|
210 | bm_pool_cnt = BM_POOL_MAX; |
---|
211 | } else if (major == 2 && minor == 0) { |
---|
212 | bman_ip_rev = BMAN_REV20; |
---|
213 | bm_pool_cnt = 8; |
---|
214 | } else if (major == 2 && minor == 1) { |
---|
215 | bman_ip_rev = BMAN_REV21; |
---|
216 | bm_pool_cnt = BM_POOL_MAX; |
---|
217 | } else { |
---|
218 | dev_err(dev, "Unknown Bman version:%04x,%02x,%02x\n", |
---|
219 | id, major, minor); |
---|
220 | return -ENODEV; |
---|
221 | } |
---|
222 | |
---|
223 | bm_set_memory(fbpr_a, fbpr_sz); |
---|
224 | |
---|
225 | err_irq = platform_get_irq(pdev, 0); |
---|
226 | if (err_irq <= 0) { |
---|
227 | dev_info(dev, "Can't get %s IRQ\n", node->full_name); |
---|
228 | return -ENODEV; |
---|
229 | } |
---|
230 | ret = devm_request_irq(dev, err_irq, bman_isr, IRQF_SHARED, "bman-err", |
---|
231 | dev); |
---|
232 | if (ret) { |
---|
233 | dev_err(dev, "devm_request_irq() failed %d for '%s'\n", |
---|
234 | ret, node->full_name); |
---|
235 | return ret; |
---|
236 | } |
---|
237 | /* Disable Buffer Pool State Change */ |
---|
238 | bm_ccsr_out(REG_ERR_ISDR, BM_EIRQ_BSCN); |
---|
239 | /* |
---|
240 | * Write-to-clear any stale bits, (eg. starvation being asserted prior |
---|
241 | * to resource allocation during driver init). |
---|
242 | */ |
---|
243 | bm_ccsr_out(REG_ERR_ISR, 0xffffffff); |
---|
244 | /* Enable Error Interrupts */ |
---|
245 | bm_ccsr_out(REG_ERR_IER, 0xffffffff); |
---|
246 | |
---|
247 | bm_bpalloc = devm_gen_pool_create(dev, 0, -1, "bman-bpalloc"); |
---|
248 | if (IS_ERR(bm_bpalloc)) { |
---|
249 | ret = PTR_ERR(bm_bpalloc); |
---|
250 | dev_err(dev, "bman-bpalloc pool init failed (%d)\n", ret); |
---|
251 | return ret; |
---|
252 | } |
---|
253 | |
---|
254 | /* seed BMan resource pool */ |
---|
255 | ret = gen_pool_add(bm_bpalloc, DPAA_GENALLOC_OFF, bm_pool_cnt, -1); |
---|
256 | if (ret) { |
---|
257 | dev_err(dev, "Failed to seed BPID range [%d..%d] (%d)\n", |
---|
258 | 0, bm_pool_cnt - 1, ret); |
---|
259 | return ret; |
---|
260 | } |
---|
261 | |
---|
262 | return 0; |
---|
263 | }; |
---|
264 | |
---|
265 | #ifndef __rtems__ |
---|
266 | static const struct of_device_id fsl_bman_ids[] = { |
---|
267 | { |
---|
268 | .compatible = "fsl,bman", |
---|
269 | }, |
---|
270 | {} |
---|
271 | }; |
---|
272 | |
---|
273 | static struct platform_driver fsl_bman_driver = { |
---|
274 | .driver = { |
---|
275 | .name = KBUILD_MODNAME, |
---|
276 | .of_match_table = fsl_bman_ids, |
---|
277 | .suppress_bind_attrs = true, |
---|
278 | }, |
---|
279 | .probe = fsl_bman_probe, |
---|
280 | }; |
---|
281 | |
---|
282 | builtin_platform_driver(fsl_bman_driver); |
---|
283 | #else /* __rtems__ */ |
---|
284 | #include <sys/types.h> |
---|
285 | #include <sys/kernel.h> |
---|
286 | #include <rtems.h> |
---|
287 | #include <bsp/fdt.h> |
---|
288 | #include <bsp/qoriq.h> |
---|
289 | #include <linux/of_address.h> |
---|
290 | #include <linux/of_irq.h> |
---|
291 | |
---|
292 | static struct bm_portal_config bman_configs[NR_CPUS]; |
---|
293 | |
---|
294 | u16 bman_pool_max; |
---|
295 | |
---|
296 | SYSINIT_REFERENCE(irqs); |
---|
297 | |
---|
298 | static void |
---|
299 | bman_sysinit(void) |
---|
300 | { |
---|
301 | const char *fdt = bsp_fdt_get(); |
---|
302 | struct device_node dn; |
---|
303 | struct platform_device ofdev = { |
---|
304 | .dev = { |
---|
305 | .of_node = &dn, |
---|
306 | .base = (uintptr_t)&qoriq |
---|
307 | } |
---|
308 | }; |
---|
309 | const char *name; |
---|
310 | int cpu_count = (int)rtems_get_processor_count(); |
---|
311 | int cpu; |
---|
312 | int ret; |
---|
313 | int node; |
---|
314 | int parent; |
---|
315 | |
---|
316 | qoriq_reset_qman_and_bman(); |
---|
317 | qoriq_clear_ce_portal(&qoriq_bman_portal[0][0], |
---|
318 | sizeof(qoriq_bman_portal[0])); |
---|
319 | qoriq_clear_ci_portal(&qoriq_bman_portal[1][0], |
---|
320 | sizeof(qoriq_bman_portal[1])); |
---|
321 | |
---|
322 | memset(&dn, 0, sizeof(dn)); |
---|
323 | |
---|
324 | name = "fsl,bman"; |
---|
325 | node = fdt_node_offset_by_compatible(fdt, 0, name); |
---|
326 | if (node < 0) |
---|
327 | panic("bman: no bman in FDT"); |
---|
328 | |
---|
329 | dn.full_name = name; |
---|
330 | dn.offset = node; |
---|
331 | ret = fsl_bman_probe(&ofdev); |
---|
332 | if (ret != 0) |
---|
333 | panic("bman: probe failed"); |
---|
334 | |
---|
335 | name = "fsl,bman-portal"; |
---|
336 | node = fdt_node_offset_by_compatible(fdt, 0, name); |
---|
337 | if (node < 0) |
---|
338 | panic("bman: no portals in FDT"); |
---|
339 | parent = fdt_parent_offset(fdt, node); |
---|
340 | if (parent < 0) |
---|
341 | panic("bman: no parent of portals in FDT"); |
---|
342 | node = fdt_first_subnode(fdt, parent); |
---|
343 | |
---|
344 | dn.full_name = name; |
---|
345 | dn.offset = node; |
---|
346 | |
---|
347 | for (cpu = 0; cpu < cpu_count; ++cpu) { |
---|
348 | struct bm_portal_config *pcfg = &bman_configs[cpu]; |
---|
349 | struct bman_portal *portal; |
---|
350 | struct resource res; |
---|
351 | |
---|
352 | if (node < 0) |
---|
353 | panic("bman: missing portal in FDT"); |
---|
354 | |
---|
355 | ret = of_address_to_resource(&dn, 0, &res); |
---|
356 | if (ret != 0) |
---|
357 | panic("bman: no portal CE address"); |
---|
358 | pcfg->addr_virt[0] = (__iomem void *) |
---|
359 | ((uintptr_t)&qoriq_bman_portal[0][0] + (uintptr_t)res.start); |
---|
360 | BSD_ASSERT((uintptr_t)pcfg->addr_virt[0] >= |
---|
361 | (uintptr_t)&qoriq_bman_portal[0][0]); |
---|
362 | BSD_ASSERT((uintptr_t)pcfg->addr_virt[0] < |
---|
363 | (uintptr_t)&qoriq_bman_portal[1][0]); |
---|
364 | |
---|
365 | ret = of_address_to_resource(&dn, 1, &res); |
---|
366 | if (ret != 0) |
---|
367 | panic("bman: no portal CI address"); |
---|
368 | pcfg->addr_virt[1] = (__iomem void *) |
---|
369 | ((uintptr_t)&qoriq_bman_portal[0][0] + (uintptr_t)res.start); |
---|
370 | BSD_ASSERT((uintptr_t)pcfg->addr_virt[1] >= |
---|
371 | (uintptr_t)&qoriq_bman_portal[1][0]); |
---|
372 | BSD_ASSERT((uintptr_t)pcfg->addr_virt[1] < |
---|
373 | (uintptr_t)&qoriq_bman_portal[2][0]); |
---|
374 | |
---|
375 | pcfg->irq = of_irq_to_resource(&dn, 0, NULL); |
---|
376 | if (pcfg->irq == NO_IRQ) |
---|
377 | panic("bman: no portal interrupt"); |
---|
378 | |
---|
379 | pcfg->cpu = cpu; |
---|
380 | |
---|
381 | portal = bman_create_affine_portal(pcfg); |
---|
382 | if (portal == NULL) |
---|
383 | panic("bman: cannot create portal"); |
---|
384 | |
---|
385 | bman_p_irqsource_add(portal, BM_PIRQ_RCRI); |
---|
386 | |
---|
387 | node = fdt_next_subnode(fdt, node); |
---|
388 | dn.offset = node; |
---|
389 | } |
---|
390 | } |
---|
391 | SYSINIT(bman, SI_SUB_CPU, SI_ORDER_FIRST, bman_sysinit, NULL); |
---|
392 | #endif /* __rtems__ */ |
---|