aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorSylvain Munaut <tnt@246tNt.com>2007-09-16 06:53:27 -0400
committerGrant Likely <grant.likely@secretlab.ca>2007-10-16 19:09:34 -0400
commit2f9ea1bde0d12d8fb5a7bdc7ab6834275d456262 (patch)
treef24cbb1c117788dd8cb529bf7812f4567f962812 /arch/powerpc
parent07e6e93136ca61f071c819c69e1ec5bff9fda46f (diff)
[POWERPC] bestcomm: core bestcomm support for Freescale MPC5200
This patch adds support for the core of the BestComm API for the Freescale MPC5200(b). The BestComm engine is a microcode-controlled / tasks-based DMA used by several of the onchip devices. Setting up the tasks / memory allocation and all common low level functions are handled by this patch. The specifics details of each tasks and their microcode are split-out in separate patches. This is not the official API, but a much cleaner one. (hopefully) Signed-off-by: Sylvain Munaut <tnt@246tNt.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/platforms/Kconfig2
-rw-r--r--arch/powerpc/sysdev/Makefile1
-rw-r--r--arch/powerpc/sysdev/bestcomm/Kconfig18
-rw-r--r--arch/powerpc/sysdev/bestcomm/Makefile8
-rw-r--r--arch/powerpc/sysdev/bestcomm/bestcomm.c528
-rw-r--r--arch/powerpc/sysdev/bestcomm/bestcomm.h190
-rw-r--r--arch/powerpc/sysdev/bestcomm/bestcomm_priv.h334
-rw-r--r--arch/powerpc/sysdev/bestcomm/sram.c177
-rw-r--r--arch/powerpc/sysdev/bestcomm/sram.h54
9 files changed, 1312 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index 3724cb43d8a5..bdced1e42293 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -315,4 +315,6 @@ config FSL_ULI1575
315config CPM 315config CPM
316 bool 316 bool
317 317
318source "arch/powerpc/sysdev/bestcomm/Kconfig"
319
318endmenu 320endmenu
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 1a6f5641ebc8..99a77d743d48 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o
14obj-$(CONFIG_FSL_PCI) += fsl_pci.o 14obj-$(CONFIG_FSL_PCI) += fsl_pci.o
15obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o 15obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
16obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ 16obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
17obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/
17mv64x60-$(CONFIG_PCI) += mv64x60_pci.o 18mv64x60-$(CONFIG_PCI) += mv64x60_pci.o
18obj-$(CONFIG_MV64X60) += $(mv64x60-y) mv64x60_pic.o mv64x60_dev.o \ 19obj-$(CONFIG_MV64X60) += $(mv64x60-y) mv64x60_pic.o mv64x60_dev.o \
19 mv64x60_udbg.o 20 mv64x60_udbg.o
diff --git a/arch/powerpc/sysdev/bestcomm/Kconfig b/arch/powerpc/sysdev/bestcomm/Kconfig
new file mode 100644
index 000000000000..3366e24c10d6
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/Kconfig
@@ -0,0 +1,18 @@
1#
2# Kconfig options for Bestcomm
3#
4
5config PPC_BESTCOMM
6 tristate "Bestcomm DMA engine support"
7 depends on PPC_MPC52xx
8 default n
9 select PPC_LIB_RHEAP
10 help
11 BestComm is the name of the communication coprocessor found
12 on the Freescale MPC5200 family of processor. It's usage is
13 optionnal for some drivers (like ATA), but required for
14 others (like FEC).
15
16 If you want to use drivers that require DMA operations,
17 answer Y or M. Otherwise say N.
18
diff --git a/arch/powerpc/sysdev/bestcomm/Makefile b/arch/powerpc/sysdev/bestcomm/Makefile
new file mode 100644
index 000000000000..a24aa06faaf5
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/Makefile
@@ -0,0 +1,8 @@
1#
2# Makefile for BestComm & co
3#
4
5bestcomm-core-objs := bestcomm.o sram.o
6
7obj-$(CONFIG_PPC_BESTCOMM) += bestcomm-core.o
8
diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.c b/arch/powerpc/sysdev/bestcomm/bestcomm.c
new file mode 100644
index 000000000000..48492a83e5a7
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/bestcomm.c
@@ -0,0 +1,528 @@
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 "sram.h"
27#include "bestcomm_priv.h"
28#include "bestcomm.h"
29
30#define DRIVER_NAME "bestcomm-core"
31
32
33struct bcom_engine *bcom_eng = NULL;
34EXPORT_SYMBOL_GPL(bcom_eng); /* needed for inline functions */
35
36
37/* ======================================================================== */
38/* Public and private API */
39/* ======================================================================== */
40
41/* Private API */
42
43struct bcom_task *
44bcom_task_alloc(int bd_count, int bd_size, int priv_size)
45{
46 int i, tasknum = -1;
47 struct bcom_task *tsk;
48
49 /* Get and reserve a task num */
50 spin_lock(&bcom_eng->lock);
51
52 for (i=0; i<BCOM_MAX_TASKS; i++)
53 if (!bcom_eng->tdt[i].stop) { /* we use stop as a marker */
54 bcom_eng->tdt[i].stop = 0xfffffffful; /* dummy addr */
55 tasknum = i;
56 break;
57 }
58
59 spin_unlock(&bcom_eng->lock);
60
61 if (tasknum < 0)
62 return NULL;
63
64 /* Allocate our structure */
65 tsk = kzalloc(sizeof(struct bcom_task) + priv_size, GFP_KERNEL);
66 if (!tsk)
67 goto error;
68
69 tsk->tasknum = tasknum;
70 if (priv_size)
71 tsk->priv = (void*)tsk + sizeof(struct bcom_task);
72
73 /* Get IRQ of that task */
74 tsk->irq = irq_of_parse_and_map(bcom_eng->ofnode, tsk->tasknum);
75 if (tsk->irq == NO_IRQ)
76 goto error;
77
78 /* Init the BDs, if needed */
79 if (bd_count) {
80 tsk->cookie = kmalloc(sizeof(void*) * bd_count, GFP_KERNEL);
81 if (!tsk->cookie)
82 goto error;
83
84 tsk->bd = bcom_sram_alloc(bd_count * bd_size, 4, &tsk->bd_pa);
85 if (!tsk->bd)
86 goto error;
87 memset(tsk->bd, 0x00, bd_count * bd_size);
88
89 tsk->num_bd = bd_count;
90 tsk->bd_size = bd_size;
91 }
92
93 return tsk;
94
95error:
96 if (tsk) {
97 if (tsk->irq != NO_IRQ)
98 irq_dispose_mapping(tsk->irq);
99 bcom_sram_free(tsk->bd);
100 kfree(tsk->cookie);
101 kfree(tsk);
102 }
103
104 bcom_eng->tdt[tasknum].stop = 0;
105
106 return NULL;
107}
108EXPORT_SYMBOL_GPL(bcom_task_alloc);
109
110void
111bcom_task_free(struct bcom_task *tsk)
112{
113 /* Stop the task */
114 bcom_disable_task(tsk->tasknum);
115
116 /* Clear TDT */
117 bcom_eng->tdt[tsk->tasknum].start = 0;
118 bcom_eng->tdt[tsk->tasknum].stop = 0;
119
120 /* Free everything */
121 irq_dispose_mapping(tsk->irq);
122 bcom_sram_free(tsk->bd);
123 kfree(tsk->cookie);
124 kfree(tsk);
125}
126EXPORT_SYMBOL_GPL(bcom_task_free);
127
128int
129bcom_load_image(int task, u32 *task_image)
130{
131 struct bcom_task_header *hdr = (struct bcom_task_header *)task_image;
132 struct bcom_tdt *tdt;
133 u32 *desc, *var, *inc;
134 u32 *desc_src, *var_src, *inc_src;
135
136 /* Safety checks */
137 if (hdr->magic != BCOM_TASK_MAGIC) {
138 printk(KERN_ERR DRIVER_NAME
139 ": Trying to load invalid microcode\n");
140 return -EINVAL;
141 }
142
143 if ((task < 0) || (task >= BCOM_MAX_TASKS)) {
144 printk(KERN_ERR DRIVER_NAME
145 ": Trying to load invalid task %d\n", task);
146 return -EINVAL;
147 }
148
149 /* Initial load or reload */
150 tdt = &bcom_eng->tdt[task];
151
152 if (tdt->start) {
153 desc = bcom_task_desc(task);
154 if (hdr->desc_size != bcom_task_num_descs(task)) {
155 printk(KERN_ERR DRIVER_NAME
156 ": Trying to reload wrong task image "
157 "(%d size %d/%d)!\n",
158 task,
159 hdr->desc_size,
160 bcom_task_num_descs(task));
161 return -EINVAL;
162 }
163 } else {
164 phys_addr_t start_pa;
165
166 desc = bcom_sram_alloc(hdr->desc_size * sizeof(u32), 4, &start_pa);
167 if (!desc)
168 return -ENOMEM;
169
170 tdt->start = start_pa;
171 tdt->stop = start_pa + ((hdr->desc_size-1) * sizeof(u32));
172 }
173
174 var = bcom_task_var(task);
175 inc = bcom_task_inc(task);
176
177 /* Clear & copy */
178 memset(var, 0x00, BCOM_VAR_SIZE);
179 memset(inc, 0x00, BCOM_INC_SIZE);
180
181 desc_src = (u32 *)(hdr + 1);
182 var_src = desc_src + hdr->desc_size;
183 inc_src = var_src + hdr->var_size;
184
185 memcpy(desc, desc_src, hdr->desc_size * sizeof(u32));
186 memcpy(var + hdr->first_var, var_src, hdr->var_size * sizeof(u32));
187 memcpy(inc, inc_src, hdr->inc_size * sizeof(u32));
188
189 return 0;
190}
191EXPORT_SYMBOL_GPL(bcom_load_image);
192
193void
194bcom_set_initiator(int task, int initiator)
195{
196 int i;
197 int num_descs;
198 u32 *desc;
199 int next_drd_has_initiator;
200
201 bcom_set_tcr_initiator(task, initiator);
202
203 /* Just setting tcr is apparently not enough due to some problem */
204 /* with it. So we just go thru all the microcode and replace in */
205 /* the DRD directly */
206
207 desc = bcom_task_desc(task);
208 next_drd_has_initiator = 1;
209 num_descs = bcom_task_num_descs(task);
210
211 for (i=0; i<num_descs; i++, desc++) {
212 if (!bcom_desc_is_drd(*desc))
213 continue;
214 if (next_drd_has_initiator)
215 if (bcom_desc_initiator(*desc) != BCOM_INITIATOR_ALWAYS)
216 bcom_set_desc_initiator(desc, initiator);
217 next_drd_has_initiator = !bcom_drd_is_extended(*desc);
218 }
219}
220EXPORT_SYMBOL_GPL(bcom_set_initiator);
221
222
223/* Public API */
224
225void
226bcom_enable(struct bcom_task *tsk)
227{
228 bcom_enable_task(tsk->tasknum);
229}
230EXPORT_SYMBOL_GPL(bcom_enable);
231
232void
233bcom_disable(struct bcom_task *tsk)
234{
235 bcom_disable_task(tsk->tasknum);
236}
237EXPORT_SYMBOL_GPL(bcom_disable);
238
239
240/* ======================================================================== */
241/* Engine init/cleanup */
242/* ======================================================================== */
243
244/* Function Descriptor table */
245/* this will need to be updated if Freescale changes their task code FDT */
246static u32 fdt_ops[] = {
247 0xa0045670, /* FDT[48] - load_acc() */
248 0x80045670, /* FDT[49] - unload_acc() */
249 0x21800000, /* FDT[50] - and() */
250 0x21e00000, /* FDT[51] - or() */
251 0x21500000, /* FDT[52] - xor() */
252 0x21400000, /* FDT[53] - andn() */
253 0x21500000, /* FDT[54] - not() */
254 0x20400000, /* FDT[55] - add() */
255 0x20500000, /* FDT[56] - sub() */
256 0x20800000, /* FDT[57] - lsh() */
257 0x20a00000, /* FDT[58] - rsh() */
258 0xc0170000, /* FDT[59] - crc8() */
259 0xc0145670, /* FDT[60] - crc16() */
260 0xc0345670, /* FDT[61] - crc32() */
261 0xa0076540, /* FDT[62] - endian32() */
262 0xa0000760, /* FDT[63] - endian16() */
263};
264
265
266static int __devinit
267bcom_engine_init(void)
268{
269 int task;
270 phys_addr_t tdt_pa, ctx_pa, var_pa, fdt_pa;
271 unsigned int tdt_size, ctx_size, var_size, fdt_size;
272
273 /* Allocate & clear SRAM zones for FDT, TDTs, contexts and vars/incs */
274 tdt_size = BCOM_MAX_TASKS * sizeof(struct bcom_tdt);
275 ctx_size = BCOM_MAX_TASKS * BCOM_CTX_SIZE;
276 var_size = BCOM_MAX_TASKS * (BCOM_VAR_SIZE + BCOM_INC_SIZE);
277 fdt_size = BCOM_FDT_SIZE;
278
279 bcom_eng->tdt = bcom_sram_alloc(tdt_size, sizeof(u32), &tdt_pa);
280 bcom_eng->ctx = bcom_sram_alloc(ctx_size, BCOM_CTX_ALIGN, &ctx_pa);
281 bcom_eng->var = bcom_sram_alloc(var_size, BCOM_VAR_ALIGN, &var_pa);
282 bcom_eng->fdt = bcom_sram_alloc(fdt_size, BCOM_FDT_ALIGN, &fdt_pa);
283
284 if (!bcom_eng->tdt || !bcom_eng->ctx || !bcom_eng->var || !bcom_eng->fdt) {
285 printk(KERN_ERR "DMA: SRAM alloc failed in engine init !\n");
286
287 bcom_sram_free(bcom_eng->tdt);
288 bcom_sram_free(bcom_eng->ctx);
289 bcom_sram_free(bcom_eng->var);
290 bcom_sram_free(bcom_eng->fdt);
291
292 return -ENOMEM;
293 }
294
295 memset(bcom_eng->tdt, 0x00, tdt_size);
296 memset(bcom_eng->ctx, 0x00, ctx_size);
297 memset(bcom_eng->var, 0x00, var_size);
298 memset(bcom_eng->fdt, 0x00, fdt_size);
299
300 /* Copy the FDT for the EU#3 */
301 memcpy(&bcom_eng->fdt[48], fdt_ops, sizeof(fdt_ops));
302
303 /* Initialize Task base structure */
304 for (task=0; task<BCOM_MAX_TASKS; task++)
305 {
306 out_be16(&bcom_eng->regs->tcr[task], 0);
307 out_8(&bcom_eng->regs->ipr[task], 0);
308
309 bcom_eng->tdt[task].context = ctx_pa;
310 bcom_eng->tdt[task].var = var_pa;
311 bcom_eng->tdt[task].fdt = fdt_pa;
312
313 var_pa += BCOM_VAR_SIZE + BCOM_INC_SIZE;
314 ctx_pa += BCOM_CTX_SIZE;
315 }
316
317 out_be32(&bcom_eng->regs->taskBar, tdt_pa);
318
319 /* Init 'always' initiator */
320 out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS);
321
322 /* Disable COMM Bus Prefetch, apparently it's not reliable yet */
323 /* FIXME: This should be done on 5200 and not 5200B ... */
324 out_be16(&bcom_eng->regs->PtdCntrl, in_be16(&bcom_eng->regs->PtdCntrl) | 1);
325
326 /* Init lock */
327 spin_lock_init(&bcom_eng->lock);
328
329 return 0;
330}
331
332static void
333bcom_engine_cleanup(void)
334{
335 int task;
336
337 /* Stop all tasks */
338 for (task=0; task<BCOM_MAX_TASKS; task++)
339 {
340 out_be16(&bcom_eng->regs->tcr[task], 0);
341 out_8(&bcom_eng->regs->ipr[task], 0);
342 }
343
344 out_be32(&bcom_eng->regs->taskBar, 0ul);
345
346 /* Release the SRAM zones */
347 bcom_sram_free(bcom_eng->tdt);
348 bcom_sram_free(bcom_eng->ctx);
349 bcom_sram_free(bcom_eng->var);
350 bcom_sram_free(bcom_eng->fdt);
351}
352
353
354/* ======================================================================== */
355/* OF platform driver */
356/* ======================================================================== */
357
358static int __devinit
359mpc52xx_bcom_probe(struct of_device *op, const struct of_device_id *match)
360{
361 struct device_node *ofn_sram;
362 struct resource res_bcom;
363
364 int rv;
365
366 /* Inform user we're ok so far */
367 printk(KERN_INFO "DMA: MPC52xx BestComm driver\n");
368
369 /* Get the bestcomm node */
370 of_node_get(op->node);
371
372 /* Prepare SRAM */
373 ofn_sram = of_find_compatible_node(NULL, "sram", "mpc5200-sram");
374 if (!ofn_sram) {
375 printk(KERN_ERR DRIVER_NAME ": "
376 "No SRAM found in device tree\n");
377 rv = -ENODEV;
378 goto error_ofput;
379 }
380 rv = bcom_sram_init(ofn_sram, DRIVER_NAME);
381 of_node_put(ofn_sram);
382
383 if (rv) {
384 printk(KERN_ERR DRIVER_NAME ": "
385 "Error in SRAM init\n");
386 goto error_ofput;
387 }
388
389 /* Get a clean struct */
390 bcom_eng = kzalloc(sizeof(struct bcom_engine), GFP_KERNEL);
391 if (!bcom_eng) {
392 printk(KERN_ERR DRIVER_NAME ": "
393 "Can't allocate state structure\n");
394 rv = -ENOMEM;
395 goto error_sramclean;
396 }
397
398 /* Save the node */
399 bcom_eng->ofnode = op->node;
400
401 /* Get, reserve & map io */
402 if (of_address_to_resource(op->node, 0, &res_bcom)) {
403 printk(KERN_ERR DRIVER_NAME ": "
404 "Can't get resource\n");
405 rv = -EINVAL;
406 goto error_sramclean;
407 }
408
409 if (!request_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma),
410 DRIVER_NAME)) {
411 printk(KERN_ERR DRIVER_NAME ": "
412 "Can't request registers region\n");
413 rv = -EBUSY;
414 goto error_sramclean;
415 }
416
417 bcom_eng->regs_base = res_bcom.start;
418 bcom_eng->regs = ioremap(res_bcom.start, sizeof(struct mpc52xx_sdma));
419 if (!bcom_eng->regs) {
420 printk(KERN_ERR DRIVER_NAME ": "
421 "Can't map registers\n");
422 rv = -ENOMEM;
423 goto error_release;
424 }
425
426 /* Now, do the real init */
427 rv = bcom_engine_init();
428 if (rv)
429 goto error_unmap;
430
431 /* Done ! */
432 printk(KERN_INFO "DMA: MPC52xx BestComm engine @%08lx ok !\n",
433 bcom_eng->regs_base);
434
435 return 0;
436
437 /* Error path */
438error_unmap:
439 iounmap(bcom_eng->regs);
440error_release:
441 release_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma));
442error_sramclean:
443 kfree(bcom_eng);
444 bcom_sram_cleanup();
445error_ofput:
446 of_node_put(op->node);
447
448 printk(KERN_ERR "DMA: MPC52xx BestComm init failed !\n");
449
450 return rv;
451}
452
453
454static int
455mpc52xx_bcom_remove(struct of_device *op)
456{
457 /* Clean up the engine */
458 bcom_engine_cleanup();
459
460 /* Cleanup SRAM */
461 bcom_sram_cleanup();
462
463 /* Release regs */
464 iounmap(bcom_eng->regs);
465 release_mem_region(bcom_eng->regs_base, sizeof(struct mpc52xx_sdma));
466
467 /* Release the node */
468 of_node_put(bcom_eng->ofnode);
469
470 /* Release memory */
471 kfree(bcom_eng);
472 bcom_eng = NULL;
473
474 return 0;
475}
476
477static struct of_device_id mpc52xx_bcom_of_match[] = {
478 {
479 .type = "dma-controller",
480 .compatible = "mpc5200-bestcomm",
481 },
482 {},
483};
484
485MODULE_DEVICE_TABLE(of, mpc52xx_bcom_of_match);
486
487
488static struct of_platform_driver mpc52xx_bcom_of_platform_driver = {
489 .owner = THIS_MODULE,
490 .name = DRIVER_NAME,
491 .match_table = mpc52xx_bcom_of_match,
492 .probe = mpc52xx_bcom_probe,
493 .remove = mpc52xx_bcom_remove,
494 .driver = {
495 .name = DRIVER_NAME,
496 .owner = THIS_MODULE,
497 },
498};
499
500
501/* ======================================================================== */
502/* Module */
503/* ======================================================================== */
504
505static int __init
506mpc52xx_bcom_init(void)
507{
508 return of_register_platform_driver(&mpc52xx_bcom_of_platform_driver);
509}
510
511static void __exit
512mpc52xx_bcom_exit(void)
513{
514 of_unregister_platform_driver(&mpc52xx_bcom_of_platform_driver);
515}
516
517/* If we're not a module, we must make sure everything is setup before */
518/* anyone tries to use us ... that's why we use subsys_initcall instead */
519/* of module_init. */
520subsys_initcall(mpc52xx_bcom_init);
521module_exit(mpc52xx_bcom_exit);
522
523MODULE_DESCRIPTION("Freescale MPC52xx BestComm DMA");
524MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
525MODULE_AUTHOR("Andrey Volkov <avolkov@varma-el.com>");
526MODULE_AUTHOR("Dale Farnsworth <dfarnsworth@mvista.com>");
527MODULE_LICENSE("GPL v2");
528
diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.h b/arch/powerpc/sysdev/bestcomm/bestcomm.h
new file mode 100644
index 000000000000..e802cb4eb69a
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/bestcomm.h
@@ -0,0 +1,190 @@
1/*
2 * Public header for the MPC52xx processor BestComm driver
3 *
4 *
5 * Copyright (C) 2006 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#ifndef __BESTCOMM_H__
17#define __BESTCOMM_H__
18
19struct bcom_bd; /* defined later on ... */
20
21
22/* ======================================================================== */
23/* Generic task managment */
24/* ======================================================================== */
25
26/**
27 * struct bcom_task - Structure describing a loaded BestComm task
28 *
29 * This structure is never built by the driver it self. It's built and
30 * filled the intermediate layer of the BestComm API, the task dependent
31 * support code.
32 *
33 * Most likely you don't need to poke around inside this structure. The
34 * fields are exposed in the header just for the sake of inline functions
35 */
36struct bcom_task {
37 unsigned int tasknum;
38 unsigned int flags;
39 int irq;
40
41 struct bcom_bd *bd;
42 phys_addr_t bd_pa;
43 void **cookie;
44 unsigned short index;
45 unsigned short outdex;
46 unsigned int num_bd;
47 unsigned int bd_size;
48
49 void* priv;
50};
51
52#define BCOM_FLAGS_NONE 0x00000000ul
53#define BCOM_FLAGS_ENABLE_TASK (1ul << 0)
54
55/**
56 * bcom_enable - Enable a BestComm task
57 * @tsk: The BestComm task structure
58 *
59 * This function makes sure the given task is enabled and can be run
60 * by the BestComm engine as needed
61 */
62extern void bcom_enable(struct bcom_task *tsk);
63
64/**
65 * bcom_disable - Disable a BestComm task
66 * @tsk: The BestComm task structure
67 *
68 * This function disable a given task, making sure it's not executed
69 * by the BestComm engine.
70 */
71extern void bcom_disable(struct bcom_task *tsk);
72
73
74/**
75 * bcom_get_task_irq - Returns the irq number of a BestComm task
76 * @tsk: The BestComm task structure
77 */
78static inline int
79bcom_get_task_irq(struct bcom_task *tsk) {
80 return tsk->irq;
81}
82
83/* ======================================================================== */
84/* BD based tasks helpers */
85/* ======================================================================== */
86
87/**
88 * struct bcom_bd - Structure describing a generic BestComm buffer descriptor
89 * @status: The current status of this buffer. Exact meaning depends on the
90 * task type
91 * @data: An array of u32 whose meaning depends on the task type.
92 */
93struct bcom_bd {
94 u32 status;
95 u32 data[1]; /* variable, but at least 1 */
96};
97
98#define BCOM_BD_READY 0x40000000ul
99
100/** _bcom_next_index - Get next input index.
101 * @tsk: pointer to task structure
102 *
103 * Support function; Device drivers should not call this
104 */
105static inline int
106_bcom_next_index(struct bcom_task *tsk)
107{
108 return ((tsk->index + 1) == tsk->num_bd) ? 0 : tsk->index + 1;
109}
110
111/** _bcom_next_outdex - Get next output index.
112 * @tsk: pointer to task structure
113 *
114 * Support function; Device drivers should not call this
115 */
116static inline int
117_bcom_next_outdex(struct bcom_task *tsk)
118{
119 return ((tsk->outdex + 1) == tsk->num_bd) ? 0 : tsk->outdex + 1;
120}
121
122/**
123 * bcom_queue_empty - Checks if a BestComm task BD queue is empty
124 * @tsk: The BestComm task structure
125 */
126static inline int
127bcom_queue_empty(struct bcom_task *tsk)
128{
129 return tsk->index == tsk->outdex;
130}
131
132/**
133 * bcom_queue_full - Checks if a BestComm task BD queue is full
134 * @tsk: The BestComm task structure
135 */
136static inline int
137bcom_queue_full(struct bcom_task *tsk)
138{
139 return tsk->outdex == _bcom_next_index(tsk);
140}
141
142/**
143 * bcom_buffer_done - Checks if a BestComm
144 * @tsk: The BestComm task structure
145 */
146static inline int
147bcom_buffer_done(struct bcom_task *tsk)
148{
149 if (bcom_queue_empty(tsk))
150 return 0;
151 return !(tsk->bd[tsk->outdex].status & BCOM_BD_READY);
152}
153
154/**
155 * bcom_prepare_next_buffer - clear status of next available buffer.
156 * @tsk: The BestComm task structure
157 *
158 * Returns pointer to next buffer descriptor
159 */
160static inline struct bcom_bd *
161bcom_prepare_next_buffer(struct bcom_task *tsk)
162{
163 tsk->bd[tsk->index].status = 0; /* cleanup last status */
164 return &tsk->bd[tsk->index];
165}
166
167static inline void
168bcom_submit_next_buffer(struct bcom_task *tsk, void *cookie)
169{
170 tsk->cookie[tsk->index] = cookie;
171 mb(); /* ensure the bd is really up-to-date */
172 tsk->bd[tsk->index].status |= BCOM_BD_READY;
173 tsk->index = _bcom_next_index(tsk);
174 if (tsk->flags & BCOM_FLAGS_ENABLE_TASK)
175 bcom_enable(tsk);
176}
177
178static inline void *
179bcom_retrieve_buffer(struct bcom_task *tsk, u32 *p_status, struct bcom_bd **p_bd)
180{
181 void *cookie = tsk->cookie[tsk->outdex];
182 if (p_status)
183 *p_status = tsk->bd[tsk->outdex].status;
184 if (p_bd)
185 *p_bd = &tsk->bd[tsk->outdex];
186 tsk->outdex = _bcom_next_outdex(tsk);
187 return cookie;
188}
189
190#endif /* __BESTCOMM_H__ */
diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h b/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h
new file mode 100644
index 000000000000..866a2915ef2f
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h
@@ -0,0 +1,334 @@
1/*
2 * Private header for the MPC52xx processor BestComm driver
3 *
4 * By private, we mean that driver should not use it directly. It's meant
5 * to be used by the BestComm engine driver itself and by the intermediate
6 * layer between the core and the drivers.
7 *
8 * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com>
9 * Copyright (C) 2005 Varma Electronics Oy,
10 * ( by Andrey Volkov <avolkov@varma-el.com> )
11 * Copyright (C) 2003-2004 MontaVista, Software, Inc.
12 * ( by Dale Farnsworth <dfarnsworth@mvista.com> )
13 *
14 * This file is licensed under the terms of the GNU General Public License
15 * version 2. This program is licensed "as is" without any warranty of any
16 * kind, whether express or implied.
17 */
18
19#ifndef __BESTCOMM_PRIV_H__
20#define __BESTCOMM_PRIV_H__
21
22#include <linux/spinlock.h>
23#include <linux/of.h>
24#include <asm/io.h>
25#include <asm/mpc52xx.h>
26
27#include "sram.h"
28
29
30/* ======================================================================== */
31/* Engine related stuff */
32/* ======================================================================== */
33
34/* Zones sizes and needed alignments */
35#define BCOM_MAX_TASKS 16
36#define BCOM_MAX_VAR 24
37#define BCOM_MAX_INC 8
38#define BCOM_MAX_FDT 64
39#define BCOM_MAX_CTX 20
40#define BCOM_CTX_SIZE (BCOM_MAX_CTX * sizeof(u32))
41#define BCOM_CTX_ALIGN 0x100
42#define BCOM_VAR_SIZE (BCOM_MAX_VAR * sizeof(u32))
43#define BCOM_INC_SIZE (BCOM_MAX_INC * sizeof(u32))
44#define BCOM_VAR_ALIGN 0x80
45#define BCOM_FDT_SIZE (BCOM_MAX_FDT * sizeof(u32))
46#define BCOM_FDT_ALIGN 0x100
47
48/**
49 * struct bcom_tdt - Task Descriptor Table Entry
50 *
51 */
52struct bcom_tdt {
53 u32 start;
54 u32 stop;
55 u32 var;
56 u32 fdt;
57 u32 exec_status; /* used internally by BestComm engine */
58 u32 mvtp; /* used internally by BestComm engine */
59 u32 context;
60 u32 litbase;
61};
62
63/**
64 * struct bcom_engine
65 *
66 * This holds all info needed globaly to handle the engine
67 */
68struct bcom_engine {
69 struct device_node *ofnode;
70 struct mpc52xx_sdma __iomem *regs;
71 phys_addr_t regs_base;
72
73 struct bcom_tdt *tdt;
74 u32 *ctx;
75 u32 *var;
76 u32 *fdt;
77
78 spinlock_t lock;
79};
80
81extern struct bcom_engine *bcom_eng;
82
83
84/* ======================================================================== */
85/* Tasks related stuff */
86/* ======================================================================== */
87
88/* Tasks image header */
89#define BCOM_TASK_MAGIC 0x4243544B /* 'BCTK' */
90
91struct bcom_task_header {
92 u32 magic;
93 u8 desc_size; /* the size fields */
94 u8 var_size; /* are given in number */
95 u8 inc_size; /* of 32-bits words */
96 u8 first_var;
97 u8 reserved[8];
98};
99
100/* Descriptors stucture & co */
101#define BCOM_DESC_NOP 0x000001f8
102#define BCOM_LCD_MASK 0x80000000
103#define BCOM_DRD_EXTENDED 0x40000000
104#define BCOM_DRD_INITIATOR_SHIFT 21
105
106/* Tasks pragma */
107#define BCOM_PRAGMA_BIT_RSV 7 /* reserved pragma bit */
108#define BCOM_PRAGMA_BIT_PRECISE_INC 6 /* increment 0=when possible, */
109 /* 1=iter end */
110#define BCOM_PRAGMA_BIT_RST_ERROR_NO 5 /* don't reset errors on */
111 /* task enable */
112#define BCOM_PRAGMA_BIT_PACK 4 /* pack data enable */
113#define BCOM_PRAGMA_BIT_INTEGER 3 /* data alignment */
114 /* 0=frac(msb), 1=int(lsb) */
115#define BCOM_PRAGMA_BIT_SPECREAD 2 /* XLB speculative read */
116#define BCOM_PRAGMA_BIT_CW 1 /* write line buffer enable */
117#define BCOM_PRAGMA_BIT_RL 0 /* read line buffer enable */
118
119 /* Looks like XLB speculative read generates XLB errors when a buffer
120 * is at the end of the physical memory. i.e. when accessing the
121 * lasts words, the engine tries to prefetch the next but there is no
122 * next ...
123 */
124#define BCOM_STD_PRAGMA ((0 << BCOM_PRAGMA_BIT_RSV) | \
125 (0 << BCOM_PRAGMA_BIT_PRECISE_INC) | \
126 (0 << BCOM_PRAGMA_BIT_RST_ERROR_NO) | \
127 (0 << BCOM_PRAGMA_BIT_PACK) | \
128 (0 << BCOM_PRAGMA_BIT_INTEGER) | \
129 (0 << BCOM_PRAGMA_BIT_SPECREAD) | \
130 (1 << BCOM_PRAGMA_BIT_CW) | \
131 (1 << BCOM_PRAGMA_BIT_RL))
132
133#define BCOM_PCI_PRAGMA ((0 << BCOM_PRAGMA_BIT_RSV) | \
134 (0 << BCOM_PRAGMA_BIT_PRECISE_INC) | \
135 (0 << BCOM_PRAGMA_BIT_RST_ERROR_NO) | \
136 (0 << BCOM_PRAGMA_BIT_PACK) | \
137 (1 << BCOM_PRAGMA_BIT_INTEGER) | \
138 (0 << BCOM_PRAGMA_BIT_SPECREAD) | \
139 (1 << BCOM_PRAGMA_BIT_CW) | \
140 (1 << BCOM_PRAGMA_BIT_RL))
141
142#define BCOM_ATA_PRAGMA BCOM_STD_PRAGMA
143#define BCOM_CRC16_DP_0_PRAGMA BCOM_STD_PRAGMA
144#define BCOM_CRC16_DP_1_PRAGMA BCOM_STD_PRAGMA
145#define BCOM_FEC_RX_BD_PRAGMA BCOM_STD_PRAGMA
146#define BCOM_FEC_TX_BD_PRAGMA BCOM_STD_PRAGMA
147#define BCOM_GEN_DP_0_PRAGMA BCOM_STD_PRAGMA
148#define BCOM_GEN_DP_1_PRAGMA BCOM_STD_PRAGMA
149#define BCOM_GEN_DP_2_PRAGMA BCOM_STD_PRAGMA
150#define BCOM_GEN_DP_3_PRAGMA BCOM_STD_PRAGMA
151#define BCOM_GEN_DP_BD_0_PRAGMA BCOM_STD_PRAGMA
152#define BCOM_GEN_DP_BD_1_PRAGMA BCOM_STD_PRAGMA
153#define BCOM_GEN_RX_BD_PRAGMA BCOM_STD_PRAGMA
154#define BCOM_GEN_TX_BD_PRAGMA BCOM_STD_PRAGMA
155#define BCOM_GEN_LPC_PRAGMA BCOM_STD_PRAGMA
156#define BCOM_PCI_RX_PRAGMA BCOM_PCI_PRAGMA
157#define BCOM_PCI_TX_PRAGMA BCOM_PCI_PRAGMA
158
159/* Initiators number */
160#define BCOM_INITIATOR_ALWAYS 0
161#define BCOM_INITIATOR_SCTMR_0 1
162#define BCOM_INITIATOR_SCTMR_1 2
163#define BCOM_INITIATOR_FEC_RX 3
164#define BCOM_INITIATOR_FEC_TX 4
165#define BCOM_INITIATOR_ATA_RX 5
166#define BCOM_INITIATOR_ATA_TX 6
167#define BCOM_INITIATOR_SCPCI_RX 7
168#define BCOM_INITIATOR_SCPCI_TX 8
169#define BCOM_INITIATOR_PSC3_RX 9
170#define BCOM_INITIATOR_PSC3_TX 10
171#define BCOM_INITIATOR_PSC2_RX 11
172#define BCOM_INITIATOR_PSC2_TX 12
173#define BCOM_INITIATOR_PSC1_RX 13
174#define BCOM_INITIATOR_PSC1_TX 14
175#define BCOM_INITIATOR_SCTMR_2 15
176#define BCOM_INITIATOR_SCLPC 16
177#define BCOM_INITIATOR_PSC5_RX 17
178#define BCOM_INITIATOR_PSC5_TX 18
179#define BCOM_INITIATOR_PSC4_RX 19
180#define BCOM_INITIATOR_PSC4_TX 20
181#define BCOM_INITIATOR_I2C2_RX 21
182#define BCOM_INITIATOR_I2C2_TX 22
183#define BCOM_INITIATOR_I2C1_RX 23
184#define BCOM_INITIATOR_I2C1_TX 24
185#define BCOM_INITIATOR_PSC6_RX 25
186#define BCOM_INITIATOR_PSC6_TX 26
187#define BCOM_INITIATOR_IRDA_RX 25
188#define BCOM_INITIATOR_IRDA_TX 26
189#define BCOM_INITIATOR_SCTMR_3 27
190#define BCOM_INITIATOR_SCTMR_4 28
191#define BCOM_INITIATOR_SCTMR_5 29
192#define BCOM_INITIATOR_SCTMR_6 30
193#define BCOM_INITIATOR_SCTMR_7 31
194
195/* Initiators priorities */
196#define BCOM_IPR_ALWAYS 7
197#define BCOM_IPR_SCTMR_0 2
198#define BCOM_IPR_SCTMR_1 2
199#define BCOM_IPR_FEC_RX 6
200#define BCOM_IPR_FEC_TX 5
201#define BCOM_IPR_ATA_RX 4
202#define BCOM_IPR_ATA_TX 3
203#define BCOM_IPR_SCPCI_RX 2
204#define BCOM_IPR_SCPCI_TX 2
205#define BCOM_IPR_PSC3_RX 2
206#define BCOM_IPR_PSC3_TX 2
207#define BCOM_IPR_PSC2_RX 2
208#define BCOM_IPR_PSC2_TX 2
209#define BCOM_IPR_PSC1_RX 2
210#define BCOM_IPR_PSC1_TX 2
211#define BCOM_IPR_SCTMR_2 2
212#define BCOM_IPR_SCLPC 2
213#define BCOM_IPR_PSC5_RX 2
214#define BCOM_IPR_PSC5_TX 2
215#define BCOM_IPR_PSC4_RX 2
216#define BCOM_IPR_PSC4_TX 2
217#define BCOM_IPR_I2C2_RX 2
218#define BCOM_IPR_I2C2_TX 2
219#define BCOM_IPR_I2C1_RX 2
220#define BCOM_IPR_I2C1_TX 2
221#define BCOM_IPR_PSC6_RX 2
222#define BCOM_IPR_PSC6_TX 2
223#define BCOM_IPR_IRDA_RX 2
224#define BCOM_IPR_IRDA_TX 2
225#define BCOM_IPR_SCTMR_3 2
226#define BCOM_IPR_SCTMR_4 2
227#define BCOM_IPR_SCTMR_5 2
228#define BCOM_IPR_SCTMR_6 2
229#define BCOM_IPR_SCTMR_7 2
230
231
232/* ======================================================================== */
233/* API */
234/* ======================================================================== */
235
236extern struct bcom_task *bcom_task_alloc(int bd_count, int bd_size, int priv_size);
237extern void bcom_task_free(struct bcom_task *tsk);
238extern int bcom_load_image(int task, u32 *task_image);
239extern void bcom_set_initiator(int task, int initiator);
240
241
242#define TASK_ENABLE 0x8000
243
244static inline void
245bcom_enable_task(int task)
246{
247 u16 reg;
248 reg = in_be16(&bcom_eng->regs->tcr[task]);
249 out_be16(&bcom_eng->regs->tcr[task], reg | TASK_ENABLE);
250}
251
252static inline void
253bcom_disable_task(int task)
254{
255 u16 reg = in_be16(&bcom_eng->regs->tcr[task]);
256 out_be16(&bcom_eng->regs->tcr[task], reg & ~TASK_ENABLE);
257}
258
259
260static inline u32 *
261bcom_task_desc(int task)
262{
263 return bcom_sram_pa2va(bcom_eng->tdt[task].start);
264}
265
266static inline int
267bcom_task_num_descs(int task)
268{
269 return (bcom_eng->tdt[task].stop - bcom_eng->tdt[task].start)/sizeof(u32) + 1;
270}
271
272static inline u32 *
273bcom_task_var(int task)
274{
275 return bcom_sram_pa2va(bcom_eng->tdt[task].var);
276}
277
278static inline u32 *
279bcom_task_inc(int task)
280{
281 return &bcom_task_var(task)[BCOM_MAX_VAR];
282}
283
284
285static inline int
286bcom_drd_is_extended(u32 desc)
287{
288 return (desc) & BCOM_DRD_EXTENDED;
289}
290
291static inline int
292bcom_desc_is_drd(u32 desc)
293{
294 return !(desc & BCOM_LCD_MASK) && desc != BCOM_DESC_NOP;
295}
296
297static inline int
298bcom_desc_initiator(u32 desc)
299{
300 return (desc >> BCOM_DRD_INITIATOR_SHIFT) & 0x1f;
301}
302
303static inline void
304bcom_set_desc_initiator(u32 *desc, int initiator)
305{
306 *desc = (*desc & ~(0x1f << BCOM_DRD_INITIATOR_SHIFT)) |
307 ((initiator & 0x1f) << BCOM_DRD_INITIATOR_SHIFT);
308}
309
310
311static inline void
312bcom_set_task_pragma(int task, int pragma)
313{
314 u32 *fdt = &bcom_eng->tdt[task].fdt;
315 *fdt = (*fdt & ~0xff) | pragma;
316}
317
318static inline void
319bcom_set_task_auto_start(int task, int next_task)
320{
321 u16 __iomem *tcr = &bcom_eng->regs->tcr[task];
322 out_be16(tcr, (in_be16(tcr) & ~0xff) | 0x00c0 | next_task);
323}
324
325static inline void
326bcom_set_tcr_initiator(int task, int initiator)
327{
328 u16 __iomem *tcr = &bcom_eng->regs->tcr[task];
329 out_be16(tcr, (in_be16(tcr) & ~0x1f00) | ((initiator & 0x1f) << 8));
330}
331
332
333#endif /* __BESTCOMM_PRIV_H__ */
334
diff --git a/arch/powerpc/sysdev/bestcomm/sram.c b/arch/powerpc/sysdev/bestcomm/sram.c
new file mode 100644
index 000000000000..99784383a843
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/sram.c
@@ -0,0 +1,177 @@
1/*
2 * Simple memory allocator for on-board SRAM
3 *
4 *
5 * Maintainer : Sylvain Munaut <tnt@246tNt.com>
6 *
7 * Copyright (C) 2005 Sylvain Munaut <tnt@246tNt.com>
8 *
9 * This file is licensed under the terms of the GNU General Public License
10 * version 2. This program is licensed "as is" without any warranty of any
11 * kind, whether express or implied.
12 */
13
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/slab.h>
17#include <linux/spinlock.h>
18#include <linux/string.h>
19#include <linux/ioport.h>
20#include <linux/of.h>
21
22#include <asm/io.h>
23#include <asm/mmu.h>
24
25#include "sram.h"
26
27
28/* Struct keeping our 'state' */
29struct bcom_sram *bcom_sram = NULL;
30EXPORT_SYMBOL_GPL(bcom_sram); /* needed for inline functions */
31
32
33/* ======================================================================== */
34/* Public API */
35/* ======================================================================== */
36/* DO NOT USE in interrupts, if needed in irq handler, we should use the
37 _irqsave version of the spin_locks */
38
39int bcom_sram_init(struct device_node *sram_node, char *owner)
40{
41 int rv;
42 const u32 *regaddr_p;
43 u64 regaddr64, size64;
44 unsigned int psize;
45
46 /* Create our state struct */
47 if (bcom_sram) {
48 printk(KERN_ERR "%s: bcom_sram_init: "
49 "Already initialized !\n", owner);
50 return -EBUSY;
51 }
52
53 bcom_sram = kmalloc(sizeof(struct bcom_sram), GFP_KERNEL);
54 if (!bcom_sram) {
55 printk(KERN_ERR "%s: bcom_sram_init: "
56 "Couldn't allocate internal state !\n", owner);
57 return -ENOMEM;
58 }
59
60 /* Get address and size of the sram */
61 regaddr_p = of_get_address(sram_node, 0, &size64, NULL);
62 if (!regaddr_p) {
63 printk(KERN_ERR "%s: bcom_sram_init: "
64 "Invalid device node !\n", owner);
65 rv = -EINVAL;
66 goto error_free;
67 }
68
69 regaddr64 = of_translate_address(sram_node, regaddr_p);
70
71 bcom_sram->base_phys = (phys_addr_t) regaddr64;
72 bcom_sram->size = (unsigned int) size64;
73
74 /* Request region */
75 if (!request_mem_region(bcom_sram->base_phys, bcom_sram->size, owner)) {
76 printk(KERN_ERR "%s: bcom_sram_init: "
77 "Couldn't request region !\n", owner);
78 rv = -EBUSY;
79 goto error_free;
80 }
81
82 /* Map SRAM */
83 /* sram is not really __iomem */
84 bcom_sram->base_virt = (void*) ioremap(bcom_sram->base_phys, bcom_sram->size);
85
86 if (!bcom_sram->base_virt) {
87 printk(KERN_ERR "%s: bcom_sram_init: "
88 "Map error SRAM zone 0x%08lx (0x%0x)!\n",
89 owner, bcom_sram->base_phys, bcom_sram->size );
90 rv = -ENOMEM;
91 goto error_release;
92 }
93
94 /* Create an rheap (defaults to 32 bits word alignment) */
95 bcom_sram->rh = rh_create(4);
96
97 /* Attach the free zones */
98#if 0
99 /* Currently disabled ... for future use only */
100 reg_addr_p = of_get_property(sram_node, "available", &psize);
101#else
102 regaddr_p = NULL;
103 psize = 0;
104#endif
105
106 if (!regaddr_p || !psize) {
107 /* Attach the whole zone */
108 rh_attach_region(bcom_sram->rh, 0, bcom_sram->size);
109 } else {
110 /* Attach each zone independently */
111 while (psize >= 2 * sizeof(u32)) {
112 phys_addr_t zbase = of_translate_address(sram_node, regaddr_p);
113 rh_attach_region(bcom_sram->rh, zbase - bcom_sram->base_phys, regaddr_p[1]);
114 regaddr_p += 2;
115 psize -= 2 * sizeof(u32);
116 }
117 }
118
119 /* Init our spinlock */
120 spin_lock_init(&bcom_sram->lock);
121
122 return 0;
123
124error_release:
125 release_mem_region(bcom_sram->base_phys, bcom_sram->size);
126error_free:
127 kfree(bcom_sram);
128 bcom_sram = NULL;
129
130 return rv;
131}
132EXPORT_SYMBOL_GPL(bcom_sram_init);
133
134void bcom_sram_cleanup(void)
135{
136 /* Free resources */
137 if (bcom_sram) {
138 rh_destroy(bcom_sram->rh);
139 iounmap((void __iomem *)bcom_sram->base_virt);
140 release_mem_region(bcom_sram->base_phys, bcom_sram->size);
141 kfree(bcom_sram);
142 bcom_sram = NULL;
143 }
144}
145EXPORT_SYMBOL_GPL(bcom_sram_cleanup);
146
147void* bcom_sram_alloc(int size, int align, phys_addr_t *phys)
148{
149 unsigned long offset;
150
151 spin_lock(&bcom_sram->lock);
152 offset = rh_alloc_align(bcom_sram->rh, size, align, NULL);
153 spin_unlock(&bcom_sram->lock);
154
155 if (IS_ERR_VALUE(offset))
156 return NULL;
157
158 *phys = bcom_sram->base_phys + offset;
159 return bcom_sram->base_virt + offset;
160}
161EXPORT_SYMBOL_GPL(bcom_sram_alloc);
162
163void bcom_sram_free(void *ptr)
164{
165 unsigned long offset;
166
167 if (!ptr)
168 return;
169
170 offset = ptr - bcom_sram->base_virt;
171
172 spin_lock(&bcom_sram->lock);
173 rh_free(bcom_sram->rh, offset);
174 spin_unlock(&bcom_sram->lock);
175}
176EXPORT_SYMBOL_GPL(bcom_sram_free);
177
diff --git a/arch/powerpc/sysdev/bestcomm/sram.h b/arch/powerpc/sysdev/bestcomm/sram.h
new file mode 100644
index 000000000000..b6d668963cce
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/sram.h
@@ -0,0 +1,54 @@
1/*
2 * Handling of a sram zone for bestcomm
3 *
4 *
5 * Copyright (C) 2007 Sylvain Munaut <tnt@246tNt.com>
6 *
7 * This file is licensed under the terms of the GNU General Public License
8 * version 2. This program is licensed "as is" without any warranty of any
9 * kind, whether express or implied.
10 */
11
12#ifndef __BESTCOMM_SRAM_H__
13#define __BESTCOMM_SRAM_H__
14
15#include <asm/rheap.h>
16#include <asm/mmu.h>
17#include <linux/spinlock.h>
18
19
20/* Structure used internally */
21 /* The internals are here for the inline functions
22 * sake, certainly not for the user to mess with !
23 */
24struct bcom_sram {
25 phys_addr_t base_phys;
26 void *base_virt;
27 unsigned int size;
28 rh_info_t *rh;
29 spinlock_t lock;
30};
31
32extern struct bcom_sram *bcom_sram;
33
34
35/* Public API */
36extern int bcom_sram_init(struct device_node *sram_node, char *owner);
37extern void bcom_sram_cleanup(void);
38
39extern void* bcom_sram_alloc(int size, int align, phys_addr_t *phys);
40extern void bcom_sram_free(void *ptr);
41
42static inline phys_addr_t bcom_sram_va2pa(void *va) {
43 return bcom_sram->base_phys +
44 (unsigned long)(va - bcom_sram->base_virt);
45}
46
47static inline void *bcom_sram_pa2va(phys_addr_t pa) {
48 return bcom_sram->base_virt +
49 (unsigned long)(pa - bcom_sram->base_phys);
50}
51
52
53#endif /* __BESTCOMM_SRAM_H__ */
54