1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#include <linux/module.h>
17#include <linux/kernel.h>
18#include <linux/slab.h>
19#include <linux/of.h>
20#include <linux/of_device.h>
21#include <linux/of_platform.h>
22#include <asm/io.h>
23#include <asm/irq.h>
24#include <asm/mpc52xx.h>
25
26#include <linux/fsl/bestcomm/sram.h>
27#include <linux/fsl/bestcomm/bestcomm_priv.h>
28#include "linux/fsl/bestcomm/bestcomm.h"
29
30#define DRIVER_NAME "bestcomm-core"
31
32
33static const struct of_device_id mpc52xx_sram_ids[] = {
34 { .compatible = "fsl,mpc5200-sram", },
35 { .compatible = "mpc5200-sram", },
36 {}
37};
38
39
40struct bcom_engine *bcom_eng = NULL;
41EXPORT_SYMBOL_GPL(bcom_eng);
42
43
44
45
46
47
48
49struct bcom_task *
50bcom_task_alloc(int bd_count, int bd_size, int priv_size)
51{
52 int i, tasknum = -1;
53 struct bcom_task *tsk;
54
55
56 if (!bcom_eng)
57 return NULL;
58
59
60 spin_lock(&bcom_eng->lock);
61
62 for (i=0; i<BCOM_MAX_TASKS; i++)
63 if (!bcom_eng->tdt[i].stop) {
64 bcom_eng->tdt[i].stop = 0xfffffffful;
65 tasknum = i;
66 break;
67 }
68
69 spin_unlock(&bcom_eng->lock);
70
71 if (tasknum < 0)
72 return NULL;
73
74
75 tsk = kzalloc(sizeof(struct bcom_task) + priv_size, GFP_KERNEL);
76 if (!tsk)
77 goto error;
78
79 tsk->tasknum = tasknum;
80 if (priv_size)
81 tsk->priv = (void*)tsk + sizeof(struct bcom_task);
82
83
84 tsk->irq = irq_of_parse_and_map(bcom_eng->ofnode, tsk->tasknum);
85 if (!tsk->irq)
86 goto error;
87
88
89 if (bd_count) {
90 tsk->cookie = kmalloc_array(bd_count, sizeof(void *),
91 GFP_KERNEL);
92 if (!tsk->cookie)
93 goto error;
94
95 tsk->bd = bcom_sram_alloc(bd_count * bd_size, 4, &tsk->bd_pa);
96 if (!tsk->bd)
97 goto error;
98 memset(tsk->bd, 0x00, bd_count * bd_size);
99
100 tsk->num_bd = bd_count;
101 tsk->bd_size = bd_size;
102 }
103
104 return tsk;
105
106error:
107 if (tsk) {
108 if (tsk->irq)
109 irq_dispose_mapping(tsk->irq);
110 bcom_sram_free(tsk->bd);
111 kfree(tsk->cookie);
112 kfree(tsk);
113 }
114
115 bcom_eng->tdt[tasknum].stop = 0;
116
117 return NULL;
118}
119EXPORT_SYMBOL_GPL(bcom_task_alloc);
120
121void
122bcom_task_free(struct bcom_task *tsk)
123{
124
125 bcom_disable_task(tsk->tasknum);
126
127
128 bcom_eng->tdt[tsk->tasknum].start = 0;
129 bcom_eng->tdt[tsk->tasknum].stop = 0;
130
131
132 irq_dispose_mapping(tsk->irq);
133 bcom_sram_free(tsk->bd);
134 kfree(tsk->cookie);
135 kfree(tsk);
136}
137EXPORT_SYMBOL_GPL(bcom_task_free);
138
139int
140bcom_load_image(int task, u32 *task_image)
141{
142 struct bcom_task_header *hdr = (struct bcom_task_header *)task_image;
143 struct bcom_tdt *tdt;
144 u32 *desc, *var, *inc;
145 u32 *desc_src, *var_src, *inc_src;
146
147
148 if (hdr->magic != BCOM_TASK_MAGIC) {
149 printk(KERN_ERR DRIVER_NAME
150 ": Trying to load invalid microcode\n");
151 return -EINVAL;
152 }
153
154 if ((task < 0) || (task >= BCOM_MAX_TASKS)) {
155 printk(KERN_ERR DRIVER_NAME
156 ": Trying to load invalid task %d\n", task);
157 return -EINVAL;
158 }
159
160
161 tdt = &bcom_eng->tdt[task];
162
163 if (tdt->start) {
164 desc = bcom_task_desc(task);
165 if (hdr->desc_size != bcom_task_num_descs(task)) {
166 printk(KERN_ERR DRIVER_NAME
167 ": Trying to reload wrong task image "
168 "(%d size %d/%d)!\n",
169 task,
170 hdr->desc_size,
171 bcom_task_num_descs(task));
172 return -EINVAL;
173 }
174 } else {
175 phys_addr_t start_pa;
176
177 desc = bcom_sram_alloc(hdr->desc_size * sizeof(u32), 4, &start_pa);
178 if (!desc)
179 return -ENOMEM;
180
181 tdt->start = start_pa;
182 tdt->stop = start_pa + ((hdr->desc_size-1) * sizeof(u32));
183 }
184
185 var = bcom_task_var(task);
186 inc = bcom_task_inc(task);
187
188
189 memset(var, 0x00, BCOM_VAR_SIZE);
190 memset(inc, 0x00, BCOM_INC_SIZE);
191
192 desc_src = (u32 *)(hdr + 1);
193 var_src = desc_src + hdr->desc_size;
194 inc_src = var_src + hdr->var_size;
195
196 memcpy(desc, desc_src, hdr->desc_size * sizeof(u32));
197 memcpy(var + hdr->first_var, var_src, hdr->var_size * sizeof(u32));
198 memcpy(inc, inc_src, hdr->inc_size * sizeof(u32));
199
200 return 0;
201}
202EXPORT_SYMBOL_GPL(bcom_load_image);
203
204void
205bcom_set_initiator(int task, int initiator)
206{
207 int i;
208 int num_descs;
209 u32 *desc;
210 int next_drd_has_initiator;
211
212 bcom_set_tcr_initiator(task, initiator);
213
214
215
216
217
218 desc = bcom_task_desc(task);
219 next_drd_has_initiator = 1;
220 num_descs = bcom_task_num_descs(task);
221
222 for (i=0; i<num_descs; i++, desc++) {
223 if (!bcom_desc_is_drd(*desc))
224 continue;
225 if (next_drd_has_initiator)
226 if (bcom_desc_initiator(*desc) != BCOM_INITIATOR_ALWAYS)
227 bcom_set_desc_initiator(desc, initiator);
228 next_drd_has_initiator = !bcom_drd_is_extended(*desc);
229 }
230}
231EXPORT_SYMBOL_GPL(bcom_set_initiator);
232
233
234
235
236void
237bcom_enable(struct bcom_task *tsk)
238{
239 bcom_enable_task(tsk->tasknum);
240}
241EXPORT_SYMBOL_GPL(bcom_enable);
242
243void
244bcom_disable(struct bcom_task *tsk)
245{
246 bcom_disable_task(tsk->tasknum);
247}
248EXPORT_SYMBOL_GPL(bcom_disable);
249
250
251
252
253
254
255
256
257static u32 fdt_ops[] = {
258 0xa0045670,
259 0x80045670,
260 0x21800000,
261 0x21e00000,
262 0x21500000,
263 0x21400000,
264 0x21500000,
265 0x20400000,
266 0x20500000,
267 0x20800000,
268 0x20a00000,
269 0xc0170000,
270 0xc0145670,
271 0xc0345670,
272 0xa0076540,
273 0xa0000760,
274};
275
276
277static int bcom_engine_init(void)
278{
279 int task;
280 phys_addr_t tdt_pa, ctx_pa, var_pa, fdt_pa;
281 unsigned int tdt_size, ctx_size, var_size, fdt_size;
282
283
284 tdt_size = BCOM_MAX_TASKS * sizeof(struct bcom_tdt);
285 ctx_size = BCOM_MAX_TASKS * BCOM_CTX_SIZE;
286 var_size = BCOM_MAX_TASKS * (BCOM_VAR_SIZE + BCOM_INC_SIZE);
287 fdt_size = BCOM_FDT_SIZE;
288
289 bcom_eng->tdt = bcom_sram_alloc(tdt_size, sizeof(u32), &tdt_pa);
290 bcom_eng->ctx = bcom_sram_alloc(ctx_size, BCOM_CTX_ALIGN, &ctx_pa);
291 bcom_eng->var = bcom_sram_alloc(var_size, BCOM_VAR_ALIGN, &var_pa);
292 bcom_eng->fdt = bcom_sram_alloc(fdt_size, BCOM_FDT_ALIGN, &fdt_pa);
293
294 if (!bcom_eng->tdt || !bcom_eng->ctx || !bcom_eng->var || !bcom_eng->fdt) {
295 printk(KERN_ERR "DMA: SRAM alloc failed in engine init !\n");
296
297 bcom_sram_free(bcom_eng->tdt);
298 bcom_sram_free(bcom_eng->ctx);
299 bcom_sram_free(bcom_eng->var);
300 bcom_sram_free(bcom_eng->fdt);
301
302 return -ENOMEM;
303 }
304
305 memset(bcom_eng->tdt, 0x00, tdt_size);
306 memset(bcom_eng->ctx, 0x00, ctx_size);
307 memset(bcom_eng->var, 0x00, var_size);
308 memset(bcom_eng->fdt, 0x00, fdt_size);
309
310
311 memcpy(&bcom_eng->fdt[48], fdt_ops, sizeof(fdt_ops));
312
313
314 for (task=0; task<BCOM_MAX_TASKS; task++)
315 {
316 out_be16(&bcom_eng->regs->tcr[task], 0);
317 out_8(&bcom_eng->regs->ipr[task], 0);
318
319 bcom_eng->tdt[task].context = ctx_pa;
320 bcom_eng->tdt[task].var = var_pa;
321 bcom_eng->tdt[task].fdt = fdt_pa;
322
323 var_pa += BCOM_VAR_SIZE + BCOM_INC_SIZE;
324 ctx_pa += BCOM_CTX_SIZE;
325 }
326
327 out_be32(&bcom_eng->regs->taskBar, tdt_pa);
328
329
330 out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS);
331
332
333 if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR)
334 bcom_disable_prefetch();
335
336
337 spin_lock_init(&bcom_eng->lock);
338
339 return 0;
340}
341
342static void
343bcom_engine_cleanup(void)
344{
345 int task;
346
347
348 for (task=0; task<BCOM_MAX_TASKS; task++)
349 {
350 out_be16(&bcom_eng->regs->tcr[task], 0);
351 out_8(&bcom_eng->regs->ipr[task], 0);
352 }
353
354 out_be32(&bcom_eng->regs->taskBar, 0ul);
355
356
357 bcom_sram_free(bcom_eng->tdt);
358 bcom_sram_free(bcom_eng->ctx);
359 bcom_sram_free(bcom_eng->var);
360 bcom_sram_free(bcom_eng->fdt);
361}
362
363
364
365
366
367
368static int mpc52xx_bcom_probe(struct platform_device *op)
369{
370 struct device_node *ofn_sram;
371 struct resource res_bcom;
372
373 int rv;
374
375
376 printk(KERN_INFO "DMA: MPC52xx BestComm driver\n");
377
378
379 of_node_get(op->dev.of_node);
380
381
382 ofn_sram = of_find_matching_node(NULL, mpc52xx_sram_ids);
383 if (!ofn_sram) {
384 printk(KERN_ERR DRIVER_NAME ": "
385 "No SRAM found in device tree\n");
386 rv = -ENODEV;
387 goto error_ofput;
388 }
389 rv = bcom_sram_init(ofn_sram, DRIVER_NAME);
390 of_node_put(ofn_sram);
391
392 if (rv) {
393 printk(KERN_ERR DRIVER_NAME ": "
394 "Error in SRAM init\n");
395 goto error_ofput;
396 }
397
398
399 bcom_eng = kzalloc(sizeof(struct bcom_engine), GFP_KERNEL);
400 if (!bcom_eng) {
401 rv = -ENOMEM;
402 goto error_sramclean;
403 }
404
405
406 bcom_eng->ofnode = op->dev.of_node;
407
408
409 if (of_address_to_resource(op->dev.of_node, 0, &res_bcom)) {
410 printk(KERN_ERR DRIVER_NAME ": "
411 "Can't get resource\n");
412 rv = -EINVAL;
413 goto error_sramclean;
414 }
415
416 if (!request_mem_region(res_bcom.start, resource_size(&res_bcom),
417 DRIVER_NAME)) {
418 printk(KERN_ERR DRIVER_NAME ": "
419 "Can't request registers region\n");
420 rv = -EBUSY;
421 goto error_sramclean;
422 }
423
424 bcom_eng->regs_base = res_bcom.start;
425 bcom_eng->regs = ioremap(res_bcom.start, sizeof(struct mpc52xx_sdma));
426 if (!bcom_eng->regs) {
427 printk(KERN_ERR DRIVER_NAME ": "
428 "Can't map registers\n");
429 rv = -ENOMEM;
430 goto error_release;
431 }
432
433
434 rv = bcom_engine_init();
435 if (rv)
436 goto error_unmap;
437
438
439 printk(KERN_INFO "DMA: MPC52xx BestComm engine @%08lx ok !\n",
440 (long)bcom_eng->regs_base);
441
442 return 0;
443
444
445error_unmap:
446 iounmap(bcom_eng->regs);
447error_release:
448 release_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma));
449error_sramclean:
450 kfree(bcom_eng);
451 bcom_sram_cleanup();
452error_ofput:
453 of_node_put(op->dev.of_node);
454
455 printk(KERN_ERR "DMA: MPC52xx BestComm init failed !\n");
456
457 return rv;
458}
459
460
461static int mpc52xx_bcom_remove(struct platform_device *op)
462{
463
464 bcom_engine_cleanup();
465
466
467 bcom_sram_cleanup();
468
469
470 iounmap(bcom_eng->regs);
471 release_mem_region(bcom_eng->regs_base, sizeof(struct mpc52xx_sdma));
472
473
474 of_node_put(bcom_eng->ofnode);
475
476
477 kfree(bcom_eng);
478 bcom_eng = NULL;
479
480 return 0;
481}
482
483static const struct of_device_id mpc52xx_bcom_of_match[] = {
484 { .compatible = "fsl,mpc5200-bestcomm", },
485 { .compatible = "mpc5200-bestcomm", },
486 {},
487};
488
489MODULE_DEVICE_TABLE(of, mpc52xx_bcom_of_match);
490
491
492static struct platform_driver mpc52xx_bcom_of_platform_driver = {
493 .probe = mpc52xx_bcom_probe,
494 .remove = mpc52xx_bcom_remove,
495 .driver = {
496 .name = DRIVER_NAME,
497 .of_match_table = mpc52xx_bcom_of_match,
498 },
499};
500
501
502
503
504
505
506static int __init
507mpc52xx_bcom_init(void)
508{
509 return platform_driver_register(&mpc52xx_bcom_of_platform_driver);
510}
511
512static void __exit
513mpc52xx_bcom_exit(void)
514{
515 platform_driver_unregister(&mpc52xx_bcom_of_platform_driver);
516}
517
518
519
520
521subsys_initcall(mpc52xx_bcom_init);
522module_exit(mpc52xx_bcom_exit);
523
524MODULE_DESCRIPTION("Freescale MPC52xx BestComm DMA");
525MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
526MODULE_AUTHOR("Andrey Volkov <avolkov@varma-el.com>");
527MODULE_AUTHOR("Dale Farnsworth <dfarnsworth@mvista.com>");
528MODULE_LICENSE("GPL v2");
529
530