Browse Source

Merge branch 'for-2.6.24' of git://git.secretlab.ca/git/linux-2.6-mpc52xx into merge

Paul Mackerras 17 years ago
parent
commit
4acadb965c

+ 4 - 0
arch/powerpc/Kconfig

@@ -699,3 +699,7 @@ source "crypto/Kconfig"
 config PPC_CLOCK
 	bool
 	default n
+
+config PPC_LIB_RHEAP
+	bool
+

+ 17 - 1
arch/powerpc/boot/dts/lite5200b.dts

@@ -277,10 +277,26 @@
 		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 {

+ 1 - 4
arch/powerpc/lib/Makefile

@@ -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

+ 15 - 0
arch/powerpc/lib/rheap.c

@@ -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);
+

+ 4 - 0
arch/powerpc/platforms/Kconfig

@@ -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

+ 1 - 0
arch/powerpc/platforms/Kconfig.cputype

@@ -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"

+ 1 - 0
arch/powerpc/sysdev/Makefile

@@ -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

+ 39 - 0
arch/powerpc/sysdev/bestcomm/Kconfig

@@ -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.
+

+ 14 - 0
arch/powerpc/sysdev/bestcomm/Makefile

@@ -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
+ 

+ 154 - 0
arch/powerpc/sysdev/bestcomm/ata.c

@@ -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");
+

+ 37 - 0
arch/powerpc/sysdev/bestcomm/ata.h

@@ -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__ */
+

+ 67 - 0
arch/powerpc/sysdev/bestcomm/bcom_ata_task.c

@@ -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,
+};
+

+ 78 - 0
arch/powerpc/sysdev/bestcomm/bcom_fec_rx_task.c

@@ -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,
+};
+

+ 91 - 0
arch/powerpc/sysdev/bestcomm/bcom_fec_tx_task.c

@@ -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,
+};
+

+ 63 - 0
arch/powerpc/sysdev/bestcomm/bcom_gen_bd_rx_task.c

@@ -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,
+};
+

+ 69 - 0
arch/powerpc/sysdev/bestcomm/bcom_gen_bd_tx_task.c

@@ -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,
+};
+

+ 528 - 0
arch/powerpc/sysdev/bestcomm/bestcomm.c

@@ -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");
+

+ 190 - 0
arch/powerpc/sysdev/bestcomm/bestcomm.h

@@ -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__ */

+ 334 - 0
arch/powerpc/sysdev/bestcomm/bestcomm_priv.h

@@ -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__ */
+

+ 270 - 0
arch/powerpc/sysdev/bestcomm/fec.c

@@ -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");
+

+ 61 - 0
arch/powerpc/sysdev/bestcomm/fec.h

@@ -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__ */
+

+ 260 - 0
arch/powerpc/sysdev/bestcomm/gen_bd.c

@@ -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");
+

+ 48 - 0
arch/powerpc/sysdev/bestcomm/gen_bd.h

@@ -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__ */
+

+ 177 - 0
arch/powerpc/sysdev/bestcomm/sram.c

@@ -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);
+

+ 54 - 0
arch/powerpc/sysdev/bestcomm/sram.h

@@ -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__ */
+

+ 6 - 0
arch/ppc/Kconfig

@@ -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"

+ 8 - 2
include/asm-ppc/mpc52xx_psc.h

@@ -28,6 +28,10 @@
 #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 */