aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2007-10-17 08:31:13 -0400
committerPaul Mackerras <paulus@samba.org>2007-10-17 08:31:13 -0400
commit4acadb965c4aa587aac29a0a91203c4745d6fb4e (patch)
treed2284b40a6b8948947890e1ca33ae23545b6e5a7 /arch/powerpc
parent5cae826e9e54a31f06b4c11b73f4af29e2ea4932 (diff)
parentb147d93d62d161559a49e0108767122caa4d2576 (diff)
Merge branch 'for-2.6.24' of git://git.secretlab.ca/git/linux-2.6-mpc52xx into merge
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/Kconfig4
-rw-r--r--arch/powerpc/boot/dts/lite5200b.dts18
-rw-r--r--arch/powerpc/lib/Makefile5
-rw-r--r--arch/powerpc/lib/rheap.c15
-rw-r--r--arch/powerpc/platforms/Kconfig4
-rw-r--r--arch/powerpc/platforms/Kconfig.cputype1
-rw-r--r--arch/powerpc/sysdev/Makefile1
-rw-r--r--arch/powerpc/sysdev/bestcomm/Kconfig39
-rw-r--r--arch/powerpc/sysdev/bestcomm/Makefile14
-rw-r--r--arch/powerpc/sysdev/bestcomm/ata.c154
-rw-r--r--arch/powerpc/sysdev/bestcomm/ata.h37
-rw-r--r--arch/powerpc/sysdev/bestcomm/bcom_ata_task.c67
-rw-r--r--arch/powerpc/sysdev/bestcomm/bcom_fec_rx_task.c78
-rw-r--r--arch/powerpc/sysdev/bestcomm/bcom_fec_tx_task.c91
-rw-r--r--arch/powerpc/sysdev/bestcomm/bcom_gen_bd_rx_task.c63
-rw-r--r--arch/powerpc/sysdev/bestcomm/bcom_gen_bd_tx_task.c69
-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/fec.c270
-rw-r--r--arch/powerpc/sysdev/bestcomm/fec.h61
-rw-r--r--arch/powerpc/sysdev/bestcomm/gen_bd.c260
-rw-r--r--arch/powerpc/sysdev/bestcomm/gen_bd.h48
-rw-r--r--arch/powerpc/sysdev/bestcomm/sram.c177
-rw-r--r--arch/powerpc/sysdev/bestcomm/sram.h54
25 files changed, 2577 insertions, 5 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 5e001ad588a7..5624fb060d9d 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -699,3 +699,7 @@ source "crypto/Kconfig"
699config PPC_CLOCK 699config PPC_CLOCK
700 bool 700 bool
701 default n 701 default n
702
703config PPC_LIB_RHEAP
704 bool
705
diff --git a/arch/powerpc/boot/dts/lite5200b.dts b/arch/powerpc/boot/dts/lite5200b.dts
index a6bb1d0558ef..6582c9a39b27 100644
--- a/arch/powerpc/boot/dts/lite5200b.dts
+++ b/arch/powerpc/boot/dts/lite5200b.dts
@@ -277,10 +277,26 @@
277 ethernet@3000 { 277 ethernet@3000 {
278 device_type = "network"; 278 device_type = "network";
279 compatible = "mpc5200b-fec","mpc5200-fec"; 279 compatible = "mpc5200b-fec","mpc5200-fec";
280 reg = <3000 800>; 280 reg = <3000 400>;
281 mac-address = [ 02 03 04 05 06 07 ]; // Bad! 281 mac-address = [ 02 03 04 05 06 07 ]; // Bad!
282 interrupts = <2 5 0>; 282 interrupts = <2 5 0>;
283 interrupt-parent = <&mpc5200_pic>; 283 interrupt-parent = <&mpc5200_pic>;
284 phy-handle = <&phy0>;
285 };
286
287 mdio@3000 {
288 #address-cells = <1>;
289 #size-cells = <0>;
290 device_type = "mdio";
291 compatible = "mpc5200b-fec-phy";
292 reg = <3000 400>; // fec range, since we need to setup fec interrupts
293 interrupts = <2 5 0>; // these are for "mii command finished", not link changes & co.
294 interrupt-parent = <&mpc5200_pic>;
295
296 phy0:ethernet-phy@0 {
297 device_type = "ethernet-phy";
298 reg = <0>;
299 };
284 }; 300 };
285 301
286 ata@3a00 { 302 ata@3a00 {
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index 65d492e316a6..4bb023f4c869 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -14,7 +14,6 @@ endif
14 14
15obj-$(CONFIG_PPC64) += copypage_64.o copyuser_64.o \ 15obj-$(CONFIG_PPC64) += copypage_64.o copyuser_64.o \
16 memcpy_64.o usercopy_64.o mem_64.o string.o 16 memcpy_64.o usercopy_64.o mem_64.o string.o
17obj-$(CONFIG_QUICC_ENGINE) += rheap.o
18obj-$(CONFIG_XMON) += sstep.o 17obj-$(CONFIG_XMON) += sstep.o
19obj-$(CONFIG_KPROBES) += sstep.o 18obj-$(CONFIG_KPROBES) += sstep.o
20obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-noncoherent.o 19obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-noncoherent.o
@@ -23,6 +22,4 @@ ifeq ($(CONFIG_PPC64),y)
23obj-$(CONFIG_SMP) += locks.o 22obj-$(CONFIG_SMP) += locks.o
24endif 23endif
25 24
26# Temporary hack until we have migrated to asm-powerpc 25obj-$(CONFIG_PPC_LIB_RHEAP) += rheap.o
27obj-$(CONFIG_8xx) += rheap.o
28obj-$(CONFIG_CPM2) += rheap.o
diff --git a/arch/powerpc/lib/rheap.c b/arch/powerpc/lib/rheap.c
index ada5b42dd231..22c3b4f53de7 100644
--- a/arch/powerpc/lib/rheap.c
+++ b/arch/powerpc/lib/rheap.c
@@ -15,6 +15,7 @@
15#include <linux/types.h> 15#include <linux/types.h>
16#include <linux/errno.h> 16#include <linux/errno.h>
17#include <linux/kernel.h> 17#include <linux/kernel.h>
18#include <linux/module.h>
18#include <linux/mm.h> 19#include <linux/mm.h>
19#include <linux/err.h> 20#include <linux/err.h>
20#include <linux/slab.h> 21#include <linux/slab.h>
@@ -275,6 +276,7 @@ rh_info_t *rh_create(unsigned int alignment)
275 276
276 return info; 277 return info;
277} 278}
279EXPORT_SYMBOL_GPL(rh_create);
278 280
279/* 281/*
280 * Destroy a dynamically created remote heap. Deallocate only if the areas 282 * Destroy a dynamically created remote heap. Deallocate only if the areas
@@ -288,6 +290,7 @@ void rh_destroy(rh_info_t * info)
288 if ((info->flags & RHIF_STATIC_INFO) == 0) 290 if ((info->flags & RHIF_STATIC_INFO) == 0)
289 kfree(info); 291 kfree(info);
290} 292}
293EXPORT_SYMBOL_GPL(rh_destroy);
291 294
292/* 295/*
293 * Initialize in place a remote heap info block. This is needed to support 296 * Initialize in place a remote heap info block. This is needed to support
@@ -320,6 +323,7 @@ void rh_init(rh_info_t * info, unsigned int alignment, int max_blocks,
320 for (i = 0, blk = block; i < max_blocks; i++, blk++) 323 for (i = 0, blk = block; i < max_blocks; i++, blk++)
321 list_add(&blk->list, &info->empty_list); 324 list_add(&blk->list, &info->empty_list);
322} 325}
326EXPORT_SYMBOL_GPL(rh_init);
323 327
324/* Attach a free memory region, coalesces regions if adjuscent */ 328/* Attach a free memory region, coalesces regions if adjuscent */
325int rh_attach_region(rh_info_t * info, unsigned long start, int size) 329int rh_attach_region(rh_info_t * info, unsigned long start, int size)
@@ -360,6 +364,7 @@ int rh_attach_region(rh_info_t * info, unsigned long start, int size)
360 364
361 return 0; 365 return 0;
362} 366}
367EXPORT_SYMBOL_GPL(rh_attach_region);
363 368
364/* Detatch given address range, splits free block if needed. */ 369/* Detatch given address range, splits free block if needed. */
365unsigned long rh_detach_region(rh_info_t * info, unsigned long start, int size) 370unsigned long rh_detach_region(rh_info_t * info, unsigned long start, int size)
@@ -428,6 +433,7 @@ unsigned long rh_detach_region(rh_info_t * info, unsigned long start, int size)
428 433
429 return s; 434 return s;
430} 435}
436EXPORT_SYMBOL_GPL(rh_detach_region);
431 437
432/* Allocate a block of memory at the specified alignment. The value returned 438/* Allocate a block of memory at the specified alignment. The value returned
433 * is an offset into the buffer initialized by rh_init(), or a negative number 439 * is an offset into the buffer initialized by rh_init(), or a negative number
@@ -502,6 +508,7 @@ unsigned long rh_alloc_align(rh_info_t * info, int size, int alignment, const ch
502 508
503 return start; 509 return start;
504} 510}
511EXPORT_SYMBOL_GPL(rh_alloc_align);
505 512
506/* Allocate a block of memory at the default alignment. The value returned is 513/* Allocate a block of memory at the default alignment. The value returned is
507 * an offset into the buffer initialized by rh_init(), or a negative number if 514 * an offset into the buffer initialized by rh_init(), or a negative number if
@@ -511,6 +518,7 @@ unsigned long rh_alloc(rh_info_t * info, int size, const char *owner)
511{ 518{
512 return rh_alloc_align(info, size, info->alignment, owner); 519 return rh_alloc_align(info, size, info->alignment, owner);
513} 520}
521EXPORT_SYMBOL_GPL(rh_alloc);
514 522
515/* Allocate a block of memory at the given offset, rounded up to the default 523/* Allocate a block of memory at the given offset, rounded up to the default
516 * alignment. The value returned is an offset into the buffer initialized by 524 * alignment. The value returned is an offset into the buffer initialized by
@@ -594,6 +602,7 @@ unsigned long rh_alloc_fixed(rh_info_t * info, unsigned long start, int size, co
594 602
595 return start; 603 return start;
596} 604}
605EXPORT_SYMBOL_GPL(rh_alloc_fixed);
597 606
598/* Deallocate the memory previously allocated by one of the rh_alloc functions. 607/* Deallocate the memory previously allocated by one of the rh_alloc functions.
599 * The return value is the size of the deallocated block, or a negative number 608 * The return value is the size of the deallocated block, or a negative number
@@ -626,6 +635,7 @@ int rh_free(rh_info_t * info, unsigned long start)
626 635
627 return size; 636 return size;
628} 637}
638EXPORT_SYMBOL_GPL(rh_free);
629 639
630int rh_get_stats(rh_info_t * info, int what, int max_stats, rh_stats_t * stats) 640int rh_get_stats(rh_info_t * info, int what, int max_stats, rh_stats_t * stats)
631{ 641{
@@ -663,6 +673,7 @@ int rh_get_stats(rh_info_t * info, int what, int max_stats, rh_stats_t * stats)
663 673
664 return nr; 674 return nr;
665} 675}
676EXPORT_SYMBOL_GPL(rh_get_stats);
666 677
667int rh_set_owner(rh_info_t * info, unsigned long start, const char *owner) 678int rh_set_owner(rh_info_t * info, unsigned long start, const char *owner)
668{ 679{
@@ -687,6 +698,7 @@ int rh_set_owner(rh_info_t * info, unsigned long start, const char *owner)
687 698
688 return size; 699 return size;
689} 700}
701EXPORT_SYMBOL_GPL(rh_set_owner);
690 702
691void rh_dump(rh_info_t * info) 703void rh_dump(rh_info_t * info)
692{ 704{
@@ -722,6 +734,7 @@ void rh_dump(rh_info_t * info)
722 st[i].size, st[i].owner != NULL ? st[i].owner : ""); 734 st[i].size, st[i].owner != NULL ? st[i].owner : "");
723 printk(KERN_INFO "\n"); 735 printk(KERN_INFO "\n");
724} 736}
737EXPORT_SYMBOL_GPL(rh_dump);
725 738
726void rh_dump_blk(rh_info_t * info, rh_block_t * blk) 739void rh_dump_blk(rh_info_t * info, rh_block_t * blk)
727{ 740{
@@ -729,3 +742,5 @@ void rh_dump_blk(rh_info_t * info, rh_block_t * blk)
729 "blk @0x%p: 0x%lx-0x%lx (%u)\n", 742 "blk @0x%p: 0x%lx-0x%lx (%u)\n",
730 blk, blk->start, blk->start + blk->size, blk->size); 743 blk, blk->start, blk->start + blk->size, blk->size);
731} 744}
745EXPORT_SYMBOL_GPL(rh_dump_blk);
746
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index 186397f283bb..229d355ed86a 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -264,6 +264,7 @@ config TAU_AVERAGE
264 264
265config QUICC_ENGINE 265config QUICC_ENGINE
266 bool 266 bool
267 select PPC_LIB_RHEAP
267 help 268 help
268 The QUICC Engine (QE) is a new generation of communications 269 The QUICC Engine (QE) is a new generation of communications
269 coprocessors on Freescale embedded CPUs (akin to CPM in older chips). 270 coprocessors on Freescale embedded CPUs (akin to CPM in older chips).
@@ -274,6 +275,7 @@ config CPM2
274 bool 275 bool
275 default n 276 default n
276 select CPM 277 select CPM
278 select PPC_LIB_RHEAP
277 help 279 help
278 The CPM2 (Communications Processor Module) is a coprocessor on 280 The CPM2 (Communications Processor Module) is a coprocessor on
279 embedded CPUs made by Freescale. Selecting this option means that 281 embedded CPUs made by Freescale. Selecting this option means that
@@ -313,4 +315,6 @@ config FSL_ULI1575
313config CPM 315config CPM
314 bool 316 bool
315 317
318source "arch/powerpc/sysdev/bestcomm/Kconfig"
319
316endmenu 320endmenu
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 4c315be25015..3c7325ec36ec 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -37,6 +37,7 @@ config PPC_8xx
37 select FSL_SOC 37 select FSL_SOC
38 select 8xx 38 select 8xx
39 select WANT_DEVICE_TREE 39 select WANT_DEVICE_TREE
40 select PPC_LIB_RHEAP
40 41
41config 40x 42config 40x
42 bool "AMCC 40x" 43 bool "AMCC 40x"
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..57cc56562567
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/Kconfig
@@ -0,0 +1,39 @@
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
19config PPC_BESTCOMM_ATA
20 tristate "Bestcomm ATA task support"
21 depends on PPC_BESTCOMM
22 default n
23 help
24 This option enables the support for the ATA task.
25
26config PPC_BESTCOMM_FEC
27 tristate "Bestcomm FEC tasks support"
28 depends on PPC_BESTCOMM
29 default n
30 help
31 This option enables the support for the FEC tasks.
32
33config PPC_BESTCOMM_GEN_BD
34 tristate "Bestcomm GenBD tasks support"
35 depends on PPC_BESTCOMM
36 default n
37 help
38 This option enables the support for the GenBD tasks.
39
diff --git a/arch/powerpc/sysdev/bestcomm/Makefile b/arch/powerpc/sysdev/bestcomm/Makefile
new file mode 100644
index 000000000000..aed2df2a6580
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/Makefile
@@ -0,0 +1,14 @@
1#
2# Makefile for BestComm & co
3#
4
5bestcomm-core-objs := bestcomm.o sram.o
6bestcomm-ata-objs := ata.o bcom_ata_task.o
7bestcomm-fec-objs := fec.o bcom_fec_rx_task.o bcom_fec_tx_task.o
8bestcomm-gen-bd-objs := gen_bd.o bcom_gen_bd_rx_task.o bcom_gen_bd_tx_task.o
9
10obj-$(CONFIG_PPC_BESTCOMM) += bestcomm-core.o
11obj-$(CONFIG_PPC_BESTCOMM_ATA) += bestcomm-ata.o
12obj-$(CONFIG_PPC_BESTCOMM_FEC) += bestcomm-fec.o
13obj-$(CONFIG_PPC_BESTCOMM_GEN_BD) += bestcomm-gen-bd.o
14
diff --git a/arch/powerpc/sysdev/bestcomm/ata.c b/arch/powerpc/sysdev/bestcomm/ata.c
new file mode 100644
index 000000000000..1f5258fb38c3
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/ata.c
@@ -0,0 +1,154 @@
1/*
2 * Bestcomm ATA task driver
3 *
4 *
5 * Patterned after bestcomm/fec.c by Dale Farnsworth <dfarnsworth@mvista.com>
6 * 2003-2004 (c) MontaVista, Software, Inc.
7 *
8 * Copyright (C) 2006-2007 Sylvain Munaut <tnt@246tNt.com>
9 * Copyright (C) 2006 Freescale - John Rigby
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/kernel.h>
17#include <linux/module.h>
18#include <linux/types.h>
19#include <asm/io.h>
20
21#include "bestcomm.h"
22#include "bestcomm_priv.h"
23#include "ata.h"
24
25
26/* ======================================================================== */
27/* Task image/var/inc */
28/* ======================================================================== */
29
30/* ata task image */
31extern u32 bcom_ata_task[];
32
33/* ata task vars that need to be set before enabling the task */
34struct bcom_ata_var {
35 u32 enable; /* (u16*) address of task's control register */
36 u32 bd_base; /* (struct bcom_bd*) beginning of ring buffer */
37 u32 bd_last; /* (struct bcom_bd*) end of ring buffer */
38 u32 bd_start; /* (struct bcom_bd*) current bd */
39 u32 buffer_size; /* size of receive buffer */
40};
41
42/* ata task incs that need to be set before enabling the task */
43struct bcom_ata_inc {
44 u16 pad0;
45 s16 incr_bytes;
46 u16 pad1;
47 s16 incr_dst;
48 u16 pad2;
49 s16 incr_src;
50};
51
52
53/* ======================================================================== */
54/* Task support code */
55/* ======================================================================== */
56
57struct bcom_task *
58bcom_ata_init(int queue_len, int maxbufsize)
59{
60 struct bcom_task *tsk;
61 struct bcom_ata_var *var;
62 struct bcom_ata_inc *inc;
63
64 tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_ata_bd), 0);
65 if (!tsk)
66 return NULL;
67
68 tsk->flags = BCOM_FLAGS_NONE;
69
70 bcom_ata_reset_bd(tsk);
71
72 var = (struct bcom_ata_var *) bcom_task_var(tsk->tasknum);
73 inc = (struct bcom_ata_inc *) bcom_task_inc(tsk->tasknum);
74
75 if (bcom_load_image(tsk->tasknum, bcom_ata_task)) {
76 bcom_task_free(tsk);
77 return NULL;
78 }
79
80 var->enable = bcom_eng->regs_base +
81 offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);
82 var->bd_base = tsk->bd_pa;
83 var->bd_last = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);
84 var->bd_start = tsk->bd_pa;
85 var->buffer_size = maxbufsize;
86
87 /* Configure some stuff */
88 bcom_set_task_pragma(tsk->tasknum, BCOM_ATA_PRAGMA);
89 bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
90
91 out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ATA_RX], BCOM_IPR_ATA_RX);
92 out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ATA_TX], BCOM_IPR_ATA_TX);
93
94 out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */
95
96 return tsk;
97}
98EXPORT_SYMBOL_GPL(bcom_ata_init);
99
100void bcom_ata_rx_prepare(struct bcom_task *tsk)
101{
102 struct bcom_ata_inc *inc;
103
104 inc = (struct bcom_ata_inc *) bcom_task_inc(tsk->tasknum);
105
106 inc->incr_bytes = -(s16)sizeof(u32);
107 inc->incr_src = 0;
108 inc->incr_dst = sizeof(u32);
109
110 bcom_set_initiator(tsk->tasknum, BCOM_INITIATOR_ATA_RX);
111}
112EXPORT_SYMBOL_GPL(bcom_ata_rx_prepare);
113
114void bcom_ata_tx_prepare(struct bcom_task *tsk)
115{
116 struct bcom_ata_inc *inc;
117
118 inc = (struct bcom_ata_inc *) bcom_task_inc(tsk->tasknum);
119
120 inc->incr_bytes = -(s16)sizeof(u32);
121 inc->incr_src = sizeof(u32);
122 inc->incr_dst = 0;
123
124 bcom_set_initiator(tsk->tasknum, BCOM_INITIATOR_ATA_TX);
125}
126EXPORT_SYMBOL_GPL(bcom_ata_tx_prepare);
127
128void bcom_ata_reset_bd(struct bcom_task *tsk)
129{
130 struct bcom_ata_var *var;
131
132 /* Reset all BD */
133 memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
134
135 tsk->index = 0;
136 tsk->outdex = 0;
137
138 var = (struct bcom_ata_var *) bcom_task_var(tsk->tasknum);
139 var->bd_start = var->bd_base;
140}
141EXPORT_SYMBOL_GPL(bcom_ata_reset_bd);
142
143void bcom_ata_release(struct bcom_task *tsk)
144{
145 /* Nothing special for the ATA tasks */
146 bcom_task_free(tsk);
147}
148EXPORT_SYMBOL_GPL(bcom_ata_release);
149
150
151MODULE_DESCRIPTION("BestComm ATA task driver");
152MODULE_AUTHOR("John Rigby");
153MODULE_LICENSE("GPL v2");
154
diff --git a/arch/powerpc/sysdev/bestcomm/ata.h b/arch/powerpc/sysdev/bestcomm/ata.h
new file mode 100644
index 000000000000..10982769c465
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/ata.h
@@ -0,0 +1,37 @@
1/*
2 * Header for Bestcomm ATA task driver
3 *
4 *
5 * Copyright (C) 2006 Freescale - John Rigby
6 * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com>
7 *
8 * This file is licensed under the terms of the GNU General Public License
9 * version 2. This program is licensed "as is" without any warranty of any
10 * kind, whether express or implied.
11 */
12
13#ifndef __BESTCOMM_ATA_H__
14#define __BESTCOMM_ATA_H__
15
16
17struct bcom_ata_bd {
18 u32 status;
19 u32 dst_pa;
20 u32 src_pa;
21};
22
23extern struct bcom_task *
24bcom_ata_init(int queue_len, int maxbufsize);
25
26extern void
27bcom_ata_rx_prepare(struct bcom_task *tsk);
28
29extern void
30bcom_ata_tx_prepare(struct bcom_task *tsk);
31
32extern void
33bcom_ata_reset_bd(struct bcom_task *tsk);
34
35
36#endif /* __BESTCOMM_ATA_H__ */
37
diff --git a/arch/powerpc/sysdev/bestcomm/bcom_ata_task.c b/arch/powerpc/sysdev/bestcomm/bcom_ata_task.c
new file mode 100644
index 000000000000..cc6049a4e469
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/bcom_ata_task.c
@@ -0,0 +1,67 @@
1/*
2 * Bestcomm ATA task microcode
3 *
4 * Copyright (c) 2004 Freescale Semiconductor, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published
8 * by the Free Software Foundation.
9 *
10 * Created based on bestcom/code_dma/image_rtos1/dma_image.hex
11 */
12
13#include <asm/types.h>
14
15/*
16 * The header consists of the following fields:
17 * u32 magic;
18 * u8 desc_size;
19 * u8 var_size;
20 * u8 inc_size;
21 * u8 first_var;
22 * u8 reserved[8];
23 *
24 * The size fields contain the number of 32-bit words.
25 */
26
27u32 bcom_ata_task[] = {
28 /* header */
29 0x4243544b,
30 0x0e060709,
31 0x00000000,
32 0x00000000,
33
34 /* Task descriptors */
35 0x8198009b, /* LCD: idx0 = var3; idx0 <= var2; idx0 += inc3 */
36 0x13e00c08, /* DRD1A: var3 = var1; FN=0 MORE init=31 WS=0 RS=0 */
37 0xb8000264, /* LCD: idx1 = *idx0, idx2 = var0; idx1 < var9; idx1 += inc4, idx2 += inc4 */
38 0x10000f00, /* DRD1A: var3 = idx0; FN=0 MORE init=0 WS=0 RS=0 */
39 0x60140002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */
40 0x0c8cfc8a, /* DRD2B1: *idx2 = EU3(); EU3(*idx2,var10) */
41 0xd8988240, /* LCDEXT: idx1 = idx1; idx1 > var9; idx1 += inc0 */
42 0xf845e011, /* LCDEXT: idx2 = *(idx0 + var00000015); ; idx2 += inc2 */
43 0xb845e00a, /* LCD: idx3 = *(idx0 + var00000019); ; idx3 += inc1 */
44 0x0bfecf90, /* DRD1A: *idx3 = *idx2; FN=0 TFD init=31 WS=3 RS=3 */
45 0x9898802d, /* LCD: idx1 = idx1; idx1 once var0; idx1 += inc5 */
46 0x64000005, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 INT EXT init=0 WS=0 RS=0 */
47 0x0c0cf849, /* DRD2B1: *idx0 = EU3(); EU3(idx1,var9) */
48 0x000001f8, /* NOP */
49
50 /* VAR[9]-VAR[14] */
51 0x40000000,
52 0x7fff7fff,
53 0x00000000,
54 0x00000000,
55 0x00000000,
56 0x00000000,
57
58 /* INC[0]-INC[6] */
59 0x40000000,
60 0xe0000000,
61 0xe0000000,
62 0xa000000c,
63 0x20000000,
64 0x00000000,
65 0x00000000,
66};
67
diff --git a/arch/powerpc/sysdev/bestcomm/bcom_fec_rx_task.c b/arch/powerpc/sysdev/bestcomm/bcom_fec_rx_task.c
new file mode 100644
index 000000000000..a1ad6a02fcef
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/bcom_fec_rx_task.c
@@ -0,0 +1,78 @@
1/*
2 * Bestcomm FEC RX task microcode
3 *
4 * Copyright (c) 2004 Freescale Semiconductor, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published
8 * by the Free Software Foundation.
9 *
10 * Automatically created based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex
11 * on Tue Mar 22 11:19:38 2005 GMT
12 */
13
14#include <asm/types.h>
15
16/*
17 * The header consists of the following fields:
18 * u32 magic;
19 * u8 desc_size;
20 * u8 var_size;
21 * u8 inc_size;
22 * u8 first_var;
23 * u8 reserved[8];
24 *
25 * The size fields contain the number of 32-bit words.
26 */
27
28u32 bcom_fec_rx_task[] = {
29 /* header */
30 0x4243544b,
31 0x18060709,
32 0x00000000,
33 0x00000000,
34
35 /* Task descriptors */
36 0x808220e3, /* LCD: idx0 = var1, idx1 = var4; idx1 <= var3; idx0 += inc4, idx1 += inc3 */
37 0x10601010, /* DRD1A: var4 = var2; FN=0 MORE init=3 WS=0 RS=0 */
38 0xb8800264, /* LCD: idx2 = *idx1, idx3 = var0; idx2 < var9; idx2 += inc4, idx3 += inc4 */
39 0x10001308, /* DRD1A: var4 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
40 0x60140002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */
41 0x0cccfcca, /* DRD2B1: *idx3 = EU3(); EU3(*idx3,var10) */
42 0x80004000, /* LCDEXT: idx2 = 0x00000000; ; */
43 0xb8c58029, /* LCD: idx3 = *(idx1 + var00000015); idx3 once var0; idx3 += inc5 */
44 0x60000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=0 RS=0 */
45 0x088cf8cc, /* DRD2B1: idx2 = EU3(); EU3(idx3,var12) */
46 0x991982f2, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var11; idx2 += inc6, idx3 += inc2 */
47 0x006acf80, /* DRD1A: *idx3 = *idx0; FN=0 init=3 WS=1 RS=1 */
48 0x80004000, /* LCDEXT: idx2 = 0x00000000; ; */
49 0x9999802d, /* LCD: idx3 = idx3; idx3 once var0; idx3 += inc5 */
50 0x70000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */
51 0x034cfc4e, /* DRD2B1: var13 = EU3(); EU3(*idx1,var14) */
52 0x00008868, /* DRD1A: idx2 = var13; FN=0 init=0 WS=0 RS=0 */
53 0x99198341, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var13; idx2 += inc0, idx3 += inc1 */
54 0x007ecf80, /* DRD1A: *idx3 = *idx0; FN=0 init=3 WS=3 RS=3 */
55 0x99198272, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var9; idx2 += inc6, idx3 += inc2 */
56 0x046acf80, /* DRD1A: *idx3 = *idx0; FN=0 INT init=3 WS=1 RS=1 */
57 0x9819002d, /* LCD: idx2 = idx0; idx2 once var0; idx2 += inc5 */
58 0x0060c790, /* DRD1A: *idx1 = *idx2; FN=0 init=3 WS=0 RS=0 */
59 0x000001f8, /* NOP */
60
61 /* VAR[9]-VAR[14] */
62 0x40000000,
63 0x7fff7fff,
64 0x00000000,
65 0x00000003,
66 0x40000008,
67 0x43ffffff,
68
69 /* INC[0]-INC[6] */
70 0x40000000,
71 0xe0000000,
72 0xe0000000,
73 0xa0000008,
74 0x20000000,
75 0x00000000,
76 0x4000ffff,
77};
78
diff --git a/arch/powerpc/sysdev/bestcomm/bcom_fec_tx_task.c b/arch/powerpc/sysdev/bestcomm/bcom_fec_tx_task.c
new file mode 100644
index 000000000000..b1c495c3a65a
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/bcom_fec_tx_task.c
@@ -0,0 +1,91 @@
1/*
2 * Bestcomm FEC TX task microcode
3 *
4 * Copyright (c) 2004 Freescale Semiconductor, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published
8 * by the Free Software Foundation.
9 *
10 * Automatically created based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex
11 * on Tue Mar 22 11:19:29 2005 GMT
12 */
13
14#include <asm/types.h>
15
16/*
17 * The header consists of the following fields:
18 * u32 magic;
19 * u8 desc_size;
20 * u8 var_size;
21 * u8 inc_size;
22 * u8 first_var;
23 * u8 reserved[8];
24 *
25 * The size fields contain the number of 32-bit words.
26 */
27
28u32 bcom_fec_tx_task[] = {
29 /* header */
30 0x4243544b,
31 0x2407070d,
32 0x00000000,
33 0x00000000,
34
35 /* Task descriptors */
36 0x8018001b, /* LCD: idx0 = var0; idx0 <= var0; idx0 += inc3 */
37 0x60000005, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */
38 0x01ccfc0d, /* DRD2B1: var7 = EU3(); EU3(*idx0,var13) */
39 0x8082a123, /* LCD: idx0 = var1, idx1 = var5; idx1 <= var4; idx0 += inc4, idx1 += inc3 */
40 0x10801418, /* DRD1A: var5 = var3; FN=0 MORE init=4 WS=0 RS=0 */
41 0xf88103a4, /* LCDEXT: idx2 = *idx1, idx3 = var2; idx2 < var14; idx2 += inc4, idx3 += inc4 */
42 0x801a6024, /* LCD: idx4 = var0; ; idx4 += inc4 */
43 0x10001708, /* DRD1A: var5 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
44 0x60140002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */
45 0x0cccfccf, /* DRD2B1: *idx3 = EU3(); EU3(*idx3,var15) */
46 0x991a002c, /* LCD: idx2 = idx2, idx3 = idx4; idx2 once var0; idx2 += inc5, idx3 += inc4 */
47 0x70000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */
48 0x024cfc4d, /* DRD2B1: var9 = EU3(); EU3(*idx1,var13) */
49 0x60000003, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=3 EXT init=0 WS=0 RS=0 */
50 0x0cccf247, /* DRD2B1: *idx3 = EU3(); EU3(var9,var7) */
51 0x80004000, /* LCDEXT: idx2 = 0x00000000; ; */
52 0xb8c80029, /* LCD: idx3 = *(idx1 + var0000001a); idx3 once var0; idx3 += inc5 */
53 0x70000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */
54 0x088cf8d1, /* DRD2B1: idx2 = EU3(); EU3(idx3,var17) */
55 0x00002f10, /* DRD1A: var11 = idx2; FN=0 init=0 WS=0 RS=0 */
56 0x99198432, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var16; idx2 += inc6, idx3 += inc2 */
57 0x008ac398, /* DRD1A: *idx0 = *idx3; FN=0 init=4 WS=1 RS=1 */
58 0x80004000, /* LCDEXT: idx2 = 0x00000000; ; */
59 0x9999802d, /* LCD: idx3 = idx3; idx3 once var0; idx3 += inc5 */
60 0x70000002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */
61 0x048cfc53, /* DRD2B1: var18 = EU3(); EU3(*idx1,var19) */
62 0x60000008, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=8 EXT init=0 WS=0 RS=0 */
63 0x088cf48b, /* DRD2B1: idx2 = EU3(); EU3(var18,var11) */
64 0x99198481, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var18; idx2 += inc0, idx3 += inc1 */
65 0x009ec398, /* DRD1A: *idx0 = *idx3; FN=0 init=4 WS=3 RS=3 */
66 0x991983b2, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var14; idx2 += inc6, idx3 += inc2 */
67 0x088ac398, /* DRD1A: *idx0 = *idx3; FN=0 TFD init=4 WS=1 RS=1 */
68 0x9919002d, /* LCD: idx2 = idx2; idx2 once var0; idx2 += inc5 */
69 0x60000005, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */
70 0x0c4cf88e, /* DRD2B1: *idx1 = EU3(); EU3(idx2,var14) */
71 0x000001f8, /* NOP */
72
73 /* VAR[13]-VAR[19] */
74 0x0c000000,
75 0x40000000,
76 0x7fff7fff,
77 0x00000000,
78 0x00000003,
79 0x40000004,
80 0x43ffffff,
81
82 /* INC[0]-INC[6] */
83 0x40000000,
84 0xe0000000,
85 0xe0000000,
86 0xa0000008,
87 0x20000000,
88 0x00000000,
89 0x4000ffff,
90};
91
diff --git a/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_rx_task.c b/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_rx_task.c
new file mode 100644
index 000000000000..efee022b0256
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_rx_task.c
@@ -0,0 +1,63 @@
1/*
2 * Bestcomm GenBD RX task microcode
3 *
4 * Copyright (C) 2006 AppSpec Computer Technologies Corp.
5 * Jeff Gibbons <jeff.gibbons@appspec.com>
6 * Copyright (c) 2004 Freescale Semiconductor, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published
10 * by the Free Software Foundation.
11 *
12 * Based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex
13 * on Tue Mar 4 10:14:12 2006 GMT
14 *
15 */
16
17#include <asm/types.h>
18
19/*
20 * The header consists of the following fields:
21 * u32 magic;
22 * u8 desc_size;
23 * u8 var_size;
24 * u8 inc_size;
25 * u8 first_var;
26 * u8 reserved[8];
27 *
28 * The size fields contain the number of 32-bit words.
29 */
30
31u32 bcom_gen_bd_rx_task[] = {
32 /* header */
33 0x4243544b,
34 0x0d020409,
35 0x00000000,
36 0x00000000,
37
38 /* Task descriptors */
39 0x808220da, /* LCD: idx0 = var1, idx1 = var4; idx1 <= var3; idx0 += inc3, idx1 += inc2 */
40 0x13e01010, /* DRD1A: var4 = var2; FN=0 MORE init=31 WS=0 RS=0 */
41 0xb880025b, /* LCD: idx2 = *idx1, idx3 = var0; idx2 < var9; idx2 += inc3, idx3 += inc3 */
42 0x10001308, /* DRD1A: var4 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
43 0x60140002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */
44 0x0cccfcca, /* DRD2B1: *idx3 = EU3(); EU3(*idx3,var10) */
45 0xd9190240, /* LCDEXT: idx2 = idx2; idx2 > var9; idx2 += inc0 */
46 0xb8c5e009, /* LCD: idx3 = *(idx1 + var00000015); ; idx3 += inc1 */
47 0x07fecf80, /* DRD1A: *idx3 = *idx0; FN=0 INT init=31 WS=3 RS=3 */
48 0x99190024, /* LCD: idx2 = idx2; idx2 once var0; idx2 += inc4 */
49 0x60000005, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */
50 0x0c4cf889, /* DRD2B1: *idx1 = EU3(); EU3(idx2,var9) */
51 0x000001f8, /* NOP */
52
53 /* VAR[9]-VAR[10] */
54 0x40000000,
55 0x7fff7fff,
56
57 /* INC[0]-INC[3] */
58 0x40000000,
59 0xe0000000,
60 0xa0000008,
61 0x20000000,
62};
63
diff --git a/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_tx_task.c b/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_tx_task.c
new file mode 100644
index 000000000000..c605aa42ecbb
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_tx_task.c
@@ -0,0 +1,69 @@
1/*
2 * Bestcomm GenBD TX task microcode
3 *
4 * Copyright (C) 2006 AppSpec Computer Technologies Corp.
5 * Jeff Gibbons <jeff.gibbons@appspec.com>
6 * Copyright (c) 2004 Freescale Semiconductor, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published
10 * by the Free Software Foundation.
11 *
12 * Based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex
13 * on Tue Mar 4 10:14:12 2006 GMT
14 *
15 */
16
17#include <asm/types.h>
18
19/*
20 * The header consists of the following fields:
21 * u32 magic;
22 * u8 desc_size;
23 * u8 var_size;
24 * u8 inc_size;
25 * u8 first_var;
26 * u8 reserved[8];
27 *
28 * The size fields contain the number of 32-bit words.
29 */
30
31u32 bcom_gen_bd_tx_task[] = {
32 /* header */
33 0x4243544b,
34 0x0f040609,
35 0x00000000,
36 0x00000000,
37
38 /* Task descriptors */
39 0x800220e3, /* LCD: idx0 = var0, idx1 = var4; idx1 <= var3; idx0 += inc4, idx1 += inc3 */
40 0x13e01010, /* DRD1A: var4 = var2; FN=0 MORE init=31 WS=0 RS=0 */
41 0xb8808264, /* LCD: idx2 = *idx1, idx3 = var1; idx2 < var9; idx2 += inc4, idx3 += inc4 */
42 0x10001308, /* DRD1A: var4 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
43 0x60140002, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */
44 0x0cccfcca, /* DRD2B1: *idx3 = EU3(); EU3(*idx3,var10) */
45 0xd9190300, /* LCDEXT: idx2 = idx2; idx2 > var12; idx2 += inc0 */
46 0xb8c5e009, /* LCD: idx3 = *(idx1 + var00000015); ; idx3 += inc1 */
47 0x03fec398, /* DRD1A: *idx0 = *idx3; FN=0 init=31 WS=3 RS=3 */
48 0x9919826a, /* LCD: idx2 = idx2, idx3 = idx3; idx2 > var9; idx2 += inc5, idx3 += inc2 */
49 0x0feac398, /* DRD1A: *idx0 = *idx3; FN=0 TFD INT init=31 WS=1 RS=1 */
50 0x99190036, /* LCD: idx2 = idx2; idx2 once var0; idx2 += inc6 */
51 0x60000005, /* DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */
52 0x0c4cf889, /* DRD2B1: *idx1 = EU3(); EU3(idx2,var9) */
53 0x000001f8, /* NOP */
54
55 /* VAR[9]-VAR[12] */
56 0x40000000,
57 0x7fff7fff,
58 0x00000000,
59 0x40000004,
60
61 /* INC[0]-INC[5] */
62 0x40000000,
63 0xe0000000,
64 0xe0000000,
65 0xa0000008,
66 0x20000000,
67 0x4000ffff,
68};
69
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/fec.c b/arch/powerpc/sysdev/bestcomm/fec.c
new file mode 100644
index 000000000000..957a988d23ea
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/fec.c
@@ -0,0 +1,270 @@
1/*
2 * Bestcomm FEC tasks driver
3 *
4 *
5 * Copyright (C) 2006-2007 Sylvain Munaut <tnt@246tNt.com>
6 * Copyright (C) 2003-2004 MontaVista, Software, Inc.
7 * ( by Dale Farnsworth <dfarnsworth@mvista.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/types.h>
17#include <asm/io.h>
18
19#include "bestcomm.h"
20#include "bestcomm_priv.h"
21#include "fec.h"
22
23
24/* ======================================================================== */
25/* Task image/var/inc */
26/* ======================================================================== */
27
28/* fec tasks images */
29extern u32 bcom_fec_rx_task[];
30extern u32 bcom_fec_tx_task[];
31
32/* rx task vars that need to be set before enabling the task */
33struct bcom_fec_rx_var {
34 u32 enable; /* (u16*) address of task's control register */
35 u32 fifo; /* (u32*) address of fec's fifo */
36 u32 bd_base; /* (struct bcom_bd*) beginning of ring buffer */
37 u32 bd_last; /* (struct bcom_bd*) end of ring buffer */
38 u32 bd_start; /* (struct bcom_bd*) current bd */
39 u32 buffer_size; /* size of receive buffer */
40};
41
42/* rx task incs that need to be set before enabling the task */
43struct bcom_fec_rx_inc {
44 u16 pad0;
45 s16 incr_bytes;
46 u16 pad1;
47 s16 incr_dst;
48 u16 pad2;
49 s16 incr_dst_ma;
50};
51
52/* tx task vars that need to be set before enabling the task */
53struct bcom_fec_tx_var {
54 u32 DRD; /* (u32*) address of self-modified DRD */
55 u32 fifo; /* (u32*) address of fec's fifo */
56 u32 enable; /* (u16*) address of task's control register */
57 u32 bd_base; /* (struct bcom_bd*) beginning of ring buffer */
58 u32 bd_last; /* (struct bcom_bd*) end of ring buffer */
59 u32 bd_start; /* (struct bcom_bd*) current bd */
60 u32 buffer_size; /* set by uCode for each packet */
61};
62
63/* tx task incs that need to be set before enabling the task */
64struct bcom_fec_tx_inc {
65 u16 pad0;
66 s16 incr_bytes;
67 u16 pad1;
68 s16 incr_src;
69 u16 pad2;
70 s16 incr_src_ma;
71};
72
73/* private structure in the task */
74struct bcom_fec_priv {
75 phys_addr_t fifo;
76 int maxbufsize;
77};
78
79
80/* ======================================================================== */
81/* Task support code */
82/* ======================================================================== */
83
84struct bcom_task *
85bcom_fec_rx_init(int queue_len, phys_addr_t fifo, int maxbufsize)
86{
87 struct bcom_task *tsk;
88 struct bcom_fec_priv *priv;
89
90 tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_fec_bd),
91 sizeof(struct bcom_fec_priv));
92 if (!tsk)
93 return NULL;
94
95 tsk->flags = BCOM_FLAGS_NONE;
96
97 priv = tsk->priv;
98 priv->fifo = fifo;
99 priv->maxbufsize = maxbufsize;
100
101 if (bcom_fec_rx_reset(tsk)) {
102 bcom_task_free(tsk);
103 return NULL;
104 }
105
106 return tsk;
107}
108EXPORT_SYMBOL_GPL(bcom_fec_rx_init);
109
110int
111bcom_fec_rx_reset(struct bcom_task *tsk)
112{
113 struct bcom_fec_priv *priv = tsk->priv;
114 struct bcom_fec_rx_var *var;
115 struct bcom_fec_rx_inc *inc;
116
117 /* Shutdown the task */
118 bcom_disable_task(tsk->tasknum);
119
120 /* Reset the microcode */
121 var = (struct bcom_fec_rx_var *) bcom_task_var(tsk->tasknum);
122 inc = (struct bcom_fec_rx_inc *) bcom_task_inc(tsk->tasknum);
123
124 if (bcom_load_image(tsk->tasknum, bcom_fec_rx_task))
125 return -1;
126
127 var->enable = bcom_eng->regs_base +
128 offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);
129 var->fifo = (u32) priv->fifo;
130 var->bd_base = tsk->bd_pa;
131 var->bd_last = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);
132 var->bd_start = tsk->bd_pa;
133 var->buffer_size = priv->maxbufsize;
134
135 inc->incr_bytes = -(s16)sizeof(u32); /* These should be in the */
136 inc->incr_dst = sizeof(u32); /* task image, but we stick */
137 inc->incr_dst_ma= sizeof(u8); /* to the official ones */
138
139 /* Reset the BDs */
140 tsk->index = 0;
141 tsk->outdex = 0;
142
143 memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
144
145 /* Configure some stuff */
146 bcom_set_task_pragma(tsk->tasknum, BCOM_FEC_RX_BD_PRAGMA);
147 bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
148
149 out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_FEC_RX], BCOM_IPR_FEC_RX);
150
151 out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */
152
153 return 0;
154}
155EXPORT_SYMBOL_GPL(bcom_fec_rx_reset);
156
157void
158bcom_fec_rx_release(struct bcom_task *tsk)
159{
160 /* Nothing special for the FEC tasks */
161 bcom_task_free(tsk);
162}
163EXPORT_SYMBOL_GPL(bcom_fec_rx_release);
164
165
166
167 /* Return 2nd to last DRD */
168 /* This is an ugly hack, but at least it's only done
169 once at initialization */
170static u32 *self_modified_drd(int tasknum)
171{
172 u32 *desc;
173 int num_descs;
174 int drd_count;
175 int i;
176
177 num_descs = bcom_task_num_descs(tasknum);
178 desc = bcom_task_desc(tasknum) + num_descs - 1;
179 drd_count = 0;
180 for (i=0; i<num_descs; i++, desc--)
181 if (bcom_desc_is_drd(*desc) && ++drd_count == 3)
182 break;
183 return desc;
184}
185
186struct bcom_task *
187bcom_fec_tx_init(int queue_len, phys_addr_t fifo)
188{
189 struct bcom_task *tsk;
190 struct bcom_fec_priv *priv;
191
192 tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_fec_bd),
193 sizeof(struct bcom_fec_priv));
194 if (!tsk)
195 return NULL;
196
197 tsk->flags = BCOM_FLAGS_ENABLE_TASK;
198
199 priv = tsk->priv;
200 priv->fifo = fifo;
201
202 if (bcom_fec_tx_reset(tsk)) {
203 bcom_task_free(tsk);
204 return NULL;
205 }
206
207 return tsk;
208}
209EXPORT_SYMBOL_GPL(bcom_fec_tx_init);
210
211int
212bcom_fec_tx_reset(struct bcom_task *tsk)
213{
214 struct bcom_fec_priv *priv = tsk->priv;
215 struct bcom_fec_tx_var *var;
216 struct bcom_fec_tx_inc *inc;
217
218 /* Shutdown the task */
219 bcom_disable_task(tsk->tasknum);
220
221 /* Reset the microcode */
222 var = (struct bcom_fec_tx_var *) bcom_task_var(tsk->tasknum);
223 inc = (struct bcom_fec_tx_inc *) bcom_task_inc(tsk->tasknum);
224
225 if (bcom_load_image(tsk->tasknum, bcom_fec_tx_task))
226 return -1;
227
228 var->enable = bcom_eng->regs_base +
229 offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);
230 var->fifo = (u32) priv->fifo;
231 var->DRD = bcom_sram_va2pa(self_modified_drd(tsk->tasknum));
232 var->bd_base = tsk->bd_pa;
233 var->bd_last = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);
234 var->bd_start = tsk->bd_pa;
235
236 inc->incr_bytes = -(s16)sizeof(u32); /* These should be in the */
237 inc->incr_src = sizeof(u32); /* task image, but we stick */
238 inc->incr_src_ma= sizeof(u8); /* to the official ones */
239
240 /* Reset the BDs */
241 tsk->index = 0;
242 tsk->outdex = 0;
243
244 memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
245
246 /* Configure some stuff */
247 bcom_set_task_pragma(tsk->tasknum, BCOM_FEC_TX_BD_PRAGMA);
248 bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
249
250 out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_FEC_TX], BCOM_IPR_FEC_TX);
251
252 out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */
253
254 return 0;
255}
256EXPORT_SYMBOL_GPL(bcom_fec_tx_reset);
257
258void
259bcom_fec_tx_release(struct bcom_task *tsk)
260{
261 /* Nothing special for the FEC tasks */
262 bcom_task_free(tsk);
263}
264EXPORT_SYMBOL_GPL(bcom_fec_tx_release);
265
266
267MODULE_DESCRIPTION("BestComm FEC tasks driver");
268MODULE_AUTHOR("Dale Farnsworth <dfarnsworth@mvista.com>");
269MODULE_LICENSE("GPL v2");
270
diff --git a/arch/powerpc/sysdev/bestcomm/fec.h b/arch/powerpc/sysdev/bestcomm/fec.h
new file mode 100644
index 000000000000..ee565d94d503
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/fec.h
@@ -0,0 +1,61 @@
1/*
2 * Header for Bestcomm FEC tasks driver
3 *
4 *
5 * Copyright (C) 2006-2007 Sylvain Munaut <tnt@246tNt.com>
6 * Copyright (C) 2003-2004 MontaVista, Software, Inc.
7 * ( by Dale Farnsworth <dfarnsworth@mvista.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#ifndef __BESTCOMM_FEC_H__
15#define __BESTCOMM_FEC_H__
16
17
18struct bcom_fec_bd {
19 u32 status;
20 u32 skb_pa;
21};
22
23#define BCOM_FEC_TX_BD_TFD 0x08000000ul /* transmit frame done */
24#define BCOM_FEC_TX_BD_TC 0x04000000ul /* transmit CRC */
25#define BCOM_FEC_TX_BD_ABC 0x02000000ul /* append bad CRC */
26
27#define BCOM_FEC_RX_BD_L 0x08000000ul /* buffer is last in frame */
28#define BCOM_FEC_RX_BD_BC 0x00800000ul /* DA is broadcast */
29#define BCOM_FEC_RX_BD_MC 0x00400000ul /* DA is multicast and not broadcast */
30#define BCOM_FEC_RX_BD_LG 0x00200000ul /* Rx frame length violation */
31#define BCOM_FEC_RX_BD_NO 0x00100000ul /* Rx non-octet aligned frame */
32#define BCOM_FEC_RX_BD_CR 0x00040000ul /* Rx CRC error */
33#define BCOM_FEC_RX_BD_OV 0x00020000ul /* overrun */
34#define BCOM_FEC_RX_BD_TR 0x00010000ul /* Rx frame truncated */
35#define BCOM_FEC_RX_BD_LEN_MASK 0x000007fful /* mask for length of received frame */
36#define BCOM_FEC_RX_BD_ERRORS (BCOM_FEC_RX_BD_LG | BCOM_FEC_RX_BD_NO | \
37 BCOM_FEC_RX_BD_CR | BCOM_FEC_RX_BD_OV | BCOM_FEC_RX_BD_TR)
38
39
40extern struct bcom_task *
41bcom_fec_rx_init(int queue_len, phys_addr_t fifo, int maxbufsize);
42
43extern int
44bcom_fec_rx_reset(struct bcom_task *tsk);
45
46extern void
47bcom_fec_rx_release(struct bcom_task *tsk);
48
49
50extern struct bcom_task *
51bcom_fec_tx_init(int queue_len, phys_addr_t fifo);
52
53extern int
54bcom_fec_tx_reset(struct bcom_task *tsk);
55
56extern void
57bcom_fec_tx_release(struct bcom_task *tsk);
58
59
60#endif /* __BESTCOMM_FEC_H__ */
61
diff --git a/arch/powerpc/sysdev/bestcomm/gen_bd.c b/arch/powerpc/sysdev/bestcomm/gen_bd.c
new file mode 100644
index 000000000000..8d33eafbb3f4
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/gen_bd.c
@@ -0,0 +1,260 @@
1/*
2 * Driver for MPC52xx processor BestComm General Buffer Descriptor
3 *
4 * Copyright (C) 2007 Sylvain Munaut <tnt@246tNt.com>
5 * Copyright (C) 2006 AppSpec Computer Technologies Corp.
6 * Jeff Gibbons <jeff.gibbons@appspec.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published
10 * by the Free Software Foundation.
11 *
12 */
13
14#include <linux/version.h>
15#include <linux/module.h>
16#include <linux/kernel.h>
17#include <linux/string.h>
18#include <linux/types.h>
19#include <asm/errno.h>
20#include <asm/io.h>
21
22#include <asm/mpc52xx.h>
23
24#include "bestcomm.h"
25#include "bestcomm_priv.h"
26#include "gen_bd.h"
27
28
29/* ======================================================================== */
30/* Task image/var/inc */
31/* ======================================================================== */
32
33/* gen_bd tasks images */
34extern u32 bcom_gen_bd_rx_task[];
35extern u32 bcom_gen_bd_tx_task[];
36
37/* rx task vars that need to be set before enabling the task */
38struct bcom_gen_bd_rx_var {
39 u32 enable; /* (u16*) address of task's control register */
40 u32 fifo; /* (u32*) address of gen_bd's fifo */
41 u32 bd_base; /* (struct bcom_bd*) beginning of ring buffer */
42 u32 bd_last; /* (struct bcom_bd*) end of ring buffer */
43 u32 bd_start; /* (struct bcom_bd*) current bd */
44 u32 buffer_size; /* size of receive buffer */
45};
46
47/* rx task incs that need to be set before enabling the task */
48struct bcom_gen_bd_rx_inc {
49 u16 pad0;
50 s16 incr_bytes;
51 u16 pad1;
52 s16 incr_dst;
53};
54
55/* tx task vars that need to be set before enabling the task */
56struct bcom_gen_bd_tx_var {
57 u32 fifo; /* (u32*) address of gen_bd's fifo */
58 u32 enable; /* (u16*) address of task's control register */
59 u32 bd_base; /* (struct bcom_bd*) beginning of ring buffer */
60 u32 bd_last; /* (struct bcom_bd*) end of ring buffer */
61 u32 bd_start; /* (struct bcom_bd*) current bd */
62 u32 buffer_size; /* set by uCode for each packet */
63};
64
65/* tx task incs that need to be set before enabling the task */
66struct bcom_gen_bd_tx_inc {
67 u16 pad0;
68 s16 incr_bytes;
69 u16 pad1;
70 s16 incr_src;
71 u16 pad2;
72 s16 incr_src_ma;
73};
74
75/* private structure */
76struct bcom_gen_bd_priv {
77 phys_addr_t fifo;
78 int initiator;
79 int ipr;
80 int maxbufsize;
81};
82
83
84/* ======================================================================== */
85/* Task support code */
86/* ======================================================================== */
87
88struct bcom_task *
89bcom_gen_bd_rx_init(int queue_len, phys_addr_t fifo,
90 int initiator, int ipr, int maxbufsize)
91{
92 struct bcom_task *tsk;
93 struct bcom_gen_bd_priv *priv;
94
95 tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_gen_bd),
96 sizeof(struct bcom_gen_bd_priv));
97 if (!tsk)
98 return NULL;
99
100 tsk->flags = BCOM_FLAGS_NONE;
101
102 priv = tsk->priv;
103 priv->fifo = fifo;
104 priv->initiator = initiator;
105 priv->ipr = ipr;
106 priv->maxbufsize = maxbufsize;
107
108 if (bcom_gen_bd_rx_reset(tsk)) {
109 bcom_task_free(tsk);
110 return NULL;
111 }
112
113 return tsk;
114}
115EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_init);
116
117int
118bcom_gen_bd_rx_reset(struct bcom_task *tsk)
119{
120 struct bcom_gen_bd_priv *priv = tsk->priv;
121 struct bcom_gen_bd_rx_var *var;
122 struct bcom_gen_bd_rx_inc *inc;
123
124 /* Shutdown the task */
125 bcom_disable_task(tsk->tasknum);
126
127 /* Reset the microcode */
128 var = (struct bcom_gen_bd_rx_var *) bcom_task_var(tsk->tasknum);
129 inc = (struct bcom_gen_bd_rx_inc *) bcom_task_inc(tsk->tasknum);
130
131 if (bcom_load_image(tsk->tasknum, bcom_gen_bd_rx_task))
132 return -1;
133
134 var->enable = bcom_eng->regs_base +
135 offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);
136 var->fifo = (u32) priv->fifo;
137 var->bd_base = tsk->bd_pa;
138 var->bd_last = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);
139 var->bd_start = tsk->bd_pa;
140 var->buffer_size = priv->maxbufsize;
141
142 inc->incr_bytes = -(s16)sizeof(u32);
143 inc->incr_dst = sizeof(u32);
144
145 /* Reset the BDs */
146 tsk->index = 0;
147 tsk->outdex = 0;
148
149 memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
150
151 /* Configure some stuff */
152 bcom_set_task_pragma(tsk->tasknum, BCOM_GEN_RX_BD_PRAGMA);
153 bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
154
155 out_8(&bcom_eng->regs->ipr[priv->initiator], priv->ipr);
156 bcom_set_initiator(tsk->tasknum, priv->initiator);
157
158 out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */
159
160 return 0;
161}
162EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_reset);
163
164void
165bcom_gen_bd_rx_release(struct bcom_task *tsk)
166{
167 /* Nothing special for the GenBD tasks */
168 bcom_task_free(tsk);
169}
170EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_release);
171
172
173extern struct bcom_task *
174bcom_gen_bd_tx_init(int queue_len, phys_addr_t fifo,
175 int initiator, int ipr)
176{
177 struct bcom_task *tsk;
178 struct bcom_gen_bd_priv *priv;
179
180 tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_gen_bd),
181 sizeof(struct bcom_gen_bd_priv));
182 if (!tsk)
183 return NULL;
184
185 tsk->flags = BCOM_FLAGS_NONE;
186
187 priv = tsk->priv;
188 priv->fifo = fifo;
189 priv->initiator = initiator;
190 priv->ipr = ipr;
191
192 if (bcom_gen_bd_tx_reset(tsk)) {
193 bcom_task_free(tsk);
194 return NULL;
195 }
196
197 return tsk;
198}
199EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_init);
200
201int
202bcom_gen_bd_tx_reset(struct bcom_task *tsk)
203{
204 struct bcom_gen_bd_priv *priv = tsk->priv;
205 struct bcom_gen_bd_tx_var *var;
206 struct bcom_gen_bd_tx_inc *inc;
207
208 /* Shutdown the task */
209 bcom_disable_task(tsk->tasknum);
210
211 /* Reset the microcode */
212 var = (struct bcom_gen_bd_tx_var *) bcom_task_var(tsk->tasknum);
213 inc = (struct bcom_gen_bd_tx_inc *) bcom_task_inc(tsk->tasknum);
214
215 if (bcom_load_image(tsk->tasknum, bcom_gen_bd_tx_task))
216 return -1;
217
218 var->enable = bcom_eng->regs_base +
219 offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);
220 var->fifo = (u32) priv->fifo;
221 var->bd_base = tsk->bd_pa;
222 var->bd_last = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);
223 var->bd_start = tsk->bd_pa;
224
225 inc->incr_bytes = -(s16)sizeof(u32);
226 inc->incr_src = sizeof(u32);
227 inc->incr_src_ma = sizeof(u8);
228
229 /* Reset the BDs */
230 tsk->index = 0;
231 tsk->outdex = 0;
232
233 memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
234
235 /* Configure some stuff */
236 bcom_set_task_pragma(tsk->tasknum, BCOM_GEN_TX_BD_PRAGMA);
237 bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
238
239 out_8(&bcom_eng->regs->ipr[priv->initiator], priv->ipr);
240 bcom_set_initiator(tsk->tasknum, priv->initiator);
241
242 out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */
243
244 return 0;
245}
246EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_reset);
247
248void
249bcom_gen_bd_tx_release(struct bcom_task *tsk)
250{
251 /* Nothing special for the GenBD tasks */
252 bcom_task_free(tsk);
253}
254EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_release);
255
256
257MODULE_DESCRIPTION("BestComm General Buffer Descriptor tasks driver");
258MODULE_AUTHOR("Jeff Gibbons <jeff.gibbons@appspec.com>");
259MODULE_LICENSE("GPL v2");
260
diff --git a/arch/powerpc/sysdev/bestcomm/gen_bd.h b/arch/powerpc/sysdev/bestcomm/gen_bd.h
new file mode 100644
index 000000000000..5b6fa803c6aa
--- /dev/null
+++ b/arch/powerpc/sysdev/bestcomm/gen_bd.h
@@ -0,0 +1,48 @@
1/*
2 * Header for Bestcomm General Buffer Descriptor tasks driver
3 *
4 *
5 * Copyright (C) 2007 Sylvain Munaut <tnt@246tNt.com>
6 * Copyright (C) 2006 AppSpec Computer Technologies Corp.
7 * Jeff Gibbons <jeff.gibbons@appspec.com>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License version 2 as published
11 * by the Free Software Foundation.
12 *
13 *
14 */
15
16#ifndef __BESTCOMM_GEN_BD_H__
17#define __BESTCOMM_GEN_BD_H__
18
19struct bcom_gen_bd {
20 u32 status;
21 u32 buf_pa;
22};
23
24
25extern struct bcom_task *
26bcom_gen_bd_rx_init(int queue_len, phys_addr_t fifo,
27 int initiator, int ipr, int maxbufsize);
28
29extern int
30bcom_gen_bd_rx_reset(struct bcom_task *tsk);
31
32extern void
33bcom_gen_bd_rx_release(struct bcom_task *tsk);
34
35
36extern struct bcom_task *
37bcom_gen_bd_tx_init(int queue_len, phys_addr_t fifo,
38 int initiator, int ipr);
39
40extern int
41bcom_gen_bd_tx_reset(struct bcom_task *tsk);
42
43extern void
44bcom_gen_bd_tx_release(struct bcom_task *tsk);
45
46
47#endif /* __BESTCOMM_GEN_BD_H__ */
48
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