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 "sram.h"
27#include "bestcomm_priv.h"
28#include "bestcomm.h"
29
30#define DRIVER_NAME "bestcomm-core"
31
32
33static struct of_device_id mpc52xx_sram_ids[] __devinitdata = {
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 __devinit
277bcom_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 __devinit
369mpc52xx_bcom_probe(struct of_device *op, const struct of_device_id *match)
370{
371 struct device_node *ofn_sram;
372 struct resource res_bcom;
373
374 int rv;
375
376
377 printk(KERN_INFO "DMA: MPC52xx BestComm driver\n");
378
379
380 of_node_get(op->node);
381
382
383 ofn_sram = of_find_matching_node(NULL, mpc52xx_sram_ids);
384 if (!ofn_sram) {
385 printk(KERN_ERR DRIVER_NAME ": "
386 "No SRAM found in device tree\n");
387 rv = -ENODEV;
388 goto error_ofput;
389 }
390 rv = bcom_sram_init(ofn_sram, DRIVER_NAME);
391 of_node_put(ofn_sram);
392
393 if (rv) {
394 printk(KERN_ERR DRIVER_NAME ": "
395 "Error in SRAM init\n");
396 goto error_ofput;
397 }
398
399
400 bcom_eng = kzalloc(sizeof(struct bcom_engine), GFP_KERNEL);
401 if (!bcom_eng) {
402 printk(KERN_ERR DRIVER_NAME ": "
403 "Can't allocate state structure\n");
404 rv = -ENOMEM;
405 goto error_sramclean;
406 }
407
408
409 bcom_eng->ofnode = op->node;
410
411
412 if (of_address_to_resource(op->node, 0, &res_bcom)) {
413 printk(KERN_ERR DRIVER_NAME ": "
414 "Can't get resource\n");
415 rv = -EINVAL;
416 goto error_sramclean;
417 }
418
419 if (!request_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma),
420 DRIVER_NAME)) {
421 printk(KERN_ERR DRIVER_NAME ": "
422 "Can't request registers region\n");
423 rv = -EBUSY;
424 goto error_sramclean;
425 }
426
427 bcom_eng->regs_base = res_bcom.start;
428 bcom_eng->regs = ioremap(res_bcom.start, sizeof(struct mpc52xx_sdma));
429 if (!bcom_eng->regs) {
430 printk(KERN_ERR DRIVER_NAME ": "
431 "Can't map registers\n");
432 rv = -ENOMEM;
433 goto error_release;
434 }
435
436
437 rv = bcom_engine_init();
438 if (rv)
439 goto error_unmap;
440
441
442 printk(KERN_INFO "DMA: MPC52xx BestComm engine @%08lx ok !\n",
443 (long)bcom_eng->regs_base);
444
445 return 0;
446
447
448error_unmap:
449 iounmap(bcom_eng->regs);
450error_release:
451 release_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma));
452error_sramclean:
453 kfree(bcom_eng);
454 bcom_sram_cleanup();
455error_ofput:
456 of_node_put(op->node);
457
458 printk(KERN_ERR "DMA: MPC52xx BestComm init failed !\n");
459
460 return rv;
461}
462
463
464static int
465mpc52xx_bcom_remove(struct of_device *op)
466{
467
468 bcom_engine_cleanup();
469
470
471 bcom_sram_cleanup();
472
473
474 iounmap(bcom_eng->regs);
475 release_mem_region(bcom_eng->regs_base, sizeof(struct mpc52xx_sdma));
476
477
478 of_node_put(bcom_eng->ofnode);
479
480
481 kfree(bcom_eng);
482 bcom_eng = NULL;
483
484 return 0;
485}
486
487static struct of_device_id mpc52xx_bcom_of_match[] = {
488 { .compatible = "fsl,mpc5200-bestcomm", },
489 { .compatible = "mpc5200-bestcomm", },
490 {},
491};
492
493MODULE_DEVICE_TABLE(of, mpc52xx_bcom_of_match);
494
495
496static struct of_platform_driver mpc52xx_bcom_of_platform_driver = {
497 .owner = THIS_MODULE,
498 .name = DRIVER_NAME,
499 .match_table = mpc52xx_bcom_of_match,
500 .probe = mpc52xx_bcom_probe,
501 .remove = mpc52xx_bcom_remove,
502 .driver = {
503 .name = DRIVER_NAME,
504 .owner = THIS_MODULE,
505 },
506};
507
508
509
510
511
512
513static int __init
514mpc52xx_bcom_init(void)
515{
516 return of_register_platform_driver(&mpc52xx_bcom_of_platform_driver);
517}
518
519static void __exit
520mpc52xx_bcom_exit(void)
521{
522 of_unregister_platform_driver(&mpc52xx_bcom_of_platform_driver);
523}
524
525
526
527
528subsys_initcall(mpc52xx_bcom_init);
529module_exit(mpc52xx_bcom_exit);
530
531MODULE_DESCRIPTION("Freescale MPC52xx BestComm DMA");
532MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
533MODULE_AUTHOR("Andrey Volkov <avolkov@varma-el.com>");
534MODULE_AUTHOR("Dale Farnsworth <dfarnsworth@mvista.com>");
535MODULE_LICENSE("GPL v2");
536
537