[kernel] r9210 - in dists/sid/linux-2.6/debian: . arch/powerpc patches/features/powerpc/efika patches/features/powerpc/efika/extra patches/series

Sven Luther luther at alioth.debian.org
Fri Jul 27 20:59:32 UTC 2007


Author: luther
Date: Fri Jul 27 20:59:31 2007
New Revision: 9210

Log:
[powerpc] added support for the Genesi efika platform.


Added:
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0001-powerpc-exports-rheap-symbol-to-modules.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0002-powerpc-Changes-the-config-mechanism-for-rheap.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0003-powerpc-ppc32-Update-mpc52xx_psc-structure-with-B-r.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0004-powerpc-BestComm-core-support-for-Freescale-MPC5200.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0005-powerpc-BestcComm-ATA-task-support.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0006-powerpc-BestcComm-FEC-task-support.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0007-powerpc-BestcComm-GenBD-task-support.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0008-drivers-net-Add-support-for-Freescale-MPC5200-SoC-i.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0009-sound-Add-support-for-Freescale-MPC5200-AC97-interf.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0010-powerpc-In-rheap.c-move-the-EXPORT_SYMBOL-and-use.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0011-powerpc-BestComm-move-the-EXPORT_SYMBOL-and-use-th.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0012-powerpc-BestComm-ATA-task-move-the-EXPORT_SYMBOL-a.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0013-powerpc-BestComm-FEC-task-move-the-EXPORT_SYMBOL-a.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0014-powerpc-BestComm-GenBD-task-move-the-EXPORT_SYMBOL.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0015-powerpc-BestComm-Replace-global-variable-bcom-by-b.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0016-powerpc-Make-the-BestComm-driver-a-standard-of_plat.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0017-powerpc-Fix-typo-in-BestComm-ATA-task-support-code.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0018-powerpc-BestComm-ATA-task-microcode-insert-copyri.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0019-powerpc-BestComm-FEC-task-microcode-insert-copyri.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0020-powerpc-BestComm-GenBD-task-microcode-insert-copy.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0021-powerpc-Fix-errors-in-bcom-bcom_eng-renaming.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0081-mpc52xx-correct-calculation-of-FEC-RX-errors.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0082-powerpc-pata_mpc52xx-suspend.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/extra/
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/extra/11303_Fix_mpc52xx_uart_of_assign_to_use_correct_index.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/extra/11675_mpc5200_rtc_driver.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/extra/11861_mpc52xx_sparse_fixes.patch
   dists/sid/linux-2.6/debian/patches/features/powerpc/efika/extra/12626_mpx5200_uart_drop_port_lock_across_tty_flip_buffer_call.patch
Modified:
   dists/sid/linux-2.6/debian/arch/powerpc/config.powerpc
   dists/sid/linux-2.6/debian/changelog
   dists/sid/linux-2.6/debian/patches/series/3

Modified: dists/sid/linux-2.6/debian/arch/powerpc/config.powerpc
==============================================================================
--- dists/sid/linux-2.6/debian/arch/powerpc/config.powerpc	(original)
+++ dists/sid/linux-2.6/debian/arch/powerpc/config.powerpc	Fri Jul 27 20:59:31 2007
@@ -13,8 +13,23 @@
 CONFIG_FB_IMSTT=y
 # CONFIG_PPC64 is not set
 CONFIG_CLASSIC32=y
+CONFIG_PPC_EFIKA=y
+CONFIG_PPC_BESTCOMM=m
+CONFIG_PPC_BESTCOMM_ATA=m
+CONFIG_PPC_BESTCOMM_FEC=m
+CONFIG_PPC_BESTCOMM_GEN_BD=m
+CONFIG_FSL_SOC=y
 CONFIG_SERIAL_MPC52xx=y
 CONFIG_SERIAL_MPC52xx_CONSOLE=y
 CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD=115200
+CONFIG_FEC_MPC52xx=m
 CONFIG_MII=y
+CONFIG_USE_MDIO=y
 CONFIG_PATA_MPC52xx=m
+CONFIG_USB_OHCI_HCD=m
+CONFIG_USB_OHCI_HCD_PPC_SOC=y
+CONFIG_SND_PPC_MPC52xx_AC97=m
+CONFIG_SPI_MPC52xx_PSC=m
+CONFIG_RTC_DRV_MPC5200=m
+
+

Modified: dists/sid/linux-2.6/debian/changelog
==============================================================================
--- dists/sid/linux-2.6/debian/changelog	(original)
+++ dists/sid/linux-2.6/debian/changelog	Fri Jul 27 20:59:31 2007
@@ -9,6 +9,9 @@
   * [mipsel/4kc-malta] Update the config file, thanks Aurelien Jarno.
   * [mipsel] Add patch from Yoichi Yuasa to fix IDE on Cobalt.
 
+  [ Sven Luther ]
+  * [powerpc] Added support for the Genesi efika boards.
+
  -- dann frazier <dannf at debian.org>  Wed, 25 Jul 2007 14:04:02 -0600
 
 linux-2.6 (2.6.22-2) unstable; urgency=low

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0001-powerpc-exports-rheap-symbol-to-modules.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0001-powerpc-exports-rheap-symbol-to-modules.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,47 @@
+From f8edc7ea1e33a334fc8e4d4231142221892e7ab9 Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sat, 12 May 2007 21:18:55 +0200
+Subject: [PATCH 01/21] powerpc: exports rheap symbol to modules
+
+Theses can be useful in modules too. So we export them.
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/lib/rheap.c |   17 +++++++++++++++++
+ 1 files changed, 17 insertions(+), 0 deletions(-)
+
+diff --git a/arch/powerpc/lib/rheap.c b/arch/powerpc/lib/rheap.c
+index b2f6dcc..7c5968c 100644
+--- a/arch/powerpc/lib/rheap.c
++++ b/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/slab.h>
+ 
+@@ -724,3 +725,19 @@ 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(rh_create);
++EXPORT_SYMBOL(rh_destroy);
++EXPORT_SYMBOL(rh_init);
++EXPORT_SYMBOL(rh_attach_region);
++EXPORT_SYMBOL(rh_detach_region);
++EXPORT_SYMBOL(rh_alloc_align);
++EXPORT_SYMBOL(rh_alloc);
++EXPORT_SYMBOL(rh_alloc_fixed);
++EXPORT_SYMBOL(rh_free);
++EXPORT_SYMBOL(rh_get_stats);
++EXPORT_SYMBOL(rh_set_owner);
++EXPORT_SYMBOL(rh_dump);
++EXPORT_SYMBOL(rh_dump_blk);
++
+-- 
+1.5.1.2
+

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0002-powerpc-Changes-the-config-mechanism-for-rheap.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0002-powerpc-Changes-the-config-mechanism-for-rheap.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,89 @@
+From 308d73b96b8a098ee5b6ce9485340ab44cea3493 Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sat, 12 May 2007 21:23:57 +0200
+Subject: [PATCH 02/21] powerpc: Changes the config mechanism for rheap
+
+Instead of having in the makefile all the option that
+requires rheap, we define a configuration symbol
+and when needed we make sure it's selected.
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/Kconfig           |    2 ++
+ arch/powerpc/lib/Kconfig       |    3 +++
+ arch/powerpc/lib/Makefile      |    4 +---
+ arch/powerpc/platforms/Kconfig |    2 ++
+ 4 files changed, 8 insertions(+), 3 deletions(-)
+ create mode 100644 arch/powerpc/lib/Kconfig
+
+diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
+index 56d3c0d..094e5d2 100644
+--- a/arch/powerpc/Kconfig
++++ b/arch/powerpc/Kconfig
+@@ -193,6 +193,7 @@ config PPC_8xx
+ 	bool "Freescale 8xx"
+ 	select FSL_SOC
+ 	select 8xx
++	select PPC_LIB_RHEAP
+ 
+ config 40x
+ 	bool "AMCC 40x"
+@@ -885,6 +886,7 @@ source "fs/Kconfig"
+ 
+ source "arch/powerpc/sysdev/qe_lib/Kconfig"
+ 
++source "arch/powerpc/lib/Kconfig"
+ source "lib/Kconfig"
+ 
+ menu "Instrumentation Support"
+diff --git a/arch/powerpc/lib/Kconfig b/arch/powerpc/lib/Kconfig
+new file mode 100644
+index 0000000..f383ad4
+--- /dev/null
++++ b/arch/powerpc/lib/Kconfig
+@@ -0,0 +1,3 @@
++config PPC_LIB_RHEAP
++	bool
++	default n
+diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
+index 0a486d4..a6cf399 100644
+--- a/arch/powerpc/lib/Makefile
++++ b/arch/powerpc/lib/Makefile
+@@ -13,7 +13,6 @@ endif
+ 
+ obj-$(CONFIG_PPC64)	+= checksum_64.o 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,5 +22,4 @@ 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
+diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
+index 361acfa..8432f56 100644
+--- a/arch/powerpc/platforms/Kconfig
++++ b/arch/powerpc/platforms/Kconfig
+@@ -242,6 +242,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).
+@@ -251,6 +252,7 @@ config QUICC_ENGINE
+ config CPM2
+ 	bool
+ 	default n
++	select PPC_LIB_RHEAP
+ 	help
+ 	  The CPM2 (Communications Processor Module) is a coprocessor on
+ 	  embedded CPUs made by Freescale.  Selecting this option means that
+-- 
+1.5.1.2
+

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0003-powerpc-ppc32-Update-mpc52xx_psc-structure-with-B-r.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0003-powerpc-ppc32-Update-mpc52xx_psc-structure-with-B-r.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,49 @@
+From bdfad6d143398743fbb891fddd4de24ff4021ab8 Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sat, 12 May 2007 21:37:51 +0200
+Subject: [PATCH 03/21] powerpc/ppc32: Update mpc52xx_psc structure with B revision changes
+
+On the mpc5200b the ccr register is 32 bits wide while on the
+mpc5200 it's only 16 bits. It's up to the driver to use the
+correct format depending on the chip it's running on.
+
+The 5200b also offers some more registers & status in AC97
+mode. Again, if not running on a 5200b the driver should not
+use those.
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ include/asm-ppc/mpc52xx_psc.h |   10 ++++++++--
+ 1 files changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/include/asm-ppc/mpc52xx_psc.h b/include/asm-ppc/mpc52xx_psc.h
+index 9d850b2..c82b8d4 100644
+--- a/include/asm-ppc/mpc52xx_psc.h
++++ b/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 */
+-- 
+1.5.1.2
+

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0004-powerpc-BestComm-core-support-for-Freescale-MPC5200.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0004-powerpc-BestComm-core-support-for-Freescale-MPC5200.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,1426 @@
+From ab24e9300bba7d52e168b2299da28350384d65da Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sat, 12 May 2007 21:44:37 +0200
+Subject: [PATCH 04/21] powerpc: BestComm core support for Freescale MPC5200
+
+This patch adds support for the core of the BestComm API
+for the Freescale MPC5200(b). The BestComm engine is a
+microcode-controlled / tasks-based DMA used by several
+of the onchip devices.
+
+Setting up the tasks / memory allocation and all common
+low level functions are handled by this patch.
+The specifics details of each tasks and their microcode
+are split-out in separate patches.
+
+This is not the official API, but a much cleaner one.
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/platforms/Kconfig               |    2 +
+ arch/powerpc/sysdev/Makefile                 |    1 +
+ arch/powerpc/sysdev/bestcomm/Kconfig         |   18 +
+ arch/powerpc/sysdev/bestcomm/Makefile        |    8 +
+ arch/powerpc/sysdev/bestcomm/bestcomm.c      |  600 ++++++++++++++++++++++++++
+ arch/powerpc/sysdev/bestcomm/bestcomm.h      |  136 ++++++
+ arch/powerpc/sysdev/bestcomm/bestcomm_priv.h |  325 ++++++++++++++
+ arch/powerpc/sysdev/bestcomm/sram.c          |  180 ++++++++
+ arch/powerpc/sysdev/bestcomm/sram.h          |   54 +++
+ 9 files changed, 1324 insertions(+), 0 deletions(-)
+ create mode 100644 arch/powerpc/sysdev/bestcomm/Kconfig
+ create mode 100644 arch/powerpc/sysdev/bestcomm/Makefile
+ create mode 100644 arch/powerpc/sysdev/bestcomm/bestcomm.c
+ create mode 100644 arch/powerpc/sysdev/bestcomm/bestcomm.h
+ create mode 100644 arch/powerpc/sysdev/bestcomm/bestcomm_priv.h
+ create mode 100644 arch/powerpc/sysdev/bestcomm/sram.c
+ create mode 100644 arch/powerpc/sysdev/bestcomm/sram.h
+
+diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
+index 8432f56..fc170a3 100644
+--- a/arch/powerpc/platforms/Kconfig
++++ b/arch/powerpc/platforms/Kconfig
+@@ -259,4 +259,6 @@ config CPM2
+ 	  you wish to build a kernel for a machine with a CPM2 coprocessor
+ 	  on it (826x, 827x, 8560).
+ 
++source "arch/powerpc/sysdev/bestcomm/Kconfig"
++
+ endmenu
+diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
+index c3ce0bd..89074f8 100644
+--- a/arch/powerpc/sysdev/Makefile
++++ b/arch/powerpc/sysdev/Makefile
+@@ -16,6 +16,7 @@ obj-$(CONFIG_FSL_SOC)		+= fsl_soc.o
+ obj-$(CONFIG_FSL_PCIE)		+= fsl_pcie.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
+ 
+diff --git a/arch/powerpc/sysdev/bestcomm/Kconfig b/arch/powerpc/sysdev/bestcomm/Kconfig
+new file mode 100644
+index 0000000..3366e24
+--- /dev/null
++++ b/arch/powerpc/sysdev/bestcomm/Kconfig
+@@ -0,0 +1,18 @@
++#
++# 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.
++
+diff --git a/arch/powerpc/sysdev/bestcomm/Makefile b/arch/powerpc/sysdev/bestcomm/Makefile
+new file mode 100644
+index 0000000..a24aa06
+--- /dev/null
++++ b/arch/powerpc/sysdev/bestcomm/Makefile
+@@ -0,0 +1,8 @@
++#
++# Makefile for BestComm & co
++#
++
++bestcomm-core-objs	:= bestcomm.o sram.o
++
++obj-$(CONFIG_PPC_BESTCOMM)		+= bestcomm-core.o
++ 
+diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.c b/arch/powerpc/sysdev/bestcomm/bestcomm.c
+new file mode 100644
+index 0000000..0063a1e
+--- /dev/null
++++ b/arch/powerpc/sysdev/bestcomm/bestcomm.c
+@@ -0,0 +1,600 @@
++/*
++ * Driver for MPC52xx processor BestComm peripheral controller
++ *
++ *
++ * Copyright (C) 2006-2007 Sylvain Munaut <tnt at 246tNt.com>
++ * Copyright (C) 2005      Varma Electronics Oy,
++ *                         ( by Andrey Volkov <avolkov at varma-el.com> )
++ * Copyright (C) 2003-2004 MontaVista, Software, Inc.
++ *                         ( by Dale Farnsworth <dfarnsworth at 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 <asm/io.h>
++#include <asm/irq.h>
++#include <asm/prom.h>
++#include <asm/mpc52xx.h>
++
++#include "sram.h"
++#include "bestcomm_priv.h"
++#include "bestcomm.h"
++
++#define DRIVER_NAME "bestcomm-core"
++
++
++struct bcom_engine *bcom = NULL;
++
++
++/* ======================================================================== */
++/* Public and private API                                                   */
++/* ======================================================================== */
++
++/* Debug Dump */
++
++#define BCOM_DPRINTK(a,b...) printk(KERN_DEBUG DRIVER_NAME ": " a, ## b)
++
++void
++bcom_dump_status(void)
++{
++	int i;
++	struct mpc52xx_sdma __iomem *r = bcom->regs;
++
++	BCOM_DPRINTK("BestComm status dump (pa=%08lx, va=%p)\n",
++			bcom->regs_base, bcom->regs);
++	BCOM_DPRINTK(" taskBar         = %08x\n", in_be32(&r->taskBar));
++	BCOM_DPRINTK(" currentPointer  = %08x\n", in_be32(&r->currentPointer));
++	BCOM_DPRINTK(" endPointer      = %08x\n", in_be32(&r->endPointer));
++	BCOM_DPRINTK(" variablePointer = %08x\n", in_be32(&r->variablePointer));
++	BCOM_DPRINTK(" IntVect1        = %08x\n", (u32)in_8(&r->IntVect1));
++	BCOM_DPRINTK(" IntVect2        = %08x\n", (u32)in_8(&r->IntVect2));
++	BCOM_DPRINTK(" PtdCntrl        = %08hx\n", in_be16(&r->PtdCntrl));
++	BCOM_DPRINTK(" IntPend         = %08x\n", in_be32(&r->IntPend));
++	BCOM_DPRINTK(" IntMask         = %08x\n", in_be32(&r->IntMask));
++
++	BCOM_DPRINTK(" TCR dump :\n");
++
++	for (i=0; i<16; i++) {
++		printk("%s%04hx%s",
++			(i&0x7) == 0x0 ? KERN_DEBUG "\t" : "",
++			in_be16(&r->tcr[i]),
++			(i&0x7) == 0x7 ? "\n" : " ");
++	}
++
++	BCOM_DPRINTK(" IPR dump :\n");
++
++	for (i=0; i<32; i++) {
++		printk("%s%02x%s",
++			(i&0x7) == 0x0 ? KERN_DEBUG "\t" : "",
++			(u32)in_8(&r->ipr[i]),
++			(i&0x7) == 0x7 ? "\n" : " ");
++	}
++
++	BCOM_DPRINTK(" cReqSelect      = %08x\n", in_be32(&r->cReqSelect));
++	BCOM_DPRINTK(" task_size0      = %08x\n", in_be32(&r->task_size0));
++	BCOM_DPRINTK(" task_size1      = %08x\n", in_be32(&r->task_size1));
++	BCOM_DPRINTK(" MDEDebug        = %08x\n", in_be32(&r->MDEDebug));
++	BCOM_DPRINTK(" ADSDebug        = %08x\n", in_be32(&r->ADSDebug));
++	BCOM_DPRINTK(" Value1          = %08x\n", in_be32(&r->Value1));
++	BCOM_DPRINTK(" Value2          = %08x\n", in_be32(&r->Value2));
++	BCOM_DPRINTK(" Control         = %08x\n", in_be32(&r->Control));
++	BCOM_DPRINTK(" Status          = %08x\n", in_be32(&r->Status));
++	BCOM_DPRINTK(" PTDDebug        = %08x\n", in_be32(&r->PTDDebug));
++}
++
++void
++bcom_dump_task(int task)
++{
++	int i;
++	u32 *p;
++	struct bcom_tdt *tdt = &bcom->tdt[task];
++
++	BCOM_DPRINTK("Task dump %d\n", task);
++	BCOM_DPRINTK(" tcr          = %04hx\n", bcom->regs->tcr[task]);
++	BCOM_DPRINTK(" tdt          = %p\n", &bcom->tdt[task]);
++	BCOM_DPRINTK(" tdt->start   = %08x\n", tdt->start);
++	BCOM_DPRINTK(" tdt->stop    = %08x\n", tdt->stop);
++	BCOM_DPRINTK(" tdt->var     = %08x\n", tdt->var);
++	BCOM_DPRINTK(" tdt->fdt     = %08x\n", tdt->fdt);
++	BCOM_DPRINTK(" tdt->status  = %08x\n", tdt->exec_status);
++	BCOM_DPRINTK(" tdt->mvtp    = %08x\n", tdt->mvtp);
++	BCOM_DPRINTK(" tdt->context = %08x\n", tdt->context);
++	BCOM_DPRINTK(" tdt->litbase = %08x\n", tdt->litbase);
++
++	BCOM_DPRINTK(" code    :\n");
++
++	p = bcom_task_desc(task);
++	for (i=0; i<bcom_task_num_descs(task); i++)
++		printk(KERN_DEBUG "\t%p %08x\n", &p[i], p[i]);
++
++	BCOM_DPRINTK(" var/inc :\n");
++
++	p = bcom_task_var(task);
++	for (i=0; i<BCOM_MAX_VAR+BCOM_MAX_INC; i++)
++		printk(KERN_DEBUG "\t%p %08x\n", &p[i], p[i]);
++}
++
++void
++bcom_dump_bdring(struct bcom_task *tsk)
++{
++	int i, j;
++
++	BCOM_DPRINTK("BD ring dump %d\n", tsk->tasknum);
++
++	for (i=0; i<tsk->num_bd; i++) {
++		BCOM_DPRINTK(" BD[%02d] :\n", i);
++		BCOM_DPRINTK("  cookie   : %p\n", tsk->cookie[i]);
++		BCOM_DPRINTK("  status   : %08x\n", tsk->bd[i].status);
++		for (j=0; j<(tsk->bd_size/sizeof(u32))-1; j++)
++			BCOM_DPRINTK("  data[%02d] : %08x\n",
++				j, tsk->bd[i].data[j]);
++	}
++}
++
++
++/* 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->lock);
++
++	for (i=0; i<BCOM_MAX_TASKS; i++)
++		if (!bcom->tdt[i].stop) {	/* we use stop as a marker */
++			bcom->tdt[i].stop = 0xfffffffful; /* dummy addr */
++			tasknum = i;
++			break;
++		}
++
++	spin_unlock(&bcom->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->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->tdt[tasknum].stop = 0;
++
++	return NULL;
++}
++
++void
++bcom_task_release(struct bcom_task *tsk)
++{
++	/* Stop the task */
++	bcom_disable_task(tsk->tasknum);
++
++	/* Clear TDT */
++	bcom->tdt[tsk->tasknum].start = 0;
++	bcom->tdt[tsk->tasknum].stop  = 0;
++
++	/* Free everything */
++	irq_dispose_mapping(tsk->irq);
++	bcom_sram_free(tsk->bd);
++	kfree(tsk->cookie);
++	kfree(tsk);
++}
++
++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->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;
++}
++
++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);
++	}
++}
++
++
++/* Public API */
++
++void
++bcom_enable(struct bcom_task *tsk)
++{
++	bcom_enable_task(tsk->tasknum);
++}
++
++void
++bcom_disable(struct bcom_task *tsk)
++{
++	bcom_disable_task(tsk->tasknum);
++}
++
++
++/* ======================================================================== */
++/* 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->tdt = bcom_sram_alloc(tdt_size, sizeof(u32), &tdt_pa);
++	bcom->ctx = bcom_sram_alloc(ctx_size, BCOM_CTX_ALIGN, &ctx_pa);
++	bcom->var = bcom_sram_alloc(var_size, BCOM_VAR_ALIGN, &var_pa);
++	bcom->fdt = bcom_sram_alloc(fdt_size, BCOM_FDT_ALIGN, &fdt_pa);
++
++	if (!bcom->tdt || !bcom->ctx || !bcom->var || !bcom->fdt) {
++		printk(KERN_ERR "DMA: SRAM alloc failed in engine init !\n");
++
++		bcom_sram_free(bcom->tdt);
++		bcom_sram_free(bcom->ctx);
++		bcom_sram_free(bcom->var);
++		bcom_sram_free(bcom->fdt);
++
++		return -ENOMEM;
++	}
++
++	memset(bcom->tdt, 0x00, tdt_size);
++	memset(bcom->ctx, 0x00, ctx_size);
++	memset(bcom->var, 0x00, var_size);
++	memset(bcom->fdt, 0x00, fdt_size);
++
++	/* Copy the FDT for the EU#3 */
++	memcpy(&bcom->fdt[48], fdt_ops, sizeof(fdt_ops));
++
++	/* Initialize Task base structure */
++	for (task=0; task<BCOM_MAX_TASKS; task++)
++	{
++		out_be16(&bcom->regs->tcr[task], 0);
++		out_8(&bcom->regs->ipr[task], 0);
++
++		bcom->tdt[task].context	= ctx_pa;
++		bcom->tdt[task].var	= var_pa;
++		bcom->tdt[task].fdt	= fdt_pa;
++
++		var_pa += BCOM_VAR_SIZE + BCOM_INC_SIZE;
++		ctx_pa += BCOM_CTX_SIZE;
++	}
++
++	out_be32(&bcom->regs->taskBar, tdt_pa);
++
++	/* Init 'always' initiator */
++	out_8(&bcom->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->regs->PtdCntrl, in_be16(&bcom->regs->PtdCntrl) | 1);
++
++	/* Init lock */
++	spin_lock_init(&bcom->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->regs->tcr[task], 0);
++		out_8(&bcom->regs->ipr[task], 0);
++	}
++
++	out_be32(&bcom->regs->taskBar, 0ul);
++
++	/* Release the SRAM zones */
++	bcom_sram_free(bcom->tdt);
++	bcom_sram_free(bcom->ctx);
++	bcom_sram_free(bcom->var);
++	bcom_sram_free(bcom->fdt);
++}
++
++
++/* ======================================================================== */
++/* System/Module init & cleanup                                             */
++/* ======================================================================== */
++
++static int __init
++mpc52xx_bcom_init(void)
++{
++	struct device_node *ofn_bcom, *ofn_sram;
++	struct resource res_bcom;
++
++	int rv;
++
++	/* Find the bestcomm node. If none, fails 'silently' since
++	 * we may just be on another platform */
++	ofn_bcom = of_find_compatible_node(
++			NULL, "dma-controller", "mpc5200-bestcomm");
++	if (!ofn_bcom)
++		return -ENODEV;
++
++	/* Inform user we're ok so far */
++	printk(KERN_INFO "DMA: MPC52xx BestComm driver\n");
++
++	/* 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 = kzalloc(sizeof(struct bcom_engine), GFP_KERNEL);
++	if (!bcom) {
++		printk(KERN_ERR DRIVER_NAME ": "
++			"Can't allocate state structure\n");
++		rv = -ENOMEM;
++		goto error_sramclean;
++	}
++
++	/* Save the node */
++	bcom->ofnode = ofn_bcom;
++
++	/* Get, reserve & map io */
++	if (of_address_to_resource(bcom->ofnode, 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->regs_base = res_bcom.start;
++	bcom->regs = ioremap(res_bcom.start, sizeof(struct mpc52xx_sdma));
++	if (!bcom->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->regs_base);
++
++	return 0;
++
++	/* Error path */
++error_unmap:
++	iounmap(bcom->regs);
++error_release:
++	release_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma));
++error_sramclean:
++	bcom_sram_cleanup();
++error_ofput:
++	of_node_put(bcom->ofnode);
++
++	printk(KERN_ERR "DMA: MPC52xx BestComm init failed !\n");
++
++	return rv;
++}
++
++static void __exit
++mpc52xx_bcom_exit(void)
++{
++	/* Clean up the engine */
++	bcom_engine_cleanup();
++
++	/* Cleanup SRAM */
++	bcom_sram_cleanup();
++
++	/* Release regs */
++	iounmap(bcom->regs);
++	release_mem_region(bcom->regs_base, sizeof(struct mpc52xx_sdma));
++
++	/* Release the node */
++	of_node_put(bcom->ofnode);
++
++	/* Release memory */
++	kfree(bcom);
++}
++
++#ifdef MODULE
++module_init(mpc52xx_bcom_init);
++module_exit(mpc52xx_bcom_exit);
++#endif
++
++/* If we're not a module, we must make sure everything is setup before anyone */
++/* tries to use us ... */
++#ifndef MODULE
++subsys_initcall(mpc52xx_bcom_init);
++#endif
++
++MODULE_DESCRIPTION("Freescale MPC52xx BestComm DMA");
++MODULE_AUTHOR("Sylvain Munaut <tnt at 246tNt.com>");
++MODULE_AUTHOR("Andrey Volkov <avolkov at varma-el.com>");
++MODULE_AUTHOR("Dale Farnsworth <dfarnsworth at mvista.com>");
++MODULE_LICENSE("GPL v2");
++
++
++EXPORT_SYMBOL(bcom);
++EXPORT_SYMBOL(bcom_dump_status);
++EXPORT_SYMBOL(bcom_dump_task);
++EXPORT_SYMBOL(bcom_dump_bdring);
++EXPORT_SYMBOL(bcom_task_alloc);
++EXPORT_SYMBOL(bcom_task_release);
++EXPORT_SYMBOL(bcom_load_image);
++EXPORT_SYMBOL(bcom_set_initiator);
++EXPORT_SYMBOL(bcom_enable);
++EXPORT_SYMBOL(bcom_disable);
++
+diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.h b/arch/powerpc/sysdev/bestcomm/bestcomm.h
+new file mode 100644
+index 0000000..eac3eec
+--- /dev/null
++++ b/arch/powerpc/sysdev/bestcomm/bestcomm.h
+@@ -0,0 +1,136 @@
++/*
++ * Public header for the MPC52xx processor BestComm driver
++ *
++ *
++ * Copyright (C) 2006      Sylvain Munaut <tnt at 246tNt.com>
++ * Copyright (C) 2005      Varma Electronics Oy,
++ *                         ( by Andrey Volkov <avolkov at varma-el.com> )
++ * Copyright (C) 2003-2004 MontaVista, Software, Inc.
++ *                         ( by Dale Farnsworth <dfarnsworth at 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 {
++	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)
++
++
++extern void bcom_enable(struct bcom_task *tsk);
++extern void bcom_disable(struct bcom_task *tsk);
++
++static inline int
++bcom_get_task_irq(struct bcom_task *tsk) {
++	return tsk->irq;
++}
++
++
++/* Debug dumps */
++extern void bcom_dump_status(void);
++extern void bcom_dump_task(int task);
++extern void bcom_dump_bdring(struct bcom_task *tsk);
++
++
++/* ======================================================================== */
++/* BD based tasks helpers                                                   */
++/* ======================================================================== */
++
++struct bcom_bd {
++	u32	status;
++	u32	data[1];	/* variable, but at least 1 */
++};
++
++#define BCOM_BD_READY	0x40000000ul
++
++static inline int	/* user shouldn't use this ! */
++_bcom_next_index(struct bcom_task *tsk)
++{
++	return ((tsk->index + 1) == tsk->num_bd) ? 0 : tsk->index + 1;
++}
++
++static inline int	/* user shouldn't use this ! */
++_bcom_next_outdex(struct bcom_task *tsk)
++{
++	return ((tsk->outdex + 1) == tsk->num_bd) ? 0 : tsk->outdex + 1;
++}
++
++static inline int
++bcom_queue_empty(struct bcom_task *tsk)
++{
++	return tsk->index == tsk->outdex;
++}
++
++static inline int
++bcom_queue_full(struct bcom_task *tsk)
++{
++	return tsk->outdex == _bcom_next_index(tsk);
++}
++
++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);
++}
++
++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
+index 0000000..d43b00a
+--- /dev/null
++++ b/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h
+@@ -0,0 +1,325 @@
++/*
++ * Private header for the MPC52xx processor BestComm driver
++ *
++ *
++ * Copyright (C) 2006      Sylvain Munaut <tnt at 246tNt.com>
++ * Copyright (C) 2005      Varma Electronics Oy,
++ *                         ( by Andrey Volkov <avolkov at varma-el.com> )
++ * Copyright (C) 2003-2004 MontaVista, Software, Inc.
++ *                         ( by Dale Farnsworth <dfarnsworth at 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 <asm/io.h>
++#include <asm/prom.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
++
++/* 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;
++};
++
++/* 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;
++
++
++/* ======================================================================== */
++/* 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_release(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->regs->tcr[task]);
++        out_be16(&bcom->regs->tcr[task],  reg | TASK_ENABLE);
++}
++
++static inline void
++bcom_disable_task(int task)
++{
++        u16 reg = in_be16(&bcom->regs->tcr[task]);
++        out_be16(&bcom->regs->tcr[task], reg & ~TASK_ENABLE);
++}
++
++
++static inline u32 *
++bcom_task_desc(int task)
++{
++	return bcom_sram_pa2va(bcom->tdt[task].start);
++}
++
++static inline int
++bcom_task_num_descs(int task)
++{
++	return (bcom->tdt[task].stop - bcom->tdt[task].start)/sizeof(u32) + 1;
++}
++
++static inline u32 *
++bcom_task_var(int task)
++{
++	return bcom_sram_pa2va(bcom->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->tdt[task].fdt;
++	*fdt = (*fdt & ~0xff) | pragma;
++}
++
++static inline void
++bcom_set_task_auto_start(int task, int next_task)
++{
++	u16 __iomem *tcr = &bcom->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->regs->tcr[task];
++	out_be16(tcr, (in_be16(tcr) & ~0x1f00) | ((initiator & 0x1f) << 8));
++}
++
++
++#endif /* __BESTCOMM_PRIV_H__ */
++
+diff --git a/arch/powerpc/sysdev/bestcomm/sram.c b/arch/powerpc/sysdev/bestcomm/sram.c
+new file mode 100644
+index 0000000..4f69127
+--- /dev/null
++++ b/arch/powerpc/sysdev/bestcomm/sram.c
+@@ -0,0 +1,180 @@
++/*
++ * Simple memory allocator for on-board SRAM
++ *
++ *
++ * Maintainer : Sylvain Munaut <tnt at 246tNt.com>
++ *
++ * Copyright (C) 2005 Sylvain Munaut <tnt at 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 <asm/io.h>
++#include <asm/mmu.h>
++#include <asm/prom.h>
++
++#include "sram.h"
++
++
++/* Struct keeping our 'state' */
++struct bcom_sram *bcom_sram = NULL;
++
++
++/* ======================================================================== */
++/* 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 initialiwed !\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: "
++			"Couln'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;
++}
++
++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;
++	}
++}
++
++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;
++}
++
++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(bcom_sram);
++
++EXPORT_SYMBOL(bcom_sram_init);
++EXPORT_SYMBOL(bcom_sram_cleanup);
++EXPORT_SYMBOL(bcom_sram_alloc);
++EXPORT_SYMBOL(bcom_sram_free);
++
+diff --git a/arch/powerpc/sysdev/bestcomm/sram.h b/arch/powerpc/sysdev/bestcomm/sram.h
+new file mode 100644
+index 0000000..b6d6689
+--- /dev/null
++++ b/arch/powerpc/sysdev/bestcomm/sram.h
+@@ -0,0 +1,54 @@
++/*
++ * Handling of a sram zone for bestcomm
++ *
++ *
++ * Copyright (C) 2007 Sylvain Munaut <tnt at 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__ */
++
+-- 
+1.5.1.2
+

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0005-powerpc-BestcComm-ATA-task-support.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0005-powerpc-BestcComm-ATA-task-support.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,325 @@
+From 175c346d8cb5304c063d8416566caf80f0e32beb Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sat, 12 May 2007 21:53:25 +0200
+Subject: [PATCH 05/21] powerpc: BestcComm ATA task support
+
+This is the microcode for the ATA task and the associated
+support code.
+
+The microcode itself comes directly from the offical
+API (v2.2)
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/sysdev/bestcomm/Kconfig         |    7 +
+ arch/powerpc/sysdev/bestcomm/Makefile        |    2 +
+ arch/powerpc/sysdev/bestcomm/ata.c           |  155 ++++++++++++++++++++++++++
+ arch/powerpc/sysdev/bestcomm/ata.h           |   37 ++++++
+ arch/powerpc/sysdev/bestcomm/bcom_ata_task.c |   61 ++++++++++
+ 5 files changed, 262 insertions(+), 0 deletions(-)
+ create mode 100644 arch/powerpc/sysdev/bestcomm/ata.c
+ create mode 100644 arch/powerpc/sysdev/bestcomm/ata.h
+ create mode 100644 arch/powerpc/sysdev/bestcomm/bcom_ata_task.c
+
+diff --git a/arch/powerpc/sysdev/bestcomm/Kconfig b/arch/powerpc/sysdev/bestcomm/Kconfig
+index 3366e24..9d087ce 100644
+--- a/arch/powerpc/sysdev/bestcomm/Kconfig
++++ b/arch/powerpc/sysdev/bestcomm/Kconfig
+@@ -16,3 +16,10 @@ config PPC_BESTCOMM
+ 	  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.
++
+diff --git a/arch/powerpc/sysdev/bestcomm/Makefile b/arch/powerpc/sysdev/bestcomm/Makefile
+index a24aa06..b7a6a40 100644
+--- a/arch/powerpc/sysdev/bestcomm/Makefile
++++ b/arch/powerpc/sysdev/bestcomm/Makefile
+@@ -3,6 +3,8 @@
+ #
+ 
+ bestcomm-core-objs	:= bestcomm.o sram.o
++bestcomm-ata-objs	:= ata.o bcom_ata_task.o
+ 
+ obj-$(CONFIG_PPC_BESTCOMM)		+= bestcomm-core.o
++obj-$(CONFIG_PPC_BESTCOMM_ATA)		+= bestcomm-ata.o
+  
+diff --git a/arch/powerpc/sysdev/bestcomm/ata.c b/arch/powerpc/sysdev/bestcomm/ata.c
+new file mode 100644
+index 0000000..c14f727
+--- /dev/null
++++ b/arch/powerpc/sysdev/bestcomm/ata.c
+@@ -0,0 +1,155 @@
++/*
++ * Bestcomm ATA task driver
++ *
++ *
++ * Patterned after bestcomm/fec.c by Dale Farnsworth <dfarnsworth at mvista.com>
++ *                                   2003-2004 (c) MontaVista, Software, Inc.
++ *
++ * Copyright (C) 2006-2007 Sylvain Munaut <tnt at 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(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_release(tsk);
++		return NULL;
++	}
++
++	var->enable	= bcom->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->regs->ipr[BCOM_INITIATOR_ATA_RX], BCOM_IPR_ATA_RX);
++	out_8(&bcom->regs->ipr[BCOM_INITIATOR_ATA_TX], BCOM_IPR_ATA_TX);
++
++	out_be32(&bcom->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */
++
++	return tsk;
++}
++
++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);
++}
++
++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);
++}
++
++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;
++}
++
++void bcom_ata_release(struct bcom_task *tsk)
++{
++	/* Nothing special for the ATA tasks */
++	bcom_task_release(tsk);
++}
++
++
++EXPORT_SYMBOL(bcom_ata_init);
++EXPORT_SYMBOL(bcom_ata_rx_prepare);
++EXPORT_SYMBOL(bcom_ata_tx_prepare);
++EXPORT_SYMBOL(bcom_ata_reset);
++EXPORT_SYMBOL(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
+index 0000000..1098276
+--- /dev/null
++++ b/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 at 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
+index 0000000..779cebb
+--- /dev/null
++++ b/arch/powerpc/sysdev/bestcomm/bcom_ata_task.c
+@@ -0,0 +1,61 @@
++/*
++ * Bestcomm ATA task microcode
++ *
++ * 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,
++};
++
+-- 
+1.5.1.2
+

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0006-powerpc-BestcComm-FEC-task-support.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0006-powerpc-BestcComm-FEC-task-support.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,557 @@
+From 9838c46651198f39675c3461e3c1cb377741f355 Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sat, 12 May 2007 21:57:01 +0200
+Subject: [PATCH 06/21] powerpc: BestcComm FEC task support
+
+This is the microcode for the FEC task and the associated
+support code.
+
+The microcode itself comes directly from the offical
+API (v2.2)
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/sysdev/bestcomm/Kconfig            |    7 +
+ arch/powerpc/sysdev/bestcomm/Makefile           |    2 +
+ arch/powerpc/sysdev/bestcomm/bcom_fec_rx_task.c |   72 ++++++
+ arch/powerpc/sysdev/bestcomm/bcom_fec_tx_task.c |   85 +++++++
+ arch/powerpc/sysdev/bestcomm/fec.c              |  271 +++++++++++++++++++++++
+ arch/powerpc/sysdev/bestcomm/fec.h              |   48 ++++
+ 6 files changed, 485 insertions(+), 0 deletions(-)
+ create mode 100644 arch/powerpc/sysdev/bestcomm/bcom_fec_rx_task.c
+ create mode 100644 arch/powerpc/sysdev/bestcomm/bcom_fec_tx_task.c
+ create mode 100644 arch/powerpc/sysdev/bestcomm/fec.c
+ create mode 100644 arch/powerpc/sysdev/bestcomm/fec.h
+
+diff --git a/arch/powerpc/sysdev/bestcomm/Kconfig b/arch/powerpc/sysdev/bestcomm/Kconfig
+index 9d087ce..831763b 100644
+--- a/arch/powerpc/sysdev/bestcomm/Kconfig
++++ b/arch/powerpc/sysdev/bestcomm/Kconfig
+@@ -23,3 +23,10 @@ config PPC_BESTCOMM_ATA
+ 	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.
++
+diff --git a/arch/powerpc/sysdev/bestcomm/Makefile b/arch/powerpc/sysdev/bestcomm/Makefile
+index b7a6a40..537d174 100644
+--- a/arch/powerpc/sysdev/bestcomm/Makefile
++++ b/arch/powerpc/sysdev/bestcomm/Makefile
+@@ -4,7 +4,9 @@
+ 
+ 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
+ 
+ obj-$(CONFIG_PPC_BESTCOMM)		+= bestcomm-core.o
+ obj-$(CONFIG_PPC_BESTCOMM_ATA)		+= bestcomm-ata.o
++obj-$(CONFIG_PPC_BESTCOMM_FEC)		+= bestcomm-fec.o
+  
+diff --git a/arch/powerpc/sysdev/bestcomm/bcom_fec_rx_task.c b/arch/powerpc/sysdev/bestcomm/bcom_fec_rx_task.c
+new file mode 100644
+index 0000000..48bae92
+--- /dev/null
++++ b/arch/powerpc/sysdev/bestcomm/bcom_fec_rx_task.c
+@@ -0,0 +1,72 @@
++/*
++ * Bestcomm FEC RX task microcode
++ *
++ * 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
+index 0000000..8c5aa83
+--- /dev/null
++++ b/arch/powerpc/sysdev/bestcomm/bcom_fec_tx_task.c
+@@ -0,0 +1,85 @@
++/*
++ * Bestcomm FEC TX task microcode
++ *
++ * 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/fec.c b/arch/powerpc/sysdev/bestcomm/fec.c
+new file mode 100644
+index 0000000..56ff560
+--- /dev/null
++++ b/arch/powerpc/sysdev/bestcomm/fec.c
+@@ -0,0 +1,271 @@
++/*
++ * Bestcomm FEC tasks driver
++ *
++ *
++ * Copyright (C) 2006-2007 Sylvain Munaut <tnt at 246tNt.com>
++ * Copyright (C) 2003-2004 MontaVista, Software, Inc.
++ *                         ( by Dale Farnsworth <dfarnsworth at 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_release(tsk);
++		return NULL;
++	}
++
++	return tsk;
++}
++
++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->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->regs->ipr[BCOM_INITIATOR_FEC_RX], BCOM_IPR_FEC_RX);
++
++	out_be32(&bcom->regs->IntPend, 1<<tsk->tasknum);	/* Clear ints */
++
++	return 0;
++}
++
++void
++bcom_fec_rx_release(struct bcom_task *tsk)
++{
++	/* Nothing special for the FEC tasks */
++	bcom_task_release(tsk);
++}
++
++
++
++	/* 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_release(tsk);
++		return NULL;
++	}
++
++	return tsk;
++}
++
++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->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->regs->ipr[BCOM_INITIATOR_FEC_TX], BCOM_IPR_FEC_TX);
++
++	out_be32(&bcom->regs->IntPend, 1<<tsk->tasknum);	/* Clear ints */
++
++	return 0;
++}
++
++void
++bcom_fec_tx_release(struct bcom_task *tsk)
++{
++	/* Nothing special for the FEC tasks */
++	bcom_task_release(tsk);
++}
++
++
++EXPORT_SYMBOL(bcom_fec_rx_init);
++EXPORT_SYMBOL(bcom_fec_rx_reset);
++EXPORT_SYMBOL(bcom_fec_rx_release);
++EXPORT_SYMBOL(bcom_fec_tx_init);
++EXPORT_SYMBOL(bcom_fec_tx_reset);
++EXPORT_SYMBOL(bcom_fec_tx_release);
++
++MODULE_DESCRIPTION("BestComm FEC tasks driver");
++MODULE_AUTHOR("Dale Farnsworth <dfarnsworth at 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
+index 0000000..fa880ca
+--- /dev/null
++++ b/arch/powerpc/sysdev/bestcomm/fec.h
+@@ -0,0 +1,48 @@
++/*
++ * Header for Bestcomm FEC tasks driver
++ *
++ *
++ * Copyright (C) 2006-2007 Sylvain Munaut <tnt at 246tNt.com>
++ * Copyright (C) 2003-2004 MontaVista, Software, Inc.
++ *                         ( by Dale Farnsworth <dfarnsworth at 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_INT	0x04000000ul	/* interrupt */
++
++
++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__ */
++
+-- 
+1.5.1.2
+

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0007-powerpc-BestcComm-GenBD-task-support.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0007-powerpc-BestcComm-GenBD-task-support.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,523 @@
+From 84a159c383a75786c05a2cb7f44e8f0998806cdf Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sat, 12 May 2007 22:00:07 +0200
+Subject: [PATCH 07/21] powerpc: BestcComm GenBD task support
+
+This is the microcode for the GenBD task and the associated
+support code. This is a generic task that copy data to/from
+a hardware FIFO. This is currently locked to 32bits wide
+access but could be extended as needed.
+
+The microcode itself comes directly from the offical
+API (v2.2)
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/sysdev/bestcomm/Kconfig               |    7 +
+ arch/powerpc/sysdev/bestcomm/Makefile              |    2 +
+ arch/powerpc/sysdev/bestcomm/bcom_gen_bd_rx_task.c |   62 +++++
+ arch/powerpc/sysdev/bestcomm/bcom_gen_bd_tx_task.c |   68 +++++
+ arch/powerpc/sysdev/bestcomm/gen_bd.c              |  261 ++++++++++++++++++++
+ arch/powerpc/sysdev/bestcomm/gen_bd.h              |   48 ++++
+ 6 files changed, 448 insertions(+), 0 deletions(-)
+ create mode 100644 arch/powerpc/sysdev/bestcomm/bcom_gen_bd_rx_task.c
+ create mode 100644 arch/powerpc/sysdev/bestcomm/bcom_gen_bd_tx_task.c
+ create mode 100644 arch/powerpc/sysdev/bestcomm/gen_bd.c
+ create mode 100644 arch/powerpc/sysdev/bestcomm/gen_bd.h
+
+diff --git a/arch/powerpc/sysdev/bestcomm/Kconfig b/arch/powerpc/sysdev/bestcomm/Kconfig
+index 831763b..57cc565 100644
+--- a/arch/powerpc/sysdev/bestcomm/Kconfig
++++ b/arch/powerpc/sysdev/bestcomm/Kconfig
+@@ -30,3 +30,10 @@ config PPC_BESTCOMM_FEC
+ 	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
+index 537d174..aed2df2 100644
+--- a/arch/powerpc/sysdev/bestcomm/Makefile
++++ b/arch/powerpc/sysdev/bestcomm/Makefile
+@@ -5,8 +5,10 @@
+ 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/bcom_gen_bd_rx_task.c b/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_rx_task.c
+new file mode 100644
+index 0000000..f356886
+--- /dev/null
++++ b/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_rx_task.c
+@@ -0,0 +1,62 @@
++/*
++ * Bestcomm GenBD RX task microcode
++ *
++ * Copyright (C) 2006 AppSpec Computer Technologies Corp.
++ *                    Jeff Gibbons <jeff.gibbons at 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.
++ *
++ * 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
+index 0000000..7460c39
+--- /dev/null
++++ b/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_tx_task.c
+@@ -0,0 +1,68 @@
++/*
++ * Bestcomm GenBD TX task microcode
++ *
++ * Copyright (C) 2006 AppSpec Computer Technologies Corp.
++ *                    Jeff Gibbons <jeff.gibbons at 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.
++ *
++ * 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/gen_bd.c b/arch/powerpc/sysdev/bestcomm/gen_bd.c
+new file mode 100644
+index 0000000..b221bbc
+--- /dev/null
++++ b/arch/powerpc/sysdev/bestcomm/gen_bd.c
+@@ -0,0 +1,261 @@
++/*
++ * Driver for MPC52xx processor BestComm General Buffer Descriptor
++ *
++ * Copyright (C) 2007 Sylvain Munaut <tnt at 246tNt.com>
++ * Copyright (C) 2006 AppSpec Computer Technologies Corp.
++ *                    Jeff Gibbons <jeff.gibbons at 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_release(tsk);
++		return NULL;
++	}
++
++	return tsk;
++}
++
++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->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->regs->ipr[priv->initiator], priv->ipr);
++	bcom_set_initiator(tsk->tasknum, priv->initiator);
++
++	out_be32(&bcom->regs->IntPend, 1<<tsk->tasknum);	/* Clear ints */
++
++	return 0;
++}
++
++void
++bcom_gen_bd_rx_release(struct bcom_task *tsk)
++{
++	/* Nothing special for the GenBD tasks */
++	bcom_task_release(tsk);
++}
++
++
++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_release(tsk);
++		return NULL;
++	}
++
++	return tsk;
++}
++
++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->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->regs->ipr[priv->initiator], priv->ipr);
++	bcom_set_initiator(tsk->tasknum, priv->initiator);
++
++	out_be32(&bcom->regs->IntPend, 1<<tsk->tasknum);	/* Clear ints */
++
++	return 0;
++}
++
++void
++bcom_gen_bd_tx_release(struct bcom_task *tsk)
++{
++	/* Nothing special for the GenBD tasks */
++	bcom_task_release(tsk);
++}
++
++
++EXPORT_SYMBOL(bcom_gen_bd_rx_init);
++EXPORT_SYMBOL(bcom_gen_bd_rx_reset);
++EXPORT_SYMBOL(bcom_gen_bd_rx_release);
++EXPORT_SYMBOL(bcom_gen_bd_tx_init);
++EXPORT_SYMBOL(bcom_gen_bd_tx_reset);
++EXPORT_SYMBOL(bcom_gen_bd_tx_release);
++
++MODULE_DESCRIPTION("BestComm General Buffer Descriptor tasks driver");
++MODULE_AUTHOR("Jeff Gibbons <jeff.gibbons at 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
+index 0000000..5b6fa80
+--- /dev/null
++++ b/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 at 246tNt.com>
++ * Copyright (C) 2006 AppSpec Computer Technologies Corp.
++ *                    Jeff Gibbons <jeff.gibbons at 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__ */
++
+-- 
+1.5.1.2
+

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0008-drivers-net-Add-support-for-Freescale-MPC5200-SoC-i.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0008-drivers-net-Add-support-for-Freescale-MPC5200-SoC-i.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,1839 @@
+From 46d3109d0d32cbc559dbefd0130431265d6ec5b8 Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sat, 12 May 2007 22:03:03 +0200
+Subject: [PATCH 08/21] drivers/net: Add support for Freescale MPC5200 SoC internal FEC.
+
+Not quite a clean driver, but it get things done.
+Only included to be able to test functionalityi/usage of
+the BestComm driver.
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ drivers/net/Kconfig               |    1 +
+ drivers/net/Makefile              |    1 +
+ drivers/net/fec_mpc52xx/Kconfig   |   24 ++
+ drivers/net/fec_mpc52xx/Makefile  |    7 +
+ drivers/net/fec_mpc52xx/fec.c     |  813 +++++++++++++++++++++++++++++++++++++
+ drivers/net/fec_mpc52xx/fec.h     |  306 ++++++++++++++
+ drivers/net/fec_mpc52xx/fec_phy.c |  526 ++++++++++++++++++++++++
+ drivers/net/fec_mpc52xx/fec_phy.h |   73 ++++
+ 8 files changed, 1751 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/net/fec_mpc52xx/Kconfig
+ create mode 100644 drivers/net/fec_mpc52xx/Makefile
+ create mode 100644 drivers/net/fec_mpc52xx/fec.c
+ create mode 100644 drivers/net/fec_mpc52xx/fec.h
+ create mode 100644 drivers/net/fec_mpc52xx/fec_phy.c
+ create mode 100644 drivers/net/fec_mpc52xx/fec_phy.h
+
+diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
+index fb99cd4..df8df41 100644
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -1890,6 +1890,7 @@ config NE_H8300
+ 	  controller on the Renesas H8/300 processor.
+ 
+ source "drivers/net/fec_8xx/Kconfig"
++source "drivers/net/fec_mpc52xx/Kconfig"
+ source "drivers/net/fs_enet/Kconfig"
+ 
+ endmenu
+diff --git a/drivers/net/Makefile b/drivers/net/Makefile
+index a77affa..72e092c 100644
+--- a/drivers/net/Makefile
++++ b/drivers/net/Makefile
+@@ -196,6 +196,7 @@ obj-$(CONFIG_SMC91X) += smc91x.o
+ obj-$(CONFIG_SMC911X) += smc911x.o
+ obj-$(CONFIG_DM9000) += dm9000.o
+ obj-$(CONFIG_FEC_8XX) += fec_8xx/
++obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx/
+ obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o
+ obj-$(CONFIG_MLX4_CORE) += mlx4/
+ 
+diff --git a/drivers/net/fec_mpc52xx/Kconfig b/drivers/net/fec_mpc52xx/Kconfig
+new file mode 100644
+index 0000000..1043a1a
+--- /dev/null
++++ b/drivers/net/fec_mpc52xx/Kconfig
+@@ -0,0 +1,24 @@
++menu "MPC5200 Networking Options"
++	depends PPC_MPC52xx && NET_ETHERNET
++
++config FEC_MPC52xx
++	tristate "FEC Ethernet"
++	depends on NET_ETHERNET
++	select PPC_BESTCOMM
++	select PPC_BESTCOMM_FEC
++	select CRC32
++	---help---
++	  This option enables support for the MPC5200's on-chip
++	  Fast Ethernet Controller
++
++config USE_MDIO
++	bool "Use external Ethernet MII PHY"
++	select MII
++	depends FEC_MPC52xx
++	---help---
++	  The MPC5200's FEC can connect to the Ethernet either with
++	  an external MII PHY chip or 10 Mbps 7-wire interface 
++	  (Motorola? industry standard).
++	  If your board uses an external PHY, say y, else n.
++
++endmenu
+diff --git a/drivers/net/fec_mpc52xx/Makefile b/drivers/net/fec_mpc52xx/Makefile
+new file mode 100644
+index 0000000..900c2c1
+--- /dev/null
++++ b/drivers/net/fec_mpc52xx/Makefile
+@@ -0,0 +1,7 @@
++obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
++
++fec_mpc52xx-objs := fec.o
++
++ifeq ($(CONFIG_USE_MDIO),y)
++fec_mpc52xx-objs += fec_phy.o
++endif
+diff --git a/drivers/net/fec_mpc52xx/fec.c b/drivers/net/fec_mpc52xx/fec.c
+new file mode 100644
+index 0000000..416bac7
+--- /dev/null
++++ b/drivers/net/fec_mpc52xx/fec.c
+@@ -0,0 +1,813 @@
++/*
++ * drivers/net/fec_mpc52xx/fec.c
++ *
++ * Driver for the MPC5200 Fast Ethernet Controller
++ *
++ * Originally written by Dale Farnsworth <dfarnsworth at mvista.com> and
++ * now maintained by Sylvain Munaut <tnt at 246tNt.com>
++ *
++ * Copyright (C) 2007  Sylvain Munaut <tnt at 246tNt.com>
++ * Copyrigth (C) 2003-2004  MontaVista, Software, Inc.
++ *
++ * 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/types.h>
++#include <linux/spinlock.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/crc32.h>
++
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/ethtool.h>
++#include <linux/skbuff.h>
++
++#include <asm/of_device.h>
++#include <asm/of_platform.h>
++#include <asm/io.h>
++#include <asm/delay.h>
++#include <asm/mpc52xx.h>
++
++#include <sysdev/bestcomm/bestcomm.h>
++#include <sysdev/bestcomm/fec.h>
++
++#include "fec_phy.h"
++#include "fec.h"
++
++#define DRIVER_NAME "mpc52xx-fec"
++
++static irqreturn_t fec_interrupt(int, void *);
++static irqreturn_t fec_rx_interrupt(int, void *);
++static irqreturn_t fec_tx_interrupt(int, void *);
++static struct net_device_stats *fec_get_stats(struct net_device *);
++static void fec_set_multicast_list(struct net_device *dev);
++static void fec_reinit(struct net_device *dev);
++
++static u8 mpc52xx_fec_mac_addr[6];
++static u8 null_mac[6];
++
++static void fec_tx_timeout(struct net_device *dev)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++
++	priv->stats.tx_errors++;
++
++	if (!priv->tx_full)
++		netif_wake_queue(dev);
++}
++
++static void fec_set_paddr(struct net_device *dev, u8 *mac)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	struct mpc52xx_fec *fec = priv->fec;
++
++	out_be32(&fec->paddr1, *(u32*)(&mac[0]));
++	out_be32(&fec->paddr2, (*(u16*)(&mac[4]) << 16) | 0x8808);
++}
++
++static void fec_get_paddr(struct net_device *dev, u8 *mac)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	struct mpc52xx_fec *fec = priv->fec;
++
++	*(u32*)(&mac[0]) = in_be32(&fec->paddr1);
++	*(u16*)(&mac[4]) = in_be32(&fec->paddr2) >> 16;
++}
++
++static int fec_set_mac_address(struct net_device *dev, void *addr)
++{
++	struct sockaddr *sock = (struct sockaddr *)addr;
++
++	memcpy(dev->dev_addr, sock->sa_data, dev->addr_len);
++
++	fec_set_paddr(dev, sock->sa_data);
++	return 0;
++}
++
++/* This function is called to start or restart the FEC during a link
++ * change.  This happens on fifo errors or when switching between half
++ * and full duplex.
++ */
++static void fec_restart(struct net_device *dev, int duplex)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	struct mpc52xx_fec *fec = priv->fec;
++	u32 rcntrl;
++	u32 tcntrl;
++	int i;
++
++	out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status) & 0x700000);
++	out_be32(&fec->tfifo_status, in_be32(&fec->tfifo_status) & 0x700000);
++	out_be32(&fec->reset_cntrl, 0x1000000);
++
++	/* Whack a reset.  We should wait for this. */
++	out_be32(&fec->ecntrl, FEC_ECNTRL_RESET);
++	for (i = 0; i < FEC_RESET_DELAY; ++i) {
++		if ((in_be32(&fec->ecntrl) & FEC_ECNTRL_RESET) == 0)
++			break;
++		udelay(1);
++	}
++	if (i == FEC_RESET_DELAY)
++		printk (KERN_ERR DRIVER_NAME ": FEC Reset timeout!\n");
++
++	/* Set station address. */
++	fec_set_paddr(dev, dev->dev_addr);
++
++	fec_set_multicast_list(dev);
++
++	rcntrl = FEC_RX_BUFFER_SIZE << 16;	/* max frame length */
++	rcntrl |= FEC_RCNTRL_FCE;
++	rcntrl |= MII_RCNTL_MODE;
++	if (duplex)
++		tcntrl = FEC_TCNTRL_FDEN;		/* FD enable */
++	else {
++		rcntrl |= FEC_RCNTRL_DRT;
++		tcntrl = 0;
++	}
++	out_be32(&fec->r_cntrl, rcntrl);
++	out_be32(&fec->x_cntrl, tcntrl);
++
++	set_phy_speed(fec, priv->phy_speed);
++
++	priv->full_duplex = duplex;
++
++	/* Clear any outstanding interrupt. */
++	out_be32(&fec->ievent, 0xffffffff);	/* clear intr events */
++
++	/* Enable interrupts we wish to service.
++	*/
++	out_be32(&fec->imask, FEC_IMASK_ENABLE);
++
++	/* And last, enable the transmit and receive processing.
++	*/
++	out_be32(&fec->ecntrl, FEC_ECNTRL_ETHER_EN);
++	out_be32(&fec->r_des_active, 0x01000000);
++
++	/* The tx ring is no longer full. */
++	if (priv->tx_full)
++	{
++		priv->tx_full = 0;
++		netif_wake_queue(dev);
++	}
++}
++
++static void fec_free_rx_buffers(struct bcom_task *s)
++{
++	struct sk_buff *skb;
++
++	while (!bcom_queue_empty(s)) {
++		skb = bcom_retrieve_buffer(s, NULL, NULL);
++		kfree_skb(skb);
++	}
++}
++
++static int fec_open(struct net_device *dev)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++
++	bcom_fec_rx_reset(priv->rx_dmatsk);
++	bcom_fec_tx_reset(priv->tx_dmatsk);
++
++	while (!bcom_queue_full(priv->rx_dmatsk)) {
++		struct sk_buff *skb;
++		struct bcom_fec_bd *bd;
++
++		skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE);
++		if (skb == 0)
++			goto eagain;
++
++		/* zero out the initial receive buffers to aid debugging */
++		memset(skb->data, 0, FEC_RX_BUFFER_SIZE);
++
++		bd = (struct bcom_fec_bd *)
++			bcom_prepare_next_buffer(priv->rx_dmatsk);
++
++		bd->status = FEC_RX_BUFFER_SIZE;
++		bd->skb_pa = virt_to_phys(skb->data);
++
++		bcom_submit_next_buffer(priv->rx_dmatsk, skb);
++	}
++
++	fec_set_paddr(dev, dev->dev_addr);
++
++	if (fec_mii_wait(dev) != 0)
++		return -ENODEV;
++
++	bcom_enable(priv->rx_dmatsk);
++	bcom_enable(priv->tx_dmatsk);
++
++	netif_start_queue(dev);
++
++	return 0;
++
++eagain:
++	printk(KERN_ERR "fec_open: failed\n");
++
++	fec_free_rx_buffers(priv->rx_dmatsk);
++
++	return -EAGAIN;
++}
++
++/* This will only be invoked if your driver is _not_ in XOFF state.
++ * What this means is that you need not check it, and that this
++ * invariant will hold if you make sure that the netif_*_queue()
++ * calls are done at the proper times.
++ */
++static int fec_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	struct bcom_fec_bd *bd;
++
++	if (bcom_queue_full(priv->tx_dmatsk))
++		panic("MPC52xx transmit queue overrun\n");
++
++	spin_lock_irq(&priv->lock);
++	dev->trans_start = jiffies;
++
++	bd = (struct bcom_fec_bd *)
++		bcom_prepare_next_buffer(priv->tx_dmatsk);
++
++	bd->status = skb->len | BCOM_FEC_TX_BD_TFD | BCOM_FEC_TX_BD_INT;
++	bd->skb_pa = virt_to_phys(skb->data);
++
++	bcom_submit_next_buffer(priv->tx_dmatsk, skb);
++
++	if (bcom_queue_full(priv->tx_dmatsk)) {
++		priv->tx_full = 1;
++		netif_stop_queue(dev);
++	}
++
++	spin_unlock_irq(&priv->lock);
++
++	return 0;
++}
++
++/* This handles BestComm transmit task interrupts
++ */
++static irqreturn_t fec_tx_interrupt(int irq, void *dev_id)
++{
++	struct net_device *dev = dev_id;
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++
++	for (;;) {
++		struct sk_buff *skb;
++
++		spin_lock(&priv->lock);
++		if (!bcom_buffer_done(priv->tx_dmatsk)) {
++			spin_unlock(&priv->lock);
++			break;
++		}
++		skb = bcom_retrieve_buffer(priv->tx_dmatsk, NULL, NULL);
++
++		if (priv->tx_full) {
++			priv->tx_full = 0;
++			netif_wake_queue(dev);
++		}
++		spin_unlock(&priv->lock);
++		dev_kfree_skb_irq(skb);
++	}
++
++	return IRQ_HANDLED;
++}
++
++static irqreturn_t fec_rx_interrupt(int irq, void *dev_id)
++{
++	struct net_device *dev = dev_id;
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++
++	for (;;) {
++		struct sk_buff *skb;
++		struct sk_buff *rskb;
++		struct bcom_fec_bd *bd;
++		u32 status;
++
++		if (!bcom_buffer_done(priv->rx_dmatsk))
++			break;
++
++		rskb = bcom_retrieve_buffer(priv->rx_dmatsk, &status, NULL);
++
++		/* Test for errors in received frame */
++		if (status & 0x370000) { 
++			/* Drop packet and reuse the buffer */
++			bd = (struct bcom_fec_bd *)
++				bcom_prepare_next_buffer(priv->rx_dmatsk);
++
++			bd->status = FEC_RX_BUFFER_SIZE;
++			bd->skb_pa = virt_to_phys(rskb->data);
++
++			bcom_submit_next_buffer(priv->rx_dmatsk, rskb);
++
++			priv->stats.rx_dropped++;
++
++			continue;
++		}
++
++		/* allocate replacement skb */
++		skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE);
++		if (skb) {
++			/* Process the received skb */
++			int length = (status & ((1<<11) - 1)) - sizeof(u32);
++			skb_put(rskb, length);	/* length included CRC32 */
++
++			rskb->dev = dev;
++			rskb->protocol = eth_type_trans(rskb, dev);
++			netif_rx(rskb);
++			dev->last_rx = jiffies;
++		} else {
++			/* Can't get a new one : reuse the same & drop pkt */
++			printk(KERN_NOTICE
++				"%s: Memory squeeze, dropping packet.\n",
++				dev->name);
++			priv->stats.rx_dropped++;
++
++			skb = rskb;
++		}
++
++		bd = (struct bcom_fec_bd *)
++			bcom_prepare_next_buffer(priv->rx_dmatsk);
++
++		bd->status = FEC_RX_BUFFER_SIZE;
++		bd->skb_pa = virt_to_phys(skb->data);
++
++		bcom_submit_next_buffer(priv->rx_dmatsk, skb);
++	}
++
++	return IRQ_HANDLED;
++}
++
++static irqreturn_t fec_interrupt(int irq, void *dev_id)
++{
++	struct net_device *dev = (struct net_device *)dev_id;
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	struct mpc52xx_fec *fec = priv->fec;
++	int ievent;
++
++	ievent = in_be32(&fec->ievent);
++	if (!ievent)
++		return IRQ_NONE;
++
++	out_be32(&fec->ievent, ievent);		/* clear pending events */
++
++	if (ievent & (FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR)) {
++		if (net_ratelimit() && (ievent & FEC_IEVENT_RFIFO_ERROR))
++			printk(KERN_WARNING "FEC_IEVENT_RFIFO_ERROR\n");
++		if (net_ratelimit() && (ievent & FEC_IEVENT_XFIFO_ERROR))
++			printk(KERN_WARNING "FEC_IEVENT_XFIFO_ERROR\n");
++		fec_reinit(dev);
++	}
++	else if (ievent & FEC_IEVENT_MII)
++		fec_mii(dev);
++	return IRQ_HANDLED;
++}
++
++static int fec_close(struct net_device *dev)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	unsigned long timeout;
++
++	priv->open_time = 0;
++	priv->sequence_done = 0;
++
++	netif_stop_queue(dev);
++
++	bcom_disable(priv->rx_dmatsk);		/* disable receive task */
++
++	/* Wait for queues to drain */
++	timeout = jiffies + 2*HZ;
++	while (time_before(jiffies, timeout) &&
++			(!bcom_queue_empty(priv->tx_dmatsk) ||
++			!bcom_queue_empty(priv->rx_dmatsk))) {
++		set_current_state(TASK_INTERRUPTIBLE);
++		schedule_timeout(HZ/10);
++	}
++	if (time_after_eq(jiffies, timeout))
++		printk(KERN_ERR "fec_close: queues didn't drain\n");
++
++	bcom_disable(priv->tx_dmatsk);
++
++	fec_free_rx_buffers(priv->rx_dmatsk);
++
++	fec_get_stats(dev);
++
++	return 0;
++}
++
++/*
++ * Get the current statistics.
++ * This may be called with the card open or closed.
++ */
++static struct net_device_stats *fec_get_stats(struct net_device *dev)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	struct net_device_stats *stats = &priv->stats;
++	struct mpc52xx_fec *fec = priv->fec;
++
++	stats->rx_bytes = in_be32(&fec->rmon_r_octets);
++	stats->rx_packets = in_be32(&fec->rmon_r_packets);
++	stats->rx_errors = stats->rx_packets - in_be32(&fec->ieee_r_frame_ok);
++	stats->tx_bytes = in_be32(&fec->rmon_t_octets);
++	stats->tx_packets = in_be32(&fec->rmon_t_packets);
++	stats->tx_errors = stats->tx_packets - (
++					in_be32(&fec->ieee_t_frame_ok) +
++					in_be32(&fec->rmon_t_col) +
++					in_be32(&fec->ieee_t_1col) +
++					in_be32(&fec->ieee_t_mcol) +
++					in_be32(&fec->ieee_t_def));
++	stats->multicast = in_be32(&fec->rmon_r_mc_pkt);
++	stats->collisions = in_be32(&fec->rmon_t_col);
++
++	/* detailed rx_errors: */
++	stats->rx_length_errors = in_be32(&fec->rmon_r_undersize)
++					+ in_be32(&fec->rmon_r_oversize)
++					+ in_be32(&fec->rmon_r_frag)
++					+ in_be32(&fec->rmon_r_jab);
++	stats->rx_over_errors = in_be32(&fec->r_macerr);
++	stats->rx_crc_errors = in_be32(&fec->ieee_r_crc);
++	stats->rx_frame_errors = in_be32(&fec->ieee_r_align);
++	stats->rx_fifo_errors = in_be32(&fec->rmon_r_drop);
++	stats->rx_missed_errors = in_be32(&fec->rmon_r_drop);
++
++	/* detailed tx_errors: */
++	stats->tx_aborted_errors = 0;
++	stats->tx_carrier_errors = in_be32(&fec->ieee_t_cserr);
++	stats->tx_fifo_errors = in_be32(&fec->rmon_t_drop);
++	stats->tx_heartbeat_errors = in_be32(&fec->ieee_t_sqe);
++	stats->tx_window_errors = in_be32(&fec->ieee_t_lcol);
++
++	return stats;
++}
++
++static void fec_update_stat(struct net_device *dev)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	struct net_device_stats *stats = &priv->stats;
++	struct mpc52xx_fec *fec = priv->fec;
++
++	out_be32(&fec->mib_control, FEC_MIB_DISABLE);
++	memset_io(&fec->rmon_t_drop, 0,
++			(u32)&fec->reserved10 - (u32)&fec->rmon_t_drop);
++	out_be32(&fec->mib_control, 0);
++	memset(stats, 0, sizeof *stats);
++	fec_get_stats(dev);
++}
++
++/*
++ * Set or clear the multicast filter for this adaptor.
++ */
++static void fec_set_multicast_list(struct net_device *dev)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	struct mpc52xx_fec *fec = priv->fec;
++	u32 rx_control;
++
++	rx_control = in_be32(&fec->r_cntrl);
++
++	if (dev->flags & IFF_PROMISC) {
++		rx_control |= FEC_RCNTRL_PROM;
++		out_be32(&fec->r_cntrl, rx_control);
++	} else {
++		rx_control &= ~FEC_RCNTRL_PROM;
++		out_be32(&fec->r_cntrl, rx_control);
++
++		if (dev->flags & IFF_ALLMULTI) {
++			out_be32(&fec->gaddr1, 0xffffffff);
++			out_be32(&fec->gaddr2, 0xffffffff);
++		} else {
++			u32 crc;
++			int i;
++			struct dev_mc_list *dmi;
++			u32 gaddr1 = 0x00000000;
++			u32 gaddr2 = 0x00000000;
++
++			dmi = dev->mc_list;
++			for (i=0; i<dev->mc_count; i++) {
++				crc = ether_crc_le(6, dmi->dmi_addr) >> 26;
++				if (crc >= 32)
++					gaddr1 |= 1 << (crc-32);
++				else
++					gaddr2 |= 1 << crc;
++				dmi = dmi->next;
++			}
++			out_be32(&fec->gaddr1, gaddr1);
++			out_be32(&fec->gaddr2, gaddr2);
++		}
++	}
++}
++
++static void __init fec_str2mac(char *str, unsigned char *mac)
++{
++	int i;
++	u64 val64;
++
++	val64 = simple_strtoull(str, NULL, 16);
++
++	for (i = 0; i < 6; i++)
++		mac[5-i] = val64 >> (i*8);
++}
++
++int __init mpc52xx_fec_mac_setup(char *mac_address)
++{
++	fec_str2mac(mac_address, mpc52xx_fec_mac_addr);
++	return 0;
++}
++
++__setup("mpc52xx-mac=", mpc52xx_fec_mac_setup);
++
++static void fec_hw_init(struct net_device *dev)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	struct mpc52xx_fec *fec = priv->fec;
++
++	out_be32(&fec->op_pause, 0x00010020);
++	out_be32(&fec->rfifo_cntrl, 0x0f000000);
++	out_be32(&fec->rfifo_alarm, 0x0000030c);
++	out_be32(&fec->tfifo_cntrl, 0x0f000000);
++	out_be32(&fec->tfifo_alarm, 0x00000100);
++	out_be32(&fec->x_wmrk, 0x3);		/* xmit fifo watermark = 256 */
++	out_be32(&fec->xmit_fsm, 0x03000000);	/* enable crc generation */
++	out_be32(&fec->iaddr1, 0x00000000);	/* No individual filter */
++	out_be32(&fec->iaddr2, 0x00000000);	/* No individual filter */
++
++	fec_restart(dev, 0);	/* always use half duplex mode only */
++	/*
++	 * Read MIB counters in order to reset them,
++	 * then zero all the stats fields in memory
++	 */
++	fec_update_stat(dev);
++}
++
++
++static void fec_reinit(struct net_device *dev)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	struct mpc52xx_fec *fec = priv->fec;
++
++	netif_stop_queue(dev);
++	out_be32(&fec->imask, 0x0);
++
++	/* Disable the rx and tx tasks. */
++	bcom_disable(priv->rx_dmatsk);
++	bcom_disable(priv->tx_dmatsk);
++
++	/* Stop FEC */
++	out_be32(&fec->ecntrl, in_be32(&fec->ecntrl) & ~0x2);
++
++	/* Restart the DMA tasks */
++	bcom_fec_rx_reset(priv->rx_dmatsk);
++	bcom_fec_tx_reset(priv->tx_dmatsk);
++	fec_hw_init(dev);
++
++	if (priv->sequence_done) {		 /* redo the fec_open() */
++		fec_free_rx_buffers(priv->rx_dmatsk);
++		fec_open(dev);
++	}
++	return;
++}
++
++
++/* ======================================================================== */
++/* OF Driver                                                                */
++/* ======================================================================== */
++
++static int __devinit
++mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
++{
++	int rv;
++	struct net_device *ndev;
++	struct fec_priv *priv = NULL;
++	struct resource mem;
++
++	phys_addr_t rx_fifo;
++	phys_addr_t tx_fifo;
++
++	/* Reserve FEC control zone */
++	rv = of_address_to_resource(op->node, 0, &mem);
++	if (rv) {
++		printk(KERN_ERR DRIVER_NAME ": "
++				"Error while parsing device node resource\n" );
++		return rv;
++	}
++	if ((mem.end - mem.start + 1) != sizeof(struct mpc52xx_fec)) {
++		printk(KERN_ERR DRIVER_NAME 
++			" - invalid resource size (%lx != %x), check mpc52xx_devices.c\n",
++			(unsigned long)(mem.end - mem.start + 1), sizeof(struct mpc52xx_fec));
++		return -EINVAL;
++	}
++
++	if (!request_mem_region(mem.start, sizeof(struct mpc52xx_fec),
++	                        DRIVER_NAME))
++		return -EBUSY;
++
++	/* Get the ether ndev & it's private zone */
++	ndev = alloc_etherdev(sizeof(struct fec_priv));
++	if (!ndev) {
++		rv = -ENOMEM;
++		goto probe_error;
++	}
++	
++	priv = (struct fec_priv *)ndev->priv;
++	
++	/* Init ether ndev with what we have */
++	ndev->open		= fec_open;
++	ndev->stop		= fec_close;
++	ndev->hard_start_xmit	= fec_hard_start_xmit;
++	ndev->do_ioctl		= fec_ioctl;
++	ndev->get_stats		= fec_get_stats;
++	ndev->set_mac_address	= fec_set_mac_address;
++	ndev->set_multicast_list = fec_set_multicast_list;
++	ndev->tx_timeout	= fec_tx_timeout;
++	ndev->watchdog_timeo	= FEC_WATCHDOG_TIMEOUT;
++	ndev->flags &= ~IFF_RUNNING;
++	ndev->base_addr		= mem.start;
++
++	priv->t_irq = priv->r_irq = ndev->irq = NO_IRQ; /* IRQ are free for now */
++	
++	spin_lock_init(&priv->lock);
++
++	/* ioremap the zones */
++	priv->fec = (struct mpc52xx_fec *)
++		ioremap(mem.start, sizeof(struct mpc52xx_fec));
++	
++	if (!priv->fec) {
++		rv = -ENOMEM;
++		goto probe_error;
++	}
++
++	/* Bestcomm init */
++	rx_fifo = ndev->base_addr + offsetof(struct mpc52xx_fec, rfifo_data);
++	tx_fifo = ndev->base_addr + offsetof(struct mpc52xx_fec, tfifo_data);
++
++	priv->rx_dmatsk = bcom_fec_rx_init(FEC_RX_NUM_BD, rx_fifo, FEC_RX_BUFFER_SIZE);
++	priv->tx_dmatsk = bcom_fec_tx_init(FEC_TX_NUM_BD, tx_fifo);
++
++	if (!priv->rx_dmatsk || !priv->tx_dmatsk) {
++		printk(KERN_ERR DRIVER_NAME ": "
++				"Can not init SDMA tasks\n" );
++		rv = -ENOMEM;
++		goto probe_error;
++	}
++
++	/* Get the IRQ we need one by one */
++		/* Control */
++	ndev->irq = irq_of_parse_and_map(op->node, 0);
++	if (request_irq(ndev->irq, &fec_interrupt, SA_INTERRUPT,
++	                DRIVER_NAME "_ctrl", ndev)) {
++		printk(KERN_ERR DRIVER_NAME ": ctrl interrupt request failed\n");
++		rv = -EBUSY;
++		ndev->irq = NO_IRQ;	/* Don't try to free it */
++		goto probe_error;
++	}
++
++		/* RX */
++	priv->r_irq = bcom_get_task_irq(priv->rx_dmatsk);
++	if (request_irq(priv->r_irq, &fec_rx_interrupt, SA_INTERRUPT,
++	                DRIVER_NAME "_rx", ndev)) {
++		printk(KERN_ERR DRIVER_NAME ": rx interrupt request failed\n");
++		rv = -EBUSY;
++		priv->r_irq = NO_IRQ;	/* Don't try to free it */
++		goto probe_error;
++	}
++
++		/* TX */
++	priv->t_irq = bcom_get_task_irq(priv->tx_dmatsk);
++	if (request_irq(priv->t_irq, &fec_tx_interrupt, SA_INTERRUPT,
++	                DRIVER_NAME "_tx", ndev)) {
++		printk(KERN_ERR DRIVER_NAME ": tx interrupt request failed\n");
++		rv = -EBUSY;
++		priv->t_irq = NO_IRQ;	/* Don't try to free it */
++		goto probe_error;
++	}
++
++	/* MAC address init */
++	if (memcmp(mpc52xx_fec_mac_addr, null_mac, 6) != 0)
++		memcpy(ndev->dev_addr, mpc52xx_fec_mac_addr, 6);
++	else
++		fec_get_paddr(ndev, ndev->dev_addr);
++
++	/* Phy speed */
++	priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1;
++
++	/* Hardware init */
++	fec_hw_init(ndev);
++
++	/* Register the new network device */
++	rv = register_netdev(ndev);
++	if(rv < 0)
++		goto probe_error;
++
++	/* MII init : After register ???? */
++	fec_mii_init(ndev);
++	
++	/* We're done ! */
++	dev_set_drvdata(&op->dev, ndev);
++
++	return 0;
++
++
++	/* Error handling - free everything that might be allocated */
++probe_error:
++
++	if (ndev) {
++		if (priv->rx_dmatsk)	bcom_fec_rx_release(priv->rx_dmatsk);
++		if (priv->tx_dmatsk)	bcom_fec_tx_release(priv->tx_dmatsk);
++
++		if (ndev->irq	!= NO_IRQ)	free_irq(ndev->irq, ndev);
++		if (priv->r_irq != NO_IRQ)	free_irq(priv->r_irq, ndev);
++		if (priv->t_irq != NO_IRQ)	free_irq(priv->t_irq, ndev);
++
++		if (priv->fec)		iounmap(priv->fec);
++
++		free_netdev(ndev);
++	}
++
++	release_mem_region(mem.start, sizeof(struct mpc52xx_fec));
++
++	return rv;
++}
++
++static int
++mpc52xx_fec_remove(struct of_device *op)
++{
++	struct net_device *ndev;
++	struct fec_priv *priv;
++	
++	ndev = (struct net_device *) dev_get_drvdata(&op->dev);
++	if (!ndev)
++		return 0;
++	priv = (struct fec_priv *) ndev->priv;
++
++	unregister_netdev(ndev);
++	
++	free_irq(ndev->irq, ndev);	/* FIXME : unmap irq ??? */
++	free_irq(priv->r_irq, ndev);
++	free_irq(priv->t_irq, ndev);
++
++	/* FIXME release dma tasks ??? */
++
++	iounmap(priv->fec);
++	
++	release_mem_region(ndev->base_addr, sizeof(struct mpc52xx_fec));
++
++	free_netdev(ndev);
++	
++	dev_set_drvdata(&op->dev, NULL);
++	return 0;
++}
++
++static struct of_device_id mpc52xx_fec_match[] = {
++	{
++		.type		= "network",
++		.compatible	= "mpc5200-fec",
++	},
++	{ }
++};
++
++MODULE_DEVICE_TABLE(of, mpc52xx_fec_match);
++
++static struct of_platform_driver mpc52xx_fec_driver = {
++	.owner		= THIS_MODULE,
++	.name		= DRIVER_NAME,
++	.match_table	= mpc52xx_fec_match,
++	.probe		= mpc52xx_fec_probe,
++	.remove		= mpc52xx_fec_remove,
++#ifdef CONFIG_PM
++/*	.suspend	= mpc52xx_fec_of_suspend,	TODO */
++/*	.resume		= mpc52xx_fec_of_resume,	TODO */
++#endif
++	.driver		= {
++		.name		= DRIVER_NAME,
++	},
++};
++
++
++/* ======================================================================== */
++/* Module                                                                   */
++/* ======================================================================== */
++
++static int __init
++mpc52xx_fec_init(void)
++{
++	return of_register_platform_driver(&mpc52xx_fec_driver);
++}
++
++static void __exit
++mpc52xx_fec_exit(void)
++{
++	of_unregister_platform_driver(&mpc52xx_fec_driver);
++}
++
++
++module_init(mpc52xx_fec_init);
++module_exit(mpc52xx_fec_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Dale Farnsworth");
++MODULE_DESCRIPTION("Ethernet driver for the Freescale MPC52xx FEC");
++
+diff --git a/drivers/net/fec_mpc52xx/fec.h b/drivers/net/fec_mpc52xx/fec.h
+new file mode 100644
+index 0000000..ef80b0b
+--- /dev/null
++++ b/drivers/net/fec_mpc52xx/fec.h
+@@ -0,0 +1,306 @@
++/*
++ * drivers/net/fec_mpc52xx/fec.h
++ *
++ * Driver for the MPC5200 Fast Ethernet Controller
++ *
++ * Author: Dale Farnsworth <dfarnsworth at mvista.com>
++ *
++ * 2003-2004 (c) MontaVista, Software, Inc.  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 __DRIVERS_NET_MPC52XX_FEC_H__
++#define __DRIVERS_NET_MPC52XX_FEC_H__
++
++/* Tunable constant */
++/* FEC_RX_BUFFER_SIZE includes 4 bytes for CRC32 */
++#define FEC_RX_BUFFER_SIZE	1522	/* max receive packet size */
++#define FEC_RX_NUM_BD		64
++#define FEC_TX_NUM_BD		64
++
++#define FEC_RESET_DELAY		50 	/* uS */
++
++#define FEC_WATCHDOG_TIMEOUT	((400*HZ)/1000)
++
++struct fec_priv {
++	int full_duplex;
++	int tx_full;
++	int r_irq;
++	int t_irq;
++	u32 last_transmit_time;
++	struct mpc52xx_fec *fec;
++	struct bcom_task *rx_dmatsk;
++	struct bcom_task *tx_dmatsk;
++	spinlock_t lock;
++	unsigned long open_time;
++	struct net_device_stats stats;
++#ifdef CONFIG_USE_MDIO
++	uint phy_id;
++	uint phy_id_done;
++	uint phy_status;
++	uint phy_speed;
++	phy_info_t *phy;
++	struct tasklet_struct phy_task;
++	uint sequence_done;
++	uint phy_addr;
++	struct timer_list phy_timer_list;
++	u16 old_status;
++#endif	/* CONFIG_USE_MDIO */
++};
++
++
++/* ======================================================================== */
++/* Hardware register sets & bits                                            */
++/* ======================================================================== */
++
++struct mpc52xx_fec {
++	u32 fec_id;			/* FEC + 0x000 */
++	u32 ievent;			/* FEC + 0x004 */
++	u32 imask;			/* FEC + 0x008 */
++
++	u32 reserved0[1];		/* FEC + 0x00C */
++	u32 r_des_active;		/* FEC + 0x010 */
++	u32 x_des_active;		/* FEC + 0x014 */
++	u32 r_des_active_cl;		/* FEC + 0x018 */
++	u32 x_des_active_cl;		/* FEC + 0x01C */
++	u32 ivent_set;			/* FEC + 0x020 */
++	u32 ecntrl;			/* FEC + 0x024 */
++
++	u32 reserved1[6];		/* FEC + 0x028-03C */
++	u32 mii_data;			/* FEC + 0x040 */
++	u32 mii_speed;			/* FEC + 0x044 */
++	u32 mii_status;			/* FEC + 0x048 */
++
++	u32 reserved2[5];		/* FEC + 0x04C-05C */
++	u32 mib_data;			/* FEC + 0x060 */
++	u32 mib_control;		/* FEC + 0x064 */
++
++	u32 reserved3[6];		/* FEC + 0x068-7C */
++	u32 r_activate;			/* FEC + 0x080 */
++	u32 r_cntrl;			/* FEC + 0x084 */
++	u32 r_hash;			/* FEC + 0x088 */
++	u32 r_data;			/* FEC + 0x08C */
++	u32 ar_done;			/* FEC + 0x090 */
++	u32 r_test;			/* FEC + 0x094 */
++	u32 r_mib;			/* FEC + 0x098 */
++	u32 r_da_low;			/* FEC + 0x09C */
++	u32 r_da_high;			/* FEC + 0x0A0 */
++
++	u32 reserved4[7];		/* FEC + 0x0A4-0BC */
++	u32 x_activate;			/* FEC + 0x0C0 */
++	u32 x_cntrl;			/* FEC + 0x0C4 */
++	u32 backoff;			/* FEC + 0x0C8 */
++	u32 x_data;			/* FEC + 0x0CC */
++	u32 x_status;			/* FEC + 0x0D0 */
++	u32 x_mib;			/* FEC + 0x0D4 */
++	u32 x_test;			/* FEC + 0x0D8 */
++	u32 fdxfc_da1;			/* FEC + 0x0DC */
++	u32 fdxfc_da2;			/* FEC + 0x0E0 */
++	u32 paddr1;			/* FEC + 0x0E4 */
++	u32 paddr2;			/* FEC + 0x0E8 */
++	u32 op_pause;			/* FEC + 0x0EC */
++
++	u32 reserved5[4];		/* FEC + 0x0F0-0FC */
++	u32 instr_reg;			/* FEC + 0x100 */
++	u32 context_reg;		/* FEC + 0x104 */
++	u32 test_cntrl;			/* FEC + 0x108 */
++	u32 acc_reg;			/* FEC + 0x10C */
++	u32 ones;			/* FEC + 0x110 */
++	u32 zeros;			/* FEC + 0x114 */
++	u32 iaddr1;			/* FEC + 0x118 */
++	u32 iaddr2;			/* FEC + 0x11C */
++	u32 gaddr1;			/* FEC + 0x120 */
++	u32 gaddr2;			/* FEC + 0x124 */
++	u32 random;			/* FEC + 0x128 */
++	u32 rand1;			/* FEC + 0x12C */
++	u32 tmp;			/* FEC + 0x130 */
++
++	u32 reserved6[3];		/* FEC + 0x134-13C */
++	u32 fifo_id;			/* FEC + 0x140 */
++	u32 x_wmrk;			/* FEC + 0x144 */
++	u32 fcntrl;			/* FEC + 0x148 */
++	u32 r_bound;			/* FEC + 0x14C */
++	u32 r_fstart;			/* FEC + 0x150 */
++	u32 r_count;			/* FEC + 0x154 */
++	u32 r_lag;			/* FEC + 0x158 */
++	u32 r_read;			/* FEC + 0x15C */
++	u32 r_write;			/* FEC + 0x160 */
++	u32 x_count;			/* FEC + 0x164 */
++	u32 x_lag;			/* FEC + 0x168 */
++	u32 x_retry;			/* FEC + 0x16C */
++	u32 x_write;			/* FEC + 0x170 */
++	u32 x_read;			/* FEC + 0x174 */
++
++	u32 reserved7[2];		/* FEC + 0x178-17C */
++	u32 fm_cntrl;			/* FEC + 0x180 */
++	u32 rfifo_data;			/* FEC + 0x184 */
++	u32 rfifo_status;		/* FEC + 0x188 */
++	u32 rfifo_cntrl;		/* FEC + 0x18C */
++	u32 rfifo_lrf_ptr;		/* FEC + 0x190 */
++	u32 rfifo_lwf_ptr;		/* FEC + 0x194 */
++	u32 rfifo_alarm;		/* FEC + 0x198 */
++	u32 rfifo_rdptr;		/* FEC + 0x19C */
++	u32 rfifo_wrptr;		/* FEC + 0x1A0 */
++	u32 tfifo_data;			/* FEC + 0x1A4 */
++	u32 tfifo_status;		/* FEC + 0x1A8 */
++	u32 tfifo_cntrl;		/* FEC + 0x1AC */
++	u32 tfifo_lrf_ptr;		/* FEC + 0x1B0 */
++	u32 tfifo_lwf_ptr;		/* FEC + 0x1B4 */
++	u32 tfifo_alarm;		/* FEC + 0x1B8 */
++	u32 tfifo_rdptr;		/* FEC + 0x1BC */
++	u32 tfifo_wrptr;		/* FEC + 0x1C0 */
++
++	u32 reset_cntrl;		/* FEC + 0x1C4 */
++	u32 xmit_fsm;			/* FEC + 0x1C8 */
++
++	u32 reserved8[3];		/* FEC + 0x1CC-1D4 */
++	u32 rdes_data0;			/* FEC + 0x1D8 */
++	u32 rdes_data1;			/* FEC + 0x1DC */
++	u32 r_length;			/* FEC + 0x1E0 */
++	u32 x_length;			/* FEC + 0x1E4 */
++	u32 x_addr;			/* FEC + 0x1E8 */
++	u32 cdes_data;			/* FEC + 0x1EC */
++	u32 status;			/* FEC + 0x1F0 */
++	u32 dma_control;		/* FEC + 0x1F4 */
++	u32 des_cmnd;			/* FEC + 0x1F8 */
++	u32 data;			/* FEC + 0x1FC */
++
++	u32 rmon_t_drop;		/* FEC + 0x200 */
++	u32 rmon_t_packets;		/* FEC + 0x204 */
++	u32 rmon_t_bc_pkt;		/* FEC + 0x208 */
++	u32 rmon_t_mc_pkt;		/* FEC + 0x20C */
++	u32 rmon_t_crc_align;		/* FEC + 0x210 */
++	u32 rmon_t_undersize;		/* FEC + 0x214 */
++	u32 rmon_t_oversize;		/* FEC + 0x218 */
++	u32 rmon_t_frag;		/* FEC + 0x21C */
++	u32 rmon_t_jab;			/* FEC + 0x220 */
++	u32 rmon_t_col;			/* FEC + 0x224 */
++	u32 rmon_t_p64;			/* FEC + 0x228 */
++	u32 rmon_t_p65to127;		/* FEC + 0x22C */
++	u32 rmon_t_p128to255;		/* FEC + 0x230 */
++	u32 rmon_t_p256to511;		/* FEC + 0x234 */
++	u32 rmon_t_p512to1023;		/* FEC + 0x238 */
++	u32 rmon_t_p1024to2047;		/* FEC + 0x23C */
++	u32 rmon_t_p_gte2048;		/* FEC + 0x240 */
++	u32 rmon_t_octets;		/* FEC + 0x244 */
++	u32 ieee_t_drop;		/* FEC + 0x248 */
++	u32 ieee_t_frame_ok;		/* FEC + 0x24C */
++	u32 ieee_t_1col;		/* FEC + 0x250 */
++	u32 ieee_t_mcol;		/* FEC + 0x254 */
++	u32 ieee_t_def;			/* FEC + 0x258 */
++	u32 ieee_t_lcol;		/* FEC + 0x25C */
++	u32 ieee_t_excol;		/* FEC + 0x260 */
++	u32 ieee_t_macerr;		/* FEC + 0x264 */
++	u32 ieee_t_cserr;		/* FEC + 0x268 */
++	u32 ieee_t_sqe;			/* FEC + 0x26C */
++	u32 t_fdxfc;			/* FEC + 0x270 */
++	u32 ieee_t_octets_ok;		/* FEC + 0x274 */
++
++	u32 reserved9[2];		/* FEC + 0x278-27C */
++	u32 rmon_r_drop;		/* FEC + 0x280 */
++	u32 rmon_r_packets;		/* FEC + 0x284 */
++	u32 rmon_r_bc_pkt;		/* FEC + 0x288 */
++	u32 rmon_r_mc_pkt;		/* FEC + 0x28C */
++	u32 rmon_r_crc_align;		/* FEC + 0x290 */
++	u32 rmon_r_undersize;		/* FEC + 0x294 */
++	u32 rmon_r_oversize;		/* FEC + 0x298 */
++	u32 rmon_r_frag;		/* FEC + 0x29C */
++	u32 rmon_r_jab;			/* FEC + 0x2A0 */
++
++	u32 rmon_r_resvd_0;		/* FEC + 0x2A4 */
++
++	u32 rmon_r_p64;			/* FEC + 0x2A8 */
++	u32 rmon_r_p65to127;		/* FEC + 0x2AC */
++	u32 rmon_r_p128to255;		/* FEC + 0x2B0 */
++	u32 rmon_r_p256to511;		/* FEC + 0x2B4 */
++	u32 rmon_r_p512to1023;		/* FEC + 0x2B8 */
++	u32 rmon_r_p1024to2047;		/* FEC + 0x2BC */
++	u32 rmon_r_p_gte2048;		/* FEC + 0x2C0 */
++	u32 rmon_r_octets;		/* FEC + 0x2C4 */
++	u32 ieee_r_drop;		/* FEC + 0x2C8 */
++	u32 ieee_r_frame_ok;		/* FEC + 0x2CC */
++	u32 ieee_r_crc;			/* FEC + 0x2D0 */
++	u32 ieee_r_align;		/* FEC + 0x2D4 */
++	u32 r_macerr;			/* FEC + 0x2D8 */
++	u32 r_fdxfc;			/* FEC + 0x2DC */
++	u32 ieee_r_octets_ok;		/* FEC + 0x2E0 */
++
++	u32 reserved10[7];		/* FEC + 0x2E4-2FC */
++
++	u32 reserved11[64];		/* FEC + 0x300-3FF */
++};
++
++#define	FEC_MIB_DISABLE			0x80000000
++
++#define	FEC_IEVENT_HBERR		0x80000000
++#define	FEC_IEVENT_BABR			0x40000000
++#define	FEC_IEVENT_BABT			0x20000000
++#define	FEC_IEVENT_GRA			0x10000000
++#define	FEC_IEVENT_TFINT		0x08000000
++#define	FEC_IEVENT_MII			0x00800000
++#define	FEC_IEVENT_LATE_COL		0x00200000
++#define	FEC_IEVENT_COL_RETRY_LIM	0x00100000
++#define	FEC_IEVENT_XFIFO_UN		0x00080000
++#define	FEC_IEVENT_XFIFO_ERROR		0x00040000
++#define	FEC_IEVENT_RFIFO_ERROR		0x00020000
++
++#define	FEC_IMASK_HBERR			0x80000000
++#define	FEC_IMASK_BABR			0x40000000
++#define	FEC_IMASK_BABT			0x20000000
++#define	FEC_IMASK_GRA			0x10000000
++#define	FEC_IMASK_MII			0x00800000
++#define	FEC_IMASK_LATE_COL		0x00200000
++#define	FEC_IMASK_COL_RETRY_LIM		0x00100000
++#define	FEC_IMASK_XFIFO_UN		0x00080000
++#define	FEC_IMASK_XFIFO_ERROR		0x00040000
++#define	FEC_IMASK_RFIFO_ERROR		0x00020000
++
++#define	FEC_RCNTRL_MAX_FL_SHIFT		16
++#define	FEC_RCNTRL_LOOP			0x01
++#define	FEC_RCNTRL_DRT			0x02
++#define	FEC_RCNTRL_MII_MODE		0x04
++#define	FEC_RCNTRL_PROM			0x08
++#define	FEC_RCNTRL_BC_REJ		0x10
++#define	FEC_RCNTRL_FCE			0x20
++
++#define	FEC_TCNTRL_GTS			0x00000001
++#define	FEC_TCNTRL_HBC			0x00000002
++#define	FEC_TCNTRL_FDEN			0x00000004
++#define	FEC_TCNTRL_TFC_PAUSE		0x00000008
++#define	FEC_TCNTRL_RFC_PAUSE		0x00000010
++
++#define	FEC_ECNTRL_RESET		0x00000001
++#define	FEC_ECNTRL_ETHER_EN		0x00000002
++
++struct mibCounters {
++	unsigned int byteReceived;
++	unsigned int byteSent;
++	unsigned int framesReceived;
++	unsigned int framesSent;
++	unsigned int totalByteReceived;
++	unsigned int totalFramesReceived;
++	unsigned int broadcastFramesReceived;
++	unsigned int multicastFramesReceived;
++	unsigned int cRCError;
++	unsigned int oversizeFrames;
++	unsigned int fragments;
++	unsigned int jabber;
++	unsigned int collision;
++	unsigned int lateCollision;
++	unsigned int frames64;
++	unsigned int frames65_127;
++	unsigned int frames128_255;
++	unsigned int frames256_511;
++	unsigned int frames512_1023;
++	unsigned int frames1024_MaxSize;
++	unsigned int macRxError;
++	unsigned int droppedFrames;
++	unsigned int outMulticastFrames;
++	unsigned int outBroadcastFrames;
++	unsigned int undersizeFrames;
++};
++
++
++#endif	/* __DRIVERS_NET_MPC52XX_FEC_H__ */
+diff --git a/drivers/net/fec_mpc52xx/fec_phy.c b/drivers/net/fec_mpc52xx/fec_phy.c
+new file mode 100644
+index 0000000..a032a81
+--- /dev/null
++++ b/drivers/net/fec_mpc52xx/fec_phy.c
+@@ -0,0 +1,526 @@
++/*
++ * arch/ppc/52xx_io/fec_phy.c
++ *
++ * Driver for the MPC5200 Fast Ethernet Controller
++ * Based heavily on the MII support for the MPC8xx by Dan Malek
++ *
++ * Author: Dale Farnsworth <dfarnsworth at mvista.com>
++ *
++ * 2003-2004 (c) MontaVista, Software, Inc.  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/types.h>
++#include <linux/netdevice.h>
++#include <linux/mii.h>
++#include <linux/ethtool.h>
++#include <linux/mii.h>
++#include <asm/io.h>
++#include <asm/mpc52xx.h>
++#include <sysdev/bestcomm/bestcomm.h>
++#include <sysdev/bestcomm/fec.h>
++#include "fec_phy.h"
++#include "fec.h"
++
++static int mpc52xx_netdev_ethtool_ioctl(struct net_device *dev, void *useraddr);
++
++/* MII processing.  We keep this as simple as possible.  Requests are
++ * placed on the list (if there is room).  When the request is finished
++ * by the MII, an optional function may be called.
++ */
++typedef struct mii_list {
++	uint	mii_regval;
++	void	(*mii_func)(uint val, struct net_device *dev, uint data);
++	struct	mii_list *mii_next;
++	uint	mii_data;
++} mii_list_t;
++
++#define		NMII	20
++mii_list_t	mii_cmds[NMII];
++mii_list_t	*mii_free;
++mii_list_t	*mii_head;
++mii_list_t	*mii_tail;
++
++typedef struct mdio_read_data {
++	__u16 regval;
++	struct task_struct *sleeping_task;
++} mdio_read_data_t;
++
++static int mii_queue(struct net_device *dev, int request,
++		void (*func)(uint, struct net_device *, uint), uint data);
++
++/* Make MII read/write commands for the FEC.
++ * */
++#define mk_mii_read(REG)	(0x60020000 | ((REG & 0x1f) << 18))
++#define mk_mii_write(REG, VAL)	(0x50020000 | ((REG & 0x1f) << 18) | \
++							(VAL & 0xffff))
++#define mk_mii_end	0
++
++/* Register definitions for the PHY.
++*/
++
++#define MII_REG_CR	 0	/* Control Register */
++#define MII_REG_SR	 1	/* Status Register */
++#define MII_REG_PHYIR1	 2	/* PHY Identification Register 1 */
++#define MII_REG_PHYIR2	 3	/* PHY Identification Register 2 */
++#define MII_REG_ANAR	 4	/* A-N Advertisement Register */
++#define MII_REG_ANLPAR	 5	/* A-N Link Partner Ability Register */
++#define MII_REG_ANER	 6	/* A-N Expansion Register */
++#define MII_REG_ANNPTR	 7	/* A-N Next Page Transmit Register */
++#define MII_REG_ANLPRNPR 8	/* A-N Link Partner Received Next Page Reg. */
++
++/* values for phy_status */
++
++#define PHY_CONF_ANE	0x0001	/* 1 auto-negotiation enabled */
++#define PHY_CONF_LOOP	0x0002	/* 1 loopback mode enabled */
++#define PHY_CONF_SPMASK	0x00f0	/* mask for speed */
++#define PHY_CONF_10HDX	0x0010	/* 10 Mbit half duplex supported */
++#define PHY_CONF_10FDX	0x0020	/* 10 Mbit full duplex supported */
++#define PHY_CONF_100HDX	0x0040	/* 100 Mbit half duplex supported */
++#define PHY_CONF_100FDX	0x0080	/* 100 Mbit full duplex supported */
++
++#define PHY_STAT_LINK	0x0100	/* 1 up - 0 down */
++#define PHY_STAT_FAULT	0x0200	/* 1 remote fault */
++#define PHY_STAT_ANC	0x0400	/* 1 auto-negotiation complete	*/
++#define PHY_STAT_SPMASK	0xf000	/* mask for speed */
++#define PHY_STAT_10HDX	0x1000	/* 10 Mbit half duplex selected	*/
++#define PHY_STAT_10FDX	0x2000	/* 10 Mbit full duplex selected	*/
++#define PHY_STAT_100HDX	0x4000	/* 100 Mbit half duplex selected */
++#define PHY_STAT_100FDX	0x8000	/* 100 Mbit full duplex selected */
++
++void fec_mii(struct net_device *dev)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	struct mpc52xx_fec *fec = priv->fec;
++	mii_list_t	*mip;
++	uint		mii_reg;
++
++	mii_reg = in_be32(&fec->mii_data);
++
++	if ((mip = mii_head) == NULL) {
++		printk(KERN_ERR "MII and no head!\n");
++		return;
++	}
++
++	if (mip->mii_func != NULL)
++		(*(mip->mii_func))(mii_reg, dev, mip->mii_data);
++
++	mii_head = mip->mii_next;
++	mip->mii_next = mii_free;
++	mii_free = mip;
++
++	if ((mip = mii_head) != NULL)
++		out_be32(&fec->mii_data, mip->mii_regval);
++}
++
++static int mii_queue(struct net_device *dev, int regval,
++				void (*func)(uint, struct net_device *, uint),
++				uint data)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	struct mpc52xx_fec *fec = priv->fec;
++	mii_list_t	*mip;
++	int		retval;
++
++	/* Add PHY address to register command.
++	*/
++	regval |= priv->phy_addr << 23;
++
++	retval = 0;
++
++	if ((mip = mii_free) != NULL) {
++		mii_free = mip->mii_next;
++		mip->mii_regval = regval;
++		mip->mii_func = func;
++		mip->mii_next = NULL;
++		mip->mii_data = data;
++		if (mii_head) {
++			mii_tail->mii_next = mip;
++			mii_tail = mip;
++		} else {
++			mii_head = mii_tail = mip;
++			out_be32(&fec->mii_data, regval);
++		}
++	} else
++		retval = 1;
++
++	return retval;
++}
++
++static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c)
++{
++	int k;
++
++	if (!c)
++		return;
++
++	for (k = 0; (c+k)->mii_data != mk_mii_end; k++)
++		mii_queue(dev, (c+k)->mii_data, (c+k)->funct, 0);
++}
++
++static void mii_parse_sr(uint mii_reg, struct net_device *dev, uint data)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	uint s = priv->phy_status;
++
++	s &= ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC);
++
++	if (mii_reg & 0x0004)
++		s |= PHY_STAT_LINK;
++	if (mii_reg & 0x0010)
++		s |= PHY_STAT_FAULT;
++	if (mii_reg & 0x0020)
++		s |= PHY_STAT_ANC;
++
++	priv->phy_status = s;
++}
++
++static void mii_parse_cr(uint mii_reg, struct net_device *dev, uint data)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	uint s = priv->phy_status;
++
++	s &= ~(PHY_CONF_ANE | PHY_CONF_LOOP);
++
++	if (mii_reg & 0x1000)
++		s |= PHY_CONF_ANE;
++	if (mii_reg & 0x4000)
++		s |= PHY_CONF_LOOP;
++
++	priv->phy_status = s;
++}
++
++static void mii_parse_anar(uint mii_reg, struct net_device *dev, uint data)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	uint s = priv->phy_status;
++
++	s &= ~(PHY_CONF_SPMASK);
++
++	if (mii_reg & 0x0020)
++		s |= PHY_CONF_10HDX;
++	if (mii_reg & 0x0040)
++		s |= PHY_CONF_10FDX;
++	if (mii_reg & 0x0080)
++		s |= PHY_CONF_100HDX;
++	if (mii_reg & 0x0100)
++		s |= PHY_CONF_100FDX;
++
++	priv->phy_status = s;
++}
++
++/* ------------------------------------------------------------------------- */
++/* Generic PHY support.  Should work for all PHYs, but does not support link
++ * change interrupts.
++ */
++static phy_info_t phy_info_generic = {
++	0x00000000, /* 0-->match any PHY */
++	"GENERIC",
++
++	(const phy_cmd_t []) {	/* config */
++		/* advertise only half-duplex capabilities */
++		{ mk_mii_write(MII_ADVERTISE, MII_ADVERTISE_HALF),
++			mii_parse_anar },
++
++		/* enable auto-negotiation */
++		{ mk_mii_write(MII_BMCR, BMCR_ANENABLE), mii_parse_cr },
++		{ mk_mii_end, }
++	},
++	(const phy_cmd_t []) {	/* startup */
++		/* restart auto-negotiation */
++		{ mk_mii_write(MII_BMCR, (BMCR_ANENABLE | BMCR_ANRESTART)),
++			NULL },
++		{ mk_mii_end, }
++	},
++	(const phy_cmd_t []) { /* ack_int */
++		/* We don't actually use the ack_int table with a generic
++		 * PHY, but putting a reference to mii_parse_sr here keeps
++		 * us from getting a compiler warning about unused static
++		 * functions in the case where we only compile in generic
++		 * PHY support.
++		 */
++		{ mk_mii_read(MII_BMSR), mii_parse_sr },
++		{ mk_mii_end, }
++	},
++	(const phy_cmd_t []) {	/* shutdown */
++		{ mk_mii_end, }
++	},
++};
++/* -------------------------------------------------------------------- */
++
++/* register definitions for the 971 */
++
++#define MII_LXT971_PCR	16	/* Port Control Register	*/
++#define MII_LXT971_SR2	17	/* Status Register 2		*/
++#define MII_LXT971_IER	18	/* Interrupt Enable Register	*/
++#define MII_LXT971_ISR	19	/* Interrupt Status Register	*/
++#define MII_LXT971_LCR	20	/* LED Control Register		*/
++#define MII_LXT971_TCR	30	/* Transmit Control Register	*/
++
++static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev, uint data)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	uint s = priv->phy_status;
++
++	s &= ~(PHY_STAT_SPMASK);
++
++	if (mii_reg & 0x4000) {
++		if (mii_reg & 0x0200)
++			s |= PHY_STAT_100FDX;
++		else
++			s |= PHY_STAT_100HDX;
++	} else {
++		if (mii_reg & 0x0200)
++			s |= PHY_STAT_10FDX;
++		else
++			s |= PHY_STAT_10HDX;
++	}
++	if (mii_reg & 0x0008)
++		s |= PHY_STAT_FAULT;
++
++	priv->phy_status = s;
++}
++
++static phy_info_t phy_info_lxt971 = {
++	0x0001378e,
++	"LXT971",
++
++	(const phy_cmd_t []) {	/* config */
++		{ mk_mii_write(MII_REG_ANAR, 0x0A1), NULL }, /* 10/100, HD */
++		{ mk_mii_read(MII_REG_CR), mii_parse_cr },
++		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
++		{ mk_mii_end, }
++	},
++	(const phy_cmd_t []) {	/* startup - enable interrupts */
++		{ mk_mii_write(MII_LXT971_IER, 0x00f2), NULL },
++		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
++
++		/* Somehow does the 971 tell me that the link is down
++		 * the first read after power-up.
++		 * read here to get a valid value in ack_int */
++
++		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
++		{ mk_mii_end, }
++	},
++	(const phy_cmd_t []) { /* ack_int */
++		/* find out the current status */
++
++		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
++		{ mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 },
++
++		/* we only need to read ISR to acknowledge */
++
++		{ mk_mii_read(MII_LXT971_ISR), NULL },
++		{ mk_mii_end, }
++	},
++	(const phy_cmd_t []) {	/* shutdown - disable interrupts */
++		{ mk_mii_write(MII_LXT971_IER, 0x0000), NULL },
++		{ mk_mii_end, }
++	},
++};
++
++static phy_info_t *phy_info[] = {
++	&phy_info_lxt971,
++	/* Generic PHY support.  This must be the last PHY in the table.
++	 * It will be used to support any PHY that doesn't match a previous
++	 * entry in the table.
++	 */
++	&phy_info_generic,
++	NULL
++};
++
++static void mii_display_config(struct net_device *dev)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	uint s = priv->phy_status;
++
++	printk(KERN_INFO "%s: config: auto-negotiation ", dev->name);
++
++	if (s & PHY_CONF_ANE)
++		printk("on");
++	else
++		printk("off");
++
++	if (s & PHY_CONF_100FDX)
++		printk(", 100FDX");
++	if (s & PHY_CONF_100HDX)
++		printk(", 100HDX");
++	if (s & PHY_CONF_10FDX)
++		printk(", 10FDX");
++	if (s & PHY_CONF_10HDX)
++		printk(", 10HDX");
++	if (!(s & PHY_CONF_SPMASK))
++		printk(", No speed/duplex selected?");
++
++	if (s & PHY_CONF_LOOP)
++		printk(", loopback enabled");
++
++	printk(".\n");
++
++	priv->sequence_done = 1;
++}
++
++static void mii_queue_config(uint mii_reg, struct net_device *dev, uint data)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++
++	priv->phy_task.func = (void *)mii_display_config;
++	priv->phy_task.data = (unsigned long)dev;
++	tasklet_schedule(&priv->phy_task);
++}
++
++
++phy_cmd_t phy_cmd_config[] =  { { mk_mii_read(MII_REG_CR), mii_queue_config },
++				{ mk_mii_end, } };
++
++
++/* Read remainder of PHY ID.
++*/
++static void mii_discover_phy3(uint mii_reg, struct net_device *dev, uint data)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	int	i;
++
++	priv->phy_id |= (mii_reg & 0xffff);
++
++	for (i = 0; phy_info[i]; i++) {
++		if (phy_info[i]->id == (priv->phy_id >> 4) || !phy_info[i]->id)
++			break;
++		if (phy_info[i]->id == 0)	/* check generic entry */
++			break;
++	}
++
++	if (!phy_info[i])
++		panic("%s: PHY id 0x%08x is not supported!\n",
++			dev->name, priv->phy_id);
++
++	priv->phy = phy_info[i];
++	priv->phy_id_done = 1;
++
++	printk(KERN_INFO "%s: Phy @ 0x%x, type %s (0x%08x)\n",
++		dev->name, priv->phy_addr, priv->phy->name, priv->phy_id);
++}
++
++/* Scan all of the MII PHY addresses looking for someone to respond
++ * with a valid ID.  This usually happens quickly.
++ */
++static void mii_discover_phy(uint mii_reg, struct net_device *dev, uint data)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	uint	phytype;
++
++	if ((phytype = (mii_reg & 0xffff)) != 0xffff) {
++		/* Got first part of ID, now get remainder.
++		*/
++		priv->phy_id = phytype << 16;
++		mii_queue(dev, mk_mii_read(MII_REG_PHYIR2), mii_discover_phy3,
++									0);
++	} else {
++		priv->phy_addr++;
++		if (priv->phy_addr < 32)
++			mii_queue(dev, mk_mii_read(MII_REG_PHYIR1),
++							mii_discover_phy, 0);
++		else
++			printk(KERN_ERR "fec: No PHY device found.\n");
++	}
++}
++
++static int mpc52xx_netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
++{
++	__u32 ethcmd;
++
++	if (copy_from_user(&ethcmd, useraddr, sizeof ethcmd))
++		return -EFAULT;
++
++	switch (ethcmd) {
++
++		/* Get driver info */
++	case ETHTOOL_GDRVINFO:{
++			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
++			strncpy(info.driver, "MPC5200 FEC",
++				sizeof info.driver - 1);
++			if (copy_to_user(useraddr, &info, sizeof info))
++				return -EFAULT;
++			return 0;
++		}
++		/* get message-level */
++	case ETHTOOL_GMSGLVL:{
++			struct ethtool_value edata = { ETHTOOL_GMSGLVL };
++			edata.data = 0;	/* XXX */
++			if (copy_to_user(useraddr, &edata, sizeof edata))
++				return -EFAULT;
++			return 0;
++		}
++		/* set message-level */
++	case ETHTOOL_SMSGLVL:{
++			struct ethtool_value edata;
++			if (copy_from_user(&edata, useraddr, sizeof edata))
++				return -EFAULT;
++			return 0;
++		}
++	}
++	return -EOPNOTSUPP;
++}
++
++int fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
++{
++	int retval;
++
++	switch (cmd) {
++	case SIOCETHTOOL:
++		retval = mpc52xx_netdev_ethtool_ioctl(
++					dev, (void *) rq->ifr_data);
++		break;
++
++	default:
++		retval = -EOPNOTSUPP;
++		break;
++	}
++	return retval;
++}
++
++void fec_mii_init(struct net_device *dev)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	int i;
++
++	for (i=0; i<NMII-1; i++)
++		mii_cmds[i].mii_next = &mii_cmds[i+1];
++	mii_free = mii_cmds;
++
++	/* Queue up command to detect the PHY and initialize the
++	 * remainder of the interface.
++	 */
++	priv->phy_id_done = 0;
++	priv->phy_addr = 0;
++	mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy, 0);
++
++	priv->old_status = 0;
++}
++
++int fec_mii_wait(struct net_device *dev)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++
++	if (!priv->sequence_done) {
++		if (!priv->phy) {
++			printk("KERN_ERR fec_open: PHY not configured\n");
++			return -ENODEV;		/* No PHY we understand */
++		}
++
++		mii_do_cmd(dev, priv->phy->config);
++		mii_do_cmd(dev, phy_cmd_config); /* display configuration */
++		while(!priv->sequence_done)
++			schedule();
++
++		mii_do_cmd(dev, priv->phy->startup);
++	}
++	return 0;
++}
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Dale Farnsworth");
++MODULE_DESCRIPTION("PHY driver for Motorola MPC52xx FEC");
+diff --git a/drivers/net/fec_mpc52xx/fec_phy.h b/drivers/net/fec_mpc52xx/fec_phy.h
+new file mode 100644
+index 0000000..5c23bff
+--- /dev/null
++++ b/drivers/net/fec_mpc52xx/fec_phy.h
+@@ -0,0 +1,73 @@
++/*
++ * arch/ppc/52xx_io/fec_phy.h
++ *
++ * Driver for the MPC5200 Fast Ethernet Controller
++ * Based heavily on the MII support for the MPC8xx by Dan Malek
++ *
++ * Author: Dale Farnsworth <dfarnsworth at mvista.com>
++ *
++ * 2003-2004 (c) MontaVista, Software, Inc.  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.
++ */
++
++#ifdef CONFIG_USE_MDIO
++#define MII_ADVERTISE_HALF	(ADVERTISE_100HALF | ADVERTISE_10HALF | \
++				 ADVERTISE_CSMA)
++
++#define MII_ADVERTISE_ALL	(ADVERTISE_100FULL | ADVERTISE_10FULL | \
++				 MII_ADVERTISE_HALF)
++#ifdef PHY_INTERRUPT
++#define MII_ADVERTISE_DEFAULT	MII_ADVERTISE_ALL
++#else
++#define MII_ADVERTISE_DEFAULT	MII_ADVERTISE_HALF
++#endif
++
++#define MII_RCNTL_MODE		FEC_RCNTRL_MII_MODE
++#define set_phy_speed(fec, s)	out_be32(&fec->mii_speed, s)
++#define FEC_IMASK_ENABLE	0xf0fe0000
++
++typedef struct {
++	uint mii_data;
++	void (*funct)(uint mii_reg, struct net_device *dev, uint data);
++} phy_cmd_t;
++
++typedef struct {
++	uint id;
++	char *name;
++
++	const phy_cmd_t *config;
++	const phy_cmd_t *startup;
++	const phy_cmd_t *ack_int;
++	const phy_cmd_t *shutdown;
++} phy_info_t;
++
++#else
++#define MII_RCNTL_MODE		0
++#define set_phy_speed(fec, s)
++#define FEC_IMASK_ENABLE	0xf07e0000
++#define fec_mii_wait(dev)	0
++#define fec_mii(dev)	printk(KERN_WARNING "unexpected FEC_IEVENT_MII\n")
++#define fec_mii_init(dev)
++#endif	/* CONFIG_USE_MDIO */
++
++/* MII-related definitions */
++#define FEC_MII_DATA_ST		0x40000000	/* Start frame */
++#define FEC_MII_DATA_OP_RD	0x20000000	/* Perform read */
++#define FEC_MII_DATA_OP_WR	0x10000000	/* Perform write */
++#define FEC_MII_DATA_PA_MSK	0x0f800000	/* PHY Address mask */
++#define FEC_MII_DATA_RA_MSK	0x007c0000	/* PHY Register mask */
++#define FEC_MII_DATA_TA		0x00020000	/* Turnaround */
++#define FEC_MII_DATA_DATAMSK	0x00000fff	/* PHY data mask */
++
++#define FEC_MII_DATA_RA_SHIFT	0x12		/* MII reg addr bits */
++#define FEC_MII_DATA_PA_SHIFT	0x17		/* MII PHY addr bits */
++
++#define FEC_MII_SPEED		(5 * 2)
++
++extern void fec_mii_init(struct net_device *dev);
++extern int fec_mii_wait(struct net_device *dev);
++extern void fec_mii(struct net_device *dev);
++
++extern int fec_ioctl(struct net_device *, struct ifreq *rq, int cmd);
+-- 
+1.5.1.2
+

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0009-sound-Add-support-for-Freescale-MPC5200-AC97-interf.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0009-sound-Add-support-for-Freescale-MPC5200-AC97-interf.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,935 @@
+From 37df769e87c6ae9a413626dd19252d5c0c3110f7 Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sat, 12 May 2007 22:04:46 +0200
+Subject: [PATCH 09/21] sound: Add support for Freescale MPC5200 AC97 interface.
+
+Not quite a clean driver, but it get things done (well,
+mostly).
+Only included to be able to test functionalityi/usage of
+the BestComm driver.
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ sound/ppc/Kconfig        |   16 +
+ sound/ppc/Makefile       |    3 +
+ sound/ppc/mpc52xx_ac97.c |  870 ++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 889 insertions(+), 0 deletions(-)
+ create mode 100644 sound/ppc/mpc52xx_ac97.c
+
+diff --git a/sound/ppc/Kconfig b/sound/ppc/Kconfig
+index a3fb149..afd58f7 100644
+--- a/sound/ppc/Kconfig
++++ b/sound/ppc/Kconfig
+@@ -33,3 +33,19 @@ config SND_POWERMAC_AUTO_DRC
+ 	  option.
+ 
+ endmenu
++
++
++# ALSA ppc drivers
++
++menu "ALSA PPC devices"
++	depends on SND!=n && PPC
++
++config SND_PPC_MPC52xx_AC97
++	tristate "Freescale MPC52xx AC97 interface support"
++	depends on SND && PPC_MPC52xx
++	select SND_AC97_CODEC
++	help
++	  Say Y or M if you want to support any AC97 codec attached to
++	  the Freescqle MPC52xx AC97 interface.
++
++endmenu
+diff --git a/sound/ppc/Makefile b/sound/ppc/Makefile
+index 4d95c65..c29cb9b 100644
+--- a/sound/ppc/Makefile
++++ b/sound/ppc/Makefile
+@@ -4,6 +4,9 @@
+ #
+ 
+ snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o keywest.o beep.o
++snd-mpc52xx-ac97-objs := mpc52xx_ac97.o
+ 
+ # Toplevel Module Dependency
+ obj-$(CONFIG_SND_POWERMAC) += snd-powermac.o
++
++obj-$(CONFIG_SND_PPC_MPC52xx_AC97)	+= snd-mpc52xx-ac97.o
+diff --git a/sound/ppc/mpc52xx_ac97.c b/sound/ppc/mpc52xx_ac97.c
+new file mode 100644
+index 0000000..20e2bf8
+--- /dev/null
++++ b/sound/ppc/mpc52xx_ac97.c
+@@ -0,0 +1,870 @@
++/*
++ * Driver for the PSC of the Freescale MPC52xx configured as AC97 interface
++ *
++ *
++ * Copyright (C) 2006 Sylvain Munaut <tnt at 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.
++ */
++
++#define DEBUG
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++
++#include <sound/driver.h>
++#include <sound/core.h>
++#include <sound/initval.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/ac97_codec.h>
++
++#include <asm/of_platform.h>
++#include <linux/dma-mapping.h>
++#include <asm/mpc52xx_psc.h>
++
++#include <sysdev/bestcomm/bestcomm.h>
++#include <sysdev/bestcomm/gen_bd.h>
++
++
++#define DRV_NAME "mpc52xx-psc-ac97"
++
++
++/* ======================================================================== */
++/* Structs / Defines                                                        */
++/* ======================================================================== */
++
++/* Private structure */
++struct mpc52xx_ac97_priv {
++	struct device *dev;
++	resource_size_t	mem_start;
++	resource_size_t mem_len;
++	int irq;
++	struct mpc52xx_psc __iomem *psc;
++
++	struct bcom_task *tsk_tx;
++	spinlock_t dma_lock;
++
++	struct snd_card *card;
++	struct snd_pcm *pcm;
++	struct snd_ac97 *ac97;
++
++	struct snd_pcm_substream *substream_playback;
++
++	int period_byte_size;
++	u32 period_start, period_end, period_next_p;
++};
++
++/* Register bit definition (AC97 mode specific) */
++#define PSC_AC97_SLOT_BIT(n)		(1<<(12-n))
++#define PSC_AC97_SLOTS_XMIT_SHIFT	16
++#define PSC_AC97_SLOTS_RECV_SHIFT	 0
++
++/* Bestcomm options */
++#define AC97_TX_NUM_BD	32
++#define AC97_RX_NUM_BD	32
++
++#if 0
++static u32* buffers_va[AC97_TX_NUM_BD];
++static u32  buffers_pa[AC97_TX_NUM_BD];
++#endif
++
++
++/* ======================================================================== */
++/* Buffer handling                                                          */
++/* ======================================================================== */
++
++#if 0
++static void
++mpc52xx_ac97_tx_bufalloc(struct mpc52xx_ac97_priv *priv)
++{
++	int i;
++
++	if (buffers_va[0])
++		return;
++
++	buffers_va[0] = dma_alloc_coherent(priv->dev, AC97_TX_NUM_BD * 1024, &buffers_pa[0], GFP_KERNEL);
++
++	for (i=1; i<AC97_TX_NUM_BD; i++) {
++		buffers_va[i] = buffers_va[i-1] + 1024;
++		buffers_pa[i] = buffers_pa[i-1] + 1024;
++	}
++
++	printk(KERN_INFO "Buffer alloc %08x %08x\n", buffers_va[0], buffers_pa[0]);
++}
++
++static void
++mpc52xx_ac97_tx_bufrelease(struct mpc52xx_ac97_priv *priv)
++{
++	if (buffers_va[0]) {
++		dma_free_coherent(priv->dev, AC97_TX_NUM_BD * 1024, buffers_va[0], buffers_pa[0]);
++		buffers_va[0] = NULL;
++	}
++}
++#endif
++
++static int
++mpc52xx_ac97_tx_fill(struct mpc52xx_ac97_priv *priv)
++{
++	struct snd_pcm_runtime *rt;
++
++	u32 dma_data_ptr;
++
++	rt = priv->substream_playback->runtime;
++
++	dma_data_ptr = virt_to_phys(rt->dma_area);
++
++	priv->period_byte_size	= frames_to_bytes(rt, rt->period_size);
++	priv->period_start	= dma_data_ptr;
++	priv->period_end	= dma_data_ptr + priv->period_byte_size * rt->periods;
++	priv->period_next_p	= dma_data_ptr;
++
++	spin_lock(&priv->dma_lock);
++	while (!bcom_queue_full(priv->tsk_tx)) {
++		struct bcom_gen_bd *bd;
++
++		/* Submit a new one */
++		bd = (struct bcom_gen_bd *) bcom_prepare_next_buffer(priv->tsk_tx);
++		bd->status = priv->period_byte_size;
++		bd->buf_pa = priv->period_next_p;
++		bcom_submit_next_buffer(priv->tsk_tx, NULL);
++
++		/* Next pointer */
++		priv->period_next_p += priv->period_byte_size;
++		if (priv->period_next_p >= priv->period_end)
++			priv->period_next_p = priv->period_start;
++	}
++	spin_unlock(&priv->dma_lock);
++
++	return 0;
++}
++
++
++/* ======================================================================== */
++/* ISR routine                                                              */
++/* ======================================================================== */
++
++static irqreturn_t
++mpc52xx_ac97_tx_irq(int irq, void *dev_id)
++{
++	struct mpc52xx_ac97_priv *priv = dev_id;
++	struct snd_pcm_runtime *rt;
++	struct bcom_gen_bd *bd;
++
++	rt = priv->substream_playback->runtime;
++
++	if (!bcom_buffer_done(priv->tsk_tx)) {
++		bcom_dump_status();
++		bcom_dump_task(priv->tsk_tx->tasknum);
++		bcom_dump_bdring(priv->tsk_tx);
++		bcom_disable(priv->tsk_tx);
++	}
++
++	spin_lock(&priv->dma_lock);
++	while (bcom_buffer_done(priv->tsk_tx)) {
++		/* Get the buffer back */
++		bcom_retrieve_buffer(priv->tsk_tx, NULL, NULL);
++
++		/* Submit a new one */
++		bd = (struct bcom_gen_bd *) bcom_prepare_next_buffer(priv->tsk_tx);
++		bd->status = priv->period_byte_size;
++		bd->buf_pa = priv->period_next_p;
++		bcom_submit_next_buffer(priv->tsk_tx, NULL);
++		bcom_enable(priv->tsk_tx);
++
++		/* Next pointer */
++		priv->period_next_p += priv->period_byte_size;
++		if (priv->period_next_p >= priv->period_end)
++			priv->period_next_p = priv->period_start;
++	}
++	spin_unlock(&priv->dma_lock);
++
++	snd_pcm_period_elapsed(priv->substream_playback);
++
++	return IRQ_HANDLED;
++}
++
++
++static irqreturn_t
++mpc52xx_ac97_irq(int irq, void *dev_id)
++{
++	struct mpc52xx_ac97_priv *priv = dev_id;
++
++	static int icnt = 0;
++	#if 0
++	{
++	unsigned int val;
++//	val = in_be32(&priv->psc->ac97_data);
++	printk(KERN_INFO "mpc52xx_ac97_irq fired (isr=%04x, status=%04x) %08x\n", in_be16(&priv->psc->mpc52xx_psc_imr), in_be16(&priv->psc->mpc52xx_psc_status), val);
++	out_8(&priv->psc->command,MPC52xx_PSC_RST_ERR_STAT);
++	}
++	#endif
++
++	/* Anti Crash during dev ;) */
++	#if 1
++	if ((icnt++) > 5000)
++		out_be16(&priv->psc->mpc52xx_psc_imr, 0);
++	#endif
++
++	/* Print statuts */
++	printk(KERN_DEBUG "isr: %04x", in_be16(&priv->psc->mpc52xx_psc_imr));
++	out_8(&priv->psc->command,MPC52xx_PSC_RST_ERR_STAT);
++
++	return IRQ_HANDLED;
++}
++
++/* ======================================================================== */
++/* PCM interface                                                            */
++/* ======================================================================== */
++
++/* HW desc */
++
++static struct snd_pcm_hardware mpc52xx_ac97_hw = {
++	.info			= SNDRV_PCM_INFO_INTERLEAVED		|
++					SNDRV_PCM_INFO_MMAP		|
++					SNDRV_PCM_INFO_MMAP_VALID,
++	.formats		= SNDRV_PCM_FMTBIT_S32_BE,
++	.rates			= SNDRV_PCM_RATE_8000_48000,
++	.rate_min		= 8000,
++	.rate_max		= 48000,
++	.channels_min		= 1,
++	.channels_max		= 2,	/* Support for more ? */
++	.buffer_bytes_max	= 1024*1024,
++	.period_bytes_min	= 512,
++	.period_bytes_max	= 16*1024,
++	.periods_min		= 8,
++	.periods_max		= 1024,
++	.fifo_size		= 512,
++};
++
++
++/* Playback */
++
++static int
++mpc52xx_ac97_playback_open(struct snd_pcm_substream *substream)
++{
++	struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
++
++	dev_dbg(priv->dev, "mpc52xx_ac97_playback_open(%p)\n", substream);
++
++	substream->runtime->hw = mpc52xx_ac97_hw;
++
++	priv->substream_playback = substream;
++
++	return 0;	/* FIXME */
++}
++
++static int
++mpc52xx_ac97_playback_close(struct snd_pcm_substream *substream)
++{
++	struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
++	dev_dbg(priv->dev, "mpc52xx_ac97_playback_close(%p)\n", substream);
++	priv->substream_playback = NULL;
++	return 0;	/* FIXME */
++}
++
++static int
++mpc52xx_ac97_playback_prepare(struct snd_pcm_substream *substream)
++{
++	struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
++
++	dev_dbg(priv->dev, "mpc52xx_ac97_playback_prepare(%p)\n", substream);
++
++	/* FIXME, need a spinlock to protect access */
++	if (substream->runtime->channels == 1)
++		out_be32(&priv->psc->ac97_slots, 0x01000000);
++	else
++		out_be32(&priv->psc->ac97_slots, 0x03000000);
++
++	snd_ac97_set_rate(priv->ac97, AC97_PCM_FRONT_DAC_RATE, substream->runtime->rate);
++
++	return 0;	/* FIXME */
++}
++
++
++/* Capture */
++
++static int
++mpc52xx_ac97_capture_open(struct snd_pcm_substream *substream)
++{
++	struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
++	return 0;	/* FIXME */
++}
++
++static int
++mpc52xx_ac97_capture_close(struct snd_pcm_substream *substream)
++{
++	struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
++	return 0;	/* FIXME */
++}
++
++static int
++mpc52xx_ac97_capture_prepare(struct snd_pcm_substream *substream)
++{
++	struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
++	return 0;	/* FIXME */
++}
++
++
++/* Common */
++
++static int
++mpc52xx_ac97_hw_params(struct snd_pcm_substream *substream,
++			struct snd_pcm_hw_params *params)
++{
++	struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
++	int rv;
++
++	dev_dbg(priv->dev, "mpc52xx_ac97_hw_params(%p)\n", substream);
++
++	rv = snd_pcm_lib_malloc_pages(substream,
++					params_buffer_bytes(params));
++	if (rv < 0) {
++		printk(KERN_ERR "hw params failes\n");	/* FIXME */
++		return rv;
++	}
++
++	// mpc52xx_ac97_tx_bufalloc(priv);
++
++	printk(KERN_DEBUG "%d %d %d\n", params_buffer_bytes(params), params_period_bytes(params), params_periods(params));
++
++	return 0;
++}
++
++static int
++mpc52xx_ac97_hw_free(struct snd_pcm_substream *substream)
++{
++	struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
++
++	dev_dbg(priv->dev, "mpc52xx_ac97_hw_free(%p)\n", substream);
++	// mpc52xx_ac97_tx_bufrelease(priv);
++
++	return snd_pcm_lib_free_pages(substream);
++}
++
++static int
++mpc52xx_ac97_trigger(struct snd_pcm_substream *substream, int cmd)
++{
++	struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
++	int rv = 0;
++
++	dev_dbg(priv->dev, "mpc52xx_ac97_trigger(%p,%d)\n", substream, cmd);
++
++	switch (cmd) {
++		case SNDRV_PCM_TRIGGER_START:
++			/* Enable TX taks */
++			bcom_gen_bd_tx_reset(priv->tsk_tx);
++			mpc52xx_ac97_tx_fill(priv);
++			bcom_enable(priv->tsk_tx);
++//			out_be16(&priv->psc->mpc52xx_psc_imr, 0x0800); // 0x0100
++//			out_be16(&priv->psc->mpc52xx_psc_imr, 0x0100); // 0x0100
++				/* FIXME: Shouldn't we check for overrun too ? */
++				/* also, shouldn't we just activate TX here ? */
++
++			break;
++
++		case SNDRV_PCM_TRIGGER_STOP:
++			/* Disable TX task */
++			bcom_disable(priv->tsk_tx);
++			out_be16(&priv->psc->mpc52xx_psc_imr, 0x0000); // 0x0100
++
++			break;
++
++		default:
++			rv = -EINVAL;
++	}
++
++	/* FIXME */
++	return rv;
++}
++
++static snd_pcm_uframes_t
++mpc52xx_ac97_pointer(struct snd_pcm_substream *substream)
++{
++	struct snd_pcm_runtime *runtime = substream->runtime;
++	struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
++	u32 count;
++
++//	dev_dbg(priv->dev, "mpc52xx_ac97_pointer(%p)\n", substream);
++
++	count = priv->tsk_tx->bd[priv->tsk_tx->outdex].data[0] - priv->period_start;
++
++	return bytes_to_frames(runtime, count);
++}
++
++
++/* Ops */
++
++static struct snd_pcm_ops mpc52xx_ac97_playback_ops = {
++	.open		= mpc52xx_ac97_playback_open,
++	.close		= mpc52xx_ac97_playback_close,
++	.ioctl		= snd_pcm_lib_ioctl,
++	.hw_params	= mpc52xx_ac97_hw_params,
++	.hw_free	= mpc52xx_ac97_hw_free,
++	.prepare	= mpc52xx_ac97_playback_prepare,
++	.trigger	= mpc52xx_ac97_trigger,
++	.pointer	= mpc52xx_ac97_pointer,
++};
++
++static struct snd_pcm_ops mpc52xx_ac97_capture_ops = {
++	.open		= mpc52xx_ac97_capture_open,
++	.close		= mpc52xx_ac97_capture_close,
++	.ioctl		= snd_pcm_lib_ioctl,
++	.hw_params	= mpc52xx_ac97_hw_params,
++	.hw_free	= mpc52xx_ac97_hw_free,
++	.prepare	= mpc52xx_ac97_capture_prepare,
++	.trigger	= mpc52xx_ac97_trigger,
++	.pointer	= mpc52xx_ac97_pointer,
++};
++
++
++/* ======================================================================== */
++/* AC97 Bus interface                                                       */
++/* ======================================================================== */
++
++static unsigned short
++mpc52xx_ac97_bus_read(struct snd_ac97 *ac97, unsigned short reg)
++{
++	struct mpc52xx_ac97_priv *priv = ac97->private_data;
++	int timeout;
++	unsigned int val;
++
++//	dev_dbg(priv->dev, "ac97 read: reg %04x\n", reg);
++
++	/* Wait for it to be ready */
++	timeout = 1000;
++	while ((--timeout) && (in_be16(&priv->psc->mpc52xx_psc_status) &
++						MPC52xx_PSC_SR_CMDSEND) )
++		udelay(10);
++
++	if (!timeout) {
++		printk(KERN_ERR DRV_NAME ": timeout on ac97 bus (rdy)\n");
++		return 0xffff;
++	}
++
++	/* Do the read */
++	out_be32(&priv->psc->ac97_cmd, (1<<31) | ((reg & 0x7f) << 24));
++
++	/* Wait for the answer */
++	timeout = 1000;
++	while ((--timeout) && !(in_be16(&priv->psc->mpc52xx_psc_status) &
++						MPC52xx_PSC_SR_DATA_VAL) )
++		udelay(10);
++
++	if (!timeout) {
++		printk(KERN_ERR DRV_NAME ": timeout on ac97 read (val)\n");
++		return 0xffff;
++	}
++
++	/* Get the data */
++	val = in_be32(&priv->psc->ac97_data);
++	if ( ((val>>24) & 0x7f) != reg ) {
++		printk(KERN_ERR DRV_NAME ": reg echo error on ac97 read\n");
++		return 0xffff;
++	}
++	val = (val >> 8) & 0xffff;
++
++//	dev_dbg(priv->dev, "ac97 read ok: reg %04x  val %04x\n",
++//				reg, val);
++
++	return (unsigned short) val;
++}
++
++static void
++mpc52xx_ac97_bus_write(struct snd_ac97 *ac97,
++			unsigned short reg, unsigned short val)
++{
++	struct mpc52xx_ac97_priv *priv = ac97->private_data;
++	int timeout;
++
++//	dev_dbg(priv->dev, "ac97 write: reg %04x  val %04x\n",
++//				reg, val);
++
++	/* Wait for it to be ready */
++	timeout = 1000;
++	while ((--timeout) && (in_be16(&priv->psc->mpc52xx_psc_status) &
++						MPC52xx_PSC_SR_CMDSEND) )
++		udelay(10);
++
++	if (!timeout) {
++		printk(KERN_ERR DRV_NAME ": timeout on ac97 write\n");
++		return;
++	}
++
++	/* Write data */
++	out_be32(&priv->psc->ac97_cmd, ((reg & 0x7f) << 24) | (val << 8));
++}
++
++static void
++mpc52xx_ac97_bus_reset(struct snd_ac97 *ac97)
++{
++	struct mpc52xx_ac97_priv *priv = ac97->private_data;
++
++	dev_dbg(priv->dev, "ac97 codec reset\n");
++
++	/* Do a cold reset */
++	out_8(&priv->psc->op1, 0x03);
++	udelay(10);
++	out_8(&priv->psc->op0, 0x02);
++	udelay(50);
++
++	/* PSC recover from cold reset (cfr user manual, not sure if useful) */
++	out_be32(&priv->psc->sicr, in_be32(&priv->psc->sicr));
++}
++
++
++static struct snd_ac97_bus_ops mpc52xx_ac97_bus_ops = {
++	.read	= mpc52xx_ac97_bus_read,
++	.write	= mpc52xx_ac97_bus_write,
++	.reset	= mpc52xx_ac97_bus_reset,
++};
++
++
++/* ======================================================================== */
++/* Sound driver setup                                                       */
++/* ======================================================================== */
++
++static int
++mpc52xx_ac97_setup_pcm(struct mpc52xx_ac97_priv *priv)
++{
++	int rv;
++
++	rv = snd_pcm_new(priv->card, DRV_NAME "-pcm", 0, 1, 1, &priv->pcm);
++	if (rv) {
++		printk(KERN_ERR DRV_NAME ": snd_pcm_new failed\n");
++		return rv;
++	}
++
++	rv = snd_pcm_lib_preallocate_pages_for_all(priv->pcm,
++		SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL),
++		128*1024, 128*1024);
++	if (rv) {
++		printk(KERN_ERR DRV_NAME
++			": snd_pcm_lib_preallocate_pages_for_all  failed\n");
++		return rv;
++	}
++
++	snd_pcm_set_ops(priv->pcm, SNDRV_PCM_STREAM_PLAYBACK,
++			&mpc52xx_ac97_playback_ops);
++	snd_pcm_set_ops(priv->pcm, SNDRV_PCM_STREAM_CAPTURE,
++			&mpc52xx_ac97_capture_ops);
++
++	priv->pcm->private_data = priv;
++	priv->pcm->info_flags = 0;
++
++	strcpy(priv->pcm->name, "Freescale MPC52xx PSC-AC97 PCM");
++
++	return 0;
++}
++
++static int
++mpc52xx_ac97_setup_mixer(struct mpc52xx_ac97_priv *priv)
++{
++	struct snd_ac97_bus *ac97_bus;
++	struct snd_ac97_template ac97_template;
++	int rv;
++
++	rv = snd_ac97_bus(priv->card, 0, &mpc52xx_ac97_bus_ops, NULL, &ac97_bus);
++	if (rv) {
++		printk(KERN_ERR DRV_NAME ": snd_ac97_bus failed\n");
++		return rv;
++	}
++
++	memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
++	ac97_template.private_data = priv;
++
++	rv = snd_ac97_mixer(ac97_bus, &ac97_template, &priv->ac97);
++	if (rv) {
++		printk(KERN_ERR DRV_NAME ": snd_ac97_mixer failed\n");
++		return rv;
++	}
++
++	return 0;
++}
++
++
++static int
++mpc52xx_ac97_hwinit(struct mpc52xx_ac97_priv *priv)
++{
++	/* Reset everything first by safety */
++	out_8(&priv->psc->command,MPC52xx_PSC_RST_RX);
++	out_8(&priv->psc->command,MPC52xx_PSC_RST_TX);
++	out_8(&priv->psc->command,MPC52xx_PSC_RST_ERR_STAT);
++
++	/* Do a cold reset of codec */
++	out_8(&priv->psc->op1, 0x03);
++	udelay(10);
++	out_8(&priv->psc->op0, 0x02);
++	udelay(50);
++
++	/* Configure AC97 enhanced mode */
++	out_be32(&priv->psc->sicr, 0x03010000);
++
++	/* No slots active */
++	out_be32(&priv->psc->ac97_slots, 0x00000000);
++
++	/* No IRQ */
++	out_be16(&priv->psc->mpc52xx_psc_imr, 0x0000);
++
++	/* FIFO levels */
++	out_8(&priv->psc->rfcntl, 0x07);
++	out_8(&priv->psc->tfcntl, 0x07);
++	out_be16(&priv->psc->rfalarm, 0x80);
++	out_be16(&priv->psc->tfalarm, 0x80);
++
++	/* Go */
++	out_8(&priv->psc->command,MPC52xx_PSC_TX_ENABLE);
++	out_8(&priv->psc->command,MPC52xx_PSC_RX_ENABLE);
++
++	return 0;
++}
++
++static int
++mpc52xx_ac97_hwshutdown(struct mpc52xx_ac97_priv *priv)
++{
++	/* No IRQ */
++	out_be16(&priv->psc->mpc52xx_psc_imr, 0x0000);
++
++	/* Disable TB & RX */
++	out_8(&priv->psc->command,MPC52xx_PSC_RST_RX);
++	out_8(&priv->psc->command,MPC52xx_PSC_RST_TX);
++
++	/* FIXME : Reset or put codec in low power ? */
++
++	return 0;
++}
++
++
++/* ======================================================================== */
++/* OF Platform Driver                                                       */
++/* ======================================================================== */
++
++static int __devinit
++mpc52xx_ac97_probe(struct of_device *op, const struct of_device_id *match)
++{
++	struct device_node *dn = op->node;
++	struct mpc52xx_ac97_priv *priv;
++	struct snd_card *card;
++	struct resource res;
++	int rv;
++
++	dev_dbg(&op->dev, "probing MPC52xx PSC AC97 driver\n");
++
++	/* Get card structure */
++	rv = -ENOMEM;
++	card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
++				THIS_MODULE, sizeof(struct mpc52xx_ac97_priv));
++	if (!card)
++		goto err_early;
++
++	priv = card->private_data;
++
++	/* Init our private structure */
++	priv->card = card;
++	priv->dev = &op->dev;
++
++	/* Get resources (mem,irq,...) */
++	rv = of_address_to_resource(dn, 0, &res);
++	if (rv)
++		goto err_early;
++
++	priv->mem_start = res.start;
++	priv->mem_len = res.end - res.start + 1;
++
++	if (!request_mem_region(priv->mem_start, priv->mem_len, DRV_NAME)) {
++		printk(KERN_ERR DRV_NAME ": request_mem_region failed\n");
++		rv = -EBUSY;
++		goto err_early;
++	}
++
++	priv->psc = ioremap(priv->mem_start, priv->mem_len);
++	if (!priv->psc) {
++		printk(KERN_ERR DRV_NAME ": ioremap failed\n");
++		rv = -ENOMEM;
++		goto err_iomap;
++	}
++
++	priv->irq = irq_of_parse_and_map(dn, 0);
++	if (priv->irq == NO_IRQ) {
++		printk(KERN_ERR DRV_NAME ": irq_of_parse_and_map failed\n");
++		rv = -EBUSY;
++		goto err_irqmap;
++	}
++
++	/* Setup Bestcomm tasks */
++	spin_lock_init(&priv->dma_lock);
++
++	priv->tsk_tx = bcom_gen_bd_tx_init(AC97_TX_NUM_BD,
++				priv->mem_start + offsetof(struct mpc52xx_psc,
++							tfdata),
++				12,	/* initiator : FIXME */
++				2);	/* ipr : FIXME */
++	if (!priv->tsk_tx) {
++		printk(KERN_ERR DRV_NAME ": bcom_gen_bd_tx_init failed\n");
++		rv = -ENOMEM;
++		goto err_bcomm;
++	}		
++
++	/* Low level HW Init */
++	mpc52xx_ac97_hwinit(priv);
++
++	/* Request IRQ now that we're 'stable' */
++	rv = request_irq(priv->irq, mpc52xx_ac97_irq, 0, DRV_NAME, priv);
++	if (rv < 0) {
++		printk(KERN_ERR DRV_NAME ": request_irq failed\n");
++		goto err_irqreq;
++	}
++
++	rv = request_irq(bcom_get_task_irq(priv->tsk_tx),
++				mpc52xx_ac97_tx_irq, 0, DRV_NAME "_tx", priv);
++	if (rv < 0) {
++		printk(KERN_ERR DRV_NAME ": request_irq failed\n");
++		goto err_txirqreq;
++	}
++
++	/* Prepare sound stuff */
++	rv = mpc52xx_ac97_setup_mixer(priv);
++	if (rv)
++		goto err_late;
++
++	rv = mpc52xx_ac97_setup_pcm(priv);
++	if (rv)
++		goto err_late;
++
++	/* Finally register the card */
++	snprintf(card->shortname, sizeof(card->shortname), DRV_NAME);
++	snprintf(card->longname, sizeof(card->longname),
++		"Freescale MPC52xx PSC-AC97 (%s)", card->mixername);
++
++	rv = snd_card_register(card);
++	if (rv) {
++		printk(KERN_ERR DRV_NAME ": snd_card_register failed\n");
++		goto err_late;
++	}
++
++	dev_set_drvdata(&op->dev, priv);
++
++	return 0;
++
++err_late:
++	free_irq(bcom_get_task_irq(priv->tsk_tx), priv);
++err_txirqreq:
++	free_irq(priv->irq, priv);
++err_irqreq:
++	bcom_gen_bd_tx_release(priv->tsk_tx);
++err_bcomm:
++	mpc52xx_ac97_hwshutdown(priv);
++	irq_dispose_mapping(priv->irq);
++err_irqmap:
++	iounmap(priv->psc);
++err_iomap:
++	release_mem_region(priv->mem_start, priv->mem_len);
++err_early:
++	if (card)
++		snd_card_free(card);
++	return rv;
++}
++
++static int
++mpc52xx_ac97_remove(struct of_device *op)
++{
++	struct mpc52xx_ac97_priv *priv;
++
++	dev_dbg(&op->dev, "removing MPC52xx PSC AC97 driver\n");
++
++	priv = dev_get_drvdata(&op->dev);
++	if (priv) {
++		/* Sound subsys shutdown */
++		snd_card_free(priv->card);
++
++		/* Low level HW shutdown */
++		mpc52xx_ac97_hwshutdown(priv);
++
++		/* Release bestcomm tasks */
++		free_irq(bcom_get_task_irq(priv->tsk_tx), priv);
++		bcom_gen_bd_tx_release(priv->tsk_tx);
++
++		/* Release resources */
++		iounmap(priv->psc);
++		free_irq(priv->irq, priv);
++		irq_dispose_mapping(priv->irq);
++		release_mem_region(priv->mem_start, priv->mem_len);
++	}
++
++	dev_set_drvdata(&op->dev, NULL);
++
++	return 0;
++}
++
++
++static struct of_device_id mpc52xx_ac97_of_match[] = {
++	{
++		.type		= "sound",
++		.compatible	= "mpc5200b-psc-ac97",	/* B only for now */
++	},
++};
++/* Prevent autoload during developpment phase ... */
++/* MODULE_DEVICE_TABLE(of, mpc52xx_ac97_of_match); */
++
++
++static struct of_platform_driver mpc52xx_ac97_of_driver = {
++	.owner		= THIS_MODULE,
++	.name		= DRV_NAME,
++	.match_table	= mpc52xx_ac97_of_match,
++	.probe		= mpc52xx_ac97_probe,
++	.remove		= mpc52xx_ac97_remove,
++	.driver		= {
++		.name	= DRV_NAME,
++	},
++};
++
++
++/* ======================================================================== */
++/* Module                                                                   */
++/* ======================================================================== */
++
++static int __init
++mpc52xx_ac97_init(void)
++{
++	int rv;
++
++	/* FIXME BIG FAT EFIKA HACK */
++	{
++		void *mbar;
++		mbar = ioremap(0xf0000000, 0x100000);
++		printk(KERN_INFO "EFIKA HACK: port_config %08x\n", in_be32(mbar + 0xb00));
++		out_be32(mbar + 0xb00, 0x01051124);
++		printk(KERN_INFO "EFIKA HACK: port_config %08x\n", in_be32(mbar + 0xb00));
++		iounmap(mbar);
++	}
++	/* ------------------------ */
++
++	printk(KERN_INFO "Sound: MPC52xx PSC AC97 driver\n");
++
++	rv = of_register_platform_driver(&mpc52xx_ac97_of_driver);
++	if (rv) {
++		printk(KERN_ERR DRV_NAME ": "
++			"of_register_platform_driver failed (%i)\n", rv);
++		return rv;
++	}
++
++	return 0;
++}
++
++static void __exit
++mpc52xx_ac97_exit(void)
++{
++	of_unregister_platform_driver(&mpc52xx_ac97_of_driver);
++}
++
++module_init(mpc52xx_ac97_init);
++module_exit(mpc52xx_ac97_exit);
++
++MODULE_AUTHOR("Sylvain Munaut <tnt at 246tNt.com>");
++MODULE_DESCRIPTION(DRV_NAME ": Freescale MPC52xx PSC AC97 driver");
++MODULE_LICENSE("GPL");
++
+-- 
+1.5.1.2
+

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0010-powerpc-In-rheap.c-move-the-EXPORT_SYMBOL-and-use.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0010-powerpc-In-rheap.c-move-the-EXPORT_SYMBOL-and-use.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,134 @@
+From 35613e0debc935aad9d462cdb95ede70e01b2bdc Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sun, 13 May 2007 11:12:49 +0200
+Subject: [PATCH 10/21] powerpc: In rheap.c, move the EXPORT_SYMBOL and use the _GPL version
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/lib/rheap.c |   28 +++++++++++++---------------
+ 1 files changed, 13 insertions(+), 15 deletions(-)
+
+diff --git a/arch/powerpc/lib/rheap.c b/arch/powerpc/lib/rheap.c
+index 7c5968c..23d381e 100644
+--- a/arch/powerpc/lib/rheap.c
++++ b/arch/powerpc/lib/rheap.c
+@@ -275,6 +275,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 +289,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 +322,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 +363,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 +432,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
+@@ -498,6 +503,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
+@@ -507,6 +513,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
+@@ -590,6 +597,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
+@@ -622,6 +630,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)
+ {
+@@ -659,6 +668,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)
+ {
+@@ -683,6 +693,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)
+ {
+@@ -718,6 +729,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)
+ {
+@@ -725,19 +737,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(rh_create);
+-EXPORT_SYMBOL(rh_destroy);
+-EXPORT_SYMBOL(rh_init);
+-EXPORT_SYMBOL(rh_attach_region);
+-EXPORT_SYMBOL(rh_detach_region);
+-EXPORT_SYMBOL(rh_alloc_align);
+-EXPORT_SYMBOL(rh_alloc);
+-EXPORT_SYMBOL(rh_alloc_fixed);
+-EXPORT_SYMBOL(rh_free);
+-EXPORT_SYMBOL(rh_get_stats);
+-EXPORT_SYMBOL(rh_set_owner);
+-EXPORT_SYMBOL(rh_dump);
+-EXPORT_SYMBOL(rh_dump_blk);
++EXPORT_SYMBOL_GPL(rh_dump_blk);
+ 
+-- 
+1.5.1.2
+

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0011-powerpc-BestComm-move-the-EXPORT_SYMBOL-and-use-th.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0011-powerpc-BestComm-move-the-EXPORT_SYMBOL-and-use-th.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,163 @@
+From 243d96420d058e55824581e450ac1877005f2e82 Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sun, 13 May 2007 14:15:19 +0200
+Subject: [PATCH 11/21] powerpc: BestComm, move the EXPORT_SYMBOL and use the _GPL version
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/sysdev/bestcomm/bestcomm.c |   22 ++++++++++------------
+ arch/powerpc/sysdev/bestcomm/sram.c     |   13 +++++--------
+ 2 files changed, 15 insertions(+), 20 deletions(-)
+
+diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.c b/arch/powerpc/sysdev/bestcomm/bestcomm.c
+index 0063a1e..589e37d 100644
+--- a/arch/powerpc/sysdev/bestcomm/bestcomm.c
++++ b/arch/powerpc/sysdev/bestcomm/bestcomm.c
+@@ -30,6 +30,7 @@
+ 
+ 
+ struct bcom_engine *bcom = NULL;
++EXPORT_SYMBOL_GPL(bcom);	/* needed for inline functions */
+ 
+ 
+ /* ======================================================================== */
+@@ -87,6 +88,7 @@ bcom_dump_status(void)
+ 	BCOM_DPRINTK(" Status          = %08x\n", in_be32(&r->Status));
+ 	BCOM_DPRINTK(" PTDDebug        = %08x\n", in_be32(&r->PTDDebug));
+ }
++EXPORT_SYMBOL_GPL(bcom_dump_status);
+ 
+ void
+ bcom_dump_task(int task)
+@@ -119,6 +121,7 @@ bcom_dump_task(int task)
+ 	for (i=0; i<BCOM_MAX_VAR+BCOM_MAX_INC; i++)
+ 		printk(KERN_DEBUG "\t%p %08x\n", &p[i], p[i]);
+ }
++EXPORT_SYMBOL_GPL(bcom_dump_task);
+ 
+ void
+ bcom_dump_bdring(struct bcom_task *tsk)
+@@ -136,6 +139,7 @@ bcom_dump_bdring(struct bcom_task *tsk)
+ 				j, tsk->bd[i].data[j]);
+ 	}
+ }
++EXPORT_SYMBOL_GPL(bcom_dump_bdring);
+ 
+ 
+ /* Private API */
+@@ -205,6 +209,7 @@ error:
+ 
+ 	return NULL;
+ }
++EXPORT_SYMBOL_GPL(bcom_task_alloc);
+ 
+ void
+ bcom_task_release(struct bcom_task *tsk)
+@@ -222,6 +227,7 @@ bcom_task_release(struct bcom_task *tsk)
+ 	kfree(tsk->cookie);
+ 	kfree(tsk);
+ }
++EXPORT_SYMBOL_GPL(bcom_task_release);
+ 
+ int
+ bcom_load_image(int task, u32 *task_image)
+@@ -286,6 +292,7 @@ bcom_load_image(int task, u32 *task_image)
+ 
+ 	return 0;
+ }
++EXPORT_SYMBOL_GPL(bcom_load_image);
+ 
+ void
+ bcom_set_initiator(int task, int initiator)
+@@ -314,6 +321,7 @@ bcom_set_initiator(int task, int initiator)
+ 		next_drd_has_initiator = !bcom_drd_is_extended(*desc);
+ 	}
+ }
++EXPORT_SYMBOL_GPL(bcom_set_initiator);
+ 
+ 
+ /* Public API */
+@@ -323,12 +331,14 @@ 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);
+ 
+ 
+ /* ======================================================================== */
+@@ -586,15 +596,3 @@ MODULE_AUTHOR("Andrey Volkov <avolkov at varma-el.com>");
+ MODULE_AUTHOR("Dale Farnsworth <dfarnsworth at mvista.com>");
+ MODULE_LICENSE("GPL v2");
+ 
+-
+-EXPORT_SYMBOL(bcom);
+-EXPORT_SYMBOL(bcom_dump_status);
+-EXPORT_SYMBOL(bcom_dump_task);
+-EXPORT_SYMBOL(bcom_dump_bdring);
+-EXPORT_SYMBOL(bcom_task_alloc);
+-EXPORT_SYMBOL(bcom_task_release);
+-EXPORT_SYMBOL(bcom_load_image);
+-EXPORT_SYMBOL(bcom_set_initiator);
+-EXPORT_SYMBOL(bcom_enable);
+-EXPORT_SYMBOL(bcom_disable);
+-
+diff --git a/arch/powerpc/sysdev/bestcomm/sram.c b/arch/powerpc/sysdev/bestcomm/sram.c
+index 4f69127..a5094d6 100644
+--- a/arch/powerpc/sysdev/bestcomm/sram.c
++++ b/arch/powerpc/sysdev/bestcomm/sram.c
+@@ -27,6 +27,7 @@
+ 
+ /* Struct keeping our 'state' */
+ struct bcom_sram *bcom_sram = NULL;
++EXPORT_SYMBOL_GPL(bcom_sram);	/* needed for inline functions */
+ 
+ 
+ /* ======================================================================== */
+@@ -128,6 +129,7 @@ error_free:
+ 
+ 	return rv;
+ }
++EXPORT_SYMBOL_GPL(bcom_sram_init);
+ 
+ void bcom_sram_cleanup(void)
+ {
+@@ -140,6 +142,7 @@ void bcom_sram_cleanup(void)
+ 		bcom_sram = NULL;
+ 	}
+ }
++EXPORT_SYMBOL_GPL(bcom_sram_cleanup);
+ 
+ void* bcom_sram_alloc(int size, int align, phys_addr_t *phys)
+ {
+@@ -155,6 +158,7 @@ void* bcom_sram_alloc(int size, int align, phys_addr_t *phys)
+ 	*phys = bcom_sram->base_phys + offset;
+ 	return bcom_sram->base_virt + offset;
+ }
++EXPORT_SYMBOL_GPL(bcom_sram_alloc);
+ 
+ void bcom_sram_free(void *ptr)
+ {
+@@ -169,12 +173,5 @@ void bcom_sram_free(void *ptr)
+ 	rh_free(bcom_sram->rh, offset);
+ 	spin_unlock(&bcom_sram->lock);
+ }
+-
+-
+-EXPORT_SYMBOL(bcom_sram);
+-
+-EXPORT_SYMBOL(bcom_sram_init);
+-EXPORT_SYMBOL(bcom_sram_cleanup);
+-EXPORT_SYMBOL(bcom_sram_alloc);
+-EXPORT_SYMBOL(bcom_sram_free);
++EXPORT_SYMBOL_GPL(bcom_sram_free);
+ 
+-- 
+1.5.1.2
+

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0012-powerpc-BestComm-ATA-task-move-the-EXPORT_SYMBOL-a.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0012-powerpc-BestComm-ATA-task-move-the-EXPORT_SYMBOL-a.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,66 @@
+From 7f0ff0ce6b946befdf90ec8939195ec2248352f2 Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sun, 13 May 2007 14:16:16 +0200
+Subject: [PATCH 12/21] powerpc: BestComm ATA task, move the EXPORT_SYMBOL and use the _GPL version
+
+Also fix a typo bcom_ata_reset vs bcom_ata_reset_bd
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/sysdev/bestcomm/ata.c |   11 +++++------
+ 1 files changed, 5 insertions(+), 6 deletions(-)
+
+diff --git a/arch/powerpc/sysdev/bestcomm/ata.c b/arch/powerpc/sysdev/bestcomm/ata.c
+index c14f727..edc2049 100644
+--- a/arch/powerpc/sysdev/bestcomm/ata.c
++++ b/arch/powerpc/sysdev/bestcomm/ata.c
+@@ -95,6 +95,7 @@ bcom_ata_init(int queue_len, int maxbufsize)
+ 
+ 	return tsk;
+ }
++EXPORT_SYMBOL_GPL(bcom_ata_init);
+ 
+ void bcom_ata_rx_prepare(struct bcom_task *tsk)
+ {
+@@ -108,6 +109,7 @@ void bcom_ata_rx_prepare(struct bcom_task *tsk)
+ 
+ 	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)
+ {
+@@ -121,6 +123,7 @@ void bcom_ata_tx_prepare(struct bcom_task *tsk)
+ 
+ 	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)
+ {
+@@ -135,20 +138,16 @@ void bcom_ata_reset_bd(struct bcom_task *tsk)
+ 	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_release(tsk);
+ }
++EXPORT_SYMBOL_GPL(bcom_ata_release);
+ 
+ 
+-EXPORT_SYMBOL(bcom_ata_init);
+-EXPORT_SYMBOL(bcom_ata_rx_prepare);
+-EXPORT_SYMBOL(bcom_ata_tx_prepare);
+-EXPORT_SYMBOL(bcom_ata_reset);
+-EXPORT_SYMBOL(bcom_ata_release);
+-
+ MODULE_DESCRIPTION("BestComm ATA task driver");
+ MODULE_AUTHOR("John Rigby");
+ MODULE_LICENSE("GPL v2");
+-- 
+1.5.1.2
+

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0013-powerpc-BestComm-FEC-task-move-the-EXPORT_SYMBOL-a.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0013-powerpc-BestComm-FEC-task-move-the-EXPORT_SYMBOL-a.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,74 @@
+From 6dc1bf90fb21b9f3649e69efebe798bca43d92cf Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sun, 13 May 2007 14:16:50 +0200
+Subject: [PATCH 13/21] powerpc: BestComm FEC task, move the EXPORT_SYMBOL and use the _GPL version
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/sysdev/bestcomm/fec.c |   13 ++++++-------
+ 1 files changed, 6 insertions(+), 7 deletions(-)
+
+diff --git a/arch/powerpc/sysdev/bestcomm/fec.c b/arch/powerpc/sysdev/bestcomm/fec.c
+index 56ff560..43f9551 100644
+--- a/arch/powerpc/sysdev/bestcomm/fec.c
++++ b/arch/powerpc/sysdev/bestcomm/fec.c
+@@ -105,6 +105,7 @@ bcom_fec_rx_init(int queue_len, phys_addr_t fifo, int maxbufsize)
+ 
+ 	return tsk;
+ }
++EXPORT_SYMBOL_GPL(bcom_fec_rx_init);
+ 
+ int
+ bcom_fec_rx_reset(struct bcom_task *tsk)
+@@ -151,6 +152,7 @@ bcom_fec_rx_reset(struct bcom_task *tsk)
+ 
+ 	return 0;
+ }
++EXPORT_SYMBOL_GPL(bcom_fec_rx_reset);
+ 
+ void
+ bcom_fec_rx_release(struct bcom_task *tsk)
+@@ -158,6 +160,7 @@ bcom_fec_rx_release(struct bcom_task *tsk)
+ 	/* Nothing special for the FEC tasks */
+ 	bcom_task_release(tsk);
+ }
++EXPORT_SYMBOL_GPL(bcom_fec_rx_release);
+ 
+ 
+ 
+@@ -203,6 +206,7 @@ bcom_fec_tx_init(int queue_len, phys_addr_t fifo)
+ 
+ 	return tsk;
+ }
++EXPORT_SYMBOL_GPL(bcom_fec_tx_init);
+ 
+ int
+ bcom_fec_tx_reset(struct bcom_task *tsk)
+@@ -249,6 +253,7 @@ bcom_fec_tx_reset(struct bcom_task *tsk)
+ 
+ 	return 0;
+ }
++EXPORT_SYMBOL_GPL(bcom_fec_tx_reset);
+ 
+ void
+ bcom_fec_tx_release(struct bcom_task *tsk)
+@@ -256,15 +261,9 @@ bcom_fec_tx_release(struct bcom_task *tsk)
+ 	/* Nothing special for the FEC tasks */
+ 	bcom_task_release(tsk);
+ }
++EXPORT_SYMBOL_GPL(bcom_fec_tx_release);
+ 
+ 
+-EXPORT_SYMBOL(bcom_fec_rx_init);
+-EXPORT_SYMBOL(bcom_fec_rx_reset);
+-EXPORT_SYMBOL(bcom_fec_rx_release);
+-EXPORT_SYMBOL(bcom_fec_tx_init);
+-EXPORT_SYMBOL(bcom_fec_tx_reset);
+-EXPORT_SYMBOL(bcom_fec_tx_release);
+-
+ MODULE_DESCRIPTION("BestComm FEC tasks driver");
+ MODULE_AUTHOR("Dale Farnsworth <dfarnsworth at mvista.com>");
+ MODULE_LICENSE("GPL v2");
+-- 
+1.5.1.2
+

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0014-powerpc-BestComm-GenBD-task-move-the-EXPORT_SYMBOL.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0014-powerpc-BestComm-GenBD-task-move-the-EXPORT_SYMBOL.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,74 @@
+From 8bace2b96a070378af244f7c6ec585a2e83ee2e4 Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sun, 13 May 2007 14:17:13 +0200
+Subject: [PATCH 14/21] powerpc: BestComm GenBD task, move the EXPORT_SYMBOL and use the _GPL version
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/sysdev/bestcomm/gen_bd.c |   13 ++++++-------
+ 1 files changed, 6 insertions(+), 7 deletions(-)
+
+diff --git a/arch/powerpc/sysdev/bestcomm/gen_bd.c b/arch/powerpc/sysdev/bestcomm/gen_bd.c
+index b221bbc..7e88681 100644
+--- a/arch/powerpc/sysdev/bestcomm/gen_bd.c
++++ b/arch/powerpc/sysdev/bestcomm/gen_bd.c
+@@ -112,6 +112,7 @@ bcom_gen_bd_rx_init(int queue_len, phys_addr_t fifo,
+ 
+ 	return tsk;
+ }
++EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_init);
+ 
+ int
+ bcom_gen_bd_rx_reset(struct bcom_task *tsk)
+@@ -158,6 +159,7 @@ bcom_gen_bd_rx_reset(struct bcom_task *tsk)
+ 
+ 	return 0;
+ }
++EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_reset);
+ 
+ void
+ bcom_gen_bd_rx_release(struct bcom_task *tsk)
+@@ -165,6 +167,7 @@ bcom_gen_bd_rx_release(struct bcom_task *tsk)
+ 	/* Nothing special for the GenBD tasks */
+ 	bcom_task_release(tsk);
+ }
++EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_release);
+ 
+ 
+ extern struct bcom_task *
+@@ -193,6 +196,7 @@ bcom_gen_bd_tx_init(int queue_len, phys_addr_t fifo,
+ 
+ 	return tsk;
+ }
++EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_init);
+ 
+ int
+ bcom_gen_bd_tx_reset(struct bcom_task *tsk)
+@@ -239,6 +243,7 @@ bcom_gen_bd_tx_reset(struct bcom_task *tsk)
+ 
+ 	return 0;
+ }
++EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_reset);
+ 
+ void
+ bcom_gen_bd_tx_release(struct bcom_task *tsk)
+@@ -246,15 +251,9 @@ bcom_gen_bd_tx_release(struct bcom_task *tsk)
+ 	/* Nothing special for the GenBD tasks */
+ 	bcom_task_release(tsk);
+ }
++EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_release);
+ 
+ 
+-EXPORT_SYMBOL(bcom_gen_bd_rx_init);
+-EXPORT_SYMBOL(bcom_gen_bd_rx_reset);
+-EXPORT_SYMBOL(bcom_gen_bd_rx_release);
+-EXPORT_SYMBOL(bcom_gen_bd_tx_init);
+-EXPORT_SYMBOL(bcom_gen_bd_tx_reset);
+-EXPORT_SYMBOL(bcom_gen_bd_tx_release);
+-
+ MODULE_DESCRIPTION("BestComm General Buffer Descriptor tasks driver");
+ MODULE_AUTHOR("Jeff Gibbons <jeff.gibbons at appspec.com>");
+ MODULE_LICENSE("GPL v2");
+-- 
+1.5.1.2
+

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0015-powerpc-BestComm-Replace-global-variable-bcom-by-b.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0015-powerpc-BestComm-Replace-global-variable-bcom-by-b.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,478 @@
+From a5aec9d8e0e2c317cbd2474880a420867ad58eb0 Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sun, 13 May 2007 14:26:36 +0200
+Subject: [PATCH 15/21] powerpc: BestComm, Replace global variable bcom by bcom_eng
+
+Since this is global and exported, this name is less likely
+to have collision problems.
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/sysdev/bestcomm/ata.c           |    8 +-
+ arch/powerpc/sysdev/bestcomm/bestcomm.c      |  110 +++++++++++++-------------
+ arch/powerpc/sysdev/bestcomm/bestcomm_priv.h |   22 +++---
+ arch/powerpc/sysdev/bestcomm/fec.c           |   12 ++--
+ arch/powerpc/sysdev/bestcomm/gen_bd.c        |   12 ++--
+ 5 files changed, 82 insertions(+), 82 deletions(-)
+
+diff --git a/arch/powerpc/sysdev/bestcomm/ata.c b/arch/powerpc/sysdev/bestcomm/ata.c
+index edc2049..39efb9b 100644
+--- a/arch/powerpc/sysdev/bestcomm/ata.c
++++ b/arch/powerpc/sysdev/bestcomm/ata.c
+@@ -77,7 +77,7 @@ bcom_ata_init(int queue_len, int maxbufsize)
+ 		return NULL;
+ 	}
+ 
+-	var->enable	= bcom->regs_base +
++	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);
+@@ -88,10 +88,10 @@ bcom_ata_init(int queue_len, int maxbufsize)
+ 	bcom_set_task_pragma(tsk->tasknum, BCOM_ATA_PRAGMA);
+ 	bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
+ 
+-	out_8(&bcom->regs->ipr[BCOM_INITIATOR_ATA_RX], BCOM_IPR_ATA_RX);
+-	out_8(&bcom->regs->ipr[BCOM_INITIATOR_ATA_TX], BCOM_IPR_ATA_TX);
++	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->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */
++	out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */
+ 
+ 	return tsk;
+ }
+diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.c b/arch/powerpc/sysdev/bestcomm/bestcomm.c
+index 589e37d..22684e7 100644
+--- a/arch/powerpc/sysdev/bestcomm/bestcomm.c
++++ b/arch/powerpc/sysdev/bestcomm/bestcomm.c
+@@ -29,8 +29,8 @@
+ #define DRIVER_NAME "bestcomm-core"
+ 
+ 
+-struct bcom_engine *bcom = NULL;
+-EXPORT_SYMBOL_GPL(bcom);	/* needed for inline functions */
++struct bcom_engine *bcom_eng = NULL;
++EXPORT_SYMBOL_GPL(bcom_eng);	/* needed for inline functions */
+ 
+ 
+ /* ======================================================================== */
+@@ -151,16 +151,16 @@ bcom_task_alloc(int bd_count, int bd_size, int priv_size)
+ 	struct bcom_task *tsk;
+ 
+ 	/* Get and reserve a task num */
+-	spin_lock(&bcom->lock);
++	spin_lock(&bcom_eng->lock);
+ 
+ 	for (i=0; i<BCOM_MAX_TASKS; i++)
+-		if (!bcom->tdt[i].stop) {	/* we use stop as a marker */
+-			bcom->tdt[i].stop = 0xfffffffful; /* dummy addr */
++		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->lock);
++	spin_unlock(&bcom_eng->lock);
+ 
+ 	if (tasknum < 0)
+ 		return NULL;
+@@ -175,7 +175,7 @@ bcom_task_alloc(int bd_count, int bd_size, int priv_size)
+ 		tsk->priv = (void*)tsk + sizeof(struct bcom_task);
+ 
+ 	/* Get IRQ of that task */
+-	tsk->irq = irq_of_parse_and_map(bcom->ofnode, tsk->tasknum);
++	tsk->irq = irq_of_parse_and_map(bcom_eng->ofnode, tsk->tasknum);
+ 	if (tsk->irq == NO_IRQ)
+ 		goto error;
+ 
+@@ -205,7 +205,7 @@ error:
+ 		kfree(tsk);
+ 	}
+ 
+-	bcom->tdt[tasknum].stop = 0;
++	bcom_eng->tdt[tasknum].stop = 0;
+ 
+ 	return NULL;
+ }
+@@ -218,8 +218,8 @@ bcom_task_release(struct bcom_task *tsk)
+ 	bcom_disable_task(tsk->tasknum);
+ 
+ 	/* Clear TDT */
+-	bcom->tdt[tsk->tasknum].start = 0;
+-	bcom->tdt[tsk->tasknum].stop  = 0;
++	bcom_eng->tdt[tsk->tasknum].start = 0;
++	bcom_eng->tdt[tsk->tasknum].stop  = 0;
+ 
+ 	/* Free everything */
+ 	irq_dispose_mapping(tsk->irq);
+@@ -251,7 +251,7 @@ bcom_load_image(int task, u32 *task_image)
+ 	}
+ 
+ 	/* Initial load or reload */
+-	tdt = &bcom->tdt[task];
++	tdt = &bcom_eng->tdt[task];
+ 
+ 	if (tdt->start) {
+ 		desc = bcom_task_desc(task);
+@@ -380,55 +380,55 @@ bcom_engine_init(void)
+ 	var_size = BCOM_MAX_TASKS * (BCOM_VAR_SIZE + BCOM_INC_SIZE);
+ 	fdt_size = BCOM_FDT_SIZE;
+ 
+-	bcom->tdt = bcom_sram_alloc(tdt_size, sizeof(u32), &tdt_pa);
+-	bcom->ctx = bcom_sram_alloc(ctx_size, BCOM_CTX_ALIGN, &ctx_pa);
+-	bcom->var = bcom_sram_alloc(var_size, BCOM_VAR_ALIGN, &var_pa);
+-	bcom->fdt = bcom_sram_alloc(fdt_size, BCOM_FDT_ALIGN, &fdt_pa);
++	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->tdt || !bcom->ctx || !bcom->var || !bcom->fdt) {
++	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->tdt);
+-		bcom_sram_free(bcom->ctx);
+-		bcom_sram_free(bcom->var);
+-		bcom_sram_free(bcom->fdt);
++		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->tdt, 0x00, tdt_size);
+-	memset(bcom->ctx, 0x00, ctx_size);
+-	memset(bcom->var, 0x00, var_size);
+-	memset(bcom->fdt, 0x00, fdt_size);
++	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->fdt[48], fdt_ops, sizeof(fdt_ops));
++	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->regs->tcr[task], 0);
+-		out_8(&bcom->regs->ipr[task], 0);
++		out_be16(&bcom_eng->regs->tcr[task], 0);
++		out_8(&bcom_eng->regs->ipr[task], 0);
+ 
+-		bcom->tdt[task].context	= ctx_pa;
+-		bcom->tdt[task].var	= var_pa;
+-		bcom->tdt[task].fdt	= fdt_pa;
++		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->regs->taskBar, tdt_pa);
++	out_be32(&bcom_eng->regs->taskBar, tdt_pa);
+ 
+ 	/* Init 'always' initiator */
+-	out_8(&bcom->regs->ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS);
++	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->regs->PtdCntrl, in_be16(&bcom->regs->PtdCntrl) | 1);
++	out_be16(&bcom_eng->regs->PtdCntrl, in_be16(&bcom_eng->regs->PtdCntrl) | 1);
+ 
+ 	/* Init lock */
+-	spin_lock_init(&bcom->lock);
++	spin_lock_init(&bcom_eng->lock);
+ 
+ 	return 0;
+ }
+@@ -441,17 +441,17 @@ bcom_engine_cleanup(void)
+ 	/* Stop all tasks */
+ 	for (task=0; task<BCOM_MAX_TASKS; task++)
+ 	{
+-		out_be16(&bcom->regs->tcr[task], 0);
+-		out_8(&bcom->regs->ipr[task], 0);
++		out_be16(&bcom_eng->regs->tcr[task], 0);
++		out_8(&bcom_eng->regs->ipr[task], 0);
+ 	}
+ 
+-	out_be32(&bcom->regs->taskBar, 0ul);
++	out_be32(&bcom_eng->regs->taskBar, 0ul);
+ 
+ 	/* Release the SRAM zones */
+-	bcom_sram_free(bcom->tdt);
+-	bcom_sram_free(bcom->ctx);
+-	bcom_sram_free(bcom->var);
+-	bcom_sram_free(bcom->fdt);
++	bcom_sram_free(bcom_eng->tdt);
++	bcom_sram_free(bcom_eng->ctx);
++	bcom_sram_free(bcom_eng->var);
++	bcom_sram_free(bcom_eng->fdt);
+ }
+ 
+ 
+@@ -497,8 +497,8 @@ mpc52xx_bcom_init(void)
+ 	}
+ 
+ 	/* Get a clean struct */
+-	bcom = kzalloc(sizeof(struct bcom_engine), GFP_KERNEL);
+-	if (!bcom) {
++	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;
+@@ -506,10 +506,10 @@ mpc52xx_bcom_init(void)
+ 	}
+ 
+ 	/* Save the node */
+-	bcom->ofnode = ofn_bcom;
++	bcom_eng->ofnode = ofn_bcom;
+ 
+ 	/* Get, reserve & map io */
+-	if (of_address_to_resource(bcom->ofnode, 0, &res_bcom)) {
++	if (of_address_to_resource(bcom_eng->ofnode, 0, &res_bcom)) {
+ 		printk(KERN_ERR DRIVER_NAME ": "
+ 			"Can't get resource\n");
+ 		rv = -EINVAL;
+@@ -524,9 +524,9 @@ mpc52xx_bcom_init(void)
+ 		goto error_sramclean;
+ 	}
+ 
+-	bcom->regs_base = res_bcom.start;
+-	bcom->regs = ioremap(res_bcom.start, sizeof(struct mpc52xx_sdma));
+-	if (!bcom->regs) {
++	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;
+@@ -540,19 +540,19 @@ mpc52xx_bcom_init(void)
+ 
+ 	/* Done ! */
+ 	printk(KERN_INFO "DMA: MPC52xx BestComm engine @%08lx ok !\n",
+-		bcom->regs_base);
++		bcom_eng->regs_base);
+ 
+ 	return 0;
+ 
+ 	/* Error path */
+ error_unmap:
+-	iounmap(bcom->regs);
++	iounmap(bcom_eng->regs);
+ error_release:
+ 	release_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma));
+ error_sramclean:
+ 	bcom_sram_cleanup();
+ error_ofput:
+-	of_node_put(bcom->ofnode);
++	of_node_put(bcom_eng->ofnode);
+ 
+ 	printk(KERN_ERR "DMA: MPC52xx BestComm init failed !\n");
+ 
+@@ -569,14 +569,14 @@ mpc52xx_bcom_exit(void)
+ 	bcom_sram_cleanup();
+ 
+ 	/* Release regs */
+-	iounmap(bcom->regs);
+-	release_mem_region(bcom->regs_base, sizeof(struct mpc52xx_sdma));
++	iounmap(bcom_eng->regs);
++	release_mem_region(bcom_eng->regs_base, sizeof(struct mpc52xx_sdma));
+ 
+ 	/* Release the node */
+-	of_node_put(bcom->ofnode);
++	of_node_put(bcom_eng->ofnode);
+ 
+ 	/* Release memory */
+-	kfree(bcom);
++	kfree(bcom_eng);
+ }
+ 
+ #ifdef MODULE
+diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h b/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h
+index d43b00a..6f33f0c 100644
+--- a/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h
++++ b/arch/powerpc/sysdev/bestcomm/bestcomm_priv.h
+@@ -68,7 +68,7 @@ struct bcom_engine {
+ 	spinlock_t			lock;
+ };
+ 
+-extern struct bcom_engine *bcom;
++extern struct bcom_engine *bcom_eng;
+ 
+ 
+ /* ======================================================================== */
+@@ -236,34 +236,34 @@ static inline void
+ bcom_enable_task(int task)
+ {
+         u16 reg;
+-        reg = in_be16(&bcom->regs->tcr[task]);
+-        out_be16(&bcom->regs->tcr[task],  reg | TASK_ENABLE);
++        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->regs->tcr[task]);
+-        out_be16(&bcom->regs->tcr[task], reg & ~TASK_ENABLE);
++        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->tdt[task].start);
++	return bcom_sram_pa2va(bcom_eng->tdt[task].start);
+ }
+ 
+ static inline int
+ bcom_task_num_descs(int task)
+ {
+-	return (bcom->tdt[task].stop - bcom->tdt[task].start)/sizeof(u32) + 1;
++	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->tdt[task].var);
++	return bcom_sram_pa2va(bcom_eng->tdt[task].var);
+ }
+ 
+ static inline u32 *
+@@ -302,21 +302,21 @@ bcom_set_desc_initiator(u32 *desc, int initiator)
+ static inline void
+ bcom_set_task_pragma(int task, int pragma)
+ {
+-	u32 *fdt = &bcom->tdt[task].fdt;
++	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->regs->tcr[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->regs->tcr[task];
++	u16 __iomem *tcr = &bcom_eng->regs->tcr[task];
+ 	out_be16(tcr, (in_be16(tcr) & ~0x1f00) | ((initiator & 0x1f) << 8));
+ }
+ 
+diff --git a/arch/powerpc/sysdev/bestcomm/fec.c b/arch/powerpc/sysdev/bestcomm/fec.c
+index 43f9551..1d7bf40 100644
+--- a/arch/powerpc/sysdev/bestcomm/fec.c
++++ b/arch/powerpc/sysdev/bestcomm/fec.c
+@@ -124,7 +124,7 @@ bcom_fec_rx_reset(struct bcom_task *tsk)
+ 	if (bcom_load_image(tsk->tasknum, bcom_fec_rx_task))
+ 		return -1;
+ 
+-	var->enable	= bcom->regs_base +
++	var->enable	= bcom_eng->regs_base +
+ 				offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);
+ 	var->fifo	= (u32) priv->fifo;
+ 	var->bd_base	= tsk->bd_pa;
+@@ -146,9 +146,9 @@ bcom_fec_rx_reset(struct bcom_task *tsk)
+ 	bcom_set_task_pragma(tsk->tasknum, BCOM_FEC_RX_BD_PRAGMA);
+ 	bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
+ 
+-	out_8(&bcom->regs->ipr[BCOM_INITIATOR_FEC_RX], BCOM_IPR_FEC_RX);
++	out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_FEC_RX], BCOM_IPR_FEC_RX);
+ 
+-	out_be32(&bcom->regs->IntPend, 1<<tsk->tasknum);	/* Clear ints */
++	out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum);	/* Clear ints */
+ 
+ 	return 0;
+ }
+@@ -225,7 +225,7 @@ bcom_fec_tx_reset(struct bcom_task *tsk)
+ 	if (bcom_load_image(tsk->tasknum, bcom_fec_tx_task))
+ 		return -1;
+ 
+-	var->enable	= bcom->regs_base +
++	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));
+@@ -247,9 +247,9 @@ bcom_fec_tx_reset(struct bcom_task *tsk)
+ 	bcom_set_task_pragma(tsk->tasknum, BCOM_FEC_TX_BD_PRAGMA);
+ 	bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
+ 
+-	out_8(&bcom->regs->ipr[BCOM_INITIATOR_FEC_TX], BCOM_IPR_FEC_TX);
++	out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_FEC_TX], BCOM_IPR_FEC_TX);
+ 
+-	out_be32(&bcom->regs->IntPend, 1<<tsk->tasknum);	/* Clear ints */
++	out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum);	/* Clear ints */
+ 
+ 	return 0;
+ }
+diff --git a/arch/powerpc/sysdev/bestcomm/gen_bd.c b/arch/powerpc/sysdev/bestcomm/gen_bd.c
+index 7e88681..4470482 100644
+--- a/arch/powerpc/sysdev/bestcomm/gen_bd.c
++++ b/arch/powerpc/sysdev/bestcomm/gen_bd.c
+@@ -131,7 +131,7 @@ bcom_gen_bd_rx_reset(struct bcom_task *tsk)
+ 	if (bcom_load_image(tsk->tasknum, bcom_gen_bd_rx_task))
+ 		return -1;
+ 
+-	var->enable	= bcom->regs_base +
++	var->enable	= bcom_eng->regs_base +
+ 				offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);
+ 	var->fifo	= (u32) priv->fifo;
+ 	var->bd_base	= tsk->bd_pa;
+@@ -152,10 +152,10 @@ bcom_gen_bd_rx_reset(struct bcom_task *tsk)
+ 	bcom_set_task_pragma(tsk->tasknum, BCOM_GEN_RX_BD_PRAGMA);
+ 	bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
+ 
+-	out_8(&bcom->regs->ipr[priv->initiator], priv->ipr);
++	out_8(&bcom_eng->regs->ipr[priv->initiator], priv->ipr);
+ 	bcom_set_initiator(tsk->tasknum, priv->initiator);
+ 
+-	out_be32(&bcom->regs->IntPend, 1<<tsk->tasknum);	/* Clear ints */
++	out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum);	/* Clear ints */
+ 
+ 	return 0;
+ }
+@@ -215,7 +215,7 @@ bcom_gen_bd_tx_reset(struct bcom_task *tsk)
+ 	if (bcom_load_image(tsk->tasknum, bcom_gen_bd_tx_task))
+ 		return -1;
+ 
+-	var->enable	= bcom->regs_base +
++	var->enable	= bcom_eng->regs_base +
+ 				offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);
+ 	var->fifo	= (u32) priv->fifo;
+ 	var->bd_base	= tsk->bd_pa;
+@@ -236,10 +236,10 @@ bcom_gen_bd_tx_reset(struct bcom_task *tsk)
+ 	bcom_set_task_pragma(tsk->tasknum, BCOM_GEN_TX_BD_PRAGMA);
+ 	bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
+ 
+-	out_8(&bcom->regs->ipr[priv->initiator], priv->ipr);
++	out_8(&bcom_eng->regs->ipr[priv->initiator], priv->ipr);
+ 	bcom_set_initiator(tsk->tasknum, priv->initiator);
+ 
+-	out_be32(&bcom->regs->IntPend, 1<<tsk->tasknum);	/* Clear ints */
++	out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum);	/* Clear ints */
+ 
+ 	return 0;
+ }
+-- 
+1.5.1.2
+

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0016-powerpc-Make-the-BestComm-driver-a-standard-of_plat.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0016-powerpc-Make-the-BestComm-driver-a-standard-of_plat.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,158 @@
+From 9277eb3bf88cc33e772be1505d6cb6af8fa87a9c Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sun, 13 May 2007 15:55:53 +0200
+Subject: [PATCH 16/21] powerpc: Make the BestComm driver a standard of_platform_driver
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/sysdev/bestcomm/bestcomm.c |   97 +++++++++++++++++++++++++------
+ 1 files changed, 78 insertions(+), 19 deletions(-)
+
+diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.c b/arch/powerpc/sysdev/bestcomm/bestcomm.c
+index 22684e7..68c8e39 100644
+--- a/arch/powerpc/sysdev/bestcomm/bestcomm.c
++++ b/arch/powerpc/sysdev/bestcomm/bestcomm.c
+@@ -21,6 +21,8 @@
+ #include <asm/irq.h>
+ #include <asm/prom.h>
+ #include <asm/mpc52xx.h>
++#include <asm/of_device.h>
++#include <asm/of_platform.h>
+ 
+ #include "sram.h"
+ #include "bestcomm_priv.h"
+@@ -456,27 +458,24 @@ bcom_engine_cleanup(void)
+ 
+ 
+ /* ======================================================================== */
+-/* System/Module init & cleanup                                             */
++/* OF platform driver                                                       */
+ /* ======================================================================== */
+ 
+-static int __init
+-mpc52xx_bcom_init(void)
++static int __devinit
++mpc52xx_bcom_probe(struct of_device *op, const struct of_device_id *match)
+ {
+ 	struct device_node *ofn_bcom, *ofn_sram;
+ 	struct resource res_bcom;
+ 
+ 	int rv;
+ 
+-	/* Find the bestcomm node. If none, fails 'silently' since
+-	 * we may just be on another platform */
+-	ofn_bcom = of_find_compatible_node(
+-			NULL, "dma-controller", "mpc5200-bestcomm");
+-	if (!ofn_bcom)
+-		return -ENODEV;
+-
+ 	/* Inform user we're ok so far */
+ 	printk(KERN_INFO "DMA: MPC52xx BestComm driver\n");
+ 
++	/* Get the bestcomm node */
++	ofn_bcom = op->node;
++	of_node_get(ofn_bcom);
++
+ 	/* Prepare SRAM */
+ 	ofn_sram = of_find_compatible_node(NULL, "sram", "mpc5200-sram");
+ 	if (!ofn_sram) {
+@@ -559,8 +558,9 @@ error_ofput:
+ 	return rv;
+ }
+ 
+-static void __exit
+-mpc52xx_bcom_exit(void)
++
++static int
++mpc52xx_bcom_remove(struct of_device *op)
+ {
+ 	/* Clean up the engine */
+ 	bcom_engine_cleanup();
+@@ -577,18 +577,77 @@ mpc52xx_bcom_exit(void)
+ 
+ 	/* Release memory */
+ 	kfree(bcom_eng);
++	bcom_eng = NULL;
++
++	return 0;
++}
++
++
++#ifdef CONFIG_PM
++
++static int
++mpc52xx_bcom_suspend(struct of_device *op, pm_message_t state)
++{
++	return 0;	/* FIXME : What to do here ? */
++}
++
++static int
++mpc52xx_bcom_resume(struct of_device *op)
++{
++	return 0;
+ }
+ 
+-#ifdef MODULE
+-module_init(mpc52xx_bcom_init);
+-module_exit(mpc52xx_bcom_exit);
+ #endif
+ 
+-/* If we're not a module, we must make sure everything is setup before anyone */
+-/* tries to use us ... */
+-#ifndef MODULE
+-subsys_initcall(mpc52xx_bcom_init);
++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,
++#ifdef CONFIG_PM
++	.suspend	= mpc52xx_bcom_suspend,
++	.resume		= mpc52xx_bcom_resume,
+ #endif
++	.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 at 246tNt.com>");
+-- 
+1.5.1.2
+

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0017-powerpc-Fix-typo-in-BestComm-ATA-task-support-code.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0017-powerpc-Fix-typo-in-BestComm-ATA-task-support-code.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,26 @@
+From a24fc73896e9ff7d22a8a3a9e463a28124c60045 Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sun, 13 May 2007 15:57:21 +0200
+Subject: [PATCH 17/21] powerpc: Fix typo in BestComm ATA task support code
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/sysdev/bestcomm/ata.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/arch/powerpc/sysdev/bestcomm/ata.c b/arch/powerpc/sysdev/bestcomm/ata.c
+index 39efb9b..4b213b1 100644
+--- a/arch/powerpc/sysdev/bestcomm/ata.c
++++ b/arch/powerpc/sysdev/bestcomm/ata.c
+@@ -67,7 +67,7 @@ bcom_ata_init(int queue_len, int maxbufsize)
+ 
+ 	tsk->flags = BCOM_FLAGS_NONE;
+ 
+-	bcom_ata_reset(tsk);
++	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);
+-- 
+1.5.1.2
+

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0018-powerpc-BestComm-ATA-task-microcode-insert-copyri.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0018-powerpc-BestComm-ATA-task-microcode-insert-copyri.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,33 @@
+From 31817e372ae7f351e7b02c41d9e4235f41d76153 Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sun, 13 May 2007 16:07:33 +0200
+Subject: [PATCH 18/21] powerpc: BestComm ATA task microcode : insert copyright & licence
+
+The original licence is MIT/X11, so it's GPL compatible and allows
+to sublicence to GPL.
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/sysdev/bestcomm/bcom_ata_task.c |    6 ++++++
+ 1 files changed, 6 insertions(+), 0 deletions(-)
+
+diff --git a/arch/powerpc/sysdev/bestcomm/bcom_ata_task.c b/arch/powerpc/sysdev/bestcomm/bcom_ata_task.c
+index 779cebb..cc6049a 100644
+--- a/arch/powerpc/sysdev/bestcomm/bcom_ata_task.c
++++ b/arch/powerpc/sysdev/bestcomm/bcom_ata_task.c
+@@ -1,6 +1,12 @@
+ /*
+  * 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
+  */
+ 
+-- 
+1.5.1.2
+

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0019-powerpc-BestComm-FEC-task-microcode-insert-copyri.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0019-powerpc-BestComm-FEC-task-microcode-insert-copyri.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,51 @@
+From a29445729ca5ee48d76fe142e859640050ffab79 Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sun, 13 May 2007 16:08:51 +0200
+Subject: [PATCH 19/21] powerpc: BestComm FEC task microcode : insert copyright & licence
+
+The original licence is MIT/X11, so it's GPL compatible and allows
+to sublicence to GPL.
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/sysdev/bestcomm/bcom_fec_rx_task.c |    6 ++++++
+ arch/powerpc/sysdev/bestcomm/bcom_fec_tx_task.c |    6 ++++++
+ 2 files changed, 12 insertions(+), 0 deletions(-)
+
+diff --git a/arch/powerpc/sysdev/bestcomm/bcom_fec_rx_task.c b/arch/powerpc/sysdev/bestcomm/bcom_fec_rx_task.c
+index 48bae92..a1ad6a0 100644
+--- a/arch/powerpc/sysdev/bestcomm/bcom_fec_rx_task.c
++++ b/arch/powerpc/sysdev/bestcomm/bcom_fec_rx_task.c
+@@ -1,6 +1,12 @@
+ /*
+  * 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
+  */
+diff --git a/arch/powerpc/sysdev/bestcomm/bcom_fec_tx_task.c b/arch/powerpc/sysdev/bestcomm/bcom_fec_tx_task.c
+index 8c5aa83..b1c495c 100644
+--- a/arch/powerpc/sysdev/bestcomm/bcom_fec_tx_task.c
++++ b/arch/powerpc/sysdev/bestcomm/bcom_fec_tx_task.c
+@@ -1,6 +1,12 @@
+ /*
+  * 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
+  */
+-- 
+1.5.1.2
+

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0020-powerpc-BestComm-GenBD-task-microcode-insert-copy.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0020-powerpc-BestComm-GenBD-task-microcode-insert-copy.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,41 @@
+From 6a8eba98e6331cf1ca260eb60052da65164c49bd Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sun, 13 May 2007 16:09:57 +0200
+Subject: [PATCH 20/21] powerpc: BestComm GenBD task microcode : insert copyright & licence
+
+The original licence is MIT/X11, so it's GPL compatible and allows
+to sublicence to GPL.
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/sysdev/bestcomm/bcom_gen_bd_rx_task.c |    1 +
+ arch/powerpc/sysdev/bestcomm/bcom_gen_bd_tx_task.c |    1 +
+ 2 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_rx_task.c b/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_rx_task.c
+index f356886..efee022 100644
+--- a/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_rx_task.c
++++ b/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_rx_task.c
+@@ -3,6 +3,7 @@
+  *
+  * Copyright (C) 2006 AppSpec Computer Technologies Corp.
+  *                    Jeff Gibbons <jeff.gibbons at 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
+diff --git a/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_tx_task.c b/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_tx_task.c
+index 7460c39..c605aa4 100644
+--- a/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_tx_task.c
++++ b/arch/powerpc/sysdev/bestcomm/bcom_gen_bd_tx_task.c
+@@ -3,6 +3,7 @@
+  *
+  * Copyright (C) 2006 AppSpec Computer Technologies Corp.
+  *                    Jeff Gibbons <jeff.gibbons at 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
+-- 
+1.5.1.2
+

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0021-powerpc-Fix-errors-in-bcom-bcom_eng-renaming.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0021-powerpc-Fix-errors-in-bcom-bcom_eng-renaming.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,48 @@
+From 5fa3ca52844b7ae6d70e71d6f7892e85e44a394f Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sun, 13 May 2007 16:12:23 +0200
+Subject: [PATCH 21/21] powerpc: Fix errors in bcom -> bcom_eng renaming.
+
+At some point I reversed too many changes and forgot to
+reapply the renaming to the debug functions ...
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/sysdev/bestcomm/bestcomm.c |   10 +++++-----
+ 1 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.c b/arch/powerpc/sysdev/bestcomm/bestcomm.c
+index 68c8e39..10fb476 100644
+--- a/arch/powerpc/sysdev/bestcomm/bestcomm.c
++++ b/arch/powerpc/sysdev/bestcomm/bestcomm.c
+@@ -47,10 +47,10 @@ void
+ bcom_dump_status(void)
+ {
+ 	int i;
+-	struct mpc52xx_sdma __iomem *r = bcom->regs;
++	struct mpc52xx_sdma __iomem *r = bcom_eng->regs;
+ 
+ 	BCOM_DPRINTK("BestComm status dump (pa=%08lx, va=%p)\n",
+-			bcom->regs_base, bcom->regs);
++			bcom_eng->regs_base, bcom_eng->regs);
+ 	BCOM_DPRINTK(" taskBar         = %08x\n", in_be32(&r->taskBar));
+ 	BCOM_DPRINTK(" currentPointer  = %08x\n", in_be32(&r->currentPointer));
+ 	BCOM_DPRINTK(" endPointer      = %08x\n", in_be32(&r->endPointer));
+@@ -97,11 +97,11 @@ bcom_dump_task(int task)
+ {
+ 	int i;
+ 	u32 *p;
+-	struct bcom_tdt *tdt = &bcom->tdt[task];
++	struct bcom_tdt *tdt = &bcom_eng->tdt[task];
+ 
+ 	BCOM_DPRINTK("Task dump %d\n", task);
+-	BCOM_DPRINTK(" tcr          = %04hx\n", bcom->regs->tcr[task]);
+-	BCOM_DPRINTK(" tdt          = %p\n", &bcom->tdt[task]);
++	BCOM_DPRINTK(" tcr          = %04hx\n", bcom_eng->regs->tcr[task]);
++	BCOM_DPRINTK(" tdt          = %p\n", &bcom_eng->tdt[task]);
+ 	BCOM_DPRINTK(" tdt->start   = %08x\n", tdt->start);
+ 	BCOM_DPRINTK(" tdt->stop    = %08x\n", tdt->stop);
+ 	BCOM_DPRINTK(" tdt->var     = %08x\n", tdt->var);
+-- 
+1.5.1.2
+

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0081-mpc52xx-correct-calculation-of-FEC-RX-errors.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0081-mpc52xx-correct-calculation-of-FEC-RX-errors.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,14 @@
+--- a/drivers/net/fec_mpc52xx/fec.c 2007-05-30 16:04:50.000000000 +0200
++++ b/drivers/net/fec_mpc52xx/fec.c 2007-05-30 16:09:02.000000000 +0200
+@@ -411,7 +411,9 @@
+ 
+ 	stats->rx_bytes = in_be32(&fec->rmon_r_octets);
+ 	stats->rx_packets = in_be32(&fec->rmon_r_packets);
+-	stats->rx_errors = stats->rx_packets - in_be32(&fec->ieee_r_frame_ok);
++	stats->rx_errors = stats->rx_packets - (
++			in_be32(&fec->ieee_r_frame_ok) +
++			in_be32(&fec->rmon_r_mc_pkt));
+ 	stats->tx_bytes = in_be32(&fec->rmon_t_octets);
+ 	stats->tx_packets = in_be32(&fec->rmon_t_packets);
+ 	stats->tx_errors = stats->tx_packets - (
+

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0082-powerpc-pata_mpc52xx-suspend.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/0082-powerpc-pata_mpc52xx-suspend.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,32 @@
+--- a/drivers/ata/pata_mpc52xx.c
++++ b/drivers/ata/pata_mpc52xx.c
+@@ -467,13 +467,27 @@ mpc52xx_ata_remove(struct of_device *op)
+ static int
+ mpc52xx_ata_suspend(struct of_device *op, pm_message_t state)
+ {
+-	return 0;	/* FIXME : What to do here ? */
++	struct ata_host *host = dev_get_drvdata(&op->dev);
++
++	return ata_host_suspend(host, state);
+ }
+
+ static int
+ mpc52xx_ata_resume(struct of_device *op)
+ {
+-	return 0;	/* FIXME : What to do here ? */
++	struct ata_host *host = dev_get_drvdata(&op->dev);
++	struct mpc52xx_ata_priv *priv = host->private_data;
++	int rv;
++
++	rv = mpc52xx_ata_hw_init(priv);
++	if (rv) {
++		printk(KERN_ERR DRV_NAME ": Error during HW init\n");
++		return rv;
++	}
++
++	ata_host_resume(host);
++
++	return 0;
+ }
+
+ #endif

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/extra/11303_Fix_mpc52xx_uart_of_assign_to_use_correct_index.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/extra/11303_Fix_mpc52xx_uart_of_assign_to_use_correct_index.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,20 @@
+Use idx as index into mpc52xx_uart_nodes instead of i
+
+Signed-off-by: John Rigby <jrigby at freescale.com>
+---
+ drivers/serial/mpc52xx_uart.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
+index 3cc2fb9..0648017 100644
+--- a/drivers/serial/mpc52xx_uart.c
++++ b/drivers/serial/mpc52xx_uart.c
+@@ -1114,7 +1114,7 @@ mpc52xx_uart_of_assign(struct device_node *np, int idx)
+ 	/* If the slot is already occupied, then swap slots */
+ 	if (mpc52xx_uart_nodes[idx] && (free_idx != -1))
+ 		mpc52xx_uart_nodes[free_idx] = mpc52xx_uart_nodes[idx];
+-	mpc52xx_uart_nodes[i] = np;
++	mpc52xx_uart_nodes[idx] = np;
+ }
+ 
+ static void

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/extra/11675_mpc5200_rtc_driver.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/extra/11675_mpc5200_rtc_driver.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,386 @@
+Driver for internal rtc on mpc5200.
+It isn't very useful, since its contents don't remain on
+power off.
+Can be used to set alarm for wake-up from deep-sleep or
+one second periodic interrupt ;-)
+
+
+Signed-off-by: Domen Puncer <domen.puncer at telargo.com>
+
+---
+ drivers/rtc/Kconfig               |   10 +
+ drivers/rtc/Makefile              |    1 
+ drivers/rtc/rtc-mpc5200.c         |  282 ++++++++++++++++++++++++++++++++++++++
+ include/asm-powerpc/mpc5200_rtc.h |   49 ++++++
+ 4 files changed, 342 insertions(+)
+
+Index: work-powerpc.git/drivers/rtc/Kconfig
+===================================================================
+--- work-powerpc.git.orig/drivers/rtc/Kconfig
++++ work-powerpc.git/drivers/rtc/Kconfig
+@@ -401,4 +401,14 @@ config RTC_DRV_RS5C313
+ 	help
+ 	  If you say yes here you get support for the Ricoh RS5C313 RTC chips.
+ 
++config RTC_DRV_MPC5200
++	tristate "MPC5200 RTC"
++	depends on RTC_CLASS
++	help
++	  If you say yes here you will get support for the
++	  RTC built in MPC5200(b) CPU.
++
++	  This driver can also be built as a module. If so, the module
++	  will be called rtc-mpc5200.
++
+ endmenu
+Index: work-powerpc.git/drivers/rtc/Makefile
+===================================================================
+--- work-powerpc.git.orig/drivers/rtc/Makefile
++++ work-powerpc.git/drivers/rtc/Makefile
+@@ -41,3 +41,4 @@ obj-$(CONFIG_RTC_DRV_V3020)	+= rtc-v3020
+ obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
+ obj-$(CONFIG_RTC_DRV_SH)	+= rtc-sh.o
+ obj-$(CONFIG_RTC_DRV_BFIN)	+= rtc-bfin.o
++obj-$(CONFIG_RTC_DRV_MPC5200)	+= rtc-mpc5200.o
+Index: work-powerpc.git/drivers/rtc/rtc-mpc5200.c
+===================================================================
+--- /dev/null
++++ work-powerpc.git/drivers/rtc/rtc-mpc5200.c
+@@ -0,0 +1,282 @@
++#include <linux/module.h>
++#include <linux/rtc.h>
++#include <asm/of_device.h>
++#include <asm/of_platform.h>
++#include <asm/io.h>
++#include <asm/mpc52xx.h>
++#include <asm/mpc5200_rtc.h>
++
++
++struct mpc5200_rtc_data {
++	unsigned irq;
++	unsigned irq_periodic;
++	struct mpc52xx_rtc __iomem *regs;
++	struct rtc_device *rtc;
++};
++
++static int mpc5200_rtc_read_time(struct device *dev, struct rtc_time *tm)
++{
++	struct mpc5200_rtc_data *rtc = dev_get_drvdata(dev);
++	struct mpc52xx_rtc __iomem *regs = rtc->regs;
++	int tmp;
++
++	tm->tm_sec = in_8(&regs->second);
++	tm->tm_min = in_8(&regs->minute);
++
++	/* 12 hour format? */
++	if (in_8(&regs->hour) & 0x20)
++		tm->tm_hour = (in_8(&regs->hour) >> 1) + (in_8(&regs->hour) & 1 ? 12 : 0);
++	else
++		tm->tm_hour = in_8(&regs->hour);
++
++	tmp = in_8(&regs->wday_mday);
++	tm->tm_mday = tmp & 0x1f;
++	tm->tm_mon = in_8(&regs->month) - 1;
++	tm->tm_year = in_be16(&regs->year) - 1900;
++	tm->tm_wday = (tmp >> 5) % 7;
++	tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
++	tm->tm_isdst = 0;
++
++	return 0;
++}
++
++static int mpc5200_rtc_set_time(struct device *dev, struct rtc_time *tm)
++{
++	struct mpc5200_rtc_data *rtc = dev_get_drvdata(dev);
++	struct mpc52xx_rtc __iomem *regs = rtc->regs;
++
++	/* time */
++	out_8(&regs->second_set, tm->tm_sec);
++	out_8(&regs->minute_set, tm->tm_min);
++	out_8(&regs->hour_set, tm->tm_hour);
++
++	/* set time sequence */
++	out_8(&regs->set_time, 0x1);
++	out_8(&regs->set_time, 0x3);
++	out_8(&regs->set_time, 0x1);
++	out_8(&regs->set_time, 0x0);
++
++	/* date */
++	out_8(&regs->month_set, tm->tm_mon + 1);
++	out_8(&regs->weekday_set, tm->tm_wday ? tm->tm_wday : 7);
++	out_8(&regs->date_set, tm->tm_mday);
++	out_be16(&regs->year_set, tm->tm_year + 1900);
++
++	/* set date sequence */
++	out_8(&regs->set_date, 0x1);
++	out_8(&regs->set_date, 0x3);
++	out_8(&regs->set_date, 0x1);
++	out_8(&regs->set_date, 0x0);
++
++	return 0;
++}
++
++static int mpc5200_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
++{
++	struct mpc5200_rtc_data *rtc = dev_get_drvdata(dev);
++	struct mpc52xx_rtc __iomem *regs = rtc->regs;
++
++	alrm->time.tm_sec = -1;
++	alrm->time.tm_min = in_8(&regs->alm_min_set);
++	alrm->time.tm_hour = in_8(&regs->alm_hour_set);
++
++	alrm->time.tm_mday = -1;
++	alrm->time.tm_mon = -1;
++	alrm->time.tm_year = -1;
++
++	alrm->enabled = in_8(&regs->alm_enable);
++	alrm->pending = in_8(&regs->alm_status);
++
++	return 0;
++}
++
++static int mpc5200_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
++{
++	struct mpc5200_rtc_data *rtc = dev_get_drvdata(dev);
++	struct mpc52xx_rtc __iomem *regs = rtc->regs;
++
++	out_8(&regs->alm_min_set, alrm->time.tm_min);
++	out_8(&regs->alm_hour_set, alrm->time.tm_hour);
++
++	out_8(&regs->alm_enable, alrm->enabled);
++
++	return 0;
++}
++
++static irqreturn_t rtc_handler(int irq, void *dev)
++{
++	struct mpc5200_rtc_data *rtc = dev_get_drvdata((struct device *)dev);
++	struct mpc52xx_rtc __iomem *regs = rtc->regs;
++
++	if (in_8(&regs->int_alm)) {
++		/* acknowledge */
++		out_8(&regs->int_alm, 1);
++
++		rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
++		return IRQ_HANDLED;
++	}
++
++	return IRQ_NONE;
++}
++
++static irqreturn_t rtc_handler_upd(int irq, void *dev)
++{
++	struct mpc5200_rtc_data *rtc = dev_get_drvdata((struct device *)dev);
++	struct mpc52xx_rtc __iomem *regs = rtc->regs;
++
++	if (in_8(&regs->int_sec) && (in_8(&regs->int_enable) & 0x1)) {
++		/* acknowledge */
++		out_8(&regs->int_sec, 1);
++
++		rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_UF);
++		return IRQ_HANDLED;
++	}
++
++	return IRQ_NONE;
++}
++
++static int mpc5200_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
++{
++	struct mpc5200_rtc_data *rtc = dev_get_drvdata(dev);
++	struct mpc52xx_rtc __iomem *regs = rtc->regs;
++
++	switch (cmd) {
++	/* alarm interrupt */
++	case RTC_AIE_ON:
++		out_8(&regs->alm_enable, 1);
++		break;
++	case RTC_AIE_OFF:
++		out_8(&regs->alm_enable, 0);
++		break;
++
++	/* update interrupt (periodic second in mpc5200 words) */
++	case RTC_UIE_ON:
++		out_8(&regs->int_enable, (in_8(&regs->int_enable) & ~0x8) | 0x1);
++		break;
++	case RTC_UIE_OFF:
++		out_8(&regs->int_enable, in_8(&regs->int_enable) & ~0x1);
++		break;
++
++	/* no periodic interrupts */
++	case RTC_IRQP_READ:
++	case RTC_IRQP_SET:
++		return -ENOTTY;
++
++	default:
++		return -ENOIOCTLCMD;
++	}
++	return 0;
++}
++
++static const struct rtc_class_ops mpc5200_rtc_ops = {
++	.read_time	= mpc5200_rtc_read_time,
++	.set_time	= mpc5200_rtc_set_time,
++	.read_alarm	= mpc5200_rtc_read_alarm,
++	.set_alarm	= mpc5200_rtc_set_alarm,
++	.ioctl		= mpc5200_rtc_ioctl,
++};
++
++static int __devinit mpc5200_rtc_probe(struct of_device *op, const struct of_device_id *match)
++{
++	struct mpc5200_rtc_data *rtc;
++	int err = 0;
++
++	rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
++	if (!rtc) {
++		err = -ENOMEM;
++		goto out;
++	}
++
++	rtc->regs = mpc52xx_find_and_map("mpc5200-rtc");
++	if (!rtc->regs) {
++		printk(KERN_ERR "%s: couldn't map io space\n", __func__);
++		err = -ENOSYS;
++		goto out_free;
++	}
++
++	rtc->rtc = rtc_device_register("mpc5200-rtc", &op->dev,
++			&mpc5200_rtc_ops, THIS_MODULE);
++	if (IS_ERR(rtc->rtc)) {
++		err = PTR_ERR(rtc->rtc);
++		goto out_unmap;
++	}
++
++	dev_set_drvdata(&op->dev, rtc);
++
++	rtc->irq = irq_of_parse_and_map(op->node, 1);
++	if ((err = request_irq(rtc->irq, rtc_handler, IRQF_DISABLED, "mpc5200-rtc", &op->dev))) {
++		printk(KERN_ERR "%s: could not request irq: %i\n", __func__, rtc->irq);
++		goto out_dispose;
++	}
++
++	rtc->irq_periodic = irq_of_parse_and_map(op->node, 0);
++	if ((err = request_irq(rtc->irq_periodic, rtc_handler_upd, IRQF_DISABLED,
++					"mpc5200-rtc_upd", &op->dev))) {
++		printk(KERN_ERR "%s: could not request irq: %i\n", __func__, rtc->irq_periodic);
++		goto out_dispose2;
++	}
++
++	goto out;
++
++ out_dispose2:
++	irq_dispose_mapping(rtc->irq_periodic);
++	free_irq(rtc->irq, &op->dev);
++ out_dispose:
++	irq_dispose_mapping(rtc->irq);
++ out_unmap:
++	iounmap(rtc->regs);
++ out_free:
++	kfree(rtc);
++ out:
++	return err;
++}
++
++static int __devexit mpc5200_rtc_remove(struct of_device *op)
++{
++	struct mpc5200_rtc_data *rtc = dev_get_drvdata(&op->dev);
++	struct mpc52xx_rtc __iomem *regs = rtc->regs;
++
++	/* disable interrupt, so there are no nasty surprises */
++	out_8(&regs->alm_enable, 0);
++	out_8(&regs->int_enable, in_8(&regs->int_enable) & ~0x1);
++
++	rtc_device_unregister(rtc->rtc);
++	iounmap(rtc->regs);
++	free_irq(rtc->irq, &op->dev);
++	free_irq(rtc->irq_periodic, &op->dev);
++	irq_dispose_mapping(rtc->irq);
++	irq_dispose_mapping(rtc->irq_periodic);
++	kfree(rtc);
++	dev_set_drvdata(&op->dev, NULL);
++
++	return 0;
++}
++
++static struct of_device_id mpc5200_rtc_match[] = {
++	{ .type = "rtc", .compatible = "mpc5200-rtc", },
++	{},
++};
++
++static struct of_platform_driver mpc5200_rtc_driver = {
++	.owner		= THIS_MODULE,
++	.name		= "mpc5200-rtc",
++	.match_table	= mpc5200_rtc_match,
++	.probe		= mpc5200_rtc_probe,
++	.remove		= mpc5200_rtc_remove,
++};
++
++static int __init mpc5200_rtc_init(void)
++{
++	return of_register_platform_driver(&mpc5200_rtc_driver);
++}
++
++static void __exit mpc5200_rtc_exit(void)
++{
++	of_unregister_platform_driver(&mpc5200_rtc_driver);
++}
++
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_AUTHOR("Domen Puncer <domen.puncer at telargo.com>");
++
++module_init(mpc5200_rtc_init);
++module_exit(mpc5200_rtc_exit);
+Index: work-powerpc.git/include/asm-powerpc/mpc5200_rtc.h
+===================================================================
+--- /dev/null
++++ work-powerpc.git/include/asm-powerpc/mpc5200_rtc.h
+@@ -0,0 +1,49 @@
++#ifndef _MPC5200_RTC_H_
++#define _MPC5200_RTC_H_
++
++/* RTC */
++struct mpc52xx_rtc {
++	u8	set_time;	/* RTC + 0x00 */
++	u8	hour_set;	/* RTC + 0x01 */
++	u8	minute_set;	/* RTC + 0x02 */
++	u8	second_set;	/* RTC + 0x03 */
++
++	u8	set_date;	/* RTC + 0x04 */
++	u8	month_set;	/* RTC + 0x05 */
++	u8	weekday_set;	/* RTC + 0x06 */
++	u8	date_set;	/* RTC + 0x07 */
++
++	u8	write_sw;	/* RTC + 0x08 */
++	u8	sw_set;		/* RTC + 0x09 */
++	u16	year_set;	/* RTC + 0x0a */
++
++	u8	alm_enable;	/* RTC + 0x0c */
++	u8	alm_hour_set;	/* RTC + 0x0d */
++	u8	alm_min_set;	/* RTC + 0x0e */
++	u8 	int_enable;	/* RTC + 0x0f */
++
++	u8	reserved1;
++	u8	hour;		/* RTC + 0x11 */
++	u8	minute;		/* RTC + 0x12 */
++	u8	second;		/* RTC + 0x13 */
++
++	u8	month;		/* RTC + 0x14 */
++	u8	wday_mday;	/* RTC + 0x15 */
++	u16	year;		/* RTC + 0x16 */
++
++	u8	int_alm;	/* RTC + 0x18 */
++	u8	int_sw;		/* RTC + 0x19 */
++	u8	alm_status;	/* RTC + 0x1a */
++	u8	sw_minute;	/* RTC + 0x1b */
++
++	u8	bus_error_1;	/* RTC + 0x1c */
++	u8	int_day;	/* RTC + 0x1d */
++	u8	int_min;	/* RTC + 0x1e */
++	u8	int_sec;	/* RTC + 0x1f */
++
++	u8	pterm;		/* RTC + 0x20 */
++	u8	eterm;		/* RTC + 0x21 */
++	u16	reserved2;
++};
++
++#endif /* _MPC5200_RTC_H_ */
+_______________________________________________

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/extra/11861_mpc52xx_sparse_fixes.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/extra/11861_mpc52xx_sparse_fixes.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,80 @@
+sparse caught these static functions / __iomem annotations
+under arch/powerpc/platform/52xx/
+
+
+Signed-off-by: Domen Puncer <domen.puncer at telargo.com>
+
+---
+ arch/powerpc/platforms/52xx/efika.c      |    4 ++--
+ arch/powerpc/platforms/52xx/lite5200.c   |    2 +-
+ arch/powerpc/platforms/52xx/mpc52xx_pm.c |    8 ++++----
+ 3 files changed, 7 insertions(+), 7 deletions(-)
+
+Index: work-powerpc.git/arch/powerpc/platforms/52xx/efika.c
+===================================================================
+--- work-powerpc.git.orig/arch/powerpc/platforms/52xx/efika.c
++++ work-powerpc.git/arch/powerpc/platforms/52xx/efika.c
+@@ -83,7 +83,7 @@ static struct pci_ops rtas_pci_ops = {
+ };
+ 
+ 
+-void __init efika_pcisetup(void)
++static void __init efika_pcisetup(void)
+ {
+ 	const int *bus_range;
+ 	int len;
+@@ -145,7 +145,7 @@ void __init efika_pcisetup(void)
+ }
+ 
+ #else
+-void __init efika_pcisetup(void)
++static void __init efika_pcisetup(void)
+ {}
+ #endif
+ 
+Index: work-powerpc.git/arch/powerpc/platforms/52xx/lite5200.c
+===================================================================
+--- work-powerpc.git.orig/arch/powerpc/platforms/52xx/lite5200.c
++++ work-powerpc.git/arch/powerpc/platforms/52xx/lite5200.c
+@@ -158,7 +158,7 @@ static void __init lite5200_setup_arch(v
+ 
+ }
+ 
+-void lite5200_show_cpuinfo(struct seq_file *m)
++static void lite5200_show_cpuinfo(struct seq_file *m)
+ {
+ 	struct device_node* np = of_find_all_nodes(NULL);
+ 	const char *model = NULL;
+Index: work-powerpc.git/arch/powerpc/platforms/52xx/mpc52xx_pm.c
+===================================================================
+--- work-powerpc.git.orig/arch/powerpc/platforms/52xx/mpc52xx_pm.c
++++ work-powerpc.git/arch/powerpc/platforms/52xx/mpc52xx_pm.c
+@@ -9,8 +9,8 @@
+ 
+ 
+ /* these are defined in mpc52xx_sleep.S, and only used here */
+-extern void mpc52xx_deep_sleep(void *sram, void *sdram_regs,
+-		struct mpc52xx_cdm *, struct mpc52xx_intr *);
++extern void mpc52xx_deep_sleep(void __iomem *sram, void __iomem *sdram_regs,
++		struct mpc52xx_cdm __iomem *, struct mpc52xx_intr __iomem*);
+ extern void mpc52xx_ds_sram(void);
+ extern const long mpc52xx_ds_sram_size;
+ extern void mpc52xx_ds_cached(void);
+@@ -21,7 +21,7 @@ static void __iomem *sdram;
+ static struct mpc52xx_cdm __iomem *cdm;
+ static struct mpc52xx_intr __iomem *intr;
+ static struct mpc52xx_gpio_wkup __iomem *gpiow;
+-static void *sram;
++static void __iomem *sram;
+ static int sram_size;
+ 
+ struct mpc52xx_suspend mpc52xx_suspend;
+@@ -100,7 +100,7 @@ int mpc52xx_pm_enter(suspend_state_t sta
+ 	u32 clk_enables;
+ 	u32 msr, hid0;
+ 	u32 intr_main_mask;
+-	void __iomem * irq_0x500 = (void *)CONFIG_KERNEL_START + 0x500;
++	void __iomem * irq_0x500 = (void __iomem *)CONFIG_KERNEL_START + 0x500;
+ 	unsigned long irq_0x500_stop = (unsigned long)irq_0x500 + mpc52xx_ds_cached_size;
+ 	char saved_0x500[mpc52xx_ds_cached_size];
+ 

Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/extra/12626_mpx5200_uart_drop_port_lock_across_tty_flip_buffer_call.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/extra/12626_mpx5200_uart_drop_port_lock_across_tty_flip_buffer_call.patch	Fri Jul 27 20:59:31 2007
@@ -0,0 +1,21 @@
+The port lock needs to be dropped across the tty_flip_buffer call, as it
+would lead to a deadlock with the spin_lock(&port->lock) in uart_start()
+
+Uncovered by lockdep / preempt-rt
+
+Signed-off-by: Thomas Gleixner <tglx at linutronix.de>
+
+Index: linux-2.6.22/drivers/serial/mpc52xx_uart.c
+===================================================================
+--- linux-2.6.22.orig/drivers/serial/mpc52xx_uart.c	2007-07-09 01:32:17.000000000 +0200
++++ linux-2.6.22/drivers/serial/mpc52xx_uart.c	2007-07-25 21:06:11.000000000 +0200
+@@ -501,7 +501,9 @@ mpc52xx_uart_int_rx_chars(struct uart_po
+ 		}
+ 	}
+ 
++	spin_unlock(&port->lock);
+ 	tty_flip_buffer_push(tty);
++	spin_lock(&port->lock);
+ 
+ 	return in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY;
+ }

Modified: dists/sid/linux-2.6/debian/patches/series/3
==============================================================================
--- dists/sid/linux-2.6/debian/patches/series/3	(original)
+++ dists/sid/linux-2.6/debian/patches/series/3	Fri Jul 27 20:59:31 2007
@@ -1 +1,28 @@
++ features/powerpc/efika/0001-powerpc-exports-rheap-symbol-to-modules.patch
++ features/powerpc/efika/0002-powerpc-Changes-the-config-mechanism-for-rheap.patch
++ features/powerpc/efika/0003-powerpc-ppc32-Update-mpc52xx_psc-structure-with-B-r.patch
++ features/powerpc/efika/0004-powerpc-BestComm-core-support-for-Freescale-MPC5200.patch
++ features/powerpc/efika/0005-powerpc-BestcComm-ATA-task-support.patch
++ features/powerpc/efika/0006-powerpc-BestcComm-FEC-task-support.patch
++ features/powerpc/efika/0007-powerpc-BestcComm-GenBD-task-support.patch
++ features/powerpc/efika/0008-drivers-net-Add-support-for-Freescale-MPC5200-SoC-i.patch
++ features/powerpc/efika/0009-sound-Add-support-for-Freescale-MPC5200-AC97-interf.patch
++ features/powerpc/efika/0010-powerpc-In-rheap.c-move-the-EXPORT_SYMBOL-and-use.patch
++ features/powerpc/efika/0011-powerpc-BestComm-move-the-EXPORT_SYMBOL-and-use-th.patch
++ features/powerpc/efika/0012-powerpc-BestComm-ATA-task-move-the-EXPORT_SYMBOL-a.patch
++ features/powerpc/efika/0013-powerpc-BestComm-FEC-task-move-the-EXPORT_SYMBOL-a.patch
++ features/powerpc/efika/0014-powerpc-BestComm-GenBD-task-move-the-EXPORT_SYMBOL.patch
++ features/powerpc/efika/0015-powerpc-BestComm-Replace-global-variable-bcom-by-b.patch
++ features/powerpc/efika/0016-powerpc-Make-the-BestComm-driver-a-standard-of_plat.patch
++ features/powerpc/efika/0017-powerpc-Fix-typo-in-BestComm-ATA-task-support-code.patch
++ features/powerpc/efika/0018-powerpc-BestComm-ATA-task-microcode-insert-copyri.patch
++ features/powerpc/efika/0019-powerpc-BestComm-FEC-task-microcode-insert-copyri.patch
++ features/powerpc/efika/0020-powerpc-BestComm-GenBD-task-microcode-insert-copy.patch
++ features/powerpc/efika/0021-powerpc-Fix-errors-in-bcom-bcom_eng-renaming.patch
++ features/powerpc/efika/0081-mpc52xx-correct-calculation-of-FEC-RX-errors.patch
++ features/powerpc/efika/0082-powerpc-pata_mpc52xx-suspend.patch
++ features/powerpc/efika/extra/11303_Fix_mpc52xx_uart_of_assign_to_use_correct_index.patch
++ features/powerpc/efika/extra/11675_mpc5200_rtc_driver.patch
++ features/powerpc/efika/extra/11861_mpc52xx_sparse_fixes.patch
++ features/powerpc/efika/extra/12626_mpx5200_uart_drop_port_lock_across_tty_flip_buffer_call.patch
 + bugfix/mips/cobalt-ide-resources.patch



More information about the Kernel-svn-changes mailing list