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