treewide: kmalloc() -> kmalloc_array()
[sfrench/cifs-2.6.git] / drivers / dma / bestcomm / bestcomm.c
1 /*
2  * Driver for MPC52xx processor BestComm peripheral controller
3  *
4  *
5  * Copyright (C) 2006-2007 Sylvain Munaut <tnt@246tNt.com>
6  * Copyright (C) 2005      Varma Electronics Oy,
7  *                         ( by Andrey Volkov <avolkov@varma-el.com> )
8  * Copyright (C) 2003-2004 MontaVista, Software, Inc.
9  *                         ( by Dale Farnsworth <dfarnsworth@mvista.com> )
10  *
11  * This file is licensed under the terms of the GNU General Public License
12  * version 2. This program is licensed "as is" without any warranty of any
13  * kind, whether express or implied.
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 /* MPC5200 device tree match tables */
33 static const struct of_device_id mpc52xx_sram_ids[] = {
34         { .compatible = "fsl,mpc5200-sram", },
35         { .compatible = "mpc5200-sram", },
36         {}
37 };
38
39
40 struct bcom_engine *bcom_eng = NULL;
41 EXPORT_SYMBOL_GPL(bcom_eng);    /* needed for inline functions */
42
43 /* ======================================================================== */
44 /* Public and private API                                                   */
45 /* ======================================================================== */
46
47 /* Private API */
48
49 struct bcom_task *
50 bcom_task_alloc(int bd_count, int bd_size, int priv_size)
51 {
52         int i, tasknum = -1;
53         struct bcom_task *tsk;
54
55         /* Don't try to do anything if bestcomm init failed */
56         if (!bcom_eng)
57                 return NULL;
58
59         /* Get and reserve a task num */
60         spin_lock(&bcom_eng->lock);
61
62         for (i=0; i<BCOM_MAX_TASKS; i++)
63                 if (!bcom_eng->tdt[i].stop) {   /* we use stop as a marker */
64                         bcom_eng->tdt[i].stop = 0xfffffffful; /* dummy addr */
65                         tasknum = i;
66                         break;
67                 }
68
69         spin_unlock(&bcom_eng->lock);
70
71         if (tasknum < 0)
72                 return NULL;
73
74         /* Allocate our structure */
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         /* Get IRQ of that task */
84         tsk->irq = irq_of_parse_and_map(bcom_eng->ofnode, tsk->tasknum);
85         if (!tsk->irq)
86                 goto error;
87
88         /* Init the BDs, if needed */
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
106 error:
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 }
119 EXPORT_SYMBOL_GPL(bcom_task_alloc);
120
121 void
122 bcom_task_free(struct bcom_task *tsk)
123 {
124         /* Stop the task */
125         bcom_disable_task(tsk->tasknum);
126
127         /* Clear TDT */
128         bcom_eng->tdt[tsk->tasknum].start = 0;
129         bcom_eng->tdt[tsk->tasknum].stop  = 0;
130
131         /* Free everything */
132         irq_dispose_mapping(tsk->irq);
133         bcom_sram_free(tsk->bd);
134         kfree(tsk->cookie);
135         kfree(tsk);
136 }
137 EXPORT_SYMBOL_GPL(bcom_task_free);
138
139 int
140 bcom_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         /* Safety checks */
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         /* Initial load or reload */
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         /* Clear & copy */
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 }
202 EXPORT_SYMBOL_GPL(bcom_load_image);
203
204 void
205 bcom_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         /* Just setting tcr is apparently not enough due to some problem */
215         /* with it. So we just go thru all the microcode and replace in  */
216         /* the DRD directly */
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 }
231 EXPORT_SYMBOL_GPL(bcom_set_initiator);
232
233
234 /* Public API */
235
236 void
237 bcom_enable(struct bcom_task *tsk)
238 {
239         bcom_enable_task(tsk->tasknum);
240 }
241 EXPORT_SYMBOL_GPL(bcom_enable);
242
243 void
244 bcom_disable(struct bcom_task *tsk)
245 {
246         bcom_disable_task(tsk->tasknum);
247 }
248 EXPORT_SYMBOL_GPL(bcom_disable);
249
250
251 /* ======================================================================== */
252 /* Engine init/cleanup                                                      */
253 /* ======================================================================== */
254
255 /* Function Descriptor table */
256 /* this will need to be updated if Freescale changes their task code FDT */
257 static u32 fdt_ops[] = {
258         0xa0045670,     /* FDT[48] - load_acc()   */
259         0x80045670,     /* FDT[49] - unload_acc() */
260         0x21800000,     /* FDT[50] - and()        */
261         0x21e00000,     /* FDT[51] - or()         */
262         0x21500000,     /* FDT[52] - xor()        */
263         0x21400000,     /* FDT[53] - andn()       */
264         0x21500000,     /* FDT[54] - not()        */
265         0x20400000,     /* FDT[55] - add()        */
266         0x20500000,     /* FDT[56] - sub()        */
267         0x20800000,     /* FDT[57] - lsh()        */
268         0x20a00000,     /* FDT[58] - rsh()        */
269         0xc0170000,     /* FDT[59] - crc8()       */
270         0xc0145670,     /* FDT[60] - crc16()      */
271         0xc0345670,     /* FDT[61] - crc32()      */
272         0xa0076540,     /* FDT[62] - endian32()   */
273         0xa0000760,     /* FDT[63] - endian16()   */
274 };
275
276
277 static 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         /* Allocate & clear SRAM zones for FDT, TDTs, contexts and vars/incs */
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         /* Copy the FDT for the EU#3 */
311         memcpy(&bcom_eng->fdt[48], fdt_ops, sizeof(fdt_ops));
312
313         /* Initialize Task base structure */
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         /* Init 'always' initiator */
330         out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS);
331
332         /* Disable COMM Bus Prefetch on the original 5200; it's broken */
333         if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR)
334                 bcom_disable_prefetch();
335
336         /* Init lock */
337         spin_lock_init(&bcom_eng->lock);
338
339         return 0;
340 }
341
342 static void
343 bcom_engine_cleanup(void)
344 {
345         int task;
346
347         /* Stop all tasks */
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         /* Release the SRAM zones */
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 /* OF platform driver                                                       */
366 /* ======================================================================== */
367
368 static 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         /* Inform user we're ok so far */
376         printk(KERN_INFO "DMA: MPC52xx BestComm driver\n");
377
378         /* Get the bestcomm node */
379         of_node_get(op->dev.of_node);
380
381         /* Prepare SRAM */
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         /* Get a clean struct */
399         bcom_eng = kzalloc(sizeof(struct bcom_engine), GFP_KERNEL);
400         if (!bcom_eng) {
401                 rv = -ENOMEM;
402                 goto error_sramclean;
403         }
404
405         /* Save the node */
406         bcom_eng->ofnode = op->dev.of_node;
407
408         /* Get, reserve & map io */
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         /* Now, do the real init */
434         rv = bcom_engine_init();
435         if (rv)
436                 goto error_unmap;
437
438         /* Done ! */
439         printk(KERN_INFO "DMA: MPC52xx BestComm engine @%08lx ok !\n",
440                 (long)bcom_eng->regs_base);
441
442         return 0;
443
444         /* Error path */
445 error_unmap:
446         iounmap(bcom_eng->regs);
447 error_release:
448         release_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma));
449 error_sramclean:
450         kfree(bcom_eng);
451         bcom_sram_cleanup();
452 error_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
461 static int mpc52xx_bcom_remove(struct platform_device *op)
462 {
463         /* Clean up the engine */
464         bcom_engine_cleanup();
465
466         /* Cleanup SRAM */
467         bcom_sram_cleanup();
468
469         /* Release regs */
470         iounmap(bcom_eng->regs);
471         release_mem_region(bcom_eng->regs_base, sizeof(struct mpc52xx_sdma));
472
473         /* Release the node */
474         of_node_put(bcom_eng->ofnode);
475
476         /* Release memory */
477         kfree(bcom_eng);
478         bcom_eng = NULL;
479
480         return 0;
481 }
482
483 static const struct of_device_id mpc52xx_bcom_of_match[] = {
484         { .compatible = "fsl,mpc5200-bestcomm", },
485         { .compatible = "mpc5200-bestcomm", },
486         {},
487 };
488
489 MODULE_DEVICE_TABLE(of, mpc52xx_bcom_of_match);
490
491
492 static 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 /* Module                                                                   */
504 /* ======================================================================== */
505
506 static int __init
507 mpc52xx_bcom_init(void)
508 {
509         return platform_driver_register(&mpc52xx_bcom_of_platform_driver);
510 }
511
512 static void __exit
513 mpc52xx_bcom_exit(void)
514 {
515         platform_driver_unregister(&mpc52xx_bcom_of_platform_driver);
516 }
517
518 /* If we're not a module, we must make sure everything is setup before  */
519 /* anyone tries to use us ... that's why we use subsys_initcall instead */
520 /* of module_init. */
521 subsys_initcall(mpc52xx_bcom_init);
522 module_exit(mpc52xx_bcom_exit);
523
524 MODULE_DESCRIPTION("Freescale MPC52xx BestComm DMA");
525 MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
526 MODULE_AUTHOR("Andrey Volkov <avolkov@varma-el.com>");
527 MODULE_AUTHOR("Dale Farnsworth <dfarnsworth@mvista.com>");
528 MODULE_LICENSE("GPL v2");
529