Merge branch 'for-2.6.24' of git://git.secretlab.ca/git/linux-2.6-mpc52xx into merge
authorPaul Mackerras <paulus@samba.org>
Wed, 17 Oct 2007 12:31:13 +0000 (22:31 +1000)
committerPaul Mackerras <paulus@samba.org>
Wed, 17 Oct 2007 12:31:13 +0000 (22:31 +1000)
27 files changed:
arch/powerpc/Kconfig
arch/powerpc/boot/dts/lite5200b.dts
arch/powerpc/lib/Makefile
arch/powerpc/lib/rheap.c
arch/powerpc/platforms/Kconfig
arch/powerpc/platforms/Kconfig.cputype
arch/powerpc/sysdev/Makefile
arch/powerpc/sysdev/bestcomm/Kconfig [new file with mode: 0644]
arch/powerpc/sysdev/bestcomm/Makefile [new file with mode: 0644]
arch/powerpc/sysdev/bestcomm/ata.c [new file with mode: 0644]
arch/powerpc/sysdev/bestcomm/ata.h [new file with mode: 0644]
arch/powerpc/sysdev/bestcomm/bcom_ata_task.c [new file with mode: 0644]
arch/powerpc/sysdev/bestcomm/bcom_fec_rx_task.c [new file with mode: 0644]
arch/powerpc/sysdev/bestcomm/bcom_fec_tx_task.c [new file with mode: 0644]
arch/powerpc/sysdev/bestcomm/bcom_gen_bd_rx_task.c [new file with mode: 0644]
arch/powerpc/sysdev/bestcomm/bcom_gen_bd_tx_task.c [new file with mode: 0644]
arch/powerpc/sysdev/bestcomm/bestcomm.c [new file with mode: 0644]
arch/powerpc/sysdev/bestcomm/bestcomm.h [new file with mode: 0644]
arch/powerpc/sysdev/bestcomm/bestcomm_priv.h [new file with mode: 0644]
arch/powerpc/sysdev/bestcomm/fec.c [new file with mode: 0644]
arch/powerpc/sysdev/bestcomm/fec.h [new file with mode: 0644]
arch/powerpc/sysdev/bestcomm/gen_bd.c [new file with mode: 0644]
arch/powerpc/sysdev/bestcomm/gen_bd.h [new file with mode: 0644]
arch/powerpc/sysdev/bestcomm/sram.c [new file with mode: 0644]
arch/powerpc/sysdev/bestcomm/sram.h [new file with mode: 0644]
arch/ppc/Kconfig
include/asm-ppc/mpc52xx_psc.h

index 5e001ad588a7d385ea5f916ccd32b72c92ed93fe..5624fb060d9d865b7661a8e7d58f9663587f422b 100644 (file)
@@ -699,3 +699,7 @@ source "crypto/Kconfig"
 config PPC_CLOCK
        bool
        default n
+
+config PPC_LIB_RHEAP
+       bool
+
index a6bb1d0558ef838cf281e14aa8de66d8f00d5776..6582c9a39b27aacee6f539619fab4ddf25248a6e 100644 (file)
                ethernet@3000 {
                        device_type = "network";
                        compatible = "mpc5200b-fec","mpc5200-fec";
-                       reg = <3000 800>;
+                       reg = <3000 400>;
                        mac-address = [ 02 03 04 05 06 07 ]; // Bad!
                        interrupts = <2 5 0>;
                        interrupt-parent = <&mpc5200_pic>;
+                       phy-handle = <&phy0>;
+               };
+
+               mdio@3000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       device_type = "mdio";
+                       compatible = "mpc5200b-fec-phy";
+                       reg = <3000 400>;       // fec range, since we need to setup fec interrupts
+                       interrupts = <2 5 0>;   // these are for "mii command finished", not link changes & co.
+                       interrupt-parent = <&mpc5200_pic>;
+
+                       phy0:ethernet-phy@0 {
+                               device_type = "ethernet-phy";
+                               reg = <0>;
+                       };
                };
 
                ata@3a00 {
index 65d492e316a605f5a747addfd8f7c78812175d4b..4bb023f4c8690f332152eb00706f4f7cfa85f3e8 100644 (file)
@@ -14,7 +14,6 @@ endif
 
 obj-$(CONFIG_PPC64)    += copypage_64.o copyuser_64.o \
                           memcpy_64.o usercopy_64.o mem_64.o string.o
-obj-$(CONFIG_QUICC_ENGINE) += rheap.o
 obj-$(CONFIG_XMON)     += sstep.o
 obj-$(CONFIG_KPROBES)  += sstep.o
 obj-$(CONFIG_NOT_COHERENT_CACHE)       += dma-noncoherent.o
@@ -23,6 +22,4 @@ ifeq ($(CONFIG_PPC64),y)
 obj-$(CONFIG_SMP)      += locks.o
 endif
 
-# Temporary hack until we have migrated to asm-powerpc
-obj-$(CONFIG_8xx)      += rheap.o
-obj-$(CONFIG_CPM2)     += rheap.o
+obj-$(CONFIG_PPC_LIB_RHEAP) += rheap.o
index ada5b42dd231635205bccdbc3cedd6c72f80f0cd..22c3b4f53de793e9c58b7cbab10e0f2623813c1c 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/err.h>
 #include <linux/slab.h>
@@ -275,6 +276,7 @@ rh_info_t *rh_create(unsigned int alignment)
 
        return info;
 }
+EXPORT_SYMBOL_GPL(rh_create);
 
 /*
  * Destroy a dynamically created remote heap.  Deallocate only if the areas
@@ -288,6 +290,7 @@ void rh_destroy(rh_info_t * info)
        if ((info->flags & RHIF_STATIC_INFO) == 0)
                kfree(info);
 }
+EXPORT_SYMBOL_GPL(rh_destroy);
 
 /*
  * 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,
        for (i = 0, blk = block; i < max_blocks; i++, blk++)
                list_add(&blk->list, &info->empty_list);
 }
+EXPORT_SYMBOL_GPL(rh_init);
 
 /* Attach a free memory region, coalesces regions if adjuscent */
 int 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)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(rh_attach_region);
 
 /* Detatch given address range, splits free block if needed. */
 unsigned 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)
 
        return s;
 }
+EXPORT_SYMBOL_GPL(rh_detach_region);
 
 /* Allocate a block of memory at the specified alignment.  The value returned
  * 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
 
        return start;
 }
+EXPORT_SYMBOL_GPL(rh_alloc_align);
 
 /* Allocate a block of memory at the default alignment.  The value returned is
  * 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)
 {
        return rh_alloc_align(info, size, info->alignment, owner);
 }
+EXPORT_SYMBOL_GPL(rh_alloc);
 
 /* Allocate a block of memory at the given offset, rounded up to the default
  * 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
 
        return start;
 }
+EXPORT_SYMBOL_GPL(rh_alloc_fixed);
 
 /* Deallocate the memory previously allocated by one of the rh_alloc functions.
  * 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)
 
        return size;
 }
+EXPORT_SYMBOL_GPL(rh_free);
 
 int rh_get_stats(rh_info_t * info, int what, int max_stats, rh_stats_t * stats)
 {
@@ -663,6 +673,7 @@ int rh_get_stats(rh_info_t * info, int what, int max_stats, rh_stats_t * stats)
 
        return nr;
 }
+EXPORT_SYMBOL_GPL(rh_get_stats);
 
 int rh_set_owner(rh_info_t * info, unsigned long start, const char *owner)
 {
@@ -687,6 +698,7 @@ int rh_set_owner(rh_info_t * info, unsigned long start, const char *owner)
 
        return size;
 }
+EXPORT_SYMBOL_GPL(rh_set_owner);
 
 void rh_dump(rh_info_t * info)
 {
@@ -722,6 +734,7 @@ void rh_dump(rh_info_t * info)
                       st[i].size, st[i].owner != NULL ? st[i].owner : "");
        printk(KERN_INFO "\n");
 }
+EXPORT_SYMBOL_GPL(rh_dump);
 
 void rh_dump_blk(rh_info_t * info, rh_block_t * blk)
 {
@@ -729,3 +742,5 @@ void rh_dump_blk(rh_info_t * info, rh_block_t * blk)
               "blk @0x%p: 0x%lx-0x%lx (%u)\n",
               blk, blk->start, blk->start + blk->size, blk->size);
 }
+EXPORT_SYMBOL_GPL(rh_dump_blk);
+
index 186397f283bbbcbc187f75e235b172f584d3619e..229d355ed86a7264548e1dcb0b4145a3e0349c6a 100644 (file)
@@ -264,6 +264,7 @@ config TAU_AVERAGE
 
 config QUICC_ENGINE
        bool
+       select PPC_LIB_RHEAP
        help
          The QUICC Engine (QE) is a new generation of communications
          coprocessors on Freescale embedded CPUs (akin to CPM in older chips).
@@ -274,6 +275,7 @@ config CPM2
        bool
        default n
        select CPM
+       select PPC_LIB_RHEAP
        help
          The CPM2 (Communications Processor Module) is a coprocessor on
          embedded CPUs made by Freescale.  Selecting this option means that
@@ -313,4 +315,6 @@ config FSL_ULI1575
 config CPM
        bool
 
+source "arch/powerpc/sysdev/bestcomm/Kconfig"
+
 endmenu
index 4c315be250158fcfc1d1b24804f55ce76f137eb3..3c7325ec36ecef5a1512ba9da639aee95eb7c310 100644 (file)
@@ -37,6 +37,7 @@ config PPC_8xx
        select FSL_SOC
        select 8xx
        select WANT_DEVICE_TREE
+       select PPC_LIB_RHEAP
 
 config 40x
        bool "AMCC 40x"
index 1a6f5641ebc82c16dc97ba8f9f8af57a825c8d0d..99a77d743d48c55643cfa3b59ddd09c3b65bf2ad 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_FSL_SOC)         += fsl_soc.o
 obj-$(CONFIG_FSL_PCI)          += fsl_pci.o
 obj-$(CONFIG_TSI108_BRIDGE)    += tsi108_pci.o tsi108_dev.o
 obj-$(CONFIG_QUICC_ENGINE)     += qe_lib/
+obj-$(CONFIG_PPC_BESTCOMM)     += bestcomm/
 mv64x60-$(CONFIG_PCI)          += mv64x60_pci.o
 obj-$(CONFIG_MV64X60)          += $(mv64x60-y) mv64x60_pic.o mv64x60_dev.o \
                                   mv64x60_udbg.o
diff --git a/arch/powerpc/sysdev/bestcomm/Kconfig b/arch/powerpc/sysdev/bestcomm/Kconfig
new file mode 100644 (file)
index 0000000..57cc565
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# Kconfig options for Bestcomm
+#
+
+config PPC_BESTCOMM
+       tristate "Bestcomm DMA engine support"
+       depends on PPC_MPC52xx
+       default n
+       select PPC_LIB_RHEAP
+       help
+         BestComm is the name of the communication coprocessor found
+         on the Freescale MPC5200 family of processor. It's usage is
+         optionnal for some drivers (like ATA), but required for
+         others (like FEC).
+
+         If you want to use drivers that require DMA operations,
+         answer Y or M. Otherwise say N.
+
+config PPC_BESTCOMM_ATA
+       tristate "Bestcomm ATA task support"
+       depends on PPC_BESTCOMM
+       default n
+       help
+         This option enables the support for the ATA task.
+
+config PPC_BESTCOMM_FEC
+       tristate "Bestcomm FEC tasks support"
+       depends on PPC_BESTCOMM
+       default n
+       help
+         This option enables the support for the FEC tasks.
+
+config PPC_BESTCOMM_GEN_BD
+       tristate "Bestcomm GenBD tasks support"
+       depends on PPC_BESTCOMM
+       default n
+       help
+         This option enables the support for the GenBD tasks.
+
diff --git a/arch/powerpc/sysdev/bestcomm/Makefile b/arch/powerpc/sysdev/bestcomm/Makefile
new file mode 100644 (file)
index 0000000..aed2df2
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# Makefile for BestComm & co
+#
+
+bestcomm-core-objs     := bestcomm.o sram.o
+bestcomm-ata-objs      := ata.o bcom_ata_task.o
+bestcomm-fec-objs      := fec.o bcom_fec_rx_task.o bcom_fec_tx_task.o
+bestcomm-gen-bd-objs   := gen_bd.o bcom_gen_bd_rx_task.o bcom_gen_bd_tx_task.o
+
+obj-$(CONFIG_PPC_BESTCOMM)             += bestcomm-core.o
+obj-$(CONFIG_PPC_BESTCOMM_ATA)         += bestcomm-ata.o
+obj-$(CONFIG_PPC_BESTCOMM_FEC)         += bestcomm-fec.o
+obj-$(CONFIG_PPC_BESTCOMM_GEN_BD)      += bestcomm-gen-bd.o
diff --git a/arch/powerpc/sysdev/bestcomm/ata.c b/arch/powerpc/sysdev/bestcomm/ata.c
new file mode 100644 (file)
index 0000000..1f5258f
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Bestcomm ATA task driver
+ *
+ *
+ * Patterned after bestcomm/fec.c by Dale Farnsworth <dfarnsworth@mvista.com>
+ *                                   2003-2004 (c) MontaVista, Software, Inc.
+ *
+ * Copyright (C) 2006-2007 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2006      Freescale - John Rigby
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <asm/io.h>
+
+#include "bestcomm.h"
+#include "bestcomm_priv.h"
+#include "ata.h"
+
+
+/* ======================================================================== */
+/* Task image/var/inc                                                       */
+/* ======================================================================== */
+
+/* ata task image */
+extern u32 bcom_ata_task[];
+
+/* ata task vars that need to be set before enabling the task */
+struct bcom_ata_var {
+       u32 enable;             /* (u16*) address of task's control register */
+       u32 bd_base;            /* (struct bcom_bd*) beginning of ring buffer */
+       u32 bd_last;            /* (struct bcom_bd*) end of ring buffer */
+       u32 bd_start;           /* (struct bcom_bd*) current bd */
+       u32 buffer_size;        /* size of receive buffer */
+};
+
+/* ata task incs that need to be set before enabling the task */
+struct bcom_ata_inc {
+       u16 pad0;
+       s16 incr_bytes;
+       u16 pad1;
+       s16 incr_dst;
+       u16 pad2;
+       s16 incr_src;
+};
+
+
+/* ======================================================================== */
+/* Task support code                                                        */
+/* ======================================================================== */
+
+struct bcom_task *
+bcom_ata_init(int queue_len, int maxbufsize)
+{
+       struct bcom_task *tsk;
+       struct bcom_ata_var *var;
+       struct bcom_ata_inc *inc;
+
+       tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_ata_bd), 0);
+       if (!tsk)
+               return NULL;
+
+       tsk->flags = BCOM_FLAGS_NONE;
+
+       bcom_ata_reset_bd(tsk);
+
+       var = (struct bcom_ata_var *) bcom_task_var(tsk->tasknum);
+       inc = (struct bcom_ata_inc *) bcom_task_inc(tsk->tasknum);
+
+       if (bcom_load_image(tsk->tasknum, bcom_ata_task)) {
+               bcom_task_free(tsk);
+               return NULL;
+       }
+
+       var->enable     = bcom_eng->regs_base +
+                               offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);
+       var->bd_base    = tsk->bd_pa;
+       var->bd_last    = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);
+       var->bd_start   = tsk->bd_pa;
+       var->buffer_size = maxbufsize;
+
+       /* Configure some stuff */
+       bcom_set_task_pragma(tsk->tasknum, BCOM_ATA_PRAGMA);
+       bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
+
+       out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ATA_RX], BCOM_IPR_ATA_RX);
+       out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ATA_TX], BCOM_IPR_ATA_TX);
+
+       out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */
+
+       return tsk;
+}
+EXPORT_SYMBOL_GPL(bcom_ata_init);
+
+void bcom_ata_rx_prepare(struct bcom_task *tsk)
+{
+       struct bcom_ata_inc *inc;
+
+       inc = (struct bcom_ata_inc *) bcom_task_inc(tsk->tasknum);
+
+       inc->incr_bytes = -(s16)sizeof(u32);
+       inc->incr_src   = 0;
+       inc->incr_dst   = sizeof(u32);
+
+       bcom_set_initiator(tsk->tasknum, BCOM_INITIATOR_ATA_RX);
+}
+EXPORT_SYMBOL_GPL(bcom_ata_rx_prepare);
+
+void bcom_ata_tx_prepare(struct bcom_task *tsk)
+{
+       struct bcom_ata_inc *inc;
+
+       inc = (struct bcom_ata_inc *) bcom_task_inc(tsk->tasknum);
+
+       inc->incr_bytes = -(s16)sizeof(u32);
+       inc->incr_src   = sizeof(u32);
+       inc->incr_dst   = 0;
+
+       bcom_set_initiator(tsk->tasknum, BCOM_INITIATOR_ATA_TX);
+}
+EXPORT_SYMBOL_GPL(bcom_ata_tx_prepare);
+
+void bcom_ata_reset_bd(struct bcom_task *tsk)
+{
+       struct bcom_ata_var *var;
+
+       /* Reset all BD */
+       memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
+
+       tsk->index = 0;
+       tsk->outdex = 0;
+
+       var = (struct bcom_ata_var *) bcom_task_var(tsk->tasknum);
+       var->bd_start = var->bd_base;
+}
+EXPORT_SYMBOL_GPL(bcom_ata_reset_bd);
+
+void bcom_ata_release(struct bcom_task *tsk)
+{
+       /* Nothing special for the ATA tasks */
+       bcom_task_free(tsk);
+}
+EXPORT_SYMBOL_GPL(bcom_ata_release);
+
+
+MODULE_DESCRIPTION("BestComm ATA task driver");
+MODULE_AUTHOR("John Rigby");
+MODULE_LICENSE("GPL v2");
+
diff --git a/arch/powerpc/sysdev/bestcomm/ata.h b/arch/powerpc/sysdev/bestcomm/ata.h
new file mode 100644 (file)
index 0000000..1098276
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Header for Bestcomm ATA task driver
+ *
+ *
+ * Copyright (C) 2006 Freescale - John Rigby
+ * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef __BESTCOMM_ATA_H__
+#define __BESTCOMM_ATA_H__
+
+
+struct bcom_ata_bd {
+       u32     status;
+       u32     dst_pa;
+       u32     src_pa;
+};
+
+extern struct bcom_task *
+bcom_ata_init(int queue_len, int maxbufsize);
+
+extern void
+bcom_ata_rx_prepare(struct bcom_task *tsk);
+
+extern void
+bcom_ata_tx_prepare(struct bcom_task *tsk);
+
+extern void
+bcom_ata_reset_bd(struct bcom_task *tsk);
+
+
+#endif /* __BESTCOMM_ATA_H__ */
+
diff --git a/arch/powerpc/sysdev/bestcomm/bcom_ata_task.c b/arch/powerpc/sysdev/bestcomm/bcom_ata_task.c
new file mode 100644 (file)
index 0000000..cc6049a
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Bestcomm ATA task microcode
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * Created based on bestcom/code_dma/image_rtos1/dma_image.hex
+ */
+
+#include <asm/types.h>
+
+/*
+ * The header consists of the following fields:
+ *     u32     magic;
+ *     u8      desc_size;
+ *     u8      var_size;
+ *     u8      inc_size;
+ *     u8      first_var;
+ *     u8      reserved[8];
+ *
+ * The size fields contain the number of 32-bit words.
+ */
+
+u32 bcom_ata_task[] = {
+       /* header */
+       0x4243544b,
+       0x0e060709,
+       0x00000000,
+       0x00000000,
+
+       /* Task descriptors */
+       0x8198009b, /* LCD: idx0 = var3; idx0 <= var2; idx0 += inc3 */
+       0x13e00c08, /*   DRD1A: var3 = var1; FN=0 MORE init=31 WS=0 RS=0 */
+       0xb8000264, /*   LCD: idx1 = *idx0, idx2 = var0; idx1 < var9; idx1 += inc4, idx2 += inc4 */
+       0x10000f00, /*     DRD1A: var3 = idx0; FN=0 MORE init=0 WS=0 RS=0 */
+       0x60140002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */
+       0x0c8cfc8a, /*     DRD2B1: *idx2 = EU3(); EU3(*idx2,var10)  */
+       0xd8988240, /*   LCDEXT: idx1 = idx1; idx1 > var9; idx1 += inc0 */
+       0xf845e011, /*   LCDEXT: idx2 = *(idx0 + var00000015); ; idx2 += inc2 */
+       0xb845e00a, /*   LCD: idx3 = *(idx0 + var00000019); ; idx3 += inc1 */
+       0x0bfecf90, /*     DRD1A: *idx3 = *idx2; FN=0 TFD init=31 WS=3 RS=3 */
+       0x9898802d, /*   LCD: idx1 = idx1; idx1 once var0; idx1 += inc5 */
+       0x64000005, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 INT EXT init=0 WS=0 RS=0 */
+       0x0c0cf849, /*     DRD2B1: *idx0 = EU3(); EU3(idx1,var9)  */
+       0x000001f8, /* NOP */
+
+       /* VAR[9]-VAR[14] */
+       0x40000000,
+       0x7fff7fff,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+
+       /* INC[0]-INC[6] */
+       0x40000000,
+       0xe0000000,
+       0xe0000000,
+       0xa000000c,
+       0x20000000,
+       0x00000000,
+       0x00000000,
+};
+
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 (file)
index 0000000..a1ad6a0
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Bestcomm FEC RX task microcode
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * Automatically created based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex
+ * on Tue Mar 22 11:19:38 2005 GMT
+ */
+
+#include <asm/types.h>
+
+/*
+ * The header consists of the following fields:
+ *     u32     magic;
+ *     u8      desc_size;
+ *     u8      var_size;
+ *     u8      inc_size;
+ *     u8      first_var;
+ *     u8      reserved[8];
+ *
+ * The size fields contain the number of 32-bit words.
+ */
+
+u32 bcom_fec_rx_task[] = {
+       /* header */
+       0x4243544b,
+       0x18060709,
+       0x00000000,
+       0x00000000,
+
+       /* Task descriptors */
+       0x808220e3, /* LCD: idx0 = var1, idx1 = var4; idx1 <= var3; idx0 += inc4, idx1 += inc3 */
+       0x10601010, /*   DRD1A: var4 = var2; FN=0 MORE init=3 WS=0 RS=0 */
+       0xb8800264, /*   LCD: idx2 = *idx1, idx3 = var0; idx2 < var9; idx2 += inc4, idx3 += inc4 */
+       0x10001308, /*     DRD1A: var4 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
+       0x60140002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */
+       0x0cccfcca, /*     DRD2B1: *idx3 = EU3(); EU3(*idx3,var10)  */
+       0x80004000, /*   LCDEXT: idx2 = 0x00000000; ; */
+       0xb8c58029, /*   LCD: idx3 = *(idx1 + var00000015); idx3 once var0; idx3 += inc5 */
+       0x60000002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=0 RS=0 */
+       0x088cf8cc, /*     DRD2B1: idx2 = EU3(); EU3(idx3,var12)  */
+       0x991982f2, /*   LCD: idx2 = idx2, idx3 = idx3; idx2 > var11; idx2 += inc6, idx3 += inc2 */
+       0x006acf80, /*     DRD1A: *idx3 = *idx0; FN=0 init=3 WS=1 RS=1 */
+       0x80004000, /*   LCDEXT: idx2 = 0x00000000; ; */
+       0x9999802d, /*   LCD: idx3 = idx3; idx3 once var0; idx3 += inc5 */
+       0x70000002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */
+       0x034cfc4e, /*     DRD2B1: var13 = EU3(); EU3(*idx1,var14)  */
+       0x00008868, /*     DRD1A: idx2 = var13; FN=0 init=0 WS=0 RS=0 */
+       0x99198341, /*   LCD: idx2 = idx2, idx3 = idx3; idx2 > var13; idx2 += inc0, idx3 += inc1 */
+       0x007ecf80, /*     DRD1A: *idx3 = *idx0; FN=0 init=3 WS=3 RS=3 */
+       0x99198272, /*   LCD: idx2 = idx2, idx3 = idx3; idx2 > var9; idx2 += inc6, idx3 += inc2 */
+       0x046acf80, /*     DRD1A: *idx3 = *idx0; FN=0 INT init=3 WS=1 RS=1 */
+       0x9819002d, /*   LCD: idx2 = idx0; idx2 once var0; idx2 += inc5 */
+       0x0060c790, /*     DRD1A: *idx1 = *idx2; FN=0 init=3 WS=0 RS=0 */
+       0x000001f8, /*   NOP */
+
+       /* VAR[9]-VAR[14] */
+       0x40000000,
+       0x7fff7fff,
+       0x00000000,
+       0x00000003,
+       0x40000008,
+       0x43ffffff,
+
+       /* INC[0]-INC[6] */
+       0x40000000,
+       0xe0000000,
+       0xe0000000,
+       0xa0000008,
+       0x20000000,
+       0x00000000,
+       0x4000ffff,
+};
+
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 (file)
index 0000000..b1c495c
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Bestcomm FEC TX task microcode
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * Automatically created based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex
+ * on Tue Mar 22 11:19:29 2005 GMT
+ */
+
+#include <asm/types.h>
+
+/*
+ * The header consists of the following fields:
+ *     u32     magic;
+ *     u8      desc_size;
+ *     u8      var_size;
+ *     u8      inc_size;
+ *     u8      first_var;
+ *     u8      reserved[8];
+ *
+ * The size fields contain the number of 32-bit words.
+ */
+
+u32 bcom_fec_tx_task[] = {
+       /* header */
+       0x4243544b,
+       0x2407070d,
+       0x00000000,
+       0x00000000,
+
+       /* Task descriptors */
+       0x8018001b, /* LCD: idx0 = var0; idx0 <= var0; idx0 += inc3 */
+       0x60000005, /*   DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */
+       0x01ccfc0d, /*   DRD2B1: var7 = EU3(); EU3(*idx0,var13)  */
+       0x8082a123, /* LCD: idx0 = var1, idx1 = var5; idx1 <= var4; idx0 += inc4, idx1 += inc3 */
+       0x10801418, /*   DRD1A: var5 = var3; FN=0 MORE init=4 WS=0 RS=0 */
+       0xf88103a4, /*   LCDEXT: idx2 = *idx1, idx3 = var2; idx2 < var14; idx2 += inc4, idx3 += inc4 */
+       0x801a6024, /*   LCD: idx4 = var0; ; idx4 += inc4 */
+       0x10001708, /*     DRD1A: var5 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
+       0x60140002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */
+       0x0cccfccf, /*     DRD2B1: *idx3 = EU3(); EU3(*idx3,var15)  */
+       0x991a002c, /*   LCD: idx2 = idx2, idx3 = idx4; idx2 once var0; idx2 += inc5, idx3 += inc4 */
+       0x70000002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */
+       0x024cfc4d, /*     DRD2B1: var9 = EU3(); EU3(*idx1,var13)  */
+       0x60000003, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=3 EXT init=0 WS=0 RS=0 */
+       0x0cccf247, /*     DRD2B1: *idx3 = EU3(); EU3(var9,var7)  */
+       0x80004000, /*   LCDEXT: idx2 = 0x00000000; ; */
+       0xb8c80029, /*   LCD: idx3 = *(idx1 + var0000001a); idx3 once var0; idx3 += inc5 */
+       0x70000002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */
+       0x088cf8d1, /*     DRD2B1: idx2 = EU3(); EU3(idx3,var17)  */
+       0x00002f10, /*     DRD1A: var11 = idx2; FN=0 init=0 WS=0 RS=0 */
+       0x99198432, /*   LCD: idx2 = idx2, idx3 = idx3; idx2 > var16; idx2 += inc6, idx3 += inc2 */
+       0x008ac398, /*     DRD1A: *idx0 = *idx3; FN=0 init=4 WS=1 RS=1 */
+       0x80004000, /*   LCDEXT: idx2 = 0x00000000; ; */
+       0x9999802d, /*   LCD: idx3 = idx3; idx3 once var0; idx3 += inc5 */
+       0x70000002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT MORE init=0 WS=0 RS=0 */
+       0x048cfc53, /*     DRD2B1: var18 = EU3(); EU3(*idx1,var19)  */
+       0x60000008, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=8 EXT init=0 WS=0 RS=0 */
+       0x088cf48b, /*     DRD2B1: idx2 = EU3(); EU3(var18,var11)  */
+       0x99198481, /*   LCD: idx2 = idx2, idx3 = idx3; idx2 > var18; idx2 += inc0, idx3 += inc1 */
+       0x009ec398, /*     DRD1A: *idx0 = *idx3; FN=0 init=4 WS=3 RS=3 */
+       0x991983b2, /*   LCD: idx2 = idx2, idx3 = idx3; idx2 > var14; idx2 += inc6, idx3 += inc2 */
+       0x088ac398, /*     DRD1A: *idx0 = *idx3; FN=0 TFD init=4 WS=1 RS=1 */
+       0x9919002d, /*   LCD: idx2 = idx2; idx2 once var0; idx2 += inc5 */
+       0x60000005, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */
+       0x0c4cf88e, /*     DRD2B1: *idx1 = EU3(); EU3(idx2,var14)  */
+       0x000001f8, /*   NOP */
+
+       /* VAR[13]-VAR[19] */
+       0x0c000000,
+       0x40000000,
+       0x7fff7fff,
+       0x00000000,
+       0x00000003,
+       0x40000004,
+       0x43ffffff,
+
+       /* INC[0]-INC[6] */
+       0x40000000,
+       0xe0000000,
+       0xe0000000,
+       0xa0000008,
+       0x20000000,
+       0x00000000,
+       0x4000ffff,
+};
+
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 (file)
index 0000000..efee022
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Bestcomm GenBD RX task microcode
+ *
+ * Copyright (C) 2006 AppSpec Computer Technologies Corp.
+ *                    Jeff Gibbons <jeff.gibbons@appspec.com>
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * Based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex
+ * on Tue Mar 4 10:14:12 2006 GMT
+ *
+ */
+
+#include <asm/types.h>
+
+/*
+ * The header consists of the following fields:
+ *     u32     magic;
+ *     u8      desc_size;
+ *     u8      var_size;
+ *     u8      inc_size;
+ *     u8      first_var;
+ *     u8      reserved[8];
+ *
+ * The size fields contain the number of 32-bit words.
+ */
+
+u32 bcom_gen_bd_rx_task[] = {
+       /* header */
+       0x4243544b,
+       0x0d020409,
+       0x00000000,
+       0x00000000,
+
+       /* Task descriptors */
+       0x808220da, /* LCD: idx0 = var1, idx1 = var4; idx1 <= var3; idx0 += inc3, idx1 += inc2 */
+       0x13e01010, /*   DRD1A: var4 = var2; FN=0 MORE init=31 WS=0 RS=0 */
+       0xb880025b, /*   LCD: idx2 = *idx1, idx3 = var0; idx2 < var9; idx2 += inc3, idx3 += inc3 */
+       0x10001308, /*     DRD1A: var4 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
+       0x60140002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */
+       0x0cccfcca, /*     DRD2B1: *idx3 = EU3(); EU3(*idx3,var10)  */
+       0xd9190240, /*   LCDEXT: idx2 = idx2; idx2 > var9; idx2 += inc0 */
+       0xb8c5e009, /*   LCD: idx3 = *(idx1 + var00000015); ; idx3 += inc1 */
+       0x07fecf80, /*     DRD1A: *idx3 = *idx0; FN=0 INT init=31 WS=3 RS=3 */
+       0x99190024, /*   LCD: idx2 = idx2; idx2 once var0; idx2 += inc4 */
+       0x60000005, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */
+       0x0c4cf889, /*     DRD2B1: *idx1 = EU3(); EU3(idx2,var9)  */
+       0x000001f8, /*   NOP */
+
+       /* VAR[9]-VAR[10] */
+       0x40000000,
+       0x7fff7fff,
+
+       /* INC[0]-INC[3] */
+       0x40000000,
+       0xe0000000,
+       0xa0000008,
+       0x20000000,
+};
+
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 (file)
index 0000000..c605aa4
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Bestcomm GenBD TX task microcode
+ *
+ * Copyright (C) 2006 AppSpec Computer Technologies Corp.
+ *                    Jeff Gibbons <jeff.gibbons@appspec.com>
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * Based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex
+ * on Tue Mar 4 10:14:12 2006 GMT
+ *
+ */
+
+#include <asm/types.h>
+
+/*
+ * The header consists of the following fields:
+ *     u32     magic;
+ *     u8      desc_size;
+ *     u8      var_size;
+ *     u8      inc_size;
+ *     u8      first_var;
+ *     u8      reserved[8];
+ *
+ * The size fields contain the number of 32-bit words.
+ */
+
+u32 bcom_gen_bd_tx_task[] = {
+       /* header */
+       0x4243544b,
+       0x0f040609,
+       0x00000000,
+       0x00000000,
+
+       /* Task descriptors */
+       0x800220e3, /* LCD: idx0 = var0, idx1 = var4; idx1 <= var3; idx0 += inc4, idx1 += inc3 */
+       0x13e01010, /*   DRD1A: var4 = var2; FN=0 MORE init=31 WS=0 RS=0 */
+       0xb8808264, /*   LCD: idx2 = *idx1, idx3 = var1; idx2 < var9; idx2 += inc4, idx3 += inc4 */
+       0x10001308, /*     DRD1A: var4 = idx1; FN=0 MORE init=0 WS=0 RS=0 */
+       0x60140002, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */
+       0x0cccfcca, /*     DRD2B1: *idx3 = EU3(); EU3(*idx3,var10)  */
+       0xd9190300, /*   LCDEXT: idx2 = idx2; idx2 > var12; idx2 += inc0 */
+       0xb8c5e009, /*   LCD: idx3 = *(idx1 + var00000015); ; idx3 += inc1 */
+       0x03fec398, /*     DRD1A: *idx0 = *idx3; FN=0 init=31 WS=3 RS=3 */
+       0x9919826a, /*   LCD: idx2 = idx2, idx3 = idx3; idx2 > var9; idx2 += inc5, idx3 += inc2 */
+       0x0feac398, /*     DRD1A: *idx0 = *idx3; FN=0 TFD INT init=31 WS=1 RS=1 */
+       0x99190036, /*   LCD: idx2 = idx2; idx2 once var0; idx2 += inc6 */
+       0x60000005, /*     DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */
+       0x0c4cf889, /*     DRD2B1: *idx1 = EU3(); EU3(idx2,var9)  */
+       0x000001f8, /*   NOP */
+
+       /* VAR[9]-VAR[12] */
+       0x40000000,
+       0x7fff7fff,
+       0x00000000,
+       0x40000004,
+
+       /* INC[0]-INC[5] */
+       0x40000000,
+       0xe0000000,
+       0xe0000000,
+       0xa0000008,
+       0x20000000,
+       0x4000ffff,
+};
+
diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.c b/arch/powerpc/sysdev/bestcomm/bestcomm.c
new file mode 100644 (file)
index 0000000..48492a8
--- /dev/null
@@ -0,0 +1,528 @@
+/*
+ * Driver for MPC52xx processor BestComm peripheral controller
+ *
+ *
+ * Copyright (C) 2006-2007 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2005      Varma Electronics Oy,
+ *                         ( by Andrey Volkov <avolkov@varma-el.com> )
+ * Copyright (C) 2003-2004 MontaVista, Software, Inc.
+ *                         ( by Dale Farnsworth <dfarnsworth@mvista.com> )
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mpc52xx.h>
+
+#include "sram.h"
+#include "bestcomm_priv.h"
+#include "bestcomm.h"
+
+#define DRIVER_NAME "bestcomm-core"
+
+
+struct bcom_engine *bcom_eng = NULL;
+EXPORT_SYMBOL_GPL(bcom_eng);   /* needed for inline functions */
+
+
+/* ======================================================================== */
+/* Public and private API                                                   */
+/* ======================================================================== */
+
+/* Private API */
+
+struct bcom_task *
+bcom_task_alloc(int bd_count, int bd_size, int priv_size)
+{
+       int i, tasknum = -1;
+       struct bcom_task *tsk;
+
+       /* Get and reserve a task num */
+       spin_lock(&bcom_eng->lock);
+
+       for (i=0; i<BCOM_MAX_TASKS; i++)
+               if (!bcom_eng->tdt[i].stop) {   /* we use stop as a marker */
+                       bcom_eng->tdt[i].stop = 0xfffffffful; /* dummy addr */
+                       tasknum = i;
+                       break;
+               }
+
+       spin_unlock(&bcom_eng->lock);
+
+       if (tasknum < 0)
+               return NULL;
+
+       /* Allocate our structure */
+       tsk = kzalloc(sizeof(struct bcom_task) + priv_size, GFP_KERNEL);
+       if (!tsk)
+               goto error;
+
+       tsk->tasknum = tasknum;
+       if (priv_size)
+               tsk->priv = (void*)tsk + sizeof(struct bcom_task);
+
+       /* Get IRQ of that task */
+       tsk->irq = irq_of_parse_and_map(bcom_eng->ofnode, tsk->tasknum);
+       if (tsk->irq == NO_IRQ)
+               goto error;
+
+       /* Init the BDs, if needed */
+       if (bd_count) {
+               tsk->cookie = kmalloc(sizeof(void*) * bd_count, GFP_KERNEL);
+               if (!tsk->cookie)
+                       goto error;
+
+               tsk->bd = bcom_sram_alloc(bd_count * bd_size, 4, &tsk->bd_pa);
+               if (!tsk->bd)
+                       goto error;
+               memset(tsk->bd, 0x00, bd_count * bd_size);
+
+               tsk->num_bd = bd_count;
+               tsk->bd_size = bd_size;
+       }
+
+       return tsk;
+
+error:
+       if (tsk) {
+               if (tsk->irq != NO_IRQ)
+                       irq_dispose_mapping(tsk->irq);
+               bcom_sram_free(tsk->bd);
+               kfree(tsk->cookie);
+               kfree(tsk);
+       }
+
+       bcom_eng->tdt[tasknum].stop = 0;
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(bcom_task_alloc);
+
+void
+bcom_task_free(struct bcom_task *tsk)
+{
+       /* Stop the task */
+       bcom_disable_task(tsk->tasknum);
+
+       /* Clear TDT */
+       bcom_eng->tdt[tsk->tasknum].start = 0;
+       bcom_eng->tdt[tsk->tasknum].stop  = 0;
+
+       /* Free everything */
+       irq_dispose_mapping(tsk->irq);
+       bcom_sram_free(tsk->bd);
+       kfree(tsk->cookie);
+       kfree(tsk);
+}
+EXPORT_SYMBOL_GPL(bcom_task_free);
+
+int
+bcom_load_image(int task, u32 *task_image)
+{
+       struct bcom_task_header *hdr = (struct bcom_task_header *)task_image;
+       struct bcom_tdt *tdt;
+       u32 *desc, *var, *inc;
+       u32 *desc_src, *var_src, *inc_src;
+
+       /* Safety checks */
+       if (hdr->magic != BCOM_TASK_MAGIC) {
+               printk(KERN_ERR DRIVER_NAME
+                       ": Trying to load invalid microcode\n");
+               return -EINVAL;
+       }
+
+       if ((task < 0) || (task >= BCOM_MAX_TASKS)) {
+               printk(KERN_ERR DRIVER_NAME
+                       ": Trying to load invalid task %d\n", task);
+               return -EINVAL;
+       }
+
+       /* Initial load or reload */
+       tdt = &bcom_eng->tdt[task];
+
+       if (tdt->start) {
+               desc = bcom_task_desc(task);
+               if (hdr->desc_size != bcom_task_num_descs(task)) {
+                       printk(KERN_ERR DRIVER_NAME
+                               ": Trying to reload wrong task image "
+                               "(%d size %d/%d)!\n",
+                               task,
+                               hdr->desc_size,
+                               bcom_task_num_descs(task));
+                       return -EINVAL;
+               }
+       } else {
+               phys_addr_t start_pa;
+
+               desc = bcom_sram_alloc(hdr->desc_size * sizeof(u32), 4, &start_pa);
+               if (!desc)
+                       return -ENOMEM;
+
+               tdt->start = start_pa;
+               tdt->stop = start_pa + ((hdr->desc_size-1) * sizeof(u32));
+       }
+
+       var = bcom_task_var(task);
+       inc = bcom_task_inc(task);
+
+       /* Clear & copy */
+       memset(var, 0x00, BCOM_VAR_SIZE);
+       memset(inc, 0x00, BCOM_INC_SIZE);
+
+       desc_src = (u32 *)(hdr + 1);
+       var_src = desc_src + hdr->desc_size;
+       inc_src = var_src + hdr->var_size;
+
+       memcpy(desc, desc_src, hdr->desc_size * sizeof(u32));
+       memcpy(var + hdr->first_var, var_src, hdr->var_size * sizeof(u32));
+       memcpy(inc, inc_src, hdr->inc_size * sizeof(u32));
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(bcom_load_image);
+
+void
+bcom_set_initiator(int task, int initiator)
+{
+       int i;
+       int num_descs;
+       u32 *desc;
+       int next_drd_has_initiator;
+
+       bcom_set_tcr_initiator(task, initiator);
+
+       /* Just setting tcr is apparently not enough due to some problem */
+       /* with it. So we just go thru all the microcode and replace in  */
+       /* the DRD directly */
+
+       desc = bcom_task_desc(task);
+       next_drd_has_initiator = 1;
+       num_descs = bcom_task_num_descs(task);
+
+       for (i=0; i<num_descs; i++, desc++) {
+               if (!bcom_desc_is_drd(*desc))
+                       continue;
+               if (next_drd_has_initiator)
+                       if (bcom_desc_initiator(*desc) != BCOM_INITIATOR_ALWAYS)
+                               bcom_set_desc_initiator(desc, initiator);
+               next_drd_has_initiator = !bcom_drd_is_extended(*desc);
+       }
+}
+EXPORT_SYMBOL_GPL(bcom_set_initiator);
+
+
+/* Public API */
+
+void
+bcom_enable(struct bcom_task *tsk)
+{
+       bcom_enable_task(tsk->tasknum);
+}
+EXPORT_SYMBOL_GPL(bcom_enable);
+
+void
+bcom_disable(struct bcom_task *tsk)
+{
+       bcom_disable_task(tsk->tasknum);
+}
+EXPORT_SYMBOL_GPL(bcom_disable);
+
+
+/* ======================================================================== */
+/* Engine init/cleanup                                                      */
+/* ======================================================================== */
+
+/* Function Descriptor table */
+/* this will need to be updated if Freescale changes their task code FDT */
+static u32 fdt_ops[] = {
+       0xa0045670,     /* FDT[48] - load_acc()   */
+       0x80045670,     /* FDT[49] - unload_acc() */
+       0x21800000,     /* FDT[50] - and()        */
+       0x21e00000,     /* FDT[51] - or()         */
+       0x21500000,     /* FDT[52] - xor()        */
+       0x21400000,     /* FDT[53] - andn()       */
+       0x21500000,     /* FDT[54] - not()        */
+       0x20400000,     /* FDT[55] - add()        */
+       0x20500000,     /* FDT[56] - sub()        */
+       0x20800000,     /* FDT[57] - lsh()        */
+       0x20a00000,     /* FDT[58] - rsh()        */
+       0xc0170000,     /* FDT[59] - crc8()       */
+       0xc0145670,     /* FDT[60] - crc16()      */
+       0xc0345670,     /* FDT[61] - crc32()      */
+       0xa0076540,     /* FDT[62] - endian32()   */
+       0xa0000760,     /* FDT[63] - endian16()   */
+};
+
+
+static int __devinit
+bcom_engine_init(void)
+{
+       int task;
+       phys_addr_t tdt_pa, ctx_pa, var_pa, fdt_pa;
+       unsigned int tdt_size, ctx_size, var_size, fdt_size;
+
+       /* Allocate & clear SRAM zones for FDT, TDTs, contexts and vars/incs */
+       tdt_size = BCOM_MAX_TASKS * sizeof(struct bcom_tdt);
+       ctx_size = BCOM_MAX_TASKS * BCOM_CTX_SIZE;
+       var_size = BCOM_MAX_TASKS * (BCOM_VAR_SIZE + BCOM_INC_SIZE);
+       fdt_size = BCOM_FDT_SIZE;
+
+       bcom_eng->tdt = bcom_sram_alloc(tdt_size, sizeof(u32), &tdt_pa);
+       bcom_eng->ctx = bcom_sram_alloc(ctx_size, BCOM_CTX_ALIGN, &ctx_pa);
+       bcom_eng->var = bcom_sram_alloc(var_size, BCOM_VAR_ALIGN, &var_pa);
+       bcom_eng->fdt = bcom_sram_alloc(fdt_size, BCOM_FDT_ALIGN, &fdt_pa);
+
+       if (!bcom_eng->tdt || !bcom_eng->ctx || !bcom_eng->var || !bcom_eng->fdt) {
+               printk(KERN_ERR "DMA: SRAM alloc failed in engine init !\n");
+
+               bcom_sram_free(bcom_eng->tdt);
+               bcom_sram_free(bcom_eng->ctx);
+               bcom_sram_free(bcom_eng->var);
+               bcom_sram_free(bcom_eng->fdt);
+
+               return -ENOMEM;
+       }
+
+       memset(bcom_eng->tdt, 0x00, tdt_size);
+       memset(bcom_eng->ctx, 0x00, ctx_size);
+       memset(bcom_eng->var, 0x00, var_size);
+       memset(bcom_eng->fdt, 0x00, fdt_size);
+
+       /* Copy the FDT for the EU#3 */
+       memcpy(&bcom_eng->fdt[48], fdt_ops, sizeof(fdt_ops));
+
+       /* Initialize Task base structure */
+       for (task=0; task<BCOM_MAX_TASKS; task++)
+       {
+               out_be16(&bcom_eng->regs->tcr[task], 0);
+               out_8(&bcom_eng->regs->ipr[task], 0);
+
+               bcom_eng->tdt[task].context     = ctx_pa;
+               bcom_eng->tdt[task].var = var_pa;
+               bcom_eng->tdt[task].fdt = fdt_pa;
+
+               var_pa += BCOM_VAR_SIZE + BCOM_INC_SIZE;
+               ctx_pa += BCOM_CTX_SIZE;
+       }
+
+       out_be32(&bcom_eng->regs->taskBar, tdt_pa);
+
+       /* Init 'always' initiator */
+       out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS);
+
+       /* Disable COMM Bus Prefetch, apparently it's not reliable yet */
+       /* FIXME: This should be done on 5200 and not 5200B ... */
+       out_be16(&bcom_eng->regs->PtdCntrl, in_be16(&bcom_eng->regs->PtdCntrl) | 1);
+
+       /* Init lock */
+       spin_lock_init(&bcom_eng->lock);
+
+       return 0;
+}
+
+static void
+bcom_engine_cleanup(void)
+{
+       int task;
+
+       /* Stop all tasks */
+       for (task=0; task<BCOM_MAX_TASKS; task++)
+       {
+               out_be16(&bcom_eng->regs->tcr[task], 0);
+               out_8(&bcom_eng->regs->ipr[task], 0);
+       }
+
+       out_be32(&bcom_eng->regs->taskBar, 0ul);
+
+       /* Release the SRAM zones */
+       bcom_sram_free(bcom_eng->tdt);
+       bcom_sram_free(bcom_eng->ctx);
+       bcom_sram_free(bcom_eng->var);
+       bcom_sram_free(bcom_eng->fdt);
+}
+
+
+/* ======================================================================== */
+/* OF platform driver                                                       */
+/* ======================================================================== */
+
+static int __devinit
+mpc52xx_bcom_probe(struct of_device *op, const struct of_device_id *match)
+{
+       struct device_node *ofn_sram;
+       struct resource res_bcom;
+
+       int rv;
+
+       /* Inform user we're ok so far */
+       printk(KERN_INFO "DMA: MPC52xx BestComm driver\n");
+
+       /* Get the bestcomm node */
+       of_node_get(op->node);
+
+       /* Prepare SRAM */
+       ofn_sram = of_find_compatible_node(NULL, "sram", "mpc5200-sram");
+       if (!ofn_sram) {
+               printk(KERN_ERR DRIVER_NAME ": "
+                       "No SRAM found in device tree\n");
+               rv = -ENODEV;
+               goto error_ofput;
+       }
+       rv = bcom_sram_init(ofn_sram, DRIVER_NAME);
+       of_node_put(ofn_sram);
+
+       if (rv) {
+               printk(KERN_ERR DRIVER_NAME ": "
+                       "Error in SRAM init\n");
+               goto error_ofput;
+       }
+
+       /* Get a clean struct */
+       bcom_eng = kzalloc(sizeof(struct bcom_engine), GFP_KERNEL);
+       if (!bcom_eng) {
+               printk(KERN_ERR DRIVER_NAME ": "
+                       "Can't allocate state structure\n");
+               rv = -ENOMEM;
+               goto error_sramclean;
+       }
+
+       /* Save the node */
+       bcom_eng->ofnode = op->node;
+
+       /* Get, reserve & map io */
+       if (of_address_to_resource(op->node, 0, &res_bcom)) {
+               printk(KERN_ERR DRIVER_NAME ": "
+                       "Can't get resource\n");
+               rv = -EINVAL;
+               goto error_sramclean;
+       }
+
+       if (!request_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma),
+                               DRIVER_NAME)) {
+               printk(KERN_ERR DRIVER_NAME ": "
+                       "Can't request registers region\n");
+               rv = -EBUSY;
+               goto error_sramclean;
+       }
+
+       bcom_eng->regs_base = res_bcom.start;
+       bcom_eng->regs = ioremap(res_bcom.start, sizeof(struct mpc52xx_sdma));
+       if (!bcom_eng->regs) {
+               printk(KERN_ERR DRIVER_NAME ": "
+                       "Can't map registers\n");
+               rv = -ENOMEM;
+               goto error_release;
+       }
+
+       /* Now, do the real init */
+       rv = bcom_engine_init();
+       if (rv)
+               goto error_unmap;
+
+       /* Done ! */
+       printk(KERN_INFO "DMA: MPC52xx BestComm engine @%08lx ok !\n",
+               bcom_eng->regs_base);
+
+       return 0;
+
+       /* Error path */
+error_unmap:
+       iounmap(bcom_eng->regs);
+error_release:
+       release_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma));
+error_sramclean:
+       kfree(bcom_eng);
+       bcom_sram_cleanup();
+error_ofput:
+       of_node_put(op->node);
+
+       printk(KERN_ERR "DMA: MPC52xx BestComm init failed !\n");
+
+       return rv;
+}
+
+
+static int
+mpc52xx_bcom_remove(struct of_device *op)
+{
+       /* Clean up the engine */
+       bcom_engine_cleanup();
+
+       /* Cleanup SRAM */
+       bcom_sram_cleanup();
+
+       /* Release regs */
+       iounmap(bcom_eng->regs);
+       release_mem_region(bcom_eng->regs_base, sizeof(struct mpc52xx_sdma));
+
+       /* Release the node */
+       of_node_put(bcom_eng->ofnode);
+
+       /* Release memory */
+       kfree(bcom_eng);
+       bcom_eng = NULL;
+
+       return 0;
+}
+
+static struct of_device_id mpc52xx_bcom_of_match[] = {
+       {
+               .type           = "dma-controller",
+               .compatible     = "mpc5200-bestcomm",
+       },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, mpc52xx_bcom_of_match);
+
+
+static struct of_platform_driver mpc52xx_bcom_of_platform_driver = {
+       .owner          = THIS_MODULE,
+       .name           = DRIVER_NAME,
+       .match_table    = mpc52xx_bcom_of_match,
+       .probe          = mpc52xx_bcom_probe,
+       .remove         = mpc52xx_bcom_remove,
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+
+/* ======================================================================== */
+/* Module                                                                   */
+/* ======================================================================== */
+
+static int __init
+mpc52xx_bcom_init(void)
+{
+       return of_register_platform_driver(&mpc52xx_bcom_of_platform_driver);
+}
+
+static void __exit
+mpc52xx_bcom_exit(void)
+{
+       of_unregister_platform_driver(&mpc52xx_bcom_of_platform_driver);
+}
+
+/* If we're not a module, we must make sure everything is setup before  */
+/* anyone tries to use us ... that's why we use subsys_initcall instead */
+/* of module_init. */
+subsys_initcall(mpc52xx_bcom_init);
+module_exit(mpc52xx_bcom_exit);
+
+MODULE_DESCRIPTION("Freescale MPC52xx BestComm DMA");
+MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
+MODULE_AUTHOR("Andrey Volkov <avolkov@varma-el.com>");
+MODULE_AUTHOR("Dale Farnsworth <dfarnsworth@mvista.com>");
+MODULE_LICENSE("GPL v2");
+
diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.h b/arch/powerpc/sysdev/bestcomm/bestcomm.h
new file mode 100644 (file)
index 0000000..e802cb4
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Public header for the MPC52xx processor BestComm driver
+ *
+ *
+ * Copyright (C) 2006      Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2005      Varma Electronics Oy,
+ *                         ( by Andrey Volkov <avolkov@varma-el.com> )
+ * Copyright (C) 2003-2004 MontaVista, Software, Inc.
+ *                         ( by Dale Farnsworth <dfarnsworth@mvista.com> )
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef __BESTCOMM_H__
+#define __BESTCOMM_H__
+
+struct bcom_bd; /* defined later on ... */
+
+
+/* ======================================================================== */
+/* Generic task managment                                                   */
+/* ======================================================================== */
+
+/**
+ * struct bcom_task - Structure describing a loaded BestComm task
+ *
+ * This structure is never built by the driver it self. It's built and
+ * filled the intermediate layer of the BestComm API, the task dependent
+ * support code.
+ *
+ * Most likely you don't need to poke around inside this structure. The
+ * fields are exposed in the header just for the sake of inline functions
+ */
+struct bcom_task {
+       unsigned int    tasknum;
+       unsigned int    flags;
+       int             irq;
+
+       struct bcom_bd  *bd;
+       phys_addr_t     bd_pa;
+       void            **cookie;
+       unsigned short  index;
+       unsigned short  outdex;
+       unsigned int    num_bd;
+       unsigned int    bd_size;
+
+       void*           priv;
+};
+
+#define BCOM_FLAGS_NONE         0x00000000ul
+#define BCOM_FLAGS_ENABLE_TASK  (1ul <<  0)
+
+/**
+ * bcom_enable - Enable a BestComm task
+ * @tsk: The BestComm task structure
+ *
+ * This function makes sure the given task is enabled and can be run
+ * by the BestComm engine as needed
+ */
+extern void bcom_enable(struct bcom_task *tsk);
+
+/**
+ * bcom_disable - Disable a BestComm task
+ * @tsk: The BestComm task structure
+ *
+ * This function disable a given task, making sure it's not executed
+ * by the BestComm engine.
+ */
+extern void bcom_disable(struct bcom_task *tsk);
+
+
+/**
+ * bcom_get_task_irq - Returns the irq number of a BestComm task
+ * @tsk: The BestComm task structure
+ */
+static inline int
+bcom_get_task_irq(struct bcom_task *tsk) {
+       return tsk->irq;
+}
+
+/* ======================================================================== */
+/* BD based tasks helpers                                                   */
+/* ======================================================================== */
+
+/**
+ * struct bcom_bd - Structure describing a generic BestComm buffer descriptor
+ * @status: The current status of this buffer. Exact meaning depends on the
+ *          task type
+ * @data: An array of u32 whose meaning depends on the task type.
+ */
+struct bcom_bd {
+       u32     status;
+       u32     data[1];        /* variable, but at least 1 */
+};
+
+#define BCOM_BD_READY  0x40000000ul
+
+/** _bcom_next_index - Get next input index.
+ * @tsk: pointer to task structure
+ *
+ * Support function; Device drivers should not call this
+ */
+static inline int
+_bcom_next_index(struct bcom_task *tsk)
+{
+       return ((tsk->index + 1) == tsk->num_bd) ? 0 : tsk->index + 1;
+}
+
+/** _bcom_next_outdex - Get next output index.
+ * @tsk: pointer to task structure
+ *
+ * Support function; Device drivers should not call this
+ */
+static inline int
+_bcom_next_outdex(struct bcom_task *tsk)
+{
+       return ((tsk->outdex + 1) == tsk->num_bd) ? 0 : tsk->outdex + 1;
+}
+
+/**
+ * bcom_queue_empty - Checks if a BestComm task BD queue is empty
+ * @tsk: The BestComm task structure
+ */
+static inline int
+bcom_queue_empty(struct bcom_task *tsk)
+{
+       return tsk->index == tsk->outdex;
+}
+
+/**
+ * bcom_queue_full - Checks if a BestComm task BD queue is full
+ * @tsk: The BestComm task structure
+ */
+static inline int
+bcom_queue_full(struct bcom_task *tsk)
+{
+       return tsk->outdex == _bcom_next_index(tsk);
+}
+
+/**
+ * bcom_buffer_done - Checks if a BestComm 
+ * @tsk: The BestComm task structure
+ */
+static inline int
+bcom_buffer_done(struct bcom_task *tsk)
+{
+       if (bcom_queue_empty(tsk))
+               return 0;
+       return !(tsk->bd[tsk->outdex].status & BCOM_BD_READY);
+}
+
+/**
+ * bcom_prepare_next_buffer - clear status of next available buffer.
+ * @tsk: The BestComm task structure
+ *
+ * Returns pointer to next buffer descriptor
+ */
+static inline struct bcom_bd *
+bcom_prepare_next_buffer(struct bcom_task *tsk)
+{
+       tsk->bd[tsk->index].status = 0; /* cleanup last status */
+       return &tsk->bd[tsk->index];
+}
+
+static inline void
+bcom_submit_next_buffer(struct bcom_task *tsk, void *cookie)
+{
+       tsk->cookie[tsk->index] = cookie;
+       mb();   /* ensure the bd is really up-to-date */
+       tsk->bd[tsk->index].status |= BCOM_BD_READY;
+       tsk->index = _bcom_next_index(tsk);
+       if (tsk->flags & BCOM_FLAGS_ENABLE_TASK)
+               bcom_enable(tsk);
+}
+
+static inline void *
+bcom_retrieve_buffer(struct bcom_task *tsk, u32 *p_status, struct bcom_bd **p_bd)
+{
+       void *cookie = tsk->cookie[tsk->outdex];
+       if (p_status)
+               *p_status = tsk->bd[tsk->outdex].status;
+       if (p_bd)
+               *p_bd = &tsk->bd[tsk->outdex];
+       tsk->outdex = _bcom_next_outdex(tsk);
+       return cookie;
+}
+
+#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 (file)
index 0000000..866a291
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * Private header for the MPC52xx processor BestComm driver
+ *
+ * By private, we mean that driver should not use it directly. It's meant
+ * to be used by the BestComm engine driver itself and by the intermediate
+ * layer between the core and the drivers.
+ *
+ * Copyright (C) 2006      Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2005      Varma Electronics Oy,
+ *                         ( by Andrey Volkov <avolkov@varma-el.com> )
+ * Copyright (C) 2003-2004 MontaVista, Software, Inc.
+ *                         ( by Dale Farnsworth <dfarnsworth@mvista.com> )
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef __BESTCOMM_PRIV_H__
+#define __BESTCOMM_PRIV_H__
+
+#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <asm/io.h>
+#include <asm/mpc52xx.h>
+
+#include "sram.h"
+
+
+/* ======================================================================== */
+/* Engine related stuff                                                     */
+/* ======================================================================== */
+
+/* Zones sizes and needed alignments */
+#define BCOM_MAX_TASKS         16
+#define BCOM_MAX_VAR           24
+#define BCOM_MAX_INC           8
+#define BCOM_MAX_FDT           64
+#define BCOM_MAX_CTX           20
+#define BCOM_CTX_SIZE          (BCOM_MAX_CTX * sizeof(u32))
+#define BCOM_CTX_ALIGN         0x100
+#define BCOM_VAR_SIZE          (BCOM_MAX_VAR * sizeof(u32))
+#define BCOM_INC_SIZE          (BCOM_MAX_INC * sizeof(u32))
+#define BCOM_VAR_ALIGN         0x80
+#define BCOM_FDT_SIZE          (BCOM_MAX_FDT * sizeof(u32))
+#define BCOM_FDT_ALIGN         0x100
+
+/**
+ * struct bcom_tdt - Task Descriptor Table Entry
+ *
+ */
+struct bcom_tdt {
+       u32 start;
+       u32 stop;
+       u32 var;
+       u32 fdt;
+       u32 exec_status;        /* used internally by BestComm engine */
+       u32 mvtp;               /* used internally by BestComm engine */
+       u32 context;
+       u32 litbase;
+};
+
+/**
+ * struct bcom_engine
+ *
+ * This holds all info needed globaly to handle the engine
+ */
+struct bcom_engine {
+       struct device_node              *ofnode;
+       struct mpc52xx_sdma __iomem     *regs;
+       phys_addr_t                      regs_base;
+
+       struct bcom_tdt                 *tdt;
+       u32                             *ctx;
+       u32                             *var;
+       u32                             *fdt;
+
+       spinlock_t                      lock;
+};
+
+extern struct bcom_engine *bcom_eng;
+
+
+/* ======================================================================== */
+/* Tasks related stuff                                                      */
+/* ======================================================================== */
+
+/* Tasks image header */
+#define BCOM_TASK_MAGIC                0x4243544B      /* 'BCTK' */
+
+struct bcom_task_header {
+       u32     magic;
+       u8      desc_size;      /* the size fields     */
+       u8      var_size;       /* are given in number */
+       u8      inc_size;       /* of 32-bits words    */
+       u8      first_var;
+       u8      reserved[8];
+};
+
+/* Descriptors stucture & co */
+#define BCOM_DESC_NOP          0x000001f8
+#define BCOM_LCD_MASK          0x80000000
+#define BCOM_DRD_EXTENDED      0x40000000
+#define BCOM_DRD_INITIATOR_SHIFT       21
+
+/* Tasks pragma */
+#define BCOM_PRAGMA_BIT_RSV            7       /* reserved pragma bit */
+#define BCOM_PRAGMA_BIT_PRECISE_INC    6       /* increment 0=when possible, */
+                                               /*           1=iter end */
+#define BCOM_PRAGMA_BIT_RST_ERROR_NO   5       /* don't reset errors on */
+                                               /* task enable */
+#define BCOM_PRAGMA_BIT_PACK           4       /* pack data enable */
+#define BCOM_PRAGMA_BIT_INTEGER                3       /* data alignment */
+                                               /* 0=frac(msb), 1=int(lsb) */
+#define BCOM_PRAGMA_BIT_SPECREAD       2       /* XLB speculative read */
+#define BCOM_PRAGMA_BIT_CW             1       /* write line buffer enable */
+#define BCOM_PRAGMA_BIT_RL             0       /* read line buffer enable */
+
+       /* Looks like XLB speculative read generates XLB errors when a buffer
+        * is at the end of the physical memory. i.e. when accessing the
+        * lasts words, the engine tries to prefetch the next but there is no
+        * next ...
+        */
+#define BCOM_STD_PRAGMA                ((0 << BCOM_PRAGMA_BIT_RSV)             | \
+                                (0 << BCOM_PRAGMA_BIT_PRECISE_INC)     | \
+                                (0 << BCOM_PRAGMA_BIT_RST_ERROR_NO)    | \
+                                (0 << BCOM_PRAGMA_BIT_PACK)            | \
+                                (0 << BCOM_PRAGMA_BIT_INTEGER)         | \
+                                (0 << BCOM_PRAGMA_BIT_SPECREAD)        | \
+                                (1 << BCOM_PRAGMA_BIT_CW)              | \
+                                (1 << BCOM_PRAGMA_BIT_RL))
+
+#define BCOM_PCI_PRAGMA                ((0 << BCOM_PRAGMA_BIT_RSV)             | \
+                                (0 << BCOM_PRAGMA_BIT_PRECISE_INC)     | \
+                                (0 << BCOM_PRAGMA_BIT_RST_ERROR_NO)    | \
+                                (0 << BCOM_PRAGMA_BIT_PACK)            | \
+                                (1 << BCOM_PRAGMA_BIT_INTEGER)         | \
+                                (0 << BCOM_PRAGMA_BIT_SPECREAD)        | \
+                                (1 << BCOM_PRAGMA_BIT_CW)              | \
+                                (1 << BCOM_PRAGMA_BIT_RL))
+
+#define BCOM_ATA_PRAGMA                BCOM_STD_PRAGMA
+#define BCOM_CRC16_DP_0_PRAGMA BCOM_STD_PRAGMA
+#define BCOM_CRC16_DP_1_PRAGMA BCOM_STD_PRAGMA
+#define BCOM_FEC_RX_BD_PRAGMA  BCOM_STD_PRAGMA
+#define BCOM_FEC_TX_BD_PRAGMA  BCOM_STD_PRAGMA
+#define BCOM_GEN_DP_0_PRAGMA   BCOM_STD_PRAGMA
+#define BCOM_GEN_DP_1_PRAGMA   BCOM_STD_PRAGMA
+#define BCOM_GEN_DP_2_PRAGMA   BCOM_STD_PRAGMA
+#define BCOM_GEN_DP_3_PRAGMA   BCOM_STD_PRAGMA
+#define BCOM_GEN_DP_BD_0_PRAGMA        BCOM_STD_PRAGMA
+#define BCOM_GEN_DP_BD_1_PRAGMA        BCOM_STD_PRAGMA
+#define BCOM_GEN_RX_BD_PRAGMA  BCOM_STD_PRAGMA
+#define BCOM_GEN_TX_BD_PRAGMA  BCOM_STD_PRAGMA
+#define BCOM_GEN_LPC_PRAGMA    BCOM_STD_PRAGMA
+#define BCOM_PCI_RX_PRAGMA     BCOM_PCI_PRAGMA
+#define BCOM_PCI_TX_PRAGMA     BCOM_PCI_PRAGMA
+
+/* Initiators number */
+#define BCOM_INITIATOR_ALWAYS   0
+#define BCOM_INITIATOR_SCTMR_0  1
+#define BCOM_INITIATOR_SCTMR_1  2
+#define BCOM_INITIATOR_FEC_RX   3
+#define BCOM_INITIATOR_FEC_TX   4
+#define BCOM_INITIATOR_ATA_RX   5
+#define BCOM_INITIATOR_ATA_TX   6
+#define BCOM_INITIATOR_SCPCI_RX         7
+#define BCOM_INITIATOR_SCPCI_TX         8
+#define BCOM_INITIATOR_PSC3_RX  9
+#define BCOM_INITIATOR_PSC3_TX 10
+#define BCOM_INITIATOR_PSC2_RX 11
+#define BCOM_INITIATOR_PSC2_TX 12
+#define BCOM_INITIATOR_PSC1_RX 13
+#define BCOM_INITIATOR_PSC1_TX 14
+#define BCOM_INITIATOR_SCTMR_2 15
+#define BCOM_INITIATOR_SCLPC   16
+#define BCOM_INITIATOR_PSC5_RX 17
+#define BCOM_INITIATOR_PSC5_TX 18
+#define BCOM_INITIATOR_PSC4_RX 19
+#define BCOM_INITIATOR_PSC4_TX 20
+#define BCOM_INITIATOR_I2C2_RX 21
+#define BCOM_INITIATOR_I2C2_TX 22
+#define BCOM_INITIATOR_I2C1_RX 23
+#define BCOM_INITIATOR_I2C1_TX 24
+#define BCOM_INITIATOR_PSC6_RX 25
+#define BCOM_INITIATOR_PSC6_TX 26
+#define BCOM_INITIATOR_IRDA_RX 25
+#define BCOM_INITIATOR_IRDA_TX 26
+#define BCOM_INITIATOR_SCTMR_3 27
+#define BCOM_INITIATOR_SCTMR_4 28
+#define BCOM_INITIATOR_SCTMR_5 29
+#define BCOM_INITIATOR_SCTMR_6 30
+#define BCOM_INITIATOR_SCTMR_7 31
+
+/* Initiators priorities */
+#define BCOM_IPR_ALWAYS                7
+#define BCOM_IPR_SCTMR_0       2
+#define BCOM_IPR_SCTMR_1       2
+#define BCOM_IPR_FEC_RX                6
+#define BCOM_IPR_FEC_TX                5
+#define BCOM_IPR_ATA_RX                4
+#define BCOM_IPR_ATA_TX                3
+#define BCOM_IPR_SCPCI_RX      2
+#define BCOM_IPR_SCPCI_TX      2
+#define BCOM_IPR_PSC3_RX       2
+#define BCOM_IPR_PSC3_TX       2
+#define BCOM_IPR_PSC2_RX       2
+#define BCOM_IPR_PSC2_TX       2
+#define BCOM_IPR_PSC1_RX       2
+#define BCOM_IPR_PSC1_TX       2
+#define BCOM_IPR_SCTMR_2       2
+#define BCOM_IPR_SCLPC         2
+#define BCOM_IPR_PSC5_RX       2
+#define BCOM_IPR_PSC5_TX       2
+#define BCOM_IPR_PSC4_RX       2
+#define BCOM_IPR_PSC4_TX       2
+#define BCOM_IPR_I2C2_RX       2
+#define BCOM_IPR_I2C2_TX       2
+#define BCOM_IPR_I2C1_RX       2
+#define BCOM_IPR_I2C1_TX       2
+#define BCOM_IPR_PSC6_RX       2
+#define BCOM_IPR_PSC6_TX       2
+#define BCOM_IPR_IRDA_RX       2
+#define BCOM_IPR_IRDA_TX       2
+#define BCOM_IPR_SCTMR_3       2
+#define BCOM_IPR_SCTMR_4       2
+#define BCOM_IPR_SCTMR_5       2
+#define BCOM_IPR_SCTMR_6       2
+#define BCOM_IPR_SCTMR_7       2
+
+
+/* ======================================================================== */
+/* API                                                                      */
+/* ======================================================================== */
+
+extern struct bcom_task *bcom_task_alloc(int bd_count, int bd_size, int priv_size);
+extern void bcom_task_free(struct bcom_task *tsk);
+extern int bcom_load_image(int task, u32 *task_image);
+extern void bcom_set_initiator(int task, int initiator);
+
+
+#define TASK_ENABLE             0x8000
+
+static inline void
+bcom_enable_task(int task)
+{
+        u16 reg;
+        reg = in_be16(&bcom_eng->regs->tcr[task]);
+        out_be16(&bcom_eng->regs->tcr[task],  reg | TASK_ENABLE);
+}
+
+static inline void
+bcom_disable_task(int task)
+{
+        u16 reg = in_be16(&bcom_eng->regs->tcr[task]);
+        out_be16(&bcom_eng->regs->tcr[task], reg & ~TASK_ENABLE);
+}
+
+
+static inline u32 *
+bcom_task_desc(int task)
+{
+       return bcom_sram_pa2va(bcom_eng->tdt[task].start);
+}
+
+static inline int
+bcom_task_num_descs(int task)
+{
+       return (bcom_eng->tdt[task].stop - bcom_eng->tdt[task].start)/sizeof(u32) + 1;
+}
+
+static inline u32 *
+bcom_task_var(int task)
+{
+       return bcom_sram_pa2va(bcom_eng->tdt[task].var);
+}
+
+static inline u32 *
+bcom_task_inc(int task)
+{
+       return &bcom_task_var(task)[BCOM_MAX_VAR];
+}
+
+
+static inline int
+bcom_drd_is_extended(u32 desc)
+{
+       return (desc) & BCOM_DRD_EXTENDED;
+}
+
+static inline int
+bcom_desc_is_drd(u32 desc)
+{
+       return !(desc & BCOM_LCD_MASK) && desc != BCOM_DESC_NOP;
+}
+
+static inline int
+bcom_desc_initiator(u32 desc)
+{
+       return (desc >> BCOM_DRD_INITIATOR_SHIFT) & 0x1f;
+}
+
+static inline void
+bcom_set_desc_initiator(u32 *desc, int initiator)
+{
+       *desc = (*desc & ~(0x1f << BCOM_DRD_INITIATOR_SHIFT)) |
+                       ((initiator & 0x1f) << BCOM_DRD_INITIATOR_SHIFT);
+}
+
+
+static inline void
+bcom_set_task_pragma(int task, int pragma)
+{
+       u32 *fdt = &bcom_eng->tdt[task].fdt;
+       *fdt = (*fdt & ~0xff) | pragma;
+}
+
+static inline void
+bcom_set_task_auto_start(int task, int next_task)
+{
+       u16 __iomem *tcr = &bcom_eng->regs->tcr[task];
+       out_be16(tcr, (in_be16(tcr) & ~0xff) | 0x00c0 | next_task);
+}
+
+static inline void
+bcom_set_tcr_initiator(int task, int initiator)
+{
+       u16 __iomem *tcr = &bcom_eng->regs->tcr[task];
+       out_be16(tcr, (in_be16(tcr) & ~0x1f00) | ((initiator & 0x1f) << 8));
+}
+
+
+#endif /* __BESTCOMM_PRIV_H__ */
+
diff --git a/arch/powerpc/sysdev/bestcomm/fec.c b/arch/powerpc/sysdev/bestcomm/fec.c
new file mode 100644 (file)
index 0000000..957a988
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * Bestcomm FEC tasks driver
+ *
+ *
+ * Copyright (C) 2006-2007 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2003-2004 MontaVista, Software, Inc.
+ *                         ( by Dale Farnsworth <dfarnsworth@mvista.com> )
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <asm/io.h>
+
+#include "bestcomm.h"
+#include "bestcomm_priv.h"
+#include "fec.h"
+
+
+/* ======================================================================== */
+/* Task image/var/inc                                                       */
+/* ======================================================================== */
+
+/* fec tasks images */
+extern u32 bcom_fec_rx_task[];
+extern u32 bcom_fec_tx_task[];
+
+/* rx task vars that need to be set before enabling the task */
+struct bcom_fec_rx_var {
+       u32 enable;             /* (u16*) address of task's control register */
+       u32 fifo;               /* (u32*) address of fec's fifo */
+       u32 bd_base;            /* (struct bcom_bd*) beginning of ring buffer */
+       u32 bd_last;            /* (struct bcom_bd*) end of ring buffer */
+       u32 bd_start;           /* (struct bcom_bd*) current bd */
+       u32 buffer_size;        /* size of receive buffer */
+};
+
+/* rx task incs that need to be set before enabling the task */
+struct bcom_fec_rx_inc {
+       u16 pad0;
+       s16 incr_bytes;
+       u16 pad1;
+       s16 incr_dst;
+       u16 pad2;
+       s16 incr_dst_ma;
+};
+
+/* tx task vars that need to be set before enabling the task */
+struct bcom_fec_tx_var {
+       u32 DRD;                /* (u32*) address of self-modified DRD */
+       u32 fifo;               /* (u32*) address of fec's fifo */
+       u32 enable;             /* (u16*) address of task's control register */
+       u32 bd_base;            /* (struct bcom_bd*) beginning of ring buffer */
+       u32 bd_last;            /* (struct bcom_bd*) end of ring buffer */
+       u32 bd_start;           /* (struct bcom_bd*) current bd */
+       u32 buffer_size;        /* set by uCode for each packet */
+};
+
+/* tx task incs that need to be set before enabling the task */
+struct bcom_fec_tx_inc {
+       u16 pad0;
+       s16 incr_bytes;
+       u16 pad1;
+       s16 incr_src;
+       u16 pad2;
+       s16 incr_src_ma;
+};
+
+/* private structure in the task */
+struct bcom_fec_priv {
+       phys_addr_t     fifo;
+       int             maxbufsize;
+};
+
+
+/* ======================================================================== */
+/* Task support code                                                        */
+/* ======================================================================== */
+
+struct bcom_task *
+bcom_fec_rx_init(int queue_len, phys_addr_t fifo, int maxbufsize)
+{
+       struct bcom_task *tsk;
+       struct bcom_fec_priv *priv;
+
+       tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_fec_bd),
+                               sizeof(struct bcom_fec_priv));
+       if (!tsk)
+               return NULL;
+
+       tsk->flags = BCOM_FLAGS_NONE;
+
+       priv = tsk->priv;
+       priv->fifo = fifo;
+       priv->maxbufsize = maxbufsize;
+
+       if (bcom_fec_rx_reset(tsk)) {
+               bcom_task_free(tsk);
+               return NULL;
+       }
+
+       return tsk;
+}
+EXPORT_SYMBOL_GPL(bcom_fec_rx_init);
+
+int
+bcom_fec_rx_reset(struct bcom_task *tsk)
+{
+       struct bcom_fec_priv *priv = tsk->priv;
+       struct bcom_fec_rx_var *var;
+       struct bcom_fec_rx_inc *inc;
+
+       /* Shutdown the task */
+       bcom_disable_task(tsk->tasknum);
+
+       /* Reset the microcode */
+       var = (struct bcom_fec_rx_var *) bcom_task_var(tsk->tasknum);
+       inc = (struct bcom_fec_rx_inc *) bcom_task_inc(tsk->tasknum);
+
+       if (bcom_load_image(tsk->tasknum, bcom_fec_rx_task))
+               return -1;
+
+       var->enable     = bcom_eng->regs_base +
+                               offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);
+       var->fifo       = (u32) priv->fifo;
+       var->bd_base    = tsk->bd_pa;
+       var->bd_last    = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);
+       var->bd_start   = tsk->bd_pa;
+       var->buffer_size = priv->maxbufsize;
+
+       inc->incr_bytes = -(s16)sizeof(u32);    /* These should be in the   */
+       inc->incr_dst   = sizeof(u32);          /* task image, but we stick */
+       inc->incr_dst_ma= sizeof(u8);           /* to the official ones     */
+
+       /* Reset the BDs */
+       tsk->index = 0;
+       tsk->outdex = 0;
+
+       memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
+
+       /* Configure some stuff */
+       bcom_set_task_pragma(tsk->tasknum, BCOM_FEC_RX_BD_PRAGMA);
+       bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
+
+       out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_FEC_RX], BCOM_IPR_FEC_RX);
+
+       out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum);    /* Clear ints */
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(bcom_fec_rx_reset);
+
+void
+bcom_fec_rx_release(struct bcom_task *tsk)
+{
+       /* Nothing special for the FEC tasks */
+       bcom_task_free(tsk);
+}
+EXPORT_SYMBOL_GPL(bcom_fec_rx_release);
+
+
+
+       /* Return 2nd to last DRD */
+       /* This is an ugly hack, but at least it's only done
+          once at initialization */
+static u32 *self_modified_drd(int tasknum)
+{
+       u32 *desc;
+       int num_descs;
+       int drd_count;
+       int i;
+
+       num_descs = bcom_task_num_descs(tasknum);
+       desc = bcom_task_desc(tasknum) + num_descs - 1;
+       drd_count = 0;
+       for (i=0; i<num_descs; i++, desc--)
+               if (bcom_desc_is_drd(*desc) && ++drd_count == 3)
+                       break;
+       return desc;
+}
+
+struct bcom_task *
+bcom_fec_tx_init(int queue_len, phys_addr_t fifo)
+{
+       struct bcom_task *tsk;
+       struct bcom_fec_priv *priv;
+
+       tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_fec_bd),
+                               sizeof(struct bcom_fec_priv));
+       if (!tsk)
+               return NULL;
+
+       tsk->flags = BCOM_FLAGS_ENABLE_TASK;
+
+       priv = tsk->priv;
+       priv->fifo = fifo;
+
+       if (bcom_fec_tx_reset(tsk)) {
+               bcom_task_free(tsk);
+               return NULL;
+       }
+
+       return tsk;
+}
+EXPORT_SYMBOL_GPL(bcom_fec_tx_init);
+
+int
+bcom_fec_tx_reset(struct bcom_task *tsk)
+{
+       struct bcom_fec_priv *priv = tsk->priv;
+       struct bcom_fec_tx_var *var;
+       struct bcom_fec_tx_inc *inc;
+
+       /* Shutdown the task */
+       bcom_disable_task(tsk->tasknum);
+
+       /* Reset the microcode */
+       var = (struct bcom_fec_tx_var *) bcom_task_var(tsk->tasknum);
+       inc = (struct bcom_fec_tx_inc *) bcom_task_inc(tsk->tasknum);
+
+       if (bcom_load_image(tsk->tasknum, bcom_fec_tx_task))
+               return -1;
+
+       var->enable     = bcom_eng->regs_base +
+                               offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);
+       var->fifo       = (u32) priv->fifo;
+       var->DRD        = bcom_sram_va2pa(self_modified_drd(tsk->tasknum));
+       var->bd_base    = tsk->bd_pa;
+       var->bd_last    = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);
+       var->bd_start   = tsk->bd_pa;
+
+       inc->incr_bytes = -(s16)sizeof(u32);    /* These should be in the   */
+       inc->incr_src   = sizeof(u32);          /* task image, but we stick */
+       inc->incr_src_ma= sizeof(u8);           /* to the official ones     */
+
+       /* Reset the BDs */
+       tsk->index = 0;
+       tsk->outdex = 0;
+
+       memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
+
+       /* Configure some stuff */
+       bcom_set_task_pragma(tsk->tasknum, BCOM_FEC_TX_BD_PRAGMA);
+       bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
+
+       out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_FEC_TX], BCOM_IPR_FEC_TX);
+
+       out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum);    /* Clear ints */
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(bcom_fec_tx_reset);
+
+void
+bcom_fec_tx_release(struct bcom_task *tsk)
+{
+       /* Nothing special for the FEC tasks */
+       bcom_task_free(tsk);
+}
+EXPORT_SYMBOL_GPL(bcom_fec_tx_release);
+
+
+MODULE_DESCRIPTION("BestComm FEC tasks driver");
+MODULE_AUTHOR("Dale Farnsworth <dfarnsworth@mvista.com>");
+MODULE_LICENSE("GPL v2");
+
diff --git a/arch/powerpc/sysdev/bestcomm/fec.h b/arch/powerpc/sysdev/bestcomm/fec.h
new file mode 100644 (file)
index 0000000..ee565d9
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Header for Bestcomm FEC tasks driver
+ *
+ *
+ * Copyright (C) 2006-2007 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2003-2004 MontaVista, Software, Inc.
+ *                         ( by Dale Farnsworth <dfarnsworth@mvista.com> )
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef __BESTCOMM_FEC_H__
+#define __BESTCOMM_FEC_H__
+
+
+struct bcom_fec_bd {
+       u32     status;
+       u32     skb_pa;
+};
+
+#define BCOM_FEC_TX_BD_TFD     0x08000000ul    /* transmit frame done */
+#define BCOM_FEC_TX_BD_TC      0x04000000ul    /* transmit CRC */
+#define BCOM_FEC_TX_BD_ABC     0x02000000ul    /* append bad CRC */
+
+#define BCOM_FEC_RX_BD_L       0x08000000ul    /* buffer is last in frame */
+#define BCOM_FEC_RX_BD_BC      0x00800000ul    /* DA is broadcast */
+#define BCOM_FEC_RX_BD_MC      0x00400000ul    /* DA is multicast and not broadcast */
+#define BCOM_FEC_RX_BD_LG      0x00200000ul    /* Rx frame length violation */
+#define BCOM_FEC_RX_BD_NO      0x00100000ul    /* Rx non-octet aligned frame */
+#define BCOM_FEC_RX_BD_CR      0x00040000ul    /* Rx CRC error */
+#define BCOM_FEC_RX_BD_OV      0x00020000ul    /* overrun */
+#define BCOM_FEC_RX_BD_TR      0x00010000ul    /* Rx frame truncated */
+#define BCOM_FEC_RX_BD_LEN_MASK        0x000007fful    /* mask for length of received frame */
+#define BCOM_FEC_RX_BD_ERRORS  (BCOM_FEC_RX_BD_LG | BCOM_FEC_RX_BD_NO | \
+               BCOM_FEC_RX_BD_CR | BCOM_FEC_RX_BD_OV | BCOM_FEC_RX_BD_TR)
+
+
+extern struct bcom_task *
+bcom_fec_rx_init(int queue_len, phys_addr_t fifo, int maxbufsize);
+
+extern int
+bcom_fec_rx_reset(struct bcom_task *tsk);
+
+extern void
+bcom_fec_rx_release(struct bcom_task *tsk);
+
+
+extern struct bcom_task *
+bcom_fec_tx_init(int queue_len, phys_addr_t fifo);
+
+extern int
+bcom_fec_tx_reset(struct bcom_task *tsk);
+
+extern void
+bcom_fec_tx_release(struct bcom_task *tsk);
+
+
+#endif /* __BESTCOMM_FEC_H__ */
+
diff --git a/arch/powerpc/sysdev/bestcomm/gen_bd.c b/arch/powerpc/sysdev/bestcomm/gen_bd.c
new file mode 100644 (file)
index 0000000..8d33eaf
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * Driver for MPC52xx processor BestComm General Buffer Descriptor
+ *
+ * Copyright (C) 2007 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2006 AppSpec Computer Technologies Corp.
+ *                    Jeff Gibbons <jeff.gibbons@appspec.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+
+#include <asm/mpc52xx.h>
+
+#include "bestcomm.h"
+#include "bestcomm_priv.h"
+#include "gen_bd.h"
+
+
+/* ======================================================================== */
+/* Task image/var/inc                                                       */
+/* ======================================================================== */
+
+/* gen_bd tasks images */
+extern u32 bcom_gen_bd_rx_task[];
+extern u32 bcom_gen_bd_tx_task[];
+
+/* rx task vars that need to be set before enabling the task */
+struct bcom_gen_bd_rx_var {
+       u32 enable;             /* (u16*) address of task's control register */
+       u32 fifo;               /* (u32*) address of gen_bd's fifo */
+       u32 bd_base;            /* (struct bcom_bd*) beginning of ring buffer */
+       u32 bd_last;            /* (struct bcom_bd*) end of ring buffer */
+       u32 bd_start;           /* (struct bcom_bd*) current bd */
+       u32 buffer_size;        /* size of receive buffer */
+};
+
+/* rx task incs that need to be set before enabling the task */
+struct bcom_gen_bd_rx_inc {
+       u16 pad0;
+       s16 incr_bytes;
+       u16 pad1;
+       s16 incr_dst;
+};
+
+/* tx task vars that need to be set before enabling the task */
+struct bcom_gen_bd_tx_var {
+       u32 fifo;               /* (u32*) address of gen_bd's fifo */
+       u32 enable;             /* (u16*) address of task's control register */
+       u32 bd_base;            /* (struct bcom_bd*) beginning of ring buffer */
+       u32 bd_last;            /* (struct bcom_bd*) end of ring buffer */
+       u32 bd_start;           /* (struct bcom_bd*) current bd */
+       u32 buffer_size;        /* set by uCode for each packet */
+};
+
+/* tx task incs that need to be set before enabling the task */
+struct bcom_gen_bd_tx_inc {
+       u16 pad0;
+       s16 incr_bytes;
+       u16 pad1;
+       s16 incr_src;
+       u16 pad2;
+       s16 incr_src_ma;
+};
+
+/* private structure */
+struct bcom_gen_bd_priv {
+       phys_addr_t     fifo;
+       int             initiator;
+       int             ipr;
+       int             maxbufsize;
+};
+
+
+/* ======================================================================== */
+/* Task support code                                                        */
+/* ======================================================================== */
+
+struct bcom_task *
+bcom_gen_bd_rx_init(int queue_len, phys_addr_t fifo,
+                       int initiator, int ipr, int maxbufsize)
+{
+       struct bcom_task *tsk;
+       struct bcom_gen_bd_priv *priv;
+
+       tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_gen_bd),
+                       sizeof(struct bcom_gen_bd_priv));
+       if (!tsk)
+               return NULL;
+
+       tsk->flags = BCOM_FLAGS_NONE;
+
+       priv = tsk->priv;
+       priv->fifo      = fifo;
+       priv->initiator = initiator;
+       priv->ipr       = ipr;
+       priv->maxbufsize = maxbufsize;
+
+       if (bcom_gen_bd_rx_reset(tsk)) {
+               bcom_task_free(tsk);
+               return NULL;
+       }
+
+       return tsk;
+}
+EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_init);
+
+int
+bcom_gen_bd_rx_reset(struct bcom_task *tsk)
+{
+       struct bcom_gen_bd_priv *priv = tsk->priv;
+       struct bcom_gen_bd_rx_var *var;
+       struct bcom_gen_bd_rx_inc *inc;
+
+       /* Shutdown the task */
+       bcom_disable_task(tsk->tasknum);
+
+       /* Reset the microcode */
+       var = (struct bcom_gen_bd_rx_var *) bcom_task_var(tsk->tasknum);
+       inc = (struct bcom_gen_bd_rx_inc *) bcom_task_inc(tsk->tasknum);
+
+       if (bcom_load_image(tsk->tasknum, bcom_gen_bd_rx_task))
+               return -1;
+
+       var->enable     = bcom_eng->regs_base +
+                               offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);
+       var->fifo       = (u32) priv->fifo;
+       var->bd_base    = tsk->bd_pa;
+       var->bd_last    = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);
+       var->bd_start   = tsk->bd_pa;
+       var->buffer_size = priv->maxbufsize;
+
+       inc->incr_bytes = -(s16)sizeof(u32);
+       inc->incr_dst   = sizeof(u32);
+
+       /* Reset the BDs */
+       tsk->index = 0;
+       tsk->outdex = 0;
+
+       memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
+
+       /* Configure some stuff */
+       bcom_set_task_pragma(tsk->tasknum, BCOM_GEN_RX_BD_PRAGMA);
+       bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
+
+       out_8(&bcom_eng->regs->ipr[priv->initiator], priv->ipr);
+       bcom_set_initiator(tsk->tasknum, priv->initiator);
+
+       out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum);    /* Clear ints */
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_reset);
+
+void
+bcom_gen_bd_rx_release(struct bcom_task *tsk)
+{
+       /* Nothing special for the GenBD tasks */
+       bcom_task_free(tsk);
+}
+EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_release);
+
+
+extern struct bcom_task *
+bcom_gen_bd_tx_init(int queue_len, phys_addr_t fifo,
+                       int initiator, int ipr)
+{
+       struct bcom_task *tsk;
+       struct bcom_gen_bd_priv *priv;
+
+       tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_gen_bd),
+                       sizeof(struct bcom_gen_bd_priv));
+       if (!tsk)
+               return NULL;
+
+       tsk->flags = BCOM_FLAGS_NONE;
+
+       priv = tsk->priv;
+       priv->fifo      = fifo;
+       priv->initiator = initiator;
+       priv->ipr       = ipr;
+
+       if (bcom_gen_bd_tx_reset(tsk)) {
+               bcom_task_free(tsk);
+               return NULL;
+       }
+
+       return tsk;
+}
+EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_init);
+
+int
+bcom_gen_bd_tx_reset(struct bcom_task *tsk)
+{
+       struct bcom_gen_bd_priv *priv = tsk->priv;
+       struct bcom_gen_bd_tx_var *var;
+       struct bcom_gen_bd_tx_inc *inc;
+
+       /* Shutdown the task */
+       bcom_disable_task(tsk->tasknum);
+
+       /* Reset the microcode */
+       var = (struct bcom_gen_bd_tx_var *) bcom_task_var(tsk->tasknum);
+       inc = (struct bcom_gen_bd_tx_inc *) bcom_task_inc(tsk->tasknum);
+
+       if (bcom_load_image(tsk->tasknum, bcom_gen_bd_tx_task))
+               return -1;
+
+       var->enable     = bcom_eng->regs_base +
+                               offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);
+       var->fifo       = (u32) priv->fifo;
+       var->bd_base    = tsk->bd_pa;
+       var->bd_last    = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);
+       var->bd_start   = tsk->bd_pa;
+
+       inc->incr_bytes = -(s16)sizeof(u32);
+       inc->incr_src   = sizeof(u32);
+       inc->incr_src_ma = sizeof(u8);
+
+       /* Reset the BDs */
+       tsk->index = 0;
+       tsk->outdex = 0;
+
+       memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
+
+       /* Configure some stuff */
+       bcom_set_task_pragma(tsk->tasknum, BCOM_GEN_TX_BD_PRAGMA);
+       bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
+
+       out_8(&bcom_eng->regs->ipr[priv->initiator], priv->ipr);
+       bcom_set_initiator(tsk->tasknum, priv->initiator);
+
+       out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum);    /* Clear ints */
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_reset);
+
+void
+bcom_gen_bd_tx_release(struct bcom_task *tsk)
+{
+       /* Nothing special for the GenBD tasks */
+       bcom_task_free(tsk);
+}
+EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_release);
+
+
+MODULE_DESCRIPTION("BestComm General Buffer Descriptor tasks driver");
+MODULE_AUTHOR("Jeff Gibbons <jeff.gibbons@appspec.com>");
+MODULE_LICENSE("GPL v2");
+
diff --git a/arch/powerpc/sysdev/bestcomm/gen_bd.h b/arch/powerpc/sysdev/bestcomm/gen_bd.h
new file mode 100644 (file)
index 0000000..5b6fa80
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Header for Bestcomm General Buffer Descriptor tasks driver
+ *
+ *
+ * Copyright (C) 2007 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2006 AppSpec Computer Technologies Corp.
+ *                    Jeff Gibbons <jeff.gibbons@appspec.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ *
+ */
+
+#ifndef __BESTCOMM_GEN_BD_H__
+#define __BESTCOMM_GEN_BD_H__
+
+struct bcom_gen_bd {
+       u32     status;
+       u32     buf_pa;
+};
+
+
+extern struct bcom_task *
+bcom_gen_bd_rx_init(int queue_len, phys_addr_t fifo,
+                       int initiator, int ipr, int maxbufsize);
+
+extern int
+bcom_gen_bd_rx_reset(struct bcom_task *tsk);
+
+extern void
+bcom_gen_bd_rx_release(struct bcom_task *tsk);
+
+
+extern struct bcom_task *
+bcom_gen_bd_tx_init(int queue_len, phys_addr_t fifo,
+                       int initiator, int ipr);
+
+extern int
+bcom_gen_bd_tx_reset(struct bcom_task *tsk);
+
+extern void
+bcom_gen_bd_tx_release(struct bcom_task *tsk);
+
+
+#endif  /* __BESTCOMM_GEN_BD_H__ */
+
diff --git a/arch/powerpc/sysdev/bestcomm/sram.c b/arch/powerpc/sysdev/bestcomm/sram.c
new file mode 100644 (file)
index 0000000..9978438
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Simple memory allocator for on-board SRAM
+ *
+ *
+ * Maintainer : Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Copyright (C) 2005 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/of.h>
+
+#include <asm/io.h>
+#include <asm/mmu.h>
+
+#include "sram.h"
+
+
+/* Struct keeping our 'state' */
+struct bcom_sram *bcom_sram = NULL;
+EXPORT_SYMBOL_GPL(bcom_sram);  /* needed for inline functions */
+
+
+/* ======================================================================== */
+/* Public API                                                               */
+/* ======================================================================== */
+/* DO NOT USE in interrupts, if needed in irq handler, we should use the
+   _irqsave version of the spin_locks */
+
+int bcom_sram_init(struct device_node *sram_node, char *owner)
+{
+       int rv;
+       const u32 *regaddr_p;
+       u64 regaddr64, size64;
+       unsigned int psize;
+
+       /* Create our state struct */
+       if (bcom_sram) {
+               printk(KERN_ERR "%s: bcom_sram_init: "
+                       "Already initialized !\n", owner);
+               return -EBUSY;
+       }
+
+       bcom_sram = kmalloc(sizeof(struct bcom_sram), GFP_KERNEL);
+       if (!bcom_sram) {
+               printk(KERN_ERR "%s: bcom_sram_init: "
+                       "Couldn't allocate internal state !\n", owner);
+               return -ENOMEM;
+       }
+
+       /* Get address and size of the sram */
+       regaddr_p = of_get_address(sram_node, 0, &size64, NULL);
+       if (!regaddr_p) {
+               printk(KERN_ERR "%s: bcom_sram_init: "
+                       "Invalid device node !\n", owner);
+               rv = -EINVAL;
+               goto error_free;
+       }
+
+       regaddr64 = of_translate_address(sram_node, regaddr_p);
+
+       bcom_sram->base_phys = (phys_addr_t) regaddr64;
+       bcom_sram->size = (unsigned int) size64;
+
+       /* Request region */
+       if (!request_mem_region(bcom_sram->base_phys, bcom_sram->size, owner)) {
+               printk(KERN_ERR "%s: bcom_sram_init: "
+                       "Couldn't request region !\n", owner);
+               rv = -EBUSY;
+               goto error_free;
+       }
+
+       /* Map SRAM */
+               /* sram is not really __iomem */
+       bcom_sram->base_virt = (void*) ioremap(bcom_sram->base_phys, bcom_sram->size);
+
+       if (!bcom_sram->base_virt) {
+               printk(KERN_ERR "%s: bcom_sram_init: "
+                       "Map error SRAM zone 0x%08lx (0x%0x)!\n",
+                       owner, bcom_sram->base_phys, bcom_sram->size );
+               rv = -ENOMEM;
+               goto error_release;
+       }
+
+       /* Create an rheap (defaults to 32 bits word alignment) */
+       bcom_sram->rh = rh_create(4);
+
+       /* Attach the free zones */
+#if 0
+       /* Currently disabled ... for future use only */
+       reg_addr_p = of_get_property(sram_node, "available", &psize);
+#else
+       regaddr_p = NULL;
+       psize = 0;
+#endif
+
+       if (!regaddr_p || !psize) {
+               /* Attach the whole zone */
+               rh_attach_region(bcom_sram->rh, 0, bcom_sram->size);
+       } else {
+               /* Attach each zone independently */
+               while (psize >= 2 * sizeof(u32)) {
+                       phys_addr_t zbase = of_translate_address(sram_node, regaddr_p);
+                       rh_attach_region(bcom_sram->rh, zbase - bcom_sram->base_phys, regaddr_p[1]);
+                       regaddr_p += 2;
+                       psize -= 2 * sizeof(u32);
+               }
+       }
+
+       /* Init our spinlock */
+       spin_lock_init(&bcom_sram->lock);
+
+       return 0;
+
+error_release:
+       release_mem_region(bcom_sram->base_phys, bcom_sram->size);
+error_free:
+       kfree(bcom_sram);
+       bcom_sram = NULL;
+
+       return rv;
+}
+EXPORT_SYMBOL_GPL(bcom_sram_init);
+
+void bcom_sram_cleanup(void)
+{
+       /* Free resources */
+       if (bcom_sram) {
+               rh_destroy(bcom_sram->rh);
+               iounmap((void __iomem *)bcom_sram->base_virt);
+               release_mem_region(bcom_sram->base_phys, bcom_sram->size);
+               kfree(bcom_sram);
+               bcom_sram = NULL;
+       }
+}
+EXPORT_SYMBOL_GPL(bcom_sram_cleanup);
+
+void* bcom_sram_alloc(int size, int align, phys_addr_t *phys)
+{
+       unsigned long offset;
+
+       spin_lock(&bcom_sram->lock);
+       offset = rh_alloc_align(bcom_sram->rh, size, align, NULL);
+       spin_unlock(&bcom_sram->lock);
+
+       if (IS_ERR_VALUE(offset))
+               return NULL;
+
+       *phys = bcom_sram->base_phys + offset;
+       return bcom_sram->base_virt + offset;
+}
+EXPORT_SYMBOL_GPL(bcom_sram_alloc);
+
+void bcom_sram_free(void *ptr)
+{
+       unsigned long offset;
+
+       if (!ptr)
+               return;
+
+       offset = ptr - bcom_sram->base_virt;
+
+       spin_lock(&bcom_sram->lock);
+       rh_free(bcom_sram->rh, offset);
+       spin_unlock(&bcom_sram->lock);
+}
+EXPORT_SYMBOL_GPL(bcom_sram_free);
+
diff --git a/arch/powerpc/sysdev/bestcomm/sram.h b/arch/powerpc/sysdev/bestcomm/sram.h
new file mode 100644 (file)
index 0000000..b6d6689
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Handling of a sram zone for bestcomm
+ *
+ *
+ * Copyright (C) 2007 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef __BESTCOMM_SRAM_H__
+#define __BESTCOMM_SRAM_H__
+
+#include <asm/rheap.h>
+#include <asm/mmu.h>
+#include <linux/spinlock.h>
+
+
+/* Structure used internally */
+       /* The internals are here for the inline functions
+        * sake, certainly not for the user to mess with !
+        */
+struct bcom_sram {
+       phys_addr_t              base_phys;
+       void                    *base_virt;
+       unsigned int             size;
+       rh_info_t               *rh;
+       spinlock_t               lock;
+};
+
+extern struct bcom_sram *bcom_sram;
+
+
+/* Public API */
+extern int  bcom_sram_init(struct device_node *sram_node, char *owner);
+extern void bcom_sram_cleanup(void);
+
+extern void* bcom_sram_alloc(int size, int align, phys_addr_t *phys);
+extern void  bcom_sram_free(void *ptr);
+
+static inline phys_addr_t bcom_sram_va2pa(void *va) {
+       return bcom_sram->base_phys +
+               (unsigned long)(va - bcom_sram->base_virt);
+}
+
+static inline void *bcom_sram_pa2va(phys_addr_t pa) {
+       return bcom_sram->base_virt +
+               (unsigned long)(pa - bcom_sram->base_phys);
+}
+
+
+#endif  /* __BESTCOMM_SRAM_H__ */
+
index 20dce4681259a0c6daf8f1ccf3af5826b33ca5d8..607925c8a99e050f0e1b042b531de6acc0290627 100644 (file)
@@ -102,6 +102,7 @@ config 44x
 
 config 8xx
        bool "8xx"
+       select PPC_LIB_RHEAP
 
 config E200
        bool "e200"
@@ -798,6 +799,7 @@ config CPM1
 config CPM2
        bool
        depends on 8260 || MPC8560 || MPC8555
+       select PPC_LIB_RHEAP
        default y
        help
          The CPM2 (Communications Processor Module) is a coprocessor on
@@ -1277,6 +1279,10 @@ config BOOT_LOAD
 config PIN_TLB
        bool "Pinned Kernel TLBs (860 ONLY)"
        depends on ADVANCED_OPTIONS && 8xx
+
+config PPC_LIB_RHEAP
+       bool
+
 endmenu
 
 source "net/Kconfig"
index 9d850b2b20b8e23a81ce218f10a8053d922e76af..c82b8d49a7da9fa21e978f8ccdeb1dddb7ec4f04 100644 (file)
 #define MPC52xx_PSC_MAXNUM     6
 
 /* Programmable Serial Controller (PSC) status register bits */
+#define MPC52xx_PSC_SR_UNEX_RX 0x0001
+#define MPC52xx_PSC_SR_DATA_VAL        0x0002
+#define MPC52xx_PSC_SR_DATA_OVR        0x0004
+#define MPC52xx_PSC_SR_CMDSEND 0x0008
 #define MPC52xx_PSC_SR_CDE     0x0080
 #define MPC52xx_PSC_SR_RXRDY   0x0100
 #define MPC52xx_PSC_SR_RXFULL  0x0200
@@ -132,8 +136,10 @@ struct mpc52xx_psc {
        u8              reserved5[3];
        u8              ctlr;           /* PSC + 0x1c */
        u8              reserved6[3];
-       u16             ccr;            /* PSC + 0x20 */
-       u8              reserved7[14];
+       u32             ccr;            /* PSC + 0x20 */
+       u32             ac97_slots;     /* PSC + 0x24 */
+       u32             ac97_cmd;       /* PSC + 0x28 */
+       u32             ac97_data;      /* PSC + 0x2c */
        u8              ivr;            /* PSC + 0x30 */
        u8              reserved8[3];
        u8              ip;             /* PSC + 0x34 */