Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
bestcomm.c
Go to the documentation of this file.
1 /*
2  * Driver for MPC52xx processor BestComm peripheral controller
3  *
4  *
5  * Copyright (C) 2006-2007 Sylvain Munaut <[email protected]>
6  * Copyright (C) 2005 Varma Electronics Oy,
7  * ( by Andrey Volkov <[email protected]> )
8  * Copyright (C) 2003-2004 MontaVista, Software, Inc.
9  * ( by Dale Farnsworth <[email protected]> )
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 "sram.h"
27 #include "bestcomm_priv.h"
28 #include "bestcomm.h"
29 
30 #define DRIVER_NAME "bestcomm-core"
31 
32 /* MPC5200 device tree match tables */
33 static struct of_device_id mpc52xx_sram_ids[] __devinitdata = {
34  { .compatible = "fsl,mpc5200-sram", },
35  { .compatible = "mpc5200-sram", },
36  {}
37 };
38 
39 
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 == NO_IRQ)
86  goto error;
87 
88  /* Init the BDs, if needed */
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 
105 error:
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 }
119 
120 void
122 {
123  /* Stop the task */
124  bcom_disable_task(tsk->tasknum);
125 
126  /* Clear TDT */
127  bcom_eng->tdt[tsk->tasknum].start = 0;
128  bcom_eng->tdt[tsk->tasknum].stop = 0;
129 
130  /* Free everything */
131  irq_dispose_mapping(tsk->irq);
132  bcom_sram_free(tsk->bd);
133  kfree(tsk->cookie);
134  kfree(tsk);
135 }
137 
138 int
139 bcom_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  /* Safety checks */
147  if (hdr->magic != BCOM_TASK_MAGIC) {
149  ": Trying to load invalid microcode\n");
150  return -EINVAL;
151  }
152 
153  if ((task < 0) || (task >= BCOM_MAX_TASKS)) {
155  ": Trying to load invalid task %d\n", task);
156  return -EINVAL;
157  }
158 
159  /* Initial load or reload */
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)) {
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  /* Clear & copy */
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 }
202 
203 void
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  /* Just setting tcr is apparently not enough due to some problem */
214  /* with it. So we just go thru all the microcode and replace in */
215  /* the DRD directly */
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 }
231 
232 
233 /* Public API */
234 
235 void
236 bcom_enable(struct bcom_task *tsk)
237 {
238  bcom_enable_task(tsk->tasknum);
239 }
241 
242 void
244 {
245  bcom_disable_task(tsk->tasknum);
246 }
248 
249 
250 /* ======================================================================== */
251 /* Engine init/cleanup */
252 /* ======================================================================== */
253 
254 /* Function Descriptor table */
255 /* this will need to be updated if Freescale changes their task code FDT */
256 static u32 fdt_ops[] = {
257  0xa0045670, /* FDT[48] - load_acc() */
258  0x80045670, /* FDT[49] - unload_acc() */
259  0x21800000, /* FDT[50] - and() */
260  0x21e00000, /* FDT[51] - or() */
261  0x21500000, /* FDT[52] - xor() */
262  0x21400000, /* FDT[53] - andn() */
263  0x21500000, /* FDT[54] - not() */
264  0x20400000, /* FDT[55] - add() */
265  0x20500000, /* FDT[56] - sub() */
266  0x20800000, /* FDT[57] - lsh() */
267  0x20a00000, /* FDT[58] - rsh() */
268  0xc0170000, /* FDT[59] - crc8() */
269  0xc0145670, /* FDT[60] - crc16() */
270  0xc0345670, /* FDT[61] - crc32() */
271  0xa0076540, /* FDT[62] - endian32() */
272  0xa0000760, /* FDT[63] - endian16() */
273 };
274 
275 
276 static int __devinit
277 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 __devinit 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) {
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) {
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) {
402  "Can't allocate state structure\n");
403  rv = -ENOMEM;
404  goto error_sramclean;
405  }
406 
407  /* Save the node */
408  bcom_eng->ofnode = op->dev.of_node;
409 
410  /* Get, reserve & map io */
411  if (of_address_to_resource(op->dev.of_node, 0, &res_bcom)) {
413  "Can't get resource\n");
414  rv = -EINVAL;
415  goto error_sramclean;
416  }
417 
418  if (!request_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma),
419  DRIVER_NAME)) {
421  "Can't request registers region\n");
422  rv = -EBUSY;
423  goto error_sramclean;
424  }
425 
426  bcom_eng->regs_base = res_bcom.start;
427  bcom_eng->regs = ioremap(res_bcom.start, sizeof(struct mpc52xx_sdma));
428  if (!bcom_eng->regs) {
430  "Can't map registers\n");
431  rv = -ENOMEM;
432  goto error_release;
433  }
434 
435  /* Now, do the real init */
436  rv = bcom_engine_init();
437  if (rv)
438  goto error_unmap;
439 
440  /* Done ! */
441  printk(KERN_INFO "DMA: MPC52xx BestComm engine @%08lx ok !\n",
442  (long)bcom_eng->regs_base);
443 
444  return 0;
445 
446  /* Error path */
447 error_unmap:
448  iounmap(bcom_eng->regs);
449 error_release:
450  release_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma));
451 error_sramclean:
452  kfree(bcom_eng);
454 error_ofput:
455  of_node_put(op->dev.of_node);
456 
457  printk(KERN_ERR "DMA: MPC52xx BestComm init failed !\n");
458 
459  return rv;
460 }
461 
462 
463 static int mpc52xx_bcom_remove(struct platform_device *op)
464 {
465  /* Clean up the engine */
466  bcom_engine_cleanup();
467 
468  /* Cleanup SRAM */
470 
471  /* Release regs */
472  iounmap(bcom_eng->regs);
473  release_mem_region(bcom_eng->regs_base, sizeof(struct mpc52xx_sdma));
474 
475  /* Release the node */
476  of_node_put(bcom_eng->ofnode);
477 
478  /* Release memory */
479  kfree(bcom_eng);
480  bcom_eng = NULL;
481 
482  return 0;
483 }
484 
485 static struct of_device_id mpc52xx_bcom_of_match[] = {
486  { .compatible = "fsl,mpc5200-bestcomm", },
487  { .compatible = "mpc5200-bestcomm", },
488  {},
489 };
490 
491 MODULE_DEVICE_TABLE(of, mpc52xx_bcom_of_match);
492 
493 
494 static struct platform_driver mpc52xx_bcom_of_platform_driver = {
495  .probe = mpc52xx_bcom_probe,
496  .remove = mpc52xx_bcom_remove,
497  .driver = {
498  .name = DRIVER_NAME,
499  .owner = THIS_MODULE,
500  .of_match_table = mpc52xx_bcom_of_match,
501  },
502 };
503 
504 
505 /* ======================================================================== */
506 /* Module */
507 /* ======================================================================== */
508 
509 static int __init
510 mpc52xx_bcom_init(void)
511 {
512  return platform_driver_register(&mpc52xx_bcom_of_platform_driver);
513 }
514 
515 static void __exit
516 mpc52xx_bcom_exit(void)
517 {
518  platform_driver_unregister(&mpc52xx_bcom_of_platform_driver);
519 }
520 
521 /* If we're not a module, we must make sure everything is setup before */
522 /* anyone tries to use us ... that's why we use subsys_initcall instead */
523 /* of module_init. */
524 subsys_initcall(mpc52xx_bcom_init);
525 module_exit(mpc52xx_bcom_exit);
526 
527 MODULE_DESCRIPTION("Freescale MPC52xx BestComm DMA");
528 MODULE_AUTHOR("Sylvain Munaut <[email protected]>");
529 MODULE_AUTHOR("Andrey Volkov <[email protected]>");
530 MODULE_AUTHOR("Dale Farnsworth <[email protected]>");
531 MODULE_LICENSE("GPL v2");
532