[kernel] r9218 - in dists/sid/linux-2.6/debian: . arch/powerpc patches/features/powerpc/efika patches/series
Sven Luther
luther at alioth.debian.org
Sun Jul 29 13:31:50 UTC 2007
Author: luther
Date: Sun Jul 29 13:31:50 2007
New Revision: 9218
Log:
Now that 2.6.22-3 is out of the way, these could be added in an ABI bumping
2.6.22-4. I added a description of the patches and their upstream status,
after checking them with the mpc5200 porters. Please read :
debian/patches/features/powerpc/efika/STATUS_OF_UPSTREAM_MERGE
for details.
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/11303_Fix_mpc52xx_uart_of_assign_to_use_correct_index.patch
dists/sid/linux-2.6/debian/patches/features/powerpc/efika/11675_mpc5200_rtc_driver.patch
dists/sid/linux-2.6/debian/patches/features/powerpc/efika/11861_mpc52xx_sparse_fixes.patch
dists/sid/linux-2.6/debian/patches/features/powerpc/efika/12626_mpx5200_uart_drop_port_lock_across_tty_flip_buffer_call.patch
dists/sid/linux-2.6/debian/patches/features/powerpc/efika/STATUS_OF_UPSTREAM_MERGE
dists/sid/linux-2.6/debian/patches/series/4
- copied, changed from r9217, /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/changelog
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 Sun Jul 29 13:31:50 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 Sun Jul 29 13:31:50 2007
@@ -1,3 +1,9 @@
+linux-2.6 (2.6.22-4) UNRELEASED; urgency=low
+
+ * [powerpc] Added Genesi Efika support.
+
+ -- Sven Luther <sven at powerlinux.fr> Sun, 29 Jul 2007 15:11:31 +0200
+
linux-2.6 (2.6.22-3) unstable; urgency=low
[ dann frazier ]
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 Sun Jul 29 13:31:50 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 Sun Jul 29 13:31:50 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 Sun Jul 29 13:31:50 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 Sun Jul 29 13:31:50 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 Sun Jul 29 13:31:50 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 Sun Jul 29 13:31:50 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 Sun Jul 29 13:31:50 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 Sun Jul 29 13:31:50 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(ðcmd, 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 Sun Jul 29 13:31:50 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 Sun Jul 29 13:31:50 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 Sun Jul 29 13:31:50 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 Sun Jul 29 13:31:50 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 Sun Jul 29 13:31:50 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 Sun Jul 29 13:31:50 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 Sun Jul 29 13:31:50 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 Sun Jul 29 13:31:50 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 Sun Jul 29 13:31:50 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 Sun Jul 29 13:31:50 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 Sun Jul 29 13:31:50 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 Sun Jul 29 13:31:50 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 Sun Jul 29 13:31:50 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 Sun Jul 29 13:31:50 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 Sun Jul 29 13:31:50 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/11303_Fix_mpc52xx_uart_of_assign_to_use_correct_index.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/11303_Fix_mpc52xx_uart_of_assign_to_use_correct_index.patch Sun Jul 29 13:31:50 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/11675_mpc5200_rtc_driver.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/11675_mpc5200_rtc_driver.patch Sun Jul 29 13:31:50 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(®s->second);
++ tm->tm_min = in_8(®s->minute);
++
++ /* 12 hour format? */
++ if (in_8(®s->hour) & 0x20)
++ tm->tm_hour = (in_8(®s->hour) >> 1) + (in_8(®s->hour) & 1 ? 12 : 0);
++ else
++ tm->tm_hour = in_8(®s->hour);
++
++ tmp = in_8(®s->wday_mday);
++ tm->tm_mday = tmp & 0x1f;
++ tm->tm_mon = in_8(®s->month) - 1;
++ tm->tm_year = in_be16(®s->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(®s->second_set, tm->tm_sec);
++ out_8(®s->minute_set, tm->tm_min);
++ out_8(®s->hour_set, tm->tm_hour);
++
++ /* set time sequence */
++ out_8(®s->set_time, 0x1);
++ out_8(®s->set_time, 0x3);
++ out_8(®s->set_time, 0x1);
++ out_8(®s->set_time, 0x0);
++
++ /* date */
++ out_8(®s->month_set, tm->tm_mon + 1);
++ out_8(®s->weekday_set, tm->tm_wday ? tm->tm_wday : 7);
++ out_8(®s->date_set, tm->tm_mday);
++ out_be16(®s->year_set, tm->tm_year + 1900);
++
++ /* set date sequence */
++ out_8(®s->set_date, 0x1);
++ out_8(®s->set_date, 0x3);
++ out_8(®s->set_date, 0x1);
++ out_8(®s->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(®s->alm_min_set);
++ alrm->time.tm_hour = in_8(®s->alm_hour_set);
++
++ alrm->time.tm_mday = -1;
++ alrm->time.tm_mon = -1;
++ alrm->time.tm_year = -1;
++
++ alrm->enabled = in_8(®s->alm_enable);
++ alrm->pending = in_8(®s->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(®s->alm_min_set, alrm->time.tm_min);
++ out_8(®s->alm_hour_set, alrm->time.tm_hour);
++
++ out_8(®s->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(®s->int_alm)) {
++ /* acknowledge */
++ out_8(®s->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(®s->int_sec) && (in_8(®s->int_enable) & 0x1)) {
++ /* acknowledge */
++ out_8(®s->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(®s->alm_enable, 1);
++ break;
++ case RTC_AIE_OFF:
++ out_8(®s->alm_enable, 0);
++ break;
++
++ /* update interrupt (periodic second in mpc5200 words) */
++ case RTC_UIE_ON:
++ out_8(®s->int_enable, (in_8(®s->int_enable) & ~0x8) | 0x1);
++ break;
++ case RTC_UIE_OFF:
++ out_8(®s->int_enable, in_8(®s->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(®s->alm_enable, 0);
++ out_8(®s->int_enable, in_8(®s->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/11861_mpc52xx_sparse_fixes.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/11861_mpc52xx_sparse_fixes.patch Sun Jul 29 13:31:50 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/12626_mpx5200_uart_drop_port_lock_across_tty_flip_buffer_call.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/12626_mpx5200_uart_drop_port_lock_across_tty_flip_buffer_call.patch Sun Jul 29 13:31:50 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;
+ }
Added: dists/sid/linux-2.6/debian/patches/features/powerpc/efika/STATUS_OF_UPSTREAM_MERGE
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6/debian/patches/features/powerpc/efika/STATUS_OF_UPSTREAM_MERGE Sun Jul 29 13:31:50 2007
@@ -0,0 +1,72 @@
+These patches are the lone remaining efika patches that got not yet merged.
+
+They are comprised of various groups :
+
+ 1) the bestcomm patches. They are of upstream quality, not yet commited
+ because the drivers using them are not yet fully ready, and so nothing in
+ mainline does use them :
+
+ 0004-powerpc-BestComm-core-support-for-Freescale-MPC5200.patch
+ 0005-powerpc-BestcComm-ATA-task-support.patch
+ 0006-powerpc-BestcComm-FEC-task-support.patch
+ 0007-powerpc-BestcComm-GenBD-task-support.patch
+ 0011-powerpc-BestComm-move-the-EXPORT_SYMBOL-and-use-th.patch
+ 0012-powerpc-BestComm-ATA-task-move-the-EXPORT_SYMBOL-a.patch
+ 0013-powerpc-BestComm-FEC-task-move-the-EXPORT_SYMBOL-a.patch
+ 0014-powerpc-BestComm-GenBD-task-move-the-EXPORT_SYMBOL.patch
+ 0015-powerpc-BestComm-Replace-global-variable-bcom-by-b.patch
+ 0016-powerpc-Make-the-BestComm-driver-a-standard-of_plat.patch
+ 0017-powerpc-Fix-typo-in-BestComm-ATA-task-support-code.patch
+ 0018-powerpc-BestComm-ATA-task-microcode-insert-copyri.patch
+ 0019-powerpc-BestComm-FEC-task-microcode-insert-copyri.patch
+ 0020-powerpc-BestComm-GenBD-task-microcode-insert-copy.patch
+ 0021-powerpc-Fix-errors-in-bcom-bcom_eng-renaming.patch
+
+ 2) selects the CONFIG_PPC_RHEAP thingy, and export the symbols which are
+ used by the above bestcom code, so the bestcom drivers can be built modular :
+
+ 0001-powerpc-exports-rheap-symbol-to-modules.patch
+ 0002-powerpc-Changes-the-config-mechanism-for-rheap.patch
+ 0010-powerpc-In-rheap.c-move-the-EXPORT_SYMBOL-and-use.patch
+
+ 3) the reworked ethernet driver for MPC5200 used in the Efika. This one is a
+ cleaned up and reworked thingy, which may be upstream quality, but was not
+ yet reviewed by the mpc5200 porter for lack of time :
+
+ 0008-drivers-net-Add-support-for-Freescale-MPC5200-SoC-i.patch
+
+ 4) the mpc5200 sound driver. Not yet cleaned up for upstream submission, as
+ it has less priority than the above code :
+
+ 0009-sound-Add-support-for-Freescale-MPC5200-AC97-interf.patch
+
+ 5) the mpc5200 rtc driver.
+
+ 11675_mpc5200_rtc_driver.patch
+
+ 6) suspendi/resume patch for the mpc52xx pata driver.
+
+ 0082-powerpc-pata_mpc52xx-suspend.patch
+
+ 7) assorted minor bug fixes, may be upstream already or soon will be.
+
+ 0003-powerpc-ppc32-Update-mpc52xx_psc-structure-with-B-r.patch
+ 0081-mpc52xx-correct-calculation-of-FEC-RX-errors.patch
+ 11303_Fix_mpc52xx_uart_of_assign_to_use_correct_index.patch
+ 11861_mpc52xx_sparse_fixes.patch
+ 12626_mpx5200_uart_drop_port_lock_across_tty_flip_buffer_call.patch
+
+So, these patches, except for the sound/rtc drivers, should all be of upstream
+quality, and the only thing stopping their mainline inclusion is the lack of
+time of the mpc5200 porter. Sylvain mentioned that in the worst case, he
+should have time during the christmas vacations to clean these patches up, and
+push them into mainline.
+
+None of these patches affect non-powerpc code, and furthermore, they are
+mpc5200 specific, and will not affect other powerpc cpus.
+
+They do indeed add new symbols, in order to build the bestcomm drivers
+modular, but these symbols are not used on anything except these patches.
+Still it is apparently an abi breakage, and i recomend including them with an
+abi-breaking 2.6.22-4, or if an urgent non-abi breaking upload is needed to
+just disable those patches instead of reversing this commit.
Copied: dists/sid/linux-2.6/debian/patches/series/4 (from r9217, /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/4 Sun Jul 29 13:31:50 2007
@@ -1 +1,27 @@
-+ bugfix/mips/cobalt-ide-resources.patch
++ 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/11303_Fix_mpc52xx_uart_of_assign_to_use_correct_index.patch
++ features/powerpc/efika/11675_mpc5200_rtc_driver.patch
++ features/powerpc/efika/11861_mpc52xx_sparse_fixes.patch
++ features/powerpc/efika/12626_mpx5200_uart_drop_port_lock_across_tty_flip_buffer_call.patch
More information about the Kernel-svn-changes
mailing list