[kernel] r8162 - in dists/trunk/linux-2.6/debian/patches: debian features/powerpc/efika series

Sven Luther luther at alioth.debian.org
Thu Jan 11 15:19:54 CET 2007


Author: luther
Date: Thu Jan 11 15:19:52 2007
New Revision: 8162

Added:
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0001-powerpc-serial-Dispose-irq-mapping-when-done-in-mpc52xx_serial.c.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0002-powerpc-52xx-Don-t-use-device_initcall-to-probe-of_platform_bus.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0004-powerpc-Use-common-52xx-of_platform-probe-code-for-EFIKA.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0005-powerpc-Restore-proper-link-order-in-platform.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0006-Rework-the-OHCI-quirk-mecanism-as-suggested-by-David.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0007-Implement-support-for-split-endian-OHCI.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0008-ohci-Rework-bus-glue-integration-to-allow-several-at-once.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0009-ohci-Add-support-for-OHCI-controller-on-the-of_platform-bus.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0010-libata-Add-support-for-the-MPC52xx-ATA-controller.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0011-ohci-Whitespace-and-typo-fix-in-ohci-ppc-of.c.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0012-ata-Fix-pata_mpc52xx.c-compatible-list.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0013-powerpc-serial-Fix-mpc52xx_uart.c-compatible-list.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0014-powerpc-Small-cleanup-of-EFIKA-platform.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0015-powerpc-Add-a-unified-uevent-handler-for-bus-based-on-of_device.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0016-macintosh-Use-the-new-of_device-common-uevent-handler.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0017-powerpc-Add-uevent-handler-for-of_platform_bus.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0018-powerpc-Add-uevent-handler-for-ibmebus.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0019-MPC5200-Bestcomm-platform-driver.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0020-Fec-MPC5200-eth-driver.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0021-POWERPC-Copy-bestcomm-support-files-into-arch-powerpc.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0022-MPC52xx-PCI-now-working-on-lite5200.-ugly-but-working.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0023-POWERPC-Make-FEC-work-on-the-lite5200.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0024-Add-missing-function-prototype.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0025-POWERPC-Misc-EFIKA-fixups-for-rtas-chrp.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0026-POWERPC-Cleanup-mpc52xx-PCI-support.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0027-POWERPC-Change-name-of-mpc52xx-pci-support-file-in-Makefile.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0028-POWERPC-Change-link-order-so-mpc52xx-fec-always-shows-up-as-eth0.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0029-POWERPC-Fixup-pr_print-format-for-mpc52xx-pci-support.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0030-POWERPC-Add-mpc52xx-lite5200-PCI-support.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0031-sound-Add-support-for-the-MPC52xx-PSC-AC97-Link.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0033-Fix-the-bestcomm-interrupt-property-fixes-the-ethernet-driver.txt
Removed:
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0001-Fix-compilation-issue-when-PPC_MPC52xx-and-PPC_MERGE-are-selected.diff
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0001-powerpc-Add-support-for-uevent-to-of_platform.txt
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0002-Add-USB-OHCI-glue-for-OpenFirmware-devices.diff
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0003-Add-MPC5200-serial-driver.diff
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0004-Add-MPC5200-CPU-PIO-driver-using-libata.diff
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0005-Add-MPC5200-specific-header.diff
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0006-Add-MPC5200-interrupt-controller-driver.diff
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0007-Add-MPC5200-ethernet-driver.diff
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0008-Add-MPC5200-SDMA-PIO-driver.diff
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0009-Added-RTAS-support-for-32bit-PowerPC.diff
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0010-Add-Efika-platform.diff
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0011-Filter-out-efika.diff
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0012-Backport-of_platform.diff
Modified:
   dists/trunk/linux-2.6/debian/patches/debian/powerpc-mkvmlinuz-support-powerpc.patch
   dists/trunk/linux-2.6/debian/patches/series/1~experimental.1
Log:
Fixed powerpc-mkvmlinuz-support-powerpc.patch for 2.6.20-rc4
Re-enabled powerpc-mkvmlinuz-support-ppc.patch which was disabled without reason
Updated efika patches to  2.6.20-rc4.


Modified: dists/trunk/linux-2.6/debian/patches/debian/powerpc-mkvmlinuz-support-powerpc.patch
==============================================================================
--- dists/trunk/linux-2.6/debian/patches/debian/powerpc-mkvmlinuz-support-powerpc.patch	(original)
+++ dists/trunk/linux-2.6/debian/patches/debian/powerpc-mkvmlinuz-support-powerpc.patch	Thu Jan 11 15:19:52 2007
@@ -29,12 +29,12 @@
  
  PHONY += $(BOOT_TARGETS)
  
---- linux-2.6.19/arch/powerpc/boot/Makefile.orig	2006-12-05 16:14:42.000000000 +0000
-+++ linux-2.6.19/arch/powerpc/boot/Makefile	2006-12-05 16:13:37.000000000 +0000
-@@ -176,3 +176,18 @@
- 
+--- linux-2.6.20-rc3/arch/powerpc/boot/Makefile.orig	2007-01-04 16:22:53.000000000 +0100
++++ linux-2.6.20-rc3/arch/powerpc/boot/Makefile	2007-01-04 16:23:40.000000000 +0100
+@@ -186,3 +186,19 @@
  clean-files += $(addprefix $(objtree)/, $(obj-boot) vmlinux.strip.gz)
  clean-files += $(addprefix $(objtree)/, $(obj-boot) vmlinux.bin.gz)
+ clean-files += $(image-)
 +
 +#-----------------------------------------------------------
 +# install mkvmlinuz support files
@@ -48,5 +48,6 @@
 +	mkdir -p $(INSTALL_MKVMLINUZ)
 +	$(call cmd,mkvmlinuz)
 +
-+targets	+= mkvmlinuz_support_install
++targets += mkvmlinuz_support_install
++
 +

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0001-powerpc-serial-Dispose-irq-mapping-when-done-in-mpc52xx_serial.c.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0001-powerpc-serial-Dispose-irq-mapping-when-done-in-mpc52xx_serial.c.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,27 @@
+From 733239db928c98f4d110fc33f0cf1278cf5385ef Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Mon, 18 Dec 2006 22:48:02 +0100
+Subject: [PATCH] [PATCH] powerpc/serial: Dispose irq mapping when done in mpc52xx_serial.c
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ drivers/serial/mpc52xx_uart.c |    3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
+index 9d11a75..eef3b02 100644
+--- a/drivers/serial/mpc52xx_uart.c
++++ b/drivers/serial/mpc52xx_uart.c
+@@ -997,6 +997,9 @@ mpc52xx_uart_of_remove(struct of_device *op)
+ 	if (port)
+ 		uart_remove_one_port(&mpc52xx_uart_driver, port);
+ 
++	if (port->irq != NO_IRQ)
++		irq_dispose_mapping(port->irq);
++
+ 	return 0;
+ }
+ 
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0002-powerpc-52xx-Don-t-use-device_initcall-to-probe-of_platform_bus.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0002-powerpc-52xx-Don-t-use-device_initcall-to-probe-of_platform_bus.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,68 @@
+From 1dbea513815ce823ccded38d5668bbae7416223f Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Thu, 21 Dec 2006 22:21:20 +0100
+Subject: [PATCH] [PATCH] powerpc: 52xx, Don't use device_initcall to probe of_platform_bus
+
+Using device_initcall makes it happen for every platform that
+compiles this file in. This is really bad, for obvious reasons.
+
+Instead, we use the .init field of the machine description. If
+the platform needs the hook to do something specific it can provides
+its own function and call mpc52xx_declare_of_platform_devices from
+there. If not, the mpc52xx_declare_of_platform_devices function can
+directly be used as the init hook.
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/platforms/52xx/lite5200.c       |    1 +
+ arch/powerpc/platforms/52xx/mpc52xx_common.c |    7 ++++---
+ include/asm-powerpc/mpc52xx.h                |    1 +
+ 3 files changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c
+index eaff71e..0f21bab 100644
+--- a/arch/powerpc/platforms/52xx/lite5200.c
++++ b/arch/powerpc/platforms/52xx/lite5200.c
+@@ -153,6 +153,7 @@ define_machine(lite52xx) {
+ 	.name 		= "lite52xx",
+ 	.probe 		= lite52xx_probe,
+ 	.setup_arch 	= lite52xx_setup_arch,
++	.init		= mpc52xx_declare_of_platform_devices,
+ 	.init_IRQ 	= mpc52xx_init_irq,
+ 	.get_irq 	= mpc52xx_get_irq,
+ 	.show_cpuinfo	= lite52xx_show_cpuinfo,
+diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c
+index 8331ff4..cc40889 100644
+--- a/arch/powerpc/platforms/52xx/mpc52xx_common.c
++++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c
+@@ -116,11 +116,12 @@ unmap_regs:
+ 	if (xlb) iounmap(xlb);
+ }
+ 
+-static int __init
++void __init
+ mpc52xx_declare_of_platform_devices(void)
+ {
+ 	/* Find every child of the SOC node and add it to of_platform */
+-	return of_platform_bus_probe(NULL, NULL, NULL);
++	if (of_platform_bus_probe(NULL, NULL, NULL))
++		printk(KERN_ERR __FILE__ ": "
++			"Error while probing of_platform bus\n");
+ }
+ 
+-device_initcall(mpc52xx_declare_of_platform_devices);
+diff --git a/include/asm-powerpc/mpc52xx.h b/include/asm-powerpc/mpc52xx.h
+index 4a28a85..4560d72 100644
+--- a/include/asm-powerpc/mpc52xx.h
++++ b/include/asm-powerpc/mpc52xx.h
+@@ -244,6 +244,7 @@ struct mpc52xx_cdm {
+ extern void __iomem * mpc52xx_find_and_map(const char *);
+ extern unsigned int mpc52xx_find_ipb_freq(struct device_node *node);
+ extern void mpc52xx_setup_cpu(void);
++extern void mpc52xx_declare_of_platform_devices(void);
+ 
+ extern void mpc52xx_init_irq(void);
+ extern unsigned int mpc52xx_get_irq(void);
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0004-powerpc-Use-common-52xx-of_platform-probe-code-for-EFIKA.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0004-powerpc-Use-common-52xx-of_platform-probe-code-for-EFIKA.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,106 @@
+From ae911446f91481cf26e6dc5edef034a50a6c410c Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sat, 23 Dec 2006 20:33:30 +0100
+Subject: [PATCH] [PATCH] powerpc: Use common 52xx of_platform probe code for EFIKA
+
+Now that the device tree has the good properties, we can
+remove all the efika_init code by a single call to common code.
+
+While we're modifying that file, a few whitespaces/alignement/typo
+fixes are made (nothing significant).
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/platforms/52xx/efika-setup.c |   64 ++++++++---------------------
+ 1 files changed, 18 insertions(+), 46 deletions(-)
+
+diff --git a/arch/powerpc/platforms/52xx/efika-setup.c b/arch/powerpc/platforms/52xx/efika-setup.c
+index 110c980..d61ce84 100644
+--- a/arch/powerpc/platforms/52xx/efika-setup.c
++++ b/arch/powerpc/platforms/52xx/efika-setup.c
+@@ -2,7 +2,7 @@
+  *
+  * Efika 5K2 platform setup
+  * Some code really inspired from the lite5200b platform.
+- * 
++ *
+  * Copyright (C) 2006 bplan GmbH
+  *
+  * This file is licensed under the terms of the GNU General Public License
+@@ -81,35 +81,7 @@ static void __init efika_setup_arch(void)
+ 	efika_pcisetup();
+ 
+ 	if (ppc_md.progress)
+-		ppc_md.progress("Linux/PPC " UTS_RELEASE " runnung on Efika ;-)\n", 0x0);
+-}
+-
+-static void __init efika_init(void)
+-{
+-	struct device_node *np;
+-	struct device_node *cnp = NULL;
+-	const u32 *base;
+-
+-	/* Find every child of the SOC node and add it to of_platform */
+-	np = of_find_node_by_name(NULL, "builtin");
+-	if (np) {
+-		char name[BUS_ID_SIZE];
+-		while ((cnp = of_get_next_child(np, cnp))) {
+-			strcpy(name, cnp->name);
+-
+-			base = get_property(cnp, "reg", NULL);
+-			if (base == NULL)
+-				continue;
+-
+-			snprintf(name+strlen(name), BUS_ID_SIZE, "@%x", *base);
+-			of_platform_device_create(cnp, name, NULL);
+-
+-			printk(KERN_INFO EFIKA_PLATFORM_NAME" : Added %s (type '%s' at '%s') to the known devices\n", name, cnp->type, cnp->full_name);
+-		}
+-	}
+-
+-	if (ppc_md.progress)
+-		ppc_md.progress("  Have fun with your Efika!    ", 0x7777);
++		ppc_md.progress("Linux/PPC " UTS_RELEASE " running on Efika ;-)\n", 0x0);
+ }
+ 
+ static int __init efika_probe(void)
+@@ -131,20 +103,20 @@ static int __init efika_probe(void)
+ 
+ define_machine(efika)
+ {
+-	.name = EFIKA_PLATFORM_NAME,
+-	.probe = efika_probe,
+-	.setup_arch = efika_setup_arch,
+-	.init = efika_init,
+-	.show_cpuinfo = efika_show_cpuinfo,
+-	.init_IRQ = mpc52xx_init_irq,
+-	.get_irq = mpc52xx_get_irq,
+-	.restart = rtas_restart,
+-	.power_off = rtas_power_off,
+-	.halt = rtas_halt,
+-	.set_rtc_time = rtas_set_rtc_time,
+-	.get_rtc_time = rtas_get_rtc_time,
+-	.progress = rtas_progress,
+-	.get_boot_time = rtas_get_boot_time,
+-	.calibrate_decr = generic_calibrate_decr,
+-	.phys_mem_access_prot = pci_phys_mem_access_prot,
++	.name			= EFIKA_PLATFORM_NAME,
++	.probe			= efika_probe,
++	.setup_arch		= efika_setup_arch,
++	.init			= mpc52xx_declare_of_platform_devices,
++	.show_cpuinfo		= efika_show_cpuinfo,
++	.init_IRQ		= mpc52xx_init_irq,
++	.get_irq		= mpc52xx_get_irq,
++	.restart		= rtas_restart,
++	.power_off		= rtas_power_off,
++	.halt			= rtas_halt,
++	.set_rtc_time		= rtas_set_rtc_time,
++	.get_rtc_time		= rtas_get_rtc_time,
++	.progress		= rtas_progress,
++	.get_boot_time		= rtas_get_boot_time,
++	.calibrate_decr		= generic_calibrate_decr,
++	.phys_mem_access_prot	= pci_phys_mem_access_prot,
+ };
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0005-powerpc-Restore-proper-link-order-in-platform.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0005-powerpc-Restore-proper-link-order-in-platform.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,33 @@
+From 720e2caeeff0d9585d5627d29ffd660a5a9d9f88 Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sat, 23 Dec 2006 20:43:39 +0100
+Subject: [PATCH] [PATCH] powerpc: Restore 'proper' link order in platform
+
+The 52xx was put before CHRP to allow EFIKA to be recognized
+properly. Now the efika tree is fixed up in prom_init so
+no need for this ugly hack. So we restore the 'normal'
+order.
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/platforms/Makefile |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile
+index 507d1b9..44d95ea 100644
+--- a/arch/powerpc/platforms/Makefile
++++ b/arch/powerpc/platforms/Makefile
+@@ -5,9 +5,9 @@ ifeq ($(CONFIG_PPC64),y)
+ obj-$(CONFIG_PPC_PMAC)		+= powermac/
+ endif
+ endif
+-obj-$(CONFIG_PPC_MPC52xx)	+= 52xx/
+ obj-$(CONFIG_PPC_CHRP)		+= chrp/
+ obj-$(CONFIG_4xx)		+= 4xx/
++obj-$(CONFIG_PPC_MPC52xx)	+= 52xx/
+ obj-$(CONFIG_PPC_83xx)		+= 83xx/
+ obj-$(CONFIG_PPC_85xx)		+= 85xx/
+ obj-$(CONFIG_PPC_86xx)		+= 86xx/
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0006-Rework-the-OHCI-quirk-mecanism-as-suggested-by-David.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0006-Rework-the-OHCI-quirk-mecanism-as-suggested-by-David.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,236 @@
+From 9282a04f14cef512736ac4a895fb48456e6a8989 Mon Sep 17 00:00:00 2001
+From: Benjamin Herrenschmidt <benh at kernel.crashing.org>
+Date: Thu, 14 Dec 2006 14:13:26 +1100
+Subject: [PATCH] [PATCH] Rework the OHCI quirk mecanism as suggested by David
+
+This patch applies David Brownell's suggestion for reworking the
+OHCI quirk mechanism via a table of PCI IDs. It adapts the existing
+quirks to use that mechanism.
+
+This also moves the quirks to reset() as suggested by the comment
+in there. This is necessary as we need to have the endian properly
+set before we try to init the controller.
+
+Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
+Acked-by: David Brownell <dbrownell at users.sourceforge.net>
+
+ drivers/usb/host/ohci-pci.c |  173 +++++++++++++++++++++++++++-----------------
+ 1 file changed, 110 insertions(+), 63 deletions(-)
+---
+ drivers/usb/host/ohci-pci.c |  173 +++++++++++++++++++++++++++----------------
+ 1 files changed, 110 insertions(+), 63 deletions(-)
+
+diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
+index 596e0b4..82fbec3 100644
+--- a/drivers/usb/host/ohci-pci.c
++++ b/drivers/usb/host/ohci-pci.c
+@@ -20,79 +20,128 @@
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+-static int
+-ohci_pci_reset (struct usb_hcd *hcd)
++/* AMD 756, for most chips (early revs), corrupts register
++ * values on read ... so enable the vendor workaround.
++ */
++static int __devinit ohci_quirk_amd756(struct usb_hcd *hcd)
+ {
+ 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+ 
+-	ohci_hcd_init (ohci);
+-	return ohci_init (ohci);
++	ohci->flags = OHCI_QUIRK_AMD756;
++	ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
++
++	/* also erratum 10 (suspend/resume issues) */
++	device_init_wakeup(&hcd->self.root_hub->dev, 0);
++
++	return 0;
+ }
+ 
+-static int __devinit
+-ohci_pci_start (struct usb_hcd *hcd)
++/* Apple's OHCI driver has a lot of bizarre workarounds
++ * for this chip.  Evidently control and bulk lists
++ * can get confused.  (B&W G3 models, and ...)
++ */
++static int __devinit ohci_quirk_opti(struct usb_hcd *hcd)
+ {
+ 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+-	int		ret;
+ 
+-	/* REVISIT this whole block should move to reset(), which handles
+-	 * all the other one-time init.
++	ohci_dbg (ohci, "WARNING: OPTi workarounds unavailable\n");
++
++	return 0;
++}
++
++/* Check for NSC87560. We have to look at the bridge (fn1) to
++ * identify the USB (fn2). This quirk might apply to more or
++ * even all NSC stuff.
++ */
++static int __devinit ohci_quirk_ns(struct usb_hcd *hcd)
++{
++	struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
++	struct pci_dev	*b;
++
++	b  = pci_get_slot (pdev->bus, PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
++	if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
++	    && b->vendor == PCI_VENDOR_ID_NS) {
++		struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
++
++		ohci->flags |= OHCI_QUIRK_SUPERIO;
++		ohci_dbg (ohci, "Using NSC SuperIO setup\n");
++	}
++	pci_dev_put(b);
++
++	return 0;
++}
++
++/* Check for Compaq's ZFMicro chipset, which needs short
++ * delays before control or bulk queues get re-activated
++ * in finish_unlinks()
++ */
++static int __devinit ohci_quirk_zfmicro(struct usb_hcd *hcd)
++{
++	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
++
++	ohci->flags |= OHCI_QUIRK_ZFMICRO;
++	ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n");
++
++	return 0;
++}
++
++
++/* List of quirks for OHCI */
++static const struct pci_device_id ohci_pci_quirks[] = {
++	{
++		PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x740c),
++		.driver_data = (unsigned long)ohci_quirk_amd756,
++	},
++	{
++		PCI_DEVICE(PCI_VENDOR_ID_OPTI, 0xc861),
++		.driver_data = (unsigned long)ohci_quirk_opti,
++	},
++	{
++		PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_ANY_ID),
++		.driver_data = (unsigned long)ohci_quirk_ns,
++	},
++	{
++		PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xa0f8),
++		.driver_data = (unsigned long)ohci_quirk_zfmicro,
++	},
++	/* FIXME for some of the early AMD 760 southbridges, OHCI
++	 * won't work at all.  blacklist them.
+ 	 */
++	{},
++};
++
++static int ohci_pci_reset (struct usb_hcd *hcd)
++{
++	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
++	int ret = 0;
++
+ 	if (hcd->self.controller) {
+ 		struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
++		const struct pci_device_id *quirk_id;
+ 
+-		/* AMD 756, for most chips (early revs), corrupts register
+-		 * values on read ... so enable the vendor workaround.
+-		 */
+-		if (pdev->vendor == PCI_VENDOR_ID_AMD
+-				&& pdev->device == 0x740c) {
+-			ohci->flags = OHCI_QUIRK_AMD756;
+-			ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
+-			/* also erratum 10 (suspend/resume issues) */
+-			device_init_wakeup(&hcd->self.root_hub->dev, 0);
++		quirk_id = pci_match_id(ohci_pci_quirks, pdev);
++		if (quirk_id != NULL) {
++			int (*quirk)(struct usb_hcd *ohci);
++			quirk = (void *)quirk_id->driver_data;
++			ret = quirk(hcd);
+ 		}
++	}
++	if (ret == 0) {
++		ohci_hcd_init (ohci);
++		return ohci_init (ohci);
++	}
++	return ret;
++}
+ 
+-		/* FIXME for some of the early AMD 760 southbridges, OHCI
+-		 * won't work at all.  blacklist them.
+-		 */
+-
+-		/* Apple's OHCI driver has a lot of bizarre workarounds
+-		 * for this chip.  Evidently control and bulk lists
+-		 * can get confused.  (B&W G3 models, and ...)
+-		 */
+-		else if (pdev->vendor == PCI_VENDOR_ID_OPTI
+-				&& pdev->device == 0xc861) {
+-			ohci_dbg (ohci,
+-				"WARNING: OPTi workarounds unavailable\n");
+-		}
+ 
+-		/* Check for NSC87560. We have to look at the bridge (fn1) to
+-		 * identify the USB (fn2). This quirk might apply to more or
+-		 * even all NSC stuff.
+-		 */
+-		else if (pdev->vendor == PCI_VENDOR_ID_NS) {
+-			struct pci_dev	*b;
+-
+-			b  = pci_get_slot (pdev->bus,
+-					PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
+-			if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
+-					&& b->vendor == PCI_VENDOR_ID_NS) {
+-				ohci->flags |= OHCI_QUIRK_SUPERIO;
+-				ohci_dbg (ohci, "Using NSC SuperIO setup\n");
+-			}
+-			pci_dev_put(b);
+-		}
++static int __devinit ohci_pci_start (struct usb_hcd *hcd)
++{
++	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
++	int		ret;
+ 
+-		/* Check for Compaq's ZFMicro chipset, which needs short
+-		 * delays before control or bulk queues get re-activated
+-		 * in finish_unlinks()
+-		 */
+-		else if (pdev->vendor == PCI_VENDOR_ID_COMPAQ
+-				&& pdev->device  == 0xa0f8) {
+-			ohci->flags |= OHCI_QUIRK_ZFMICRO;
+-			ohci_dbg (ohci,
+-				"enabled Compaq ZFMicro chipset quirk\n");
+-		}
++#ifdef CONFIG_PM /* avoid warnings about unused pdev */
++	if (hcd->self.controller) {
++		struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+ 
+ 		/* RWC may not be set for add-in PCI cards, since boot
+ 		 * firmware probably ignored them.  This transfers PCI
+@@ -101,16 +150,14 @@ ohci_pci_start (struct usb_hcd *hcd)
+ 		if (device_may_wakeup(&pdev->dev))
+ 			ohci->hc_control |= OHCI_CTRL_RWC;
+ 	}
++#endif /* CONFIG_PM */
+ 
+-	/* NOTE: there may have already been a first reset, to
+-	 * keep bios/smm irqs from making trouble
+-	 */
+-	if ((ret = ohci_run (ohci)) < 0) {
++	ret = ohci_run (ohci);
++	if (ret < 0) {
+ 		ohci_err (ohci, "can't start\n");
+ 		ohci_stop (hcd);
+-		return ret;
+ 	}
+-	return 0;
++	return ret;
+ }
+ 
+ #ifdef	CONFIG_PM
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0007-Implement-support-for-split-endian-OHCI.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0007-Implement-support-for-split-endian-OHCI.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,367 @@
+From a87f8738eb3651b7eea1feae793def3a48dc36c6 Mon Sep 17 00:00:00 2001
+From: Benjamin Herrenschmidt <benh at kernel.crashing.org>
+Date: Thu, 14 Dec 2006 14:13:28 +1100
+Subject: [PATCH] [PATCH] Implement support for "split" endian OHCI
+
+This patch separates support for big endian MMIO register access
+and big endian descriptors in order to support the Toshiba SCC
+implementation which has big endian registers but little endian
+in-memory descriptors.
+
+It simplifies the access functions a bit in ohci.h while at it.
+
+Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
+Acked-by: David Brownell <dbrownell at users.sourceforge.net>
+
+ drivers/usb/host/Kconfig        |   10 ++
+ drivers/usb/host/ohci-pci.c     |   26 +++++++
+ drivers/usb/host/ohci-ppc-soc.c |    2
+ drivers/usb/host/ohci.h         |  147 +++++++++++++++++++++++++---------------
+ 4 files changed, 130 insertions(+), 55 deletions(-)
+---
+ drivers/usb/host/Kconfig        |   10 ++-
+ drivers/usb/host/ohci-pci.c     |   26 +++++++
+ drivers/usb/host/ohci-ppc-soc.c |    2 +-
+ drivers/usb/host/ohci.h         |  147 +++++++++++++++++++++++++--------------
+ 4 files changed, 130 insertions(+), 55 deletions(-)
+
+diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
+index cc60759..faabce8 100644
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -101,7 +101,8 @@ config USB_OHCI_HCD_PPC_SOC
+ 	bool "OHCI support for on-chip PPC USB controller"
+ 	depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
+ 	default y
+-	select USB_OHCI_BIG_ENDIAN
++	select USB_OHCI_BIG_ENDIAN_DESC
++	select USB_OHCI_BIG_ENDIAN_MMIO
+ 	---help---
+ 	  Enables support for the USB controller on the MPC52xx or
+ 	  STB03xxx processor chip.  If unsure, say Y.
+@@ -115,7 +116,12 @@ config USB_OHCI_HCD_PCI
+ 	  Enables support for PCI-bus plug-in USB controller cards.
+ 	  If unsure, say Y.
+ 
+-config USB_OHCI_BIG_ENDIAN
++config USB_OHCI_BIG_ENDIAN_DESC
++	bool
++	depends on USB_OHCI_HCD
++	default n
++
++config USB_OHCI_BIG_ENDIAN_MMIO
+ 	bool
+ 	depends on USB_OHCI_HCD
+ 	default n
+diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
+index 82fbec3..292daf0 100644
+--- a/drivers/usb/host/ohci-pci.c
++++ b/drivers/usb/host/ohci-pci.c
+@@ -85,6 +85,27 @@ static int __devinit ohci_quirk_zfmicro(struct usb_hcd *hcd)
+ 	return 0;
+ }
+ 
++/* Check for Toshiba SCC OHCI which has big endian registers
++ * and little endian in memory data structures
++ */
++static int __devinit ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
++{
++	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
++
++	/* That chip is only present in the southbridge of some
++	 * cell based platforms which are supposed to select
++	 * CONFIG_USB_OHCI_BIG_ENDIAN_MMIO. We verify here if
++	 * that was the case though.
++	 */
++#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
++	ohci->flags |= OHCI_QUIRK_BE_MMIO;
++	ohci_dbg (ohci, "enabled big endian Toshiba quirk\n");
++	return 0;
++#else
++	ohci_err (ohci, "unsupported big endian Toshiba quirk\n");
++	return -ENXIO;
++#endif
++}
+ 
+ /* List of quirks for OHCI */
+ static const struct pci_device_id ohci_pci_quirks[] = {
+@@ -104,9 +125,14 @@ static const struct pci_device_id ohci_pci_quirks[] = {
+ 		PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xa0f8),
+ 		.driver_data = (unsigned long)ohci_quirk_zfmicro,
+ 	},
++	{
++		PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, 0x01b6),
++		.driver_data = (unsigned long)ohci_quirk_toshiba_scc,
++	},
+ 	/* FIXME for some of the early AMD 760 southbridges, OHCI
+ 	 * won't work at all.  blacklist them.
+ 	 */
++
+ 	{},
+ };
+ 
+diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
+index e1a7eb8..c7ce8e6 100644
+--- a/drivers/usb/host/ohci-ppc-soc.c
++++ b/drivers/usb/host/ohci-ppc-soc.c
+@@ -72,7 +72,7 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
+ 	}
+ 
+ 	ohci = hcd_to_ohci(hcd);
+-	ohci->flags |= OHCI_BIG_ENDIAN;
++	ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+ 	ohci_hcd_init(ohci);
+ 
+ 	retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
+index 405257f..fc7c161 100644
+--- a/drivers/usb/host/ohci.h
++++ b/drivers/usb/host/ohci.h
+@@ -394,8 +394,9 @@ struct ohci_hcd {
+ #define	OHCI_QUIRK_AMD756	0x01			/* erratum #4 */
+ #define	OHCI_QUIRK_SUPERIO	0x02			/* natsemi */
+ #define	OHCI_QUIRK_INITRESET	0x04			/* SiS, OPTi, ... */
+-#define	OHCI_BIG_ENDIAN		0x08			/* big endian HC */
+-#define	OHCI_QUIRK_ZFMICRO	0x10			/* Compaq ZFMicro chipset*/
++#define	OHCI_QUIRK_BE_DESC	0x08			/* BE descriptors */
++#define	OHCI_QUIRK_BE_MMIO	0x10			/* BE registers */
++#define	OHCI_QUIRK_ZFMICRO	0x20			/* Compaq ZFMicro chipset*/
+ 	// there are also chip quirks/bugs in init logic
+ 
+ };
+@@ -439,117 +440,156 @@ static inline struct usb_hcd *ohci_to_hcd (const struct ohci_hcd *ohci)
+  * a minority (notably the IBM STB04XXX and the Motorola MPC5200
+  * processors) implement them in big endian format.
+  *
++ * In addition some more exotic implementations like the Toshiba
++ * Spider (aka SCC) cell southbridge are "mixed" endian, that is,
++ * they have a different endianness for registers vs. in-memory
++ * descriptors.
++ *
+  * This attempts to support either format at compile time without a
+  * runtime penalty, or both formats with the additional overhead
+  * of checking a flag bit.
++ *
++ * That leads to some tricky Kconfig rules howevber. There are
++ * different defaults based on some arch/ppc platforms, though
++ * the basic rules are:
++ *
++ * Controller type              Kconfig options needed
++ * ---------------              ----------------------
++ * little endian                CONFIG_USB_OHCI_LITTLE_ENDIAN
++ *
++ * fully big endian             CONFIG_USB_OHCI_BIG_ENDIAN_DESC _and_
++ *                              CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
++ *
++ * mixed endian                 CONFIG_USB_OHCI_LITTLE_ENDIAN _and_
++ *                              CONFIG_USB_OHCI_BIG_ENDIAN_{MMIO,DESC}
++ *
++ * (If you have a mixed endian controller, you -must- also define
++ * CONFIG_USB_OHCI_LITTLE_ENDIAN or things will not work when building
++ * both your mixed endian and a fully big endian controller support in
++ * the same kernel image).
+  */
+ 
+-#ifdef CONFIG_USB_OHCI_BIG_ENDIAN
++#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_DESC
++#ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN
++#define big_endian_desc(ohci)	(ohci->flags & OHCI_QUIRK_BE_DESC)
++#else
++#define big_endian_desc(ohci)	1		/* only big endian */
++#endif
++#else
++#define big_endian_desc(ohci)	0		/* only little endian */
++#endif
+ 
++#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+ #ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN
+-#define big_endian(ohci)	(ohci->flags & OHCI_BIG_ENDIAN) /* either */
++#define big_endian_mmio(ohci)	(ohci->flags & OHCI_QUIRK_BE_MMIO)
++#else
++#define big_endian_mmio(ohci)	1		/* only big endian */
++#endif
+ #else
+-#define big_endian(ohci)	1		/* only big endian */
++#define big_endian_mmio(ohci)	0		/* only little endian */
+ #endif
+ 
+ /*
+  * Big-endian read/write functions are arch-specific.
+  * Other arches can be added if/when they're needed.
++ *
++ * REVISIT: arch/powerpc now has readl/writel_be, so the
++ * definition below can die once the STB04xxx support is
++ * finally ported over.
+  */
+-#if defined(CONFIG_PPC)
++#if defined(CONFIG_PPC) && !defined(CONFIG_PPC_MERGE)
+ #define readl_be(addr)		in_be32((__force unsigned *)addr)
+ #define writel_be(val, addr)	out_be32((__force unsigned *)addr, val)
+ #endif
+ 
+-static inline unsigned int ohci_readl (const struct ohci_hcd *ohci,
+-							__hc32 __iomem * regs)
++static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci,
++					__hc32 __iomem * regs)
+ {
+-	return big_endian(ohci) ? readl_be (regs) : readl ((__force u32 *)regs);
++	return big_endian_mmio(ohci) ?
++		readl_be ((__force u32 *)regs) :
++		readl ((__force u32 *)regs);
+ }
+ 
+-static inline void ohci_writel (const struct ohci_hcd *ohci,
+-				const unsigned int val, __hc32 __iomem *regs)
++static inline void _ohci_writel (const struct ohci_hcd *ohci,
++				 const unsigned int val, __hc32 __iomem *regs)
+ {
+-	big_endian(ohci) ? writel_be (val, regs) :
+-			   writel (val, (__force u32 *)regs);
++	big_endian_mmio(ohci) ?
++		writel_be (val, (__force u32 *)regs) :
++		writel (val, (__force u32 *)regs);
+ }
+ 
+-#else	/* !CONFIG_USB_OHCI_BIG_ENDIAN */
+-
+-#define big_endian(ohci)	0		/* only little endian */
+-
+ #ifdef CONFIG_ARCH_LH7A404
+-	/* Marc Singer: at the time this code was written, the LH7A404
+-	 * had a problem reading the USB host registers.  This
+-	 * implementation of the ohci_readl function performs the read
+-	 * twice as a work-around.
+-	 */
+-static inline unsigned int
+-ohci_readl (const struct ohci_hcd *ohci, const __hc32 *regs)
+-{
+-	*(volatile __force unsigned int*) regs;
+-	return *(volatile __force unsigned int*) regs;
+-}
++/* Marc Singer: at the time this code was written, the LH7A404
++ * had a problem reading the USB host registers.  This
++ * implementation of the ohci_readl function performs the read
++ * twice as a work-around.
++ */
++#define ohci_readl(o,r)		(_ohci_readl(o,r),_ohci_readl(o,r))
++#define ohci_writel(o,v,r)	_ohci_writel(o,v,r)
+ #else
+-	/* Standard version of ohci_readl uses standard, platform
+-	 * specific implementation. */
+-static inline unsigned int
+-ohci_readl (const struct ohci_hcd *ohci, __hc32 __iomem * regs)
+-{
+-	return readl(regs);
+-}
++#define ohci_readl(o,r)		_ohci_readl(o,r)
++#define ohci_writel(o,v,r)	_ohci_writel(o,v,r)
+ #endif
+ 
+-static inline void ohci_writel (const struct ohci_hcd *ohci,
+-				const unsigned int val, __hc32 __iomem *regs)
+-{
+-	writel (val, regs);
+-}
+-
+-#endif	/* !CONFIG_USB_OHCI_BIG_ENDIAN */
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+ /* cpu to ohci */
+ static inline __hc16 cpu_to_hc16 (const struct ohci_hcd *ohci, const u16 x)
+ {
+-	return big_endian(ohci) ? (__force __hc16)cpu_to_be16(x) : (__force __hc16)cpu_to_le16(x);
++	return big_endian_desc(ohci) ?
++		(__force __hc16)cpu_to_be16(x) :
++		(__force __hc16)cpu_to_le16(x);
+ }
+ 
+ static inline __hc16 cpu_to_hc16p (const struct ohci_hcd *ohci, const u16 *x)
+ {
+-	return big_endian(ohci) ? cpu_to_be16p(x) : cpu_to_le16p(x);
++	return big_endian_desc(ohci) ?
++		cpu_to_be16p(x) :
++		cpu_to_le16p(x);
+ }
+ 
+ static inline __hc32 cpu_to_hc32 (const struct ohci_hcd *ohci, const u32 x)
+ {
+-	return big_endian(ohci) ? (__force __hc32)cpu_to_be32(x) : (__force __hc32)cpu_to_le32(x);
++	return big_endian_desc(ohci) ?
++		(__force __hc32)cpu_to_be32(x) :
++		(__force __hc32)cpu_to_le32(x);
+ }
+ 
+ static inline __hc32 cpu_to_hc32p (const struct ohci_hcd *ohci, const u32 *x)
+ {
+-	return big_endian(ohci) ? cpu_to_be32p(x) : cpu_to_le32p(x);
++	return big_endian_desc(ohci) ?
++		cpu_to_be32p(x) :
++		cpu_to_le32p(x);
+ }
+ 
+ /* ohci to cpu */
+ static inline u16 hc16_to_cpu (const struct ohci_hcd *ohci, const __hc16 x)
+ {
+-	return big_endian(ohci) ? be16_to_cpu((__force __be16)x) : le16_to_cpu((__force __le16)x);
++	return big_endian_desc(ohci) ?
++		be16_to_cpu((__force __be16)x) :
++		le16_to_cpu((__force __le16)x);
+ }
+ 
+ static inline u16 hc16_to_cpup (const struct ohci_hcd *ohci, const __hc16 *x)
+ {
+-	return big_endian(ohci) ? be16_to_cpup((__force __be16 *)x) : le16_to_cpup((__force __le16 *)x);
++	return big_endian_desc(ohci) ?
++		be16_to_cpup((__force __be16 *)x) :
++		le16_to_cpup((__force __le16 *)x);
+ }
+ 
+ static inline u32 hc32_to_cpu (const struct ohci_hcd *ohci, const __hc32 x)
+ {
+-	return big_endian(ohci) ? be32_to_cpu((__force __be32)x) : le32_to_cpu((__force __le32)x);
++	return big_endian_desc(ohci) ?
++		be32_to_cpu((__force __be32)x) :
++		le32_to_cpu((__force __le32)x);
+ }
+ 
+ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
+ {
+-	return big_endian(ohci) ? be32_to_cpup((__force __be32 *)x) : le32_to_cpup((__force __le32 *)x);
++	return big_endian_desc(ohci) ?
++		be32_to_cpup((__force __be32 *)x) :
++		le32_to_cpup((__force __le32 *)x);
+ }
+ 
+ /*-------------------------------------------------------------------------*/
+@@ -557,6 +597,9 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
+ /* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
+  * hardware handles 16 bit reads.  That creates a different confusion on
+  * some big-endian SOC implementations.  Same thing happens with PSW access.
++ *
++ * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over
++ * to arch/powerpc
+  */
+ 
+ #ifdef CONFIG_STB03xxx
+@@ -568,7 +611,7 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
+ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
+ {
+ 	u32 tmp;
+-	if (big_endian(ohci)) {
++	if (big_endian_desc(ohci)) {
+ 		tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
+ 		tmp >>= OHCI_BE_FRAME_NO_SHIFT;
+ 	} else
+@@ -580,7 +623,7 @@ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
+ static inline __hc16 *ohci_hwPSWp(const struct ohci_hcd *ohci,
+                                  const struct td *td, int index)
+ {
+-	return (__hc16 *)(big_endian(ohci) ?
++	return (__hc16 *)(big_endian_desc(ohci) ?
+ 			&td->hwPSW[index ^ 1] : &td->hwPSW[index]);
+ }
+ 
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0008-ohci-Rework-bus-glue-integration-to-allow-several-at-once.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0008-ohci-Rework-bus-glue-integration-to-allow-several-at-once.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,470 @@
+From 51294aa1482ea961a3e51ddac587b70b7c1c8ba0 Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Wed, 13 Dec 2006 20:35:37 +0100
+Subject: [PATCH] [PATCH] ohci: Rework bus glue integration to allow several at once
+
+The previous model had the module_init & module_exit function in the
+bus glue .c files themselves. That's a problem if several glues need
+to be selected at once and the driver is built has module. This case
+is quite common in embedded system where you want to handle both the
+integrated ohci controller and some extra controller on PCI.
+
+The ohci-hcd.c file now provide the module_init & module_exit and
+appropriate driver registering/unregistering is done conditionally,
+using #ifdefs.
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+Acked-by: David Brownell <dbrownell at users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+---
+ drivers/usb/host/ohci-at91.c    |   15 ------
+ drivers/usb/host/ohci-au1xxx.c  |   16 ------
+ drivers/usb/host/ohci-ep93xx.c  |   12 -----
+ drivers/usb/host/ohci-hcd.c     |   98 +++++++++++++++++++++++++++++++++------
+ drivers/usb/host/ohci-lh7a404.c |   16 ------
+ drivers/usb/host/ohci-omap.c    |   19 --------
+ drivers/usb/host/ohci-pci.c     |   20 --------
+ drivers/usb/host/ohci-pnx4008.c |   12 -----
+ drivers/usb/host/ohci-pnx8550.c |   16 ------
+ drivers/usb/host/ohci-ppc-soc.c |   16 ------
+ drivers/usb/host/ohci-pxa27x.c  |   16 ------
+ drivers/usb/host/ohci-s3c2410.c |   12 -----
+ drivers/usb/host/ohci-sa1111.c  |   16 ------
+ 13 files changed, 83 insertions(+), 201 deletions(-)
+
+diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
+index cc40551..53f62cf 100644
+--- a/drivers/usb/host/ohci-at91.c
++++ b/drivers/usb/host/ohci-at91.c
+@@ -320,18 +320,3 @@ static struct platform_driver ohci_hcd_at91_driver = {
+ 	},
+ };
+ 
+-static int __init ohci_hcd_at91_init (void)
+-{
+-	if (usb_disabled())
+-		return -ENODEV;
+-
+-	return platform_driver_register(&ohci_hcd_at91_driver);
+-}
+-
+-static void __exit ohci_hcd_at91_cleanup (void)
+-{
+-	platform_driver_unregister(&ohci_hcd_at91_driver);
+-}
+-
+-module_init (ohci_hcd_at91_init);
+-module_exit (ohci_hcd_at91_cleanup);
+diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
+index e70b243..663a060 100644
+--- a/drivers/usb/host/ohci-au1xxx.c
++++ b/drivers/usb/host/ohci-au1xxx.c
+@@ -345,19 +345,3 @@ static struct platform_driver ohci_hcd_au1xxx_driver = {
+ 	},
+ };
+ 
+-static int __init ohci_hcd_au1xxx_init (void)
+-{
+-	pr_debug (DRIVER_INFO " (Au1xxx)");
+-	pr_debug ("block sizes: ed %d td %d\n",
+-		sizeof (struct ed), sizeof (struct td));
+-
+-	return platform_driver_register(&ohci_hcd_au1xxx_driver);
+-}
+-
+-static void __exit ohci_hcd_au1xxx_cleanup (void)
+-{
+-	platform_driver_unregister(&ohci_hcd_au1xxx_driver);
+-}
+-
+-module_init (ohci_hcd_au1xxx_init);
+-module_exit (ohci_hcd_au1xxx_cleanup);
+diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c
+index 43ae696..e9974c3 100644
+--- a/drivers/usb/host/ohci-ep93xx.c
++++ b/drivers/usb/host/ohci-ep93xx.c
+@@ -214,15 +214,3 @@ static struct platform_driver ohci_hcd_ep93xx_driver = {
+ 	},
+ };
+ 
+-static int __init ohci_hcd_ep93xx_init(void)
+-{
+-	return platform_driver_register(&ohci_hcd_ep93xx_driver);
+-}
+-
+-static void __exit ohci_hcd_ep93xx_cleanup(void)
+-{
+-	platform_driver_unregister(&ohci_hcd_ep93xx_driver);
+-}
+-
+-module_init(ohci_hcd_ep93xx_init);
+-module_exit(ohci_hcd_ep93xx_cleanup);
+diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
+index c1c1d87..9926b8f 100644
+--- a/drivers/usb/host/ohci-hcd.c
++++ b/drivers/usb/host/ohci-hcd.c
+@@ -855,63 +855,131 @@ MODULE_LICENSE ("GPL");
+ 
+ #ifdef CONFIG_PCI
+ #include "ohci-pci.c"
++#define PCI_DRIVER		ohci_pci_driver
+ #endif
+ 
+ #ifdef CONFIG_SA1111
+ #include "ohci-sa1111.c"
++#define SA1111_DRIVER		ohci_hcd_sa1111_driver
+ #endif
+ 
+ #ifdef CONFIG_ARCH_S3C2410
+ #include "ohci-s3c2410.c"
++#define PLATFORM_DRIVER		ohci_hcd_s3c2410_driver
+ #endif
+ 
+ #ifdef CONFIG_ARCH_OMAP
+ #include "ohci-omap.c"
++#define PLATFORM_DRIVER		ohci_hcd_omap_driver
+ #endif
+ 
+ #ifdef CONFIG_ARCH_LH7A404
+ #include "ohci-lh7a404.c"
++#define PLATFORM_DRIVER		ohci_hcd_lh7a404_driver
+ #endif
+ 
+ #ifdef CONFIG_PXA27x
+ #include "ohci-pxa27x.c"
++#define PLATFORM_DRIVER		ohci_hcd_pxa27x_driver
+ #endif
+ 
+ #ifdef CONFIG_ARCH_EP93XX
+ #include "ohci-ep93xx.c"
++#define PLATFORM_DRIVER		ohci_hcd_ep93xx_driver
+ #endif
+ 
+ #ifdef CONFIG_SOC_AU1X00
+ #include "ohci-au1xxx.c"
++#define PLATFORM_DRIVER		ohci_hcd_au1xxx_driver
+ #endif
+ 
+-#ifdef CONFIG_PNX8550
+-#include "ohci-pnx8550.c"
+-#endif
++#ifdef CONFIG_PNX8550 
++#include "ohci-pnx8550.c" 
++#define PLATFORM_DRIVER		ohci_hcd_pnx8550_driver
++#endif 
+ 
+ #ifdef CONFIG_USB_OHCI_HCD_PPC_SOC
+ #include "ohci-ppc-soc.c"
++#define PLATFORM_DRIVER		ohci_hcd_ppc_soc_driver
+ #endif
+ 
+ #ifdef CONFIG_ARCH_AT91
+ #include "ohci-at91.c"
++#define PLATFORM_DRIVER		ohci_hcd_at91_driver
+ #endif
+ 
+ #ifdef CONFIG_ARCH_PNX4008
+ #include "ohci-pnx4008.c"
++#define PLATFORM_DRIVER		usb_hcd_pnx4008_driver
+ #endif
+ 
+-#if !(defined(CONFIG_PCI) \
+-      || defined(CONFIG_SA1111) \
+-      || defined(CONFIG_ARCH_S3C2410) \
+-      || defined(CONFIG_ARCH_OMAP) \
+-      || defined (CONFIG_ARCH_LH7A404) \
+-      || defined (CONFIG_PXA27x) \
+-      || defined (CONFIG_ARCH_EP93XX) \
+-      || defined (CONFIG_SOC_AU1X00) \
+-      || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
+-      || defined (CONFIG_ARCH_AT91) \
+-      || defined (CONFIG_ARCH_PNX4008) \
+-	)
++
++#if	!defined(PCI_DRIVER) &&		\
++	!defined(PLATFORM_DRIVER) &&	\
++	!defined(SA1111_DRIVER)
+ #error "missing bus glue for ohci-hcd"
+ #endif
++
++static int __init ohci_hcd_mod_init(void)
++{
++	int retval = 0;
++	int ls = 0;
++
++	if (usb_disabled())
++		return -ENODEV;
++
++	printk (KERN_DEBUG "%s: " DRIVER_INFO "\n", hcd_name);
++	pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
++		sizeof (struct ed), sizeof (struct td));
++
++#ifdef PLATFORM_DRIVER
++	retval = platform_driver_register(&PLATFORM_DRIVER);
++	if (retval < 0)
++		return retval;
++	ls++;
++#endif
++
++#ifdef SA1111_DRIVER
++	retval = sa1111_driver_register(&SA1111_DRIVER);
++	if (retval < 0)
++		goto error;
++	ls++;
++#endif
++
++#ifdef PCI_DRIVER
++	retval = pci_register_driver(&PCI_DRIVER);
++	if (retval < 0)
++		goto error;
++	ls++;
++#endif
++
++	return retval;
++
++	/* Error path */
++error:
++#ifdef PLATFORM_DRIVER
++	if (ls--)
++		platform_driver_unregister(&PLATFORM_DRIVER);
++#endif
++#ifdef SA1111_DRIVER
++	if (ls--)
++		sa1111_driver_unregister(&SA1111_DRIVER);
++#endif
++	return retval;
++}
++module_init(ohci_hcd_mod_init);
++
++static void __exit ohci_hcd_mod_exit(void)
++{
++#ifdef PCI_DRIVER
++	pci_unregister_driver(&PCI_DRIVER);
++#endif
++#ifdef SA1111_DRIVER
++	sa1111_driver_unregister(&SA1111_DRIVER);
++#endif
++#ifdef PLATFORM_DRIVER
++	platform_driver_unregister(&PLATFORM_DRIVER);
++#endif
++}
++module_exit(ohci_hcd_mod_exit);
++
+diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c
+index e9807cf..4a043ab 100644
+--- a/drivers/usb/host/ohci-lh7a404.c
++++ b/drivers/usb/host/ohci-lh7a404.c
+@@ -251,19 +251,3 @@ static struct platform_driver ohci_hcd_lh7a404_driver = {
+ 	},
+ };
+ 
+-static int __init ohci_hcd_lh7a404_init (void)
+-{
+-	pr_debug (DRIVER_INFO " (LH7A404)");
+-	pr_debug ("block sizes: ed %d td %d\n",
+-		sizeof (struct ed), sizeof (struct td));
+-
+-	return platform_driver_register(&ohci_hcd_lh7a404_driver);
+-}
+-
+-static void __exit ohci_hcd_lh7a404_cleanup (void)
+-{
+-	platform_driver_unregister(&ohci_hcd_lh7a404_driver);
+-}
+-
+-module_init (ohci_hcd_lh7a404_init);
+-module_exit (ohci_hcd_lh7a404_cleanup);
+diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
+index 27be1f9..5cfa3d1 100644
+--- a/drivers/usb/host/ohci-omap.c
++++ b/drivers/usb/host/ohci-omap.c
+@@ -544,22 +544,3 @@ static struct platform_driver ohci_hcd_omap_driver = {
+ 	},
+ };
+ 
+-static int __init ohci_hcd_omap_init (void)
+-{
+-	printk (KERN_DEBUG "%s: " DRIVER_INFO " (OMAP)\n", hcd_name);
+-	if (usb_disabled())
+-		return -ENODEV;
+-
+-	pr_debug("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
+-		sizeof (struct ed), sizeof (struct td));
+-
+-	return platform_driver_register(&ohci_hcd_omap_driver);
+-}
+-
+-static void __exit ohci_hcd_omap_cleanup (void)
+-{
+-	platform_driver_unregister(&ohci_hcd_omap_driver);
+-}
+-
+-module_init (ohci_hcd_omap_init);
+-module_exit (ohci_hcd_omap_cleanup);
+diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
+index 292daf0..b331ac4 100644
+--- a/drivers/usb/host/ohci-pci.c
++++ b/drivers/usb/host/ohci-pci.c
+@@ -311,23 +311,3 @@ static struct pci_driver ohci_pci_driver = {
+ 	.shutdown =	usb_hcd_pci_shutdown,
+ };
+ 
+-
+-static int __init ohci_hcd_pci_init (void)
+-{
+-	printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name);
+-	if (usb_disabled())
+-		return -ENODEV;
+-
+-	pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
+-		sizeof (struct ed), sizeof (struct td));
+-	return pci_register_driver (&ohci_pci_driver);
+-}
+-module_init (ohci_hcd_pci_init);
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static void __exit ohci_hcd_pci_cleanup (void)
+-{
+-	pci_unregister_driver (&ohci_pci_driver);
+-}
+-module_exit (ohci_hcd_pci_cleanup);
+diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
+index 3a8cbfb..893b172 100644
+--- a/drivers/usb/host/ohci-pnx4008.c
++++ b/drivers/usb/host/ohci-pnx4008.c
+@@ -465,15 +465,3 @@ static struct platform_driver usb_hcd_pnx4008_driver = {
+ 	.remove = usb_hcd_pnx4008_remove,
+ };
+ 
+-static int __init usb_hcd_pnx4008_init(void)
+-{
+-	return platform_driver_register(&usb_hcd_pnx4008_driver);
+-}
+-
+-static void __exit usb_hcd_pnx4008_cleanup(void)
+-{
+-	return platform_driver_unregister(&usb_hcd_pnx4008_driver);
+-}
+-
+-module_init(usb_hcd_pnx4008_init);
+-module_exit(usb_hcd_pnx4008_cleanup);
+diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c
+index 6922b91..de45eb0 100644
+--- a/drivers/usb/host/ohci-pnx8550.c
++++ b/drivers/usb/host/ohci-pnx8550.c
+@@ -240,19 +240,3 @@ static struct platform_driver ohci_hcd_pnx8550_driver = {
+ 	.remove		= ohci_hcd_pnx8550_drv_remove,
+ };
+ 
+-static int __init ohci_hcd_pnx8550_init (void)
+-{
+-	pr_debug (DRIVER_INFO " (pnx8550)");
+-	pr_debug ("block sizes: ed %d td %d\n",
+-		sizeof (struct ed), sizeof (struct td));
+-
+-	return platform_driver_register(&ohci_hcd_pnx8550_driver);
+-}
+-
+-static void __exit ohci_hcd_pnx8550_cleanup (void)
+-{
+-	platform_driver_unregister(&ohci_hcd_pnx8550_driver);
+-}
+-
+-module_init (ohci_hcd_pnx8550_init);
+-module_exit (ohci_hcd_pnx8550_cleanup);
+diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
+index c7ce8e6..1a2e177 100644
+--- a/drivers/usb/host/ohci-ppc-soc.c
++++ b/drivers/usb/host/ohci-ppc-soc.c
+@@ -208,19 +208,3 @@ static struct platform_driver ohci_hcd_ppc_soc_driver = {
+ 	},
+ };
+ 
+-static int __init ohci_hcd_ppc_soc_init(void)
+-{
+-	pr_debug(DRIVER_INFO " (PPC SOC)\n");
+-	pr_debug("block sizes: ed %d td %d\n", sizeof(struct ed),
+-							sizeof(struct td));
+-
+-	return platform_driver_register(&ohci_hcd_ppc_soc_driver);
+-}
+-
+-static void __exit ohci_hcd_ppc_soc_cleanup(void)
+-{
+-	platform_driver_unregister(&ohci_hcd_ppc_soc_driver);
+-}
+-
+-module_init(ohci_hcd_ppc_soc_init);
+-module_exit(ohci_hcd_ppc_soc_cleanup);
+diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
+index 3bbea84..f1563dc 100644
+--- a/drivers/usb/host/ohci-pxa27x.c
++++ b/drivers/usb/host/ohci-pxa27x.c
+@@ -369,19 +369,3 @@ static struct platform_driver ohci_hcd_pxa27x_driver = {
+ 	},
+ };
+ 
+-static int __init ohci_hcd_pxa27x_init (void)
+-{
+-	pr_debug (DRIVER_INFO " (pxa27x)");
+-	pr_debug ("block sizes: ed %d td %d\n",
+-		sizeof (struct ed), sizeof (struct td));
+-
+-	return platform_driver_register(&ohci_hcd_pxa27x_driver);
+-}
+-
+-static void __exit ohci_hcd_pxa27x_cleanup (void)
+-{
+-	platform_driver_unregister(&ohci_hcd_pxa27x_driver);
+-}
+-
+-module_init (ohci_hcd_pxa27x_init);
+-module_exit (ohci_hcd_pxa27x_cleanup);
+diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
+index b350d45..6829814 100644
+--- a/drivers/usb/host/ohci-s3c2410.c
++++ b/drivers/usb/host/ohci-s3c2410.c
+@@ -501,15 +501,3 @@ static struct platform_driver ohci_hcd_s3c2410_driver = {
+ 	},
+ };
+ 
+-static int __init ohci_hcd_s3c2410_init (void)
+-{
+-	return platform_driver_register(&ohci_hcd_s3c2410_driver);
+-}
+-
+-static void __exit ohci_hcd_s3c2410_cleanup (void)
+-{
+-	platform_driver_unregister(&ohci_hcd_s3c2410_driver);
+-}
+-
+-module_init (ohci_hcd_s3c2410_init);
+-module_exit (ohci_hcd_s3c2410_cleanup);
+diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
+index fe0090e..0f48f2d 100644
+--- a/drivers/usb/host/ohci-sa1111.c
++++ b/drivers/usb/host/ohci-sa1111.c
+@@ -269,19 +269,3 @@ static struct sa1111_driver ohci_hcd_sa1111_driver = {
+ 	.remove		= ohci_hcd_sa1111_drv_remove,
+ };
+ 
+-static int __init ohci_hcd_sa1111_init (void)
+-{
+-	dbg (DRIVER_INFO " (SA-1111)");
+-	dbg ("block sizes: ed %d td %d",
+-		sizeof (struct ed), sizeof (struct td));
+-
+-	return sa1111_driver_register(&ohci_hcd_sa1111_driver);
+-}
+-
+-static void __exit ohci_hcd_sa1111_cleanup (void)
+-{
+-	sa1111_driver_unregister(&ohci_hcd_sa1111_driver);
+-}
+-
+-module_init (ohci_hcd_sa1111_init);
+-module_exit (ohci_hcd_sa1111_cleanup);
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0009-ohci-Add-support-for-OHCI-controller-on-the-of_platform-bus.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0009-ohci-Add-support-for-OHCI-controller-on-the-of_platform-bus.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,349 @@
+From 944afcaa19737396ed514e3e845a3db2de9377f3 Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Wed, 13 Dec 2006 21:03:30 +0100
+Subject: [PATCH] [PATCH] ohci: Add support for OHCI controller on the of_platform bus
+
+PPC embedded systems can have a ohci controller builtin. In the
+new model, it will end up as a driver on the of_platform bus,
+this patches takes care of them.
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+Acked-by: David Brownell <dbrownell at users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+---
+ drivers/usb/host/Kconfig       |   23 ++++-
+ drivers/usb/host/ohci-hcd.c    |   20 ++++
+ drivers/usb/host/ohci-ppc-of.c |  232 ++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 274 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
+index faabce8..c49715d 100644
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -107,9 +107,30 @@ config USB_OHCI_HCD_PPC_SOC
+ 	  Enables support for the USB controller on the MPC52xx or
+ 	  STB03xxx processor chip.  If unsure, say Y.
+ 
++config USB_OHCI_HCD_PPC_OF
++	bool "OHCI support for PPC USB controller on OF platform bus"
++	depends on USB_OHCI_HCD && PPC_OF
++	default y
++	---help---
++	  Enables support for the USB controller PowerPC present on the
++	  OpenFirmware platform bus.
++
++config USB_OHCI_HCD_PPC_OF_BE
++	bool "Support big endian HC"
++	depends on USB_OHCI_HCD_PPC_OF
++	default y
++	select USB_OHCI_BIG_ENDIAN_DESC
++	select USB_OHCI_BIG_ENDIAN_MMIO
++
++config USB_OHCI_HCD_PPC_OF_LE
++	bool "Support little endian HC"
++	depends on USB_OHCI_HCD_PPC_OF
++	default n
++	select USB_OHCI_LITTLE_ENDIAN
++
+ config USB_OHCI_HCD_PCI
+ 	bool "OHCI support for PCI-bus USB controllers"
+-	depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx)
++	depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF)
+ 	default y
+ 	select USB_OHCI_LITTLE_ENDIAN
+ 	---help---
+diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
+index 9926b8f..c6ae1ff 100644
+--- a/drivers/usb/host/ohci-hcd.c
++++ b/drivers/usb/host/ohci-hcd.c
+@@ -914,8 +914,14 @@ MODULE_LICENSE ("GPL");
+ #endif
+ 
+ 
++#ifdef CONFIG_USB_OHCI_HCD_PPC_OF
++#include "ohci-ppc-of.c"
++#define OF_PLATFORM_DRIVER	ohci_hcd_ppc_of_driver
++#endif
++
+ #if	!defined(PCI_DRIVER) &&		\
+ 	!defined(PLATFORM_DRIVER) &&	\
++	!defined(OF_PLATFORM_DRIVER) &&	\
+ 	!defined(SA1111_DRIVER)
+ #error "missing bus glue for ohci-hcd"
+ #endif
+@@ -939,6 +945,13 @@ static int __init ohci_hcd_mod_init(void)
+ 	ls++;
+ #endif
+ 
++#ifdef OF_PLATFORM_DRIVER
++	retval = of_register_platform_driver(&OF_PLATFORM_DRIVER);
++	if (retval < 0)
++		goto error;
++	ls++;
++#endif
++
+ #ifdef SA1111_DRIVER
+ 	retval = sa1111_driver_register(&SA1111_DRIVER);
+ 	if (retval < 0)
+@@ -961,6 +974,10 @@ error:
+ 	if (ls--)
+ 		platform_driver_unregister(&PLATFORM_DRIVER);
+ #endif
++#ifdef OF_PLATFORM_DRIVER
++	if (ls--)
++		of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
++#endif
+ #ifdef SA1111_DRIVER
+ 	if (ls--)
+ 		sa1111_driver_unregister(&SA1111_DRIVER);
+@@ -977,6 +994,9 @@ static void __exit ohci_hcd_mod_exit(void)
+ #ifdef SA1111_DRIVER
+ 	sa1111_driver_unregister(&SA1111_DRIVER);
+ #endif
++#ifdef OF_PLATFORM_DRIVER
++	of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
++#endif
+ #ifdef PLATFORM_DRIVER
+ 	platform_driver_unregister(&PLATFORM_DRIVER);
+ #endif
+diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
+new file mode 100644
+index 0000000..84b555b
+--- /dev/null
++++ b/drivers/usb/host/ohci-ppc-of.c
+@@ -0,0 +1,232 @@
++/*
++ * OHCI HCD (Host Controller Driver) for USB.
++ *
++ * (C) Copyright 1999 Roman Weissgaerber <weissg at vienna.at>
++ * (C) Copyright 2000-2002 David Brownell <dbrownell at users.sourceforge.net>
++ * (C) Copyright 2002 Hewlett-Packard Company
++ * (C) Copyright 2006 Sylvain Munaut <tnt at 246tNt.com>
++ *
++ * Bus glue for OHCI HC on the of_platform bus
++ *
++ * Modified for of_platform bus from ohci-sa1111.c
++ *
++ * This file is licenced under the GPL.
++ */
++
++#include <linux/signal.h>
++
++#include <asm/of_platform.h>
++#include <asm/prom.h>
++
++
++static int __devinit
++ohci_ppc_of_start(struct usb_hcd *hcd)
++{
++	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
++	int		ret;
++
++	if ((ret = ohci_init(ohci)) < 0)
++		return ret;
++
++	if ((ret = ohci_run(ohci)) < 0) {
++		err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
++		ohci_stop(hcd);
++		return ret;
++	}
++
++	return 0;
++}
++
++static const struct hc_driver ohci_ppc_of_hc_driver = {
++	.description =		hcd_name,
++	.product_desc =		"OF OHCI",
++	.hcd_priv_size =	sizeof(struct ohci_hcd),
++
++	/*
++	 * generic hardware linkage
++	 */
++	.irq =			ohci_irq,
++	.flags =		HCD_USB11 | HCD_MEMORY,
++
++	/*
++	 * basic lifecycle operations
++	 */
++	.start =		ohci_ppc_of_start,
++	.stop =			ohci_stop,
++	.shutdown = 		ohci_shutdown,
++
++	/*
++	 * managing i/o requests and associated device resources
++	 */
++	.urb_enqueue =		ohci_urb_enqueue,
++	.urb_dequeue =		ohci_urb_dequeue,
++	.endpoint_disable =	ohci_endpoint_disable,
++
++	/*
++	 * scheduling support
++	 */
++	.get_frame_number =	ohci_get_frame,
++
++	/*
++	 * root hub support
++	 */
++	.hub_status_data =	ohci_hub_status_data,
++	.hub_control =		ohci_hub_control,
++	.hub_irq_enable =	ohci_rhsc_enable,
++#ifdef	CONFIG_PM
++	.bus_suspend =		ohci_bus_suspend,
++	.bus_resume =		ohci_bus_resume,
++#endif
++	.start_port_reset =	ohci_start_port_reset,
++};
++
++
++static int __devinit
++ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
++{
++	struct device_node *dn = op->node;
++	struct usb_hcd *hcd;
++	struct ohci_hcd	*ohci;
++	struct resource res;
++	int irq;
++
++	int rv;
++	int is_bigendian;
++
++	if (usb_disabled())
++		return -ENODEV;
++
++	is_bigendian = 
++		device_is_compatible(dn, "ohci-bigendian") ||
++		device_is_compatible(dn, "ohci-be");;
++
++	dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
++
++	rv = of_address_to_resource(dn, 0, &res);
++	if (rv)
++		return rv;
++
++	hcd = usb_create_hcd(&ohci_ppc_of_hc_driver, &op->dev, "PPC-OF USB");
++	if (!hcd)
++		return -ENOMEM;
++
++	hcd->rsrc_start = res.start;
++	hcd->rsrc_len = res.end - res.start + 1;
++
++	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
++		printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
++		rv = -EBUSY;
++		goto err_rmr;
++	}
++
++	irq = irq_of_parse_and_map(dn, 0);
++	if (irq == NO_IRQ) {
++		printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
++		rv = -EBUSY;
++		goto err_irq;
++	}
++
++	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
++	if (!hcd->regs) {
++		printk(KERN_ERR __FILE__ ": ioremap failed\n");
++		rv = -ENOMEM;
++		goto err_ioremap;
++	}
++
++	ohci = hcd_to_ohci(hcd);
++	if (is_bigendian)
++		ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
++
++	ohci_hcd_init(ohci);
++
++	rv = usb_add_hcd(hcd, irq, 0);
++	if (rv == 0)
++		return 0;
++
++	iounmap(hcd->regs);
++err_ioremap:
++	irq_dispose_mapping(irq);
++err_irq:
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++err_rmr:
++ 	usb_put_hcd(hcd);
++
++	return rv;
++}
++
++static int ohci_hcd_ppc_of_remove(struct of_device *op)
++{
++	struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
++	dev_set_drvdata(&op->dev, NULL);
++
++	dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
++
++	usb_remove_hcd(hcd);
++
++	iounmap(hcd->regs);
++	irq_dispose_mapping(hcd->irq);
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++
++	usb_put_hcd(hcd);
++
++	return 0;
++}
++
++static int ohci_hcd_ppc_of_shutdown(struct of_device *op)
++{
++	struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
++
++        if (hcd->driver->shutdown)
++                hcd->driver->shutdown(hcd);
++
++	return 0;
++}
++
++
++static struct of_device_id ohci_hcd_ppc_of_match[] = {
++#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
++	{
++		.name = "usb",
++		.compatible = "ohci-bigendian",
++	},
++	{
++		.name = "usb",
++		.compatible = "ohci-be",
++	},
++#endif
++#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_LE
++	{
++		.name = "usb",
++		.compatible = "ohci-littledian",
++	},
++	{
++		.name = "usb",
++		.compatible = "ohci-le",
++	},
++#endif
++	{},
++};
++MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match); 
++
++#if	!defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \
++	!defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE)
++#error "No endianess selected for ppc-of-ohci"
++#endif
++
++
++static struct of_platform_driver ohci_hcd_ppc_of_driver = {
++	.name		= "ppc-of-ohci",
++	.match_table	= ohci_hcd_ppc_of_match,
++	.probe		= ohci_hcd_ppc_of_probe,
++	.remove		= ohci_hcd_ppc_of_remove,
++	.shutdown 	= ohci_hcd_ppc_of_shutdown,
++#ifdef CONFIG_PM
++	/*.suspend	= ohci_hcd_ppc_soc_drv_suspend,*/
++	/*.resume	= ohci_hcd_ppc_soc_drv_resume,*/
++#endif
++	.driver		= {
++		.name	= "ppc-of-ohci",
++		.owner	= THIS_MODULE,
++	},
++};
++
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0010-libata-Add-support-for-the-MPC52xx-ATA-controller.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0010-libata-Add-support-for-the-MPC52xx-ATA-controller.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,620 @@
+From 83ebd6314e55f9baf2c4e795397346b338274ef5 Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Fri, 8 Dec 2006 00:08:14 +0100
+Subject: [PATCH] [PATCH] libata: Add support for the MPC52xx ATA controller
+
+This patch adds initial libata support for the Freescale
+MPC5200 integrated IDE controller.
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+Signed-off-by: Jeff Garzik <jeff at garzik.org>
+---
+ drivers/ata/Kconfig        |    9 +
+ drivers/ata/Makefile       |    1 +
+ drivers/ata/pata_mpc52xx.c |  563 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 573 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
+index b34e0a9..fa1d327 100644
+--- a/drivers/ata/Kconfig
++++ b/drivers/ata/Kconfig
+@@ -337,6 +337,15 @@ config PATA_MARVELL
+ 
+ 	  If unsure, say N.
+ 
++config PATA_MPC52xx
++	tristate "Freescale MPC52xx SoC internal IDE"
++	depends on PPC_MPC52xx
++	help
++	  This option enables support for integrated IDE controller
++	  of the Freescale MPC52xx SoC.
++
++	  If unsure, say N.
++
+ config PATA_MPIIX
+ 	tristate "Intel PATA MPIIX support"
+ 	depends on PCI
+diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
+index bc3d81a..3081e1f 100644
+--- a/drivers/ata/Makefile
++++ b/drivers/ata/Makefile
+@@ -38,6 +38,7 @@ obj-$(CONFIG_PATA_NETCELL)	+= pata_netcell.o
+ obj-$(CONFIG_PATA_NS87410)	+= pata_ns87410.o
+ obj-$(CONFIG_PATA_OPTI)		+= pata_opti.o
+ obj-$(CONFIG_PATA_OPTIDMA)	+= pata_optidma.o
++obj-$(CONFIG_PATA_MPC52xx)	+= pata_mpc52xx.o
+ obj-$(CONFIG_PATA_MARVELL)	+= pata_marvell.o
+ obj-$(CONFIG_PATA_MPIIX)	+= pata_mpiix.o
+ obj-$(CONFIG_PATA_OLDPIIX)	+= pata_oldpiix.o
+diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
+new file mode 100644
+index 0000000..8b7019a
+--- /dev/null
++++ b/drivers/ata/pata_mpc52xx.c
+@@ -0,0 +1,563 @@
++/*
++ * drivers/ata/pata_mpc52xx.c
++ *
++ * libata driver for the Freescale MPC52xx on-chip IDE interface
++ *
++ * Copyright (C) 2006 Sylvain Munaut <tnt at 246tNt.com>
++ * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt
++ *
++ * 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/delay.h>
++#include <linux/libata.h>
++
++#include <asm/io.h>
++#include <asm/types.h>
++#include <asm/prom.h>
++#include <asm/of_platform.h>
++#include <asm/mpc52xx.h>
++
++
++#define DRV_NAME	"mpc52xx_ata"
++#define DRV_VERSION	"0.1.0"
++
++
++/* Private structures used by the driver */
++struct mpc52xx_ata_timings {
++	u32	pio1;
++	u32	pio2;
++};
++
++struct mpc52xx_ata_priv {
++	unsigned int			ipb_period;
++	struct mpc52xx_ata __iomem *	ata_regs;
++	int				ata_irq;
++	struct mpc52xx_ata_timings	timings[2];
++	int				csel;
++};
++
++
++/* ATAPI-4 PIO specs (in ns) */
++static const int ataspec_t0[5]    = {600, 383, 240, 180, 120};
++static const int ataspec_t1[5]    = { 70,  50,  30,  30,  25};
++static const int ataspec_t2_8[5]  = {290, 290, 290,  80,  70};
++static const int ataspec_t2_16[5] = {165, 125, 100,  80,  70};
++static const int ataspec_t2i[5]   = {  0,   0,   0,  70,  25};
++static const int ataspec_t4[5]    = { 30,  20,  15,  10,  10};
++static const int ataspec_ta[5]    = { 35,  35,  35,  35,  35};
++
++#define CALC_CLKCYC(c,v) ((((v)+(c)-1)/(c)))
++
++
++/* Bit definitions inside the registers */
++#define MPC52xx_ATA_HOSTCONF_SMR	0x80000000UL /* State machine reset */
++#define MPC52xx_ATA_HOSTCONF_FR		0x40000000UL /* FIFO Reset */
++#define MPC52xx_ATA_HOSTCONF_IE		0x02000000UL /* Enable interrupt in PIO */
++#define MPC52xx_ATA_HOSTCONF_IORDY	0x01000000UL /* Drive supports IORDY protocol */
++
++#define MPC52xx_ATA_HOSTSTAT_TIP	0x80000000UL /* Transaction in progress */
++#define MPC52xx_ATA_HOSTSTAT_UREP	0x40000000UL /* UDMA Read Extended Pause */
++#define MPC52xx_ATA_HOSTSTAT_RERR	0x02000000UL /* Read Error */
++#define MPC52xx_ATA_HOSTSTAT_WERR	0x01000000UL /* Write Error */
++
++#define MPC52xx_ATA_FIFOSTAT_EMPTY	0x01 /* FIFO Empty */
++
++#define MPC52xx_ATA_DMAMODE_WRITE	0x01 /* Write DMA */
++#define MPC52xx_ATA_DMAMODE_READ	0x02 /* Read DMA */
++#define MPC52xx_ATA_DMAMODE_UDMA	0x04 /* UDMA enabled */
++#define MPC52xx_ATA_DMAMODE_IE		0x08 /* Enable drive interrupt to CPU in DMA mode */
++#define MPC52xx_ATA_DMAMODE_FE		0x10 /* FIFO Flush enable in Rx mode */
++#define MPC52xx_ATA_DMAMODE_FR		0x20 /* FIFO Reset */
++#define MPC52xx_ATA_DMAMODE_HUT		0x40 /* Host UDMA burst terminate */
++
++
++/* Structure of the hardware registers */
++struct mpc52xx_ata {
++
++	/* Host interface registers */
++	u32 config;		/* ATA + 0x00 Host configuration */
++	u32 host_status;	/* ATA + 0x04 Host controller status */
++	u32 pio1;		/* ATA + 0x08 PIO Timing 1 */
++	u32 pio2;		/* ATA + 0x0c PIO Timing 2 */
++	u32 mdma1;		/* ATA + 0x10 MDMA Timing 1 */
++	u32 mdma2;		/* ATA + 0x14 MDMA Timing 2 */
++	u32 udma1;		/* ATA + 0x18 UDMA Timing 1 */
++	u32 udma2;		/* ATA + 0x1c UDMA Timing 2 */
++	u32 udma3;		/* ATA + 0x20 UDMA Timing 3 */
++	u32 udma4;		/* ATA + 0x24 UDMA Timing 4 */
++	u32 udma5;		/* ATA + 0x28 UDMA Timing 5 */
++	u32 share_cnt;		/* ATA + 0x2c ATA share counter */
++	u32 reserved0[3];
++
++	/* FIFO registers */
++	u32 fifo_data;		/* ATA + 0x3c */
++	u8  fifo_status_frame;	/* ATA + 0x40 */
++	u8  fifo_status;	/* ATA + 0x41 */
++	u16 reserved7[1];
++	u8  fifo_control;	/* ATA + 0x44 */
++	u8  reserved8[5];
++	u16 fifo_alarm;		/* ATA + 0x4a */
++	u16 reserved9;
++	u16 fifo_rdp;		/* ATA + 0x4e */
++	u16 reserved10;
++	u16 fifo_wrp;		/* ATA + 0x52 */
++	u16 reserved11;
++	u16 fifo_lfrdp;		/* ATA + 0x56 */
++	u16 reserved12;
++	u16 fifo_lfwrp;		/* ATA + 0x5a */
++
++	/* Drive TaskFile registers */
++	u8  tf_control;		/* ATA + 0x5c TASKFILE Control/Alt Status */
++	u8  reserved13[3];
++	u16 tf_data;		/* ATA + 0x60 TASKFILE Data */
++	u16 reserved14;
++	u8  tf_features;	/* ATA + 0x64 TASKFILE Features/Error */
++	u8  reserved15[3];
++	u8  tf_sec_count;	/* ATA + 0x68 TASKFILE Sector Count */
++	u8  reserved16[3];
++	u8  tf_sec_num;		/* ATA + 0x6c TASKFILE Sector Number */
++	u8  reserved17[3];
++	u8  tf_cyl_low;		/* ATA + 0x70 TASKFILE Cylinder Low */
++	u8  reserved18[3];
++	u8  tf_cyl_high;	/* ATA + 0x74 TASKFILE Cylinder High */
++	u8  reserved19[3];
++	u8  tf_dev_head;	/* ATA + 0x78 TASKFILE Device/Head */
++	u8  reserved20[3];
++	u8  tf_command;		/* ATA + 0x7c TASKFILE Command/Status */
++	u8  dma_mode;		/* ATA + 0x7d ATA Host DMA Mode configuration */
++	u8  reserved21[2];
++};
++
++
++/* ======================================================================== */
++/* Aux fns                                                                  */
++/* ======================================================================== */
++
++
++/* MPC52xx low level hw control */
++
++static int
++mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_priv *priv, int dev, int pio)
++{
++	struct mpc52xx_ata_timings *timing = &priv->timings[dev];
++	unsigned int ipb_period = priv->ipb_period;
++	unsigned int t0, t1, t2_8, t2_16, t2i, t4, ta;
++
++	if ((pio<0) || (pio>4))
++		return -EINVAL;
++
++	t0	= CALC_CLKCYC(ipb_period, 1000 * ataspec_t0[pio]);
++	t1	= CALC_CLKCYC(ipb_period, 1000 * ataspec_t1[pio]);
++	t2_8	= CALC_CLKCYC(ipb_period, 1000 * ataspec_t2_8[pio]);
++	t2_16	= CALC_CLKCYC(ipb_period, 1000 * ataspec_t2_16[pio]);
++	t2i	= CALC_CLKCYC(ipb_period, 1000 * ataspec_t2i[pio]);
++	t4	= CALC_CLKCYC(ipb_period, 1000 * ataspec_t4[pio]);
++	ta	= CALC_CLKCYC(ipb_period, 1000 * ataspec_ta[pio]);
++
++	timing->pio1 = (t0 << 24) | (t2_8 << 16) | (t2_16 << 8) | (t2i);
++	timing->pio2 = (t4 << 24) | (t1 << 16) | (ta << 8);
++
++	return 0;
++}
++
++static void
++mpc52xx_ata_apply_timings(struct mpc52xx_ata_priv *priv, int device)
++{
++	struct mpc52xx_ata __iomem *regs = priv->ata_regs;
++	struct mpc52xx_ata_timings *timing = &priv->timings[device];
++
++	out_be32(&regs->pio1,  timing->pio1);
++	out_be32(&regs->pio2,  timing->pio2);
++	out_be32(&regs->mdma1, 0);
++	out_be32(&regs->mdma2, 0);
++	out_be32(&regs->udma1, 0);
++	out_be32(&regs->udma2, 0);
++	out_be32(&regs->udma3, 0);
++	out_be32(&regs->udma4, 0);
++	out_be32(&regs->udma5, 0);
++
++	priv->csel = device;
++}
++
++static int
++mpc52xx_ata_hw_init(struct mpc52xx_ata_priv *priv)
++{
++	struct mpc52xx_ata __iomem *regs = priv->ata_regs;
++	int tslot;
++
++	/* Clear share_cnt (all sample code do this ...) */
++	out_be32(&regs->share_cnt, 0);
++
++	/* Configure and reset host */
++	out_be32(&regs->config,
++			MPC52xx_ATA_HOSTCONF_IE |
++			MPC52xx_ATA_HOSTCONF_IORDY |
++			MPC52xx_ATA_HOSTCONF_SMR |
++			MPC52xx_ATA_HOSTCONF_FR);
++
++	udelay(10);
++
++	out_be32(&regs->config,
++			MPC52xx_ATA_HOSTCONF_IE |
++			MPC52xx_ATA_HOSTCONF_IORDY);
++
++	/* Set the time slot to 1us */
++	tslot = CALC_CLKCYC(priv->ipb_period, 1000000);
++	out_be32(&regs->share_cnt, tslot << 16 );
++
++	/* Init timings to PIO0 */
++	memset(priv->timings, 0x00, 2*sizeof(struct mpc52xx_ata_timings));
++
++	mpc52xx_ata_compute_pio_timings(priv, 0, 0);
++	mpc52xx_ata_compute_pio_timings(priv, 1, 0);
++
++	mpc52xx_ata_apply_timings(priv, 0);
++
++	return 0;
++}
++
++
++/* ======================================================================== */
++/* libata driver                                                            */
++/* ======================================================================== */
++
++static void
++mpc52xx_ata_set_piomode(struct ata_port *ap, struct ata_device *adev)
++{
++	struct mpc52xx_ata_priv *priv = ap->host->private_data;
++	int pio, rv;
++
++	pio = adev->pio_mode - XFER_PIO_0;
++
++	rv = mpc52xx_ata_compute_pio_timings(priv, adev->devno, pio);
++
++	if (rv) {
++		printk(KERN_ERR DRV_NAME
++			": Trying to select invalid PIO mode %d\n", pio);
++		return;
++	}
++
++	mpc52xx_ata_apply_timings(priv, adev->devno);
++}
++static void
++mpc52xx_ata_dev_select(struct ata_port *ap, unsigned int device)
++{
++	struct mpc52xx_ata_priv *priv = ap->host->private_data;
++
++	if (device != priv->csel)
++		mpc52xx_ata_apply_timings(priv, device);
++
++	ata_std_dev_select(ap,device);
++}
++
++static void
++mpc52xx_ata_error_handler(struct ata_port *ap)
++{
++	ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, NULL,
++			ata_std_postreset);
++}
++
++
++
++static struct scsi_host_template mpc52xx_ata_sht = {
++	.module			= THIS_MODULE,
++	.name			= DRV_NAME,
++	.ioctl			= ata_scsi_ioctl,
++	.queuecommand		= ata_scsi_queuecmd,
++	.can_queue		= ATA_DEF_QUEUE,
++	.this_id		= ATA_SHT_THIS_ID,
++	.sg_tablesize		= LIBATA_MAX_PRD,
++	.max_sectors		= ATA_MAX_SECTORS,
++	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
++	.emulated		= ATA_SHT_EMULATED,
++	.use_clustering		= ATA_SHT_USE_CLUSTERING,
++	.proc_name		= DRV_NAME,
++	.dma_boundary		= ATA_DMA_BOUNDARY,
++	.slave_configure	= ata_scsi_slave_config,
++	.bios_param		= ata_std_bios_param,
++};
++
++static struct ata_port_operations mpc52xx_ata_port_ops = {
++	.port_disable		= ata_port_disable,
++	.set_piomode		= mpc52xx_ata_set_piomode,
++	.dev_select		= mpc52xx_ata_dev_select,
++	.tf_load		= ata_tf_load,
++	.tf_read		= ata_tf_read,
++	.check_status		= ata_check_status,
++	.exec_command		= ata_exec_command,
++	.freeze			= ata_bmdma_freeze,
++	.thaw			= ata_bmdma_thaw,
++	.error_handler		= mpc52xx_ata_error_handler,
++	.qc_prep		= ata_qc_prep,
++	.qc_issue		= ata_qc_issue_prot,
++	.data_xfer		= ata_mmio_data_xfer,
++	.irq_handler		= ata_interrupt,
++	.irq_clear		= ata_bmdma_irq_clear,
++	.port_start		= ata_port_start,
++	.port_stop		= ata_port_stop,
++	.host_stop		= ata_host_stop,
++};
++
++static struct ata_probe_ent mpc52xx_ata_probe_ent = {
++	.port_ops	= &mpc52xx_ata_port_ops,
++	.sht		= &mpc52xx_ata_sht,
++	.n_ports	= 1,
++	.pio_mask	= 0x1f,		/* Up to PIO4 */
++	.mwdma_mask	= 0x00,		/* No MWDMA   */
++	.udma_mask	= 0x00,		/* No UDMA    */
++	.port_flags	= ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_MMIO,
++	.irq_flags	= 0,
++};
++
++static int __devinit
++mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv)
++{
++	struct ata_probe_ent *ae = &mpc52xx_ata_probe_ent;
++	struct ata_ioports *aio = &ae->port[0];
++	int rv;
++
++	INIT_LIST_HEAD(&ae->node);
++	ae->dev = dev;
++	ae->irq = priv->ata_irq;
++
++	aio->cmd_addr		= 0;	/* Don't have a classic reg block */
++	aio->altstatus_addr	= (unsigned long)&priv->ata_regs->tf_control;
++	aio->ctl_addr		= (unsigned long)&priv->ata_regs->tf_control;
++	aio->data_addr		= (unsigned long)&priv->ata_regs->tf_data;
++	aio->error_addr		= (unsigned long)&priv->ata_regs->tf_features;
++	aio->feature_addr	= (unsigned long)&priv->ata_regs->tf_features;
++	aio->nsect_addr		= (unsigned long)&priv->ata_regs->tf_sec_count;
++	aio->lbal_addr		= (unsigned long)&priv->ata_regs->tf_sec_num;
++	aio->lbam_addr		= (unsigned long)&priv->ata_regs->tf_cyl_low;
++	aio->lbah_addr		= (unsigned long)&priv->ata_regs->tf_cyl_high;
++	aio->device_addr	= (unsigned long)&priv->ata_regs->tf_dev_head;
++	aio->status_addr	= (unsigned long)&priv->ata_regs->tf_command;
++	aio->command_addr	= (unsigned long)&priv->ata_regs->tf_command;
++
++	ae->private_data = priv;
++
++	rv = ata_device_add(ae);
++
++	return rv ? 0 : -EINVAL;
++}
++
++static struct mpc52xx_ata_priv *
++mpc52xx_ata_remove_one(struct device *dev)
++{
++	struct ata_host *host = dev_get_drvdata(dev);
++	struct mpc52xx_ata_priv *priv = host->private_data;
++
++	ata_host_remove(host);
++
++	return priv;
++}
++
++
++/* ======================================================================== */
++/* OF Platform driver                                                       */
++/* ======================================================================== */
++
++static int __devinit
++mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match)
++{
++	unsigned int ipb_freq;
++	struct resource res_mem;
++	int ata_irq = NO_IRQ;
++	struct mpc52xx_ata __iomem *ata_regs = NULL;
++	struct mpc52xx_ata_priv *priv = NULL;
++	int rv;
++
++	/* Get ipb frequency */
++	ipb_freq = mpc52xx_find_ipb_freq(op->node);
++	if (!ipb_freq) {
++		printk(KERN_ERR DRV_NAME ": "
++			"Unable to find IPB Bus frequency\n" );
++		return -ENODEV;
++	}
++
++	/* Get IRQ and register */
++	rv = of_address_to_resource(op->node, 0, &res_mem);
++	if (rv) {
++		printk(KERN_ERR DRV_NAME ": "
++			"Error while parsing device node resource\n" );
++		return rv;
++	}
++
++	ata_irq = irq_of_parse_and_map(op->node, 0);
++	if (ata_irq == NO_IRQ) {
++		printk(KERN_ERR DRV_NAME ": "
++			"Error while mapping the irq\n");
++		return -EINVAL;
++	}
++
++	/* Request mem region */
++	if (!request_mem_region(res_mem.start,
++				sizeof(struct mpc52xx_ata), DRV_NAME)) {
++		printk(KERN_ERR DRV_NAME ": "
++			"Error while requesting mem region\n");
++		irq_dispose_mapping(ata_irq);
++		return -EBUSY;
++	}
++
++	/* Remap registers */
++	ata_regs = ioremap(res_mem.start, sizeof(struct mpc52xx_ata));
++	if (!ata_regs) {
++		printk(KERN_ERR DRV_NAME ": "
++			"Error while mapping register set\n");
++		rv = -ENOMEM;
++		goto err;
++	}
++
++	/* Prepare our private structure */
++	priv = kmalloc(sizeof(struct mpc52xx_ata_priv), GFP_ATOMIC);
++	if (!priv) {
++		printk(KERN_ERR DRV_NAME ": "
++			"Error while allocating private structure\n");
++		rv = -ENOMEM;
++		goto err;
++	}
++
++	priv->ipb_period = 1000000000 / (ipb_freq / 1000);
++	priv->ata_regs = ata_regs;
++	priv->ata_irq = ata_irq;
++	priv->csel = -1;
++
++	/* Init the hw */
++	rv = mpc52xx_ata_hw_init(priv);
++	if (rv) {
++		printk(KERN_ERR DRV_NAME ": Error during HW init\n");
++		goto err;
++	}
++
++	/* Register ourselves to libata */
++	rv = mpc52xx_ata_init_one(&op->dev, priv);
++	if (rv) {
++		printk(KERN_ERR DRV_NAME ": "
++			"Error while registering to ATA layer\n");
++		return rv;
++	}
++
++	/* Done */
++	return 0;
++
++	/* Error path */
++err:
++	kfree(priv);
++
++	if (ata_regs)
++		iounmap(ata_regs);
++
++	release_mem_region(res_mem.start, sizeof(struct mpc52xx_ata));
++
++	irq_dispose_mapping(ata_irq);
++
++	return rv;
++}
++
++static int
++mpc52xx_ata_remove(struct of_device *op)
++{
++	struct mpc52xx_ata_priv *priv;
++	struct resource res_mem;
++	int rv;
++
++	/* Unregister */
++	priv = mpc52xx_ata_remove_one(&op->dev);
++
++	/* Free everything */
++	iounmap(priv->ata_regs);
++
++	rv = of_address_to_resource(op->node, 0, &res_mem);
++	if (rv) {
++		printk(KERN_ERR DRV_NAME ": "
++			"Error while parsing device node resource\n");
++		printk(KERN_ERR DRV_NAME ": "
++			"Zone may not be properly released\n");
++	} else
++		release_mem_region(res_mem.start, sizeof(struct mpc52xx_ata));
++
++	irq_dispose_mapping(priv->ata_irq);
++
++	kfree(priv);
++
++	return 0;
++}
++
++
++#ifdef CONFIG_PM
++
++static int
++mpc52xx_ata_suspend(struct of_device *op, pm_message_t state)
++{
++	return 0;	/* FIXME : What to do here ? */
++}
++
++static int
++mpc52xx_ata_resume(struct of_device *op)
++{
++	return 0;	/* FIXME : What to do here ? */
++}
++
++#endif
++
++
++static struct of_device_id mpc52xx_ata_of_match[] = {
++	{
++		.compatible = "mpc5200-ata",
++	},
++	{
++		.compatible = "mpc52xx-ata",
++	},
++	{},
++};
++
++
++static struct of_platform_driver mpc52xx_ata_of_platform_driver = {
++	.owner		= THIS_MODULE,
++	.name		= DRV_NAME,
++	.match_table	= mpc52xx_ata_of_match,
++	.probe		= mpc52xx_ata_probe,
++	.remove		= mpc52xx_ata_remove,
++#ifdef CONFIG_PM
++	.suspend	= mpc52xx_ata_suspend,
++	.resume		= mpc52xx_ata_resume,
++#endif
++	.driver		= {
++		.name	= DRV_NAME,
++		.owner	= THIS_MODULE,
++	},
++};
++
++
++/* ======================================================================== */
++/* Module                                                                   */
++/* ======================================================================== */
++
++static int __init
++mpc52xx_ata_init(void)
++{
++	printk(KERN_INFO "ata: MPC52xx IDE/ATA libata driver\n");
++	return of_register_platform_driver(&mpc52xx_ata_of_platform_driver);
++}
++
++static void __exit
++mpc52xx_ata_exit(void)
++{
++	of_unregister_platform_driver(&mpc52xx_ata_of_platform_driver);
++}
++
++module_init(mpc52xx_ata_init);
++module_exit(mpc52xx_ata_exit);
++
++MODULE_AUTHOR("Sylvain Munaut <tnt at 246tNt.com>");
++MODULE_DESCRIPTION("Freescale MPC52xx IDE/ATA libata driver");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(of, mpc52xx_ata_of_match);
++MODULE_VERSION(DRV_VERSION);
++
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0011-ohci-Whitespace-and-typo-fix-in-ohci-ppc-of.c.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0011-ohci-Whitespace-and-typo-fix-in-ohci-ppc-of.c.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,38 @@
+From 947dc060772ceb8b33a35bd2ded245908fa9442f Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sat, 23 Dec 2006 22:16:05 +0100
+Subject: [PATCH] [PATCH] ohci: Whitespace and typo fix in ohci-ppc-of.c
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ drivers/usb/host/ohci-ppc-of.c |    6 +++---
+ 1 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
+index 84b555b..08e237c 100644
+--- a/drivers/usb/host/ohci-ppc-of.c
++++ b/drivers/usb/host/ohci-ppc-of.c
+@@ -96,9 +96,9 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
+ 	if (usb_disabled())
+ 		return -ENODEV;
+ 
+-	is_bigendian = 
++	is_bigendian =
+ 		device_is_compatible(dn, "ohci-bigendian") ||
+-		device_is_compatible(dn, "ohci-be");;
++		device_is_compatible(dn, "ohci-be");
+ 
+ 	dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
+ 
+@@ -206,7 +206,7 @@ static struct of_device_id ohci_hcd_ppc_of_match[] = {
+ #endif
+ 	{},
+ };
+-MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match); 
++MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match);
+ 
+ #if	!defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \
+ 	!defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE)
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0012-ata-Fix-pata_mpc52xx.c-compatible-list.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0012-ata-Fix-pata_mpc52xx.c-compatible-list.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,31 @@
+From 20e872b5fed46ba15ed6f2c29cc2adf98657c9a4 Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sat, 23 Dec 2006 22:20:06 +0100
+Subject: [PATCH] [PATCH] ata: Fix pata_mpc52xx.c 'compatible' list
+
+The list contained an entry to support a non-standard device-tree,
+this is now handled by fixups in early boot.
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ drivers/ata/pata_mpc52xx.c |    4 +---
+ 1 files changed, 1 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
+index 8b7019a..ff40016 100644
+--- a/drivers/ata/pata_mpc52xx.c
++++ b/drivers/ata/pata_mpc52xx.c
+@@ -509,9 +509,7 @@ mpc52xx_ata_resume(struct of_device *op)
+ 
+ static struct of_device_id mpc52xx_ata_of_match[] = {
+ 	{
+-		.compatible = "mpc5200-ata",
+-	},
+-	{
++		.type = "ata",
+ 		.compatible = "mpc52xx-ata",
+ 	},
+ 	{},
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0013-powerpc-serial-Fix-mpc52xx_uart.c-compatible-list.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0013-powerpc-serial-Fix-mpc52xx_uart.c-compatible-list.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,28 @@
+From f3736d1a7f74d7dec888a8a8d8c593ca08a31000 Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sat, 23 Dec 2006 22:21:43 +0100
+Subject: [PATCH] [PATCH] powerpc/serial: Fix mpc52xx_uart.c 'compatible' list
+
+The list contained an entry to support a non-standard device-tree,
+this is now handled by fixups in early boot.
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ drivers/serial/mpc52xx_uart.c |    1 -
+ 1 files changed, 0 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
+index eef3b02..c20cd81 100644
+--- a/drivers/serial/mpc52xx_uart.c
++++ b/drivers/serial/mpc52xx_uart.c
+@@ -128,7 +128,6 @@ static irqreturn_t mpc52xx_uart_int(int irq,void *dev_id);
+ #if defined(CONFIG_PPC_MERGE)
+ static struct of_device_id mpc52xx_uart_of_match[] = {
+ 	{ .type = "serial", .compatible = "mpc52xx-psc-uart", },
+-	{ .type = "serial", .compatible = "mpc5200-psc", }, /* Efika only! */
+ 	{},
+ };
+ #endif
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0014-powerpc-Small-cleanup-of-EFIKA-platform.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0014-powerpc-Small-cleanup-of-EFIKA-platform.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,144 @@
+From 65cd4fcc30440e903fd99973918373ee4534b70a Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sat, 23 Dec 2006 22:39:18 +0100
+Subject: [PATCH] [PATCH] powerpc: Small cleanup of EFIKA platform
+
+This is just some cleanup to remove the efika.h header that just have
+2 lines in it and is not really necessary.
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/platforms/52xx/efika-pci.c   |   23 ++++++++++++++++-------
+ arch/powerpc/platforms/52xx/efika-setup.c |    7 ++++---
+ arch/powerpc/platforms/52xx/efika.h       |   19 -------------------
+ 3 files changed, 20 insertions(+), 29 deletions(-)
+
+diff --git a/arch/powerpc/platforms/52xx/efika-pci.c b/arch/powerpc/platforms/52xx/efika-pci.c
+index 62e05b2..3732dec 100644
+--- a/arch/powerpc/platforms/52xx/efika-pci.c
++++ b/arch/powerpc/platforms/52xx/efika-pci.c
+@@ -1,3 +1,13 @@
++/*
++ * Efika 5K2 PCI support thru RTAS
++ *
++ * Copyright (C) 2006 bplan GmbH
++ *
++ * 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/pci.h>
+@@ -12,7 +22,6 @@
+ #include <asm/pci-bridge.h>
+ #include <asm/rtas.h>
+ 
+-#include "efika.h"
+ 
+ #ifdef CONFIG_PCI
+ /*
+@@ -62,7 +71,7 @@ void __init efika_pcisetup(void)
+ 
+ 	root = of_find_node_by_path("/");
+ 	if (root == NULL) {
+-		printk(KERN_WARNING EFIKA_PLATFORM_NAME
++		printk(KERN_WARNING __FILE__
+ 		       ": Unable to find the root node\n");
+ 		return;
+ 	}
+@@ -76,30 +85,30 @@ void __init efika_pcisetup(void)
+ 	of_node_put(root);
+ 
+ 	if (pcictrl == NULL) {
+-		printk(KERN_WARNING EFIKA_PLATFORM_NAME
++		printk(KERN_WARNING __FILE__
+ 		       ": Unable to find the PCI bridge node\n");
+ 		return;
+ 	}
+ 
+ 	bus_range = get_property(pcictrl, "bus-range", &len);
+ 	if (bus_range == NULL || len < 2 * sizeof(int)) {
+-		printk(KERN_WARNING EFIKA_PLATFORM_NAME
++		printk(KERN_WARNING __FILE__
+ 		       ": Can't get bus-range for %s\n", pcictrl->full_name);
+ 		return;
+ 	}
+ 
+ 	if (bus_range[1] == bus_range[0])
+-		printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI bus %d",
++		printk(KERN_INFO __FILE__ ": PCI bus %d",
+ 		       bus_range[0]);
+ 	else
+-		printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI buses %d..%d",
++		printk(KERN_INFO __FILE__ ": PCI buses %d..%d",
+ 		       bus_range[0], bus_range[1]);
+ 	printk(" controlled by %s\n", pcictrl->full_name);
+ 	printk("\n");
+ 
+ 	hose = pcibios_alloc_controller();
+ 	if (!hose) {
+-		printk(KERN_WARNING EFIKA_PLATFORM_NAME
++		printk(KERN_WARNING __FILE__
+ 		       ": Can't allocate PCI controller structure for %s\n",
+ 		       pcictrl->full_name);
+ 		return;
+diff --git a/arch/powerpc/platforms/52xx/efika-setup.c b/arch/powerpc/platforms/52xx/efika-setup.c
+index d61ce84..17bf73a 100644
+--- a/arch/powerpc/platforms/52xx/efika-setup.c
++++ b/arch/powerpc/platforms/52xx/efika-setup.c
+@@ -1,5 +1,4 @@
+ /*
+- *
+  * Efika 5K2 platform setup
+  * Some code really inspired from the lite5200b platform.
+  *
+@@ -32,7 +31,9 @@
+ #include <asm/of_platform.h>
+ #include <asm/mpc52xx.h>
+ 
+-#include "efika.h"
++
++extern void __init efika_pcisetup(void);
++
+ 
+ static void efika_show_cpuinfo(struct seq_file *m)
+ {
+@@ -103,7 +104,7 @@ static int __init efika_probe(void)
+ 
+ define_machine(efika)
+ {
+-	.name			= EFIKA_PLATFORM_NAME,
++	.name			= "Efika",
+ 	.probe			= efika_probe,
+ 	.setup_arch		= efika_setup_arch,
+ 	.init			= mpc52xx_declare_of_platform_devices,
+diff --git a/arch/powerpc/platforms/52xx/efika.h b/arch/powerpc/platforms/52xx/efika.h
+deleted file mode 100644
+index 2f060fd..0000000
+--- a/arch/powerpc/platforms/52xx/efika.h
++++ /dev/null
+@@ -1,19 +0,0 @@
+-/*
+- * Efika 5K2 platform setup - Header file
+- *
+- * Copyright (C) 2006 bplan GmbH
+- *
+- * 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 __ARCH_POWERPC_EFIKA__
+-#define __ARCH_POWERPC_EFIKA__
+-
+-#define EFIKA_PLATFORM_NAME "Efika"
+-
+-extern void __init efika_pcisetup(void);
+-
+-#endif
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0015-powerpc-Add-a-unified-uevent-handler-for-bus-based-on-of_device.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0015-powerpc-Add-a-unified-uevent-handler-for-bus-based-on-of_device.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,116 @@
+From 90dc591d4c897c7a49191888c1e4d413cc08b8b7 Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sat, 23 Dec 2006 23:08:56 +0100
+Subject: [PATCH] [PATCH] powerpc: Add a unified uevent handler for bus based on of_device
+
+This common uevent handler allow the several bus types based on
+of_device to generate the uevent properly and avoiding
+code duplication.
+
+This handlers take a struct device as argument and can therefore
+be used as the uevent call directly if no special treatment is
+needed for the bus.
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/kernel/of_device.c |   66 +++++++++++++++++++++++++++++++++++++++
+ include/asm-powerpc/of_device.h |    3 ++
+ 2 files changed, 69 insertions(+), 0 deletions(-)
+
+diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c
+index e921514..ac024ad 100644
+--- a/arch/powerpc/kernel/of_device.c
++++ b/arch/powerpc/kernel/of_device.c
+@@ -120,6 +120,71 @@ void of_device_unregister(struct of_device *ofdev)
+ }
+ 
+ 
++int of_device_uevent(struct device *dev,
++		char **envp, int num_envp, char *buffer, int buffer_size)
++{
++	struct of_device *ofdev;
++	const char *compat;
++	char *compat2;
++	char compat_buf[128];   /* need to be size of 'compatible' */
++	int i = 0, length = 0, seen = 0, cplen, sl;
++
++	if (!dev)
++		return -ENODEV;
++
++	ofdev = to_of_device(dev);
++
++	if (add_uevent_var(envp, num_envp, &i,
++			   buffer, buffer_size, &length,
++			   "OF_NAME=%s", ofdev->node->name))
++		return -ENOMEM;
++
++	if (add_uevent_var(envp, num_envp, &i,
++			   buffer, buffer_size, &length,
++			   "OF_TYPE=%s", ofdev->node->type))
++		return -ENOMEM;
++
++        /* Since the compatible field can contain pretty much anything
++         * it's not really legal to split it out with commas. We split it
++         * up using a number of environment variables instead. */
++
++	compat = get_property(ofdev->node, "compatible", &cplen);
++	compat2 = compat_buf;
++	if (compat)
++		memcpy(compat2, compat, cplen);
++	while (compat && *compat && cplen > 0) {
++		if (add_uevent_var(envp, num_envp, &i,
++				   buffer, buffer_size, &length,
++				   "OF_COMPATIBLE_%d=%s", seen, compat))
++			return -ENOMEM;
++
++		sl = strlen (compat) + 1;
++		compat += sl;
++		compat2 += sl;
++		cplen -= sl;
++		seen++;
++		compat2[-1] = 'C'; 
++	}
++	compat2[seen?-1:0] = 0;
++
++	if (add_uevent_var(envp, num_envp, &i,
++			   buffer, buffer_size, &length,
++			   "OF_COMPATIBLE_N=%d", seen))
++		return -ENOMEM;
++
++	if (add_uevent_var(envp, num_envp, &i,
++			   buffer, buffer_size, &length,
++			   "MODALIAS=of:N%sT%sC%s",
++			   ofdev->node->name, ofdev->node->type,
++			   compat_buf))
++		return -ENOMEM;
++
++	envp[i] = NULL;
++
++	return 0;
++}
++
++
+ EXPORT_SYMBOL(of_match_node);
+ EXPORT_SYMBOL(of_match_device);
+ EXPORT_SYMBOL(of_device_register);
+@@ -127,3 +192,4 @@ EXPORT_SYMBOL(of_device_unregister);
+ EXPORT_SYMBOL(of_dev_get);
+ EXPORT_SYMBOL(of_dev_put);
+ EXPORT_SYMBOL(of_release_dev);
++EXPORT_SYMBOL(of_device_uevent);
+diff --git a/include/asm-powerpc/of_device.h b/include/asm-powerpc/of_device.h
+index a889b20..4f1aabe 100644
+--- a/include/asm-powerpc/of_device.h
++++ b/include/asm-powerpc/of_device.h
+@@ -32,5 +32,8 @@ extern int of_device_register(struct of_device *ofdev);
+ extern void of_device_unregister(struct of_device *ofdev);
+ extern void of_release_dev(struct device *dev);
+ 
++extern int of_device_uevent(struct device *dev,
++	char **envp, int num_envp, char *buffer, int buffer_size);
++
+ #endif /* __KERNEL__ */
+ #endif /* _ASM_POWERPC_OF_DEVICE_H */
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0016-macintosh-Use-the-new-of_device-common-uevent-handler.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0016-macintosh-Use-the-new-of_device-common-uevent-handler.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,130 @@
+From 2507b27c0841752a6f419439896fcb089fa4a5ba Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sat, 23 Dec 2006 23:13:56 +0100
+Subject: [PATCH] [PATCH] macintosh: Use the new of_device common uevent handler
+
+The generation of the uevent is now common to all bus using
+of_device.
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ drivers/macintosh/macio_asic.c |   98 +---------------------------------------
+ 1 files changed, 1 insertions(+), 97 deletions(-)
+
+diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
+index d562160..e851266 100644
+--- a/drivers/macintosh/macio_asic.c
++++ b/drivers/macintosh/macio_asic.c
+@@ -134,108 +134,12 @@ static int macio_device_resume(struct device * dev)
+ 	return 0;
+ }
+ 
+-static int macio_uevent(struct device *dev, char **envp, int num_envp,
+-                          char *buffer, int buffer_size)
+-{
+-	struct macio_dev * macio_dev;
+-	struct of_device * of;
+-	char *scratch;
+-	const char *compat, *compat2;
+-
+-	int i = 0;
+-	int length, cplen, cplen2, seen = 0;
+-
+-	if (!dev)
+-		return -ENODEV;
+-
+-	macio_dev = to_macio_device(dev);
+-	if (!macio_dev)
+-		return -ENODEV;
+-
+-	of = &macio_dev->ofdev;
+-
+-	/* stuff we want to pass to /sbin/hotplug */
+-	envp[i++] = scratch = buffer;
+-	length = scnprintf (scratch, buffer_size, "OF_NAME=%s", of->node->name);
+-	++length;
+-	buffer_size -= length;
+-	if ((buffer_size <= 0) || (i >= num_envp))
+-		return -ENOMEM;
+-	scratch += length;
+-
+-	envp[i++] = scratch;
+-	length = scnprintf (scratch, buffer_size, "OF_TYPE=%s", of->node->type);
+-	++length;
+-	buffer_size -= length;
+-	if ((buffer_size <= 0) || (i >= num_envp))
+-		return -ENOMEM;
+-	scratch += length;
+-
+-        /* Since the compatible field can contain pretty much anything
+-         * it's not really legal to split it out with commas. We split it
+-         * up using a number of environment variables instead. */
+-
+-	compat = get_property(of->node, "compatible", &cplen);
+-	compat2 = compat;
+-	cplen2= cplen;
+-	while (compat && cplen > 0) {
+-                envp[i++] = scratch;
+-		length = scnprintf (scratch, buffer_size,
+-		                     "OF_COMPATIBLE_%d=%s", seen, compat);
+-		++length;
+-		buffer_size -= length;
+-		if ((buffer_size <= 0) || (i >= num_envp))
+-			return -ENOMEM;
+-		scratch += length;
+-		length = strlen (compat) + 1;
+-		compat += length;
+-		cplen -= length;
+-		seen++;
+-	}
+-
+-	envp[i++] = scratch;
+-	length = scnprintf (scratch, buffer_size, "OF_COMPATIBLE_N=%d", seen);
+-	++length;
+-	buffer_size -= length;
+-	if ((buffer_size <= 0) || (i >= num_envp))
+-		return -ENOMEM;
+-	scratch += length;
+-
+-	envp[i++] = scratch;
+-	length = scnprintf (scratch, buffer_size, "MODALIAS=of:N%sT%s",
+-			of->node->name, of->node->type);
+-	/* overwrite '\0' */
+-	buffer_size -= length;
+-	if ((buffer_size <= 0) || (i >= num_envp))
+-		return -ENOMEM;
+-	scratch += length;
+-
+-	if (!compat2) {
+-		compat2 = "";
+-		cplen2 = 1;
+-	}
+-	while (cplen2 > 0) {
+-		length = snprintf (scratch, buffer_size, "C%s", compat2);
+-		buffer_size -= length;
+-		if (buffer_size <= 0)
+-			return -ENOMEM;
+-		scratch += length;
+-		length = strlen (compat2) + 1;
+-		compat2 += length;
+-		cplen2 -= length;
+-	}
+-
+-	envp[i] = NULL;
+-
+-	return 0;
+-}
+-
+ extern struct device_attribute macio_dev_attrs[];
+ 
+ struct bus_type macio_bus_type = {
+        .name	= "macio",
+        .match	= macio_bus_match,
+-       .uevent = macio_uevent,
++       .uevent = of_device_uevent,
+        .probe	= macio_device_probe,
+        .remove	= macio_device_remove,
+        .shutdown = macio_device_shutdown,
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0017-powerpc-Add-uevent-handler-for-of_platform_bus.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0017-powerpc-Add-uevent-handler-for-of_platform_bus.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,29 @@
+From 846d6cd8584eee7517543be073c8b3fe9fefd065 Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sat, 23 Dec 2006 23:16:07 +0100
+Subject: [PATCH] [PATCH] powerpc: Add uevent handler for of_platform_bus
+
+Adding this handler allow userspace to properly handle the module
+autoloading. The generation of the uevent itself is now common to
+all bus using of_device, so not much code here.
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/kernel/of_platform.c |    1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c
+index b734517..da78e44 100644
+--- a/arch/powerpc/kernel/of_platform.c
++++ b/arch/powerpc/kernel/of_platform.c
+@@ -133,6 +133,7 @@ static int of_platform_device_resume(struct device * dev)
+ struct bus_type of_platform_bus_type = {
+        .name	= "of_platform",
+        .match	= of_platform_bus_match,
++       .uevent	= of_device_uevent,
+        .probe	= of_platform_device_probe,
+        .remove	= of_platform_device_remove,
+        .suspend	= of_platform_device_suspend,
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0018-powerpc-Add-uevent-handler-for-ibmebus.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0018-powerpc-Add-uevent-handler-for-ibmebus.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,50 @@
+From ddc4a7296f3abd28a902f38ae915224d6d93edca Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Sat, 23 Dec 2006 23:20:58 +0100
+Subject: [PATCH] [PATCH] powerpc: Add uevent handler for ibmebus
+
+Adding this handler allow userspace to properly handle the module
+autoloading. The generation of the uevent itself is now common to
+all bus using of_device, so not much code here.
+
+But we still need a small wrapper to filter out the dummy root
+device node used by this bus.
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ arch/powerpc/kernel/ibmebus.c |   16 ++++++++++++++++
+ 1 files changed, 16 insertions(+), 0 deletions(-)
+
+diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c
+index 82bd2f1..2e8d9fd 100644
+--- a/arch/powerpc/kernel/ibmebus.c
++++ b/arch/powerpc/kernel/ibmebus.c
+@@ -361,9 +361,25 @@ static int ibmebus_bus_match(struct device *dev, struct device_driver *drv)
+ 	return 0;
+ }
+ 
++static int ibmebus_bus_uevent(struct device *dev,
++		char **envp, int num_envp, char *buffer, int buffer_size)
++{
++	struct ibmebus_dev *ebus_dev;
++
++	if (!dev)
++		return -ENODEV;
++
++	ebus_dev = to_ibmebus_dev(dev);
++	if (ebus_dev==ibmebus_bus_device)	/* filter dummy root device */
++		return -ENODEV;
++
++	return of_device_uevent(dev, envp, num_envp, buffer, buffer_size);
++}
++
+ struct bus_type ibmebus_bus_type = {
+ 	.name = "ibmebus",
+ 	.match = ibmebus_bus_match,
++	.uevent = ibmebus_bus_uevent,
+ };
+ EXPORT_SYMBOL(ibmebus_bus_type);
+ 
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0019-MPC5200-Bestcomm-platform-driver.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0019-MPC5200-Bestcomm-platform-driver.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,1439 @@
+From d9e27abf78b3bd714eb9c37c529d0bff7c5403d9 Mon Sep 17 00:00:00 2001
+From: Andrey Volkov <avolkov at varma-el.com>
+Date: Fri, 18 Aug 2006 10:01:38 -0600
+Subject: [PATCH] [PATCH 01/02] MPC5200 Bestcomm platform driver
+
+This is first part of "platformizied" bestcomm/fec drivers.
+
+Signed-Off-By: Andrey Volkov <avolkov at varma-el.com>
+---
+ arch/ppc/Kconfig                            |    5 +
+ arch/ppc/syslib/Makefile                    |    1 +
+ arch/ppc/syslib/bestcomm/Makefile           |    2 +
+ arch/ppc/syslib/bestcomm/bestcomm.c         |  408 +++++++++++++++++++++++
+ arch/ppc/syslib/bestcomm/bestcomm.h         |  473 +++++++++++++++++++++++++++
+ arch/ppc/syslib/bestcomm/fec.c              |  174 ++++++++++
+ arch/ppc/syslib/bestcomm/fec.h              |   71 ++++
+ arch/ppc/syslib/bestcomm/sdma_fec_rx_task.c |   71 ++++
+ arch/ppc/syslib/bestcomm/sdma_fec_tx_task.c |   84 +++++
+ arch/ppc/syslib/mpc52xx_devices.c           |   22 ++
+ arch/ppc/syslib/mpc52xx_sys.c               |    4 +-
+ include/asm-ppc/mpc52xx.h                   |    2 +
+ 12 files changed, 1315 insertions(+), 2 deletions(-)
+
+diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
+index 8eb82ef..d8a561e 100644
+--- a/arch/ppc/Kconfig
++++ b/arch/ppc/Kconfig
+@@ -775,6 +775,11 @@ config EMBEDDEDBOOT
+ config PPC_MPC52xx
+ 	bool
+ 
++config PPC_BESTCOMM
++	bool
++	depends on PPC_MPC52xx
++	default y
++
+ config 8260
+ 	bool "CPM2 Support" if WILLOW
+ 	depends on 6xx
+diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
+index dca23f2..ab015df 100644
+--- a/arch/ppc/syslib/Makefile
++++ b/arch/ppc/syslib/Makefile
+@@ -106,3 +106,4 @@ obj-$(CONFIG_PCI)		+= mpc52xx_pci.o
+ endif
+ 
+ obj-$(CONFIG_PPC_I8259)		+= i8259.o
++obj-$(CONFIG_PPC_BESTCOMM)	+= bestcomm/
+diff --git a/arch/ppc/syslib/bestcomm/Makefile b/arch/ppc/syslib/bestcomm/Makefile
+new file mode 100644
+index 0000000..02cc99a
+--- /dev/null
++++ b/arch/ppc/syslib/bestcomm/Makefile
+@@ -0,0 +1,2 @@
++obj-$(CONFIG_PPC_BESTCOMM) 	+= bestcomm.o
++obj-$(CONFIG_FEC_MPC52xx)	+= sdma_fec_rx_task.o sdma_fec_tx_task.o fec.o
+diff --git a/arch/ppc/syslib/bestcomm/bestcomm.c b/arch/ppc/syslib/bestcomm/bestcomm.c
+new file mode 100644
+index 0000000..ef45e02
+--- /dev/null
++++ b/arch/ppc/syslib/bestcomm/bestcomm.c
+@@ -0,0 +1,408 @@
++/*
++ * arch/ppc/syslib/bestcomm/bestcomm.c
++ *
++ * Driver for MPC52xx processor BestComm peripheral 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.
++ *
++ * HISTORY:
++ *
++ * 2005-08-14	Converted to platform driver by 
++ *		Andrey Volkov <avolkov at varma-el.com>, Varma Electronics Oy
++ */
++
++#include <linux/config.h>
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/string.h>
++#include <linux/device.h>
++
++#include <asm/bug.h>
++#include <asm/io.h>
++#include <asm/mpc52xx.h>
++
++#include "bestcomm.h"
++
++#define DRIVER_NAME		"mpc52xx-sdma"
++
++struct sdma_io sdma;
++
++static spinlock_t sdma_lock = SPIN_LOCK_UNLOCKED;
++
++#ifdef CONFIG_BESTCOMM_DEBUG
++void sdma_dump(void)
++{
++	int i;
++	printk("** SDMA registers: pa = %08x, va = %08x\n", sdma.base_reg_addr, sdma.io);
++	printk("**  taskBar = %08x\n", sdma.io->taskBar);
++	printk("**  currentPointer = %08x\n", sdma.io->currentPointer);
++	printk("**  endPointer = %08x\n", sdma.io->endPointer);
++	printk("**  variablePointer = %08x\n", sdma.io->variablePointer);
++
++	printk("**  IntVect1 = %08x\n", sdma.io->IntVect1);
++	printk("**  IntVect2 = %08x\n", sdma.io->IntVect2);
++	printk("**  PtdCntrl = %08x\n", sdma.io->PtdCntrl);
++
++	printk("**  IntPend = %08x\n", sdma.io->IntPend);
++	printk("**  IntMask = %08x\n", sdma.io->IntMask);
++
++	printk("**  TCR dump:");	
++
++	for (i=0;i<16;i++)  {
++		if(i%8 == 0)
++			printk("\n**   %02X:",i);
++		printk(" %04X",sdma.io->tcr[i]);
++	}
++	printk("\n**  IPR dump:");	
++	for (i=0;i<32;i++)  {
++		if(i%16 == 0)
++			printk("\n**   %02X:",i);
++		printk(" %02X",sdma.io->ipr[i]);
++	}
++	printk("\n**  cReqSelect = %08x\n", sdma.io->cReqSelect);
++	printk("**  task_size0 = %08x\n", sdma.io->task_size0);
++	printk("**  task_size1 = %08x\n", sdma.io->task_size1);
++	printk("**  MDEDebug = %08x\n", sdma.io->MDEDebug);
++	printk("**  ADSDebug = %08x\n", sdma.io->ADSDebug);
++	printk("**  Value1 = %08x\n", sdma.io->Value1);
++	printk("**  Value2 = %08x\n", sdma.io->Value2);
++	printk("**  Control = %08x\n", sdma.io->Control);
++	printk("**  Status = %08x\n", sdma.io->Status);
++	printk("**  PTDDebug = %08x\n", sdma.io->PTDDebug);
++}
++#endif
++
++#ifdef CONFIG_BESTCOMM_DEBUG
++#define SDMA_DUMP_REGS()	sdma_dump()
++#else
++#define SDMA_DUMP_REGS()
++#endif
++
++/*
++ * Use a very simple SRAM allocator.
++ * There is no mechanism for freeing space.
++ * In an attempt to minimize internal fragmentation, the SRAM is
++ * divided into two areas.
++ *
++ * Area 1 is at the beginning of SRAM
++ * and is used for allocations requiring alignments of 16 bytes or less.
++ * Successive allocations return higher addresses.
++ *
++ * Area 2 is at the end of SRAM and is used for the remaining allocations.
++ * Successive allocations return lower addresses.
++ *
++ * I've considered adding routines to support the freeing of SRAM allocations,
++ * but the SRAM is so small (16K) that fragmentation can quickly cause the
++ * SRAM to be unusable.  If you can come up with a slick way to free SRAM
++ * memory without the fragmentation problem, please do so.
++ */
++
++static u8 *area1_end;
++static u8 *area2_begin;
++
++void *sdma_sram_alloc(int size, int alignment, u32 *dma_handle)
++{
++	u8 *a;
++
++	spin_lock(&sdma_lock);
++
++	/* alignment must be a power of 2 */
++	BUG_ON(alignment & (alignment - 1));
++
++	if (alignment < 16) {
++		a = (u8 *)(((u32)area1_end + (alignment-1)) & ~(alignment-1));
++		if (a + size <= area2_begin)
++			area1_end = a + size;
++		else
++			a = 0;				/* out of memory */
++	} else {
++		a = (u8 *)(((u32)area2_begin - size) & ~(alignment - 1));
++		if (a >= area1_end)
++			area2_begin = a;
++		else
++			a = 0;				/* out of memory */
++	}
++	if(a && dma_handle)
++		*dma_handle = sdma_sram_pa(a);
++	spin_unlock(&sdma_lock);
++	return (void *)a;
++}
++
++/* this will need to be updated if Freescale changes their task code FDT */
++static u32 fdt_ops[] = {
++	0xa0045670,	/* FDT[48] */
++	0x80045670,	/* FDT[49] */
++	0x21800000,	/* FDT[50] */
++	0x21e00000,	/* FDT[51] */
++	0x21500000,	/* FDT[52] */
++	0x21400000,	/* FDT[53] */
++	0x21500000,	/* FDT[54] */
++	0x20400000,	/* FDT[55] */
++	0x20500000,	/* FDT[56] */
++	0x20800000,	/* FDT[57] */
++	0x20a00000,	/* FDT[58] */
++	0xc0170000,	/* FDT[59] */
++	0xc0145670,	/* FDT[60] */
++	0xc0345670,	/* FDT[61] */
++	0xa0076540,	/* FDT[62] */
++	0xa0000760,	/* FDT[63] */
++};
++
++static int new_task_number(void)
++{
++	struct sdma_tdt *tdt;
++	int i;
++
++	spin_lock(&sdma_lock);
++
++	tdt = sdma.tdt;
++	for (i=0; i<SDMA_MAX_TASKS; i++, tdt++)
++		if (tdt->start == 0)
++			break;
++	if (i == SDMA_MAX_TASKS)
++		i = -1;
++
++	spin_unlock(&sdma_lock);
++
++	return i;
++}
++
++int sdma_load_task(u32 *task_image)
++{
++	struct sdma_task_header *head = (struct sdma_task_header *)task_image;
++	struct sdma_tdt *tdt;
++	int tasknum;
++	u32 *desc;
++	u32 *var_src, *var_dst;
++	u32 *inc_src;
++	void *start;
++
++	BUG_ON(head->magic != SDMA_TASK_MAGIC);
++
++	tasknum = new_task_number();
++	if (tasknum < 0)
++		return -ENOMEM;
++
++	desc = (u32 *)(head + 1);
++	var_src = desc + head->desc_size;
++	inc_src = var_src + head->var_size;
++
++	tdt = &sdma.tdt[tasknum];
++
++	start = sdma_sram_alloc(head->desc_size * sizeof(u32), 4, &tdt->start);
++	if (!start)
++		return -ENOMEM;
++	tdt->stop = tdt->start + (head->desc_size - 1)*sizeof(u32);
++	var_dst = sdma_sram_va(tdt->var);
++
++	memcpy(start, desc, head->desc_size * sizeof(u32));
++	memcpy(&var_dst[head->first_var], var_src, head->var_size * sizeof(u32));
++	memcpy(&var_dst[SDMA_MAX_VAR], inc_src, head->inc_size * sizeof(u32));
++
++	return tasknum;
++}
++
++void sdma_set_initiator(int task, int initiator)
++{
++	int i;
++	int num_descs;
++	u32 *desc;
++	int next_drd_has_initiator;
++
++	sdma_set_tcr_initiator(task, initiator);
++
++	desc = sdma_task_desc(task);
++	next_drd_has_initiator = 1;
++	num_descs = sdma_task_num_descs(task);
++
++	for (i=0; i<num_descs; i++, desc++) {
++		if (!sdma_desc_is_drd(*desc))
++			continue;
++		if (next_drd_has_initiator)
++			if (sdma_desc_initiator(*desc) != SDMA_INITIATOR_ALWAYS)
++				sdma_set_desc_initiator(desc, initiator);
++		next_drd_has_initiator = !sdma_drd_is_extended(*desc);
++	}
++}
++
++struct sdma *sdma_alloc(int queue_size)
++{
++	struct sdma *s = kmalloc(sizeof(*s), GFP_KERNEL);
++	void **cookie;
++
++	if (!s)
++		return NULL;
++
++	memset(s, 0, sizeof(*s));
++
++	if (queue_size) {
++		cookie = kmalloc(sizeof(*cookie) * queue_size, GFP_KERNEL);
++		if (!cookie) {
++			kfree(s);
++			return NULL;
++		}
++		s->cookie = cookie;
++	}
++
++	s->num_bd = queue_size;
++	return s;
++}
++
++void sdma_free(struct sdma *s)
++{
++	if (s->cookie)
++		kfree(s->cookie);
++	kfree(s);
++}
++
++static int __devinit mpc52xx_sdma_probe(struct device *dev)
++{
++	struct platform_device *pdev = to_platform_device(dev);
++	int task;
++	u32 *context;
++	u32 *fdt;
++	struct sdma_tdt *tdt;
++	struct resource *mem_io, *mem_sram;
++	u32 tdt_pa, var_pa, context_pa, fdt_pa; 
++	int ret = -ENODEV;
++
++	mem_io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	mem_sram = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++	if (!mem_io || !mem_sram)
++		goto out;
++
++	if (!request_mem_region(mem_io->start, mem_io->end - mem_io->start + 1, DRIVER_NAME)) {
++		printk(KERN_ERR DRIVER_NAME " - resource unavailable\n");
++		goto out;
++	}
++	sdma.base_reg_addr = mem_io->start;
++
++	sdma.io = ioremap_nocache(mem_io->start, sizeof(struct mpc52xx_sdma));
++
++	if (!sdma.io ) {
++		printk(KERN_ERR DRIVER_NAME " - failed to map sdma regs\n");
++		ret = -ENOMEM;
++		goto map_io_error;
++	}
++
++	SDMA_DUMP_REGS();
++
++	sdma.sram_size = mem_sram->end - mem_sram->start + 1;
++	if (!request_mem_region(mem_sram->start, sdma.sram_size, DRIVER_NAME)) {
++		printk(KERN_ERR DRIVER_NAME " - resource unavailable\n");
++		goto req_sram_error;
++	}
++
++	sdma.base_sram_addr = mem_sram->start;
++	sdma.sram = ioremap_nocache(mem_sram->start, sdma.sram_size);
++	if (!sdma.sram ) {
++		printk(KERN_ERR DRIVER_NAME " - failed to map sdma sram\n");
++		ret = -ENOMEM;
++		goto map_sram_error;
++	}
++
++	area1_end = sdma.sram;
++	area2_begin = area1_end + sdma.sram_size;
++
++	memset(area1_end, 0, sdma.sram_size);
++
++	/* allocate space for task descriptors, contexts, and var tables */
++	sdma.tdt = sdma_sram_alloc(sizeof(struct sdma_tdt) * SDMA_MAX_TASKS, 4, &tdt_pa);
++
++	context = sdma_sram_alloc(SDMA_CONTEXT_SIZE * SDMA_MAX_TASKS,
++							  SDMA_CONTEXT_ALIGN, &context_pa);
++	sdma.var = sdma_sram_alloc( (SDMA_VAR_SIZE + SDMA_INC_SIZE) * SDMA_MAX_TASKS, 
++								SDMA_VAR_ALIGN, &var_pa);
++	fdt = sdma_sram_alloc(SDMA_FDT_SIZE, SDMA_FDT_ALIGN, &fdt_pa);
++	memcpy(&fdt[48], fdt_ops, sizeof(fdt_ops));
++
++	out_be32(&sdma.io->taskBar, tdt_pa);
++
++	tdt = sdma.tdt;
++	for (task=0; task < SDMA_MAX_TASKS; task++) {
++		out_be16(&sdma.io->tcr[task], 0);
++		out_8(&sdma.io->ipr[task], 0);
++
++		tdt->context = context_pa;
++		tdt->var = var_pa;
++		tdt->fdt = fdt_pa;
++		var_pa += (SDMA_MAX_VAR + SDMA_MAX_INC)*sizeof(u32);
++		context_pa += SDMA_MAX_CONTEXT*sizeof(u32);
++		tdt++;
++	}
++
++	out_8(&sdma.io->ipr[SDMA_INITIATOR_ALWAYS], SDMA_IPR_ALWAYS);
++
++	/* Disable COMM Bus Prefetch, apparently it's not reliable yet */
++	out_be16(&sdma.io->PtdCntrl, in_be16(&sdma.io->PtdCntrl) | 1);
++
++	printk(KERN_INFO "MPC52xx BestComm inited\n");
++
++	return 0;
++
++map_sram_error:
++	release_mem_region(mem_sram->start, sdma.sram_size);
++req_sram_error:
++	iounmap(sdma.io);
++map_io_error:
++	release_mem_region(mem_io->start, mem_io->end - mem_io->start + 1);
++out:
++	printk(KERN_ERR "DMA: MPC52xx BestComm init FAILED !!!\n");
++	return ret;
++}
++
++
++static struct device_driver mpc52xx_sdma_driver = {
++	.owner	  = THIS_MODULE,
++	.name	  = DRIVER_NAME,
++	.bus	  = &platform_bus_type,
++	.probe 	  = mpc52xx_sdma_probe,
++/*	.remove	  = mpc52xx_sdma_remove,	TODO */
++#ifdef CONFIG_PM
++/*	.suspend	= mpc52xx_sdma_suspend,	TODO */
++/*	.resume		= mpc52xx_sdma_resume,	TODO */
++#endif
++};
++
++static int __init
++mpc52xx_sdma_init(void)
++{
++	printk(KERN_INFO "DMA: MPC52xx BestComm driver\n");
++	return driver_register(&mpc52xx_sdma_driver);
++}
++
++#ifdef MODULE
++static void __exit
++mpc52xx_sdma_exit(void)
++{
++	driver_unregister(&mpc52xx_sdma_driver);
++}
++#endif
++
++#ifndef MODULE
++ subsys_initcall(mpc52xx_sdma_init);
++#else
++ module_init(mpc52xx_sdma_init);
++ module_exit(mpc52xx_sdma_exit);
++#endif
++
++
++MODULE_DESCRIPTION("Freescale MPC52xx BestComm DMA");
++MODULE_LICENSE("GPL");
++
++EXPORT_SYMBOL(sdma_sram_alloc);
++EXPORT_SYMBOL(sdma_load_task);
++EXPORT_SYMBOL(sdma_set_initiator);
++EXPORT_SYMBOL(sdma_free);
++EXPORT_SYMBOL(sdma);
++
++
+diff --git a/arch/ppc/syslib/bestcomm/bestcomm.h b/arch/ppc/syslib/bestcomm/bestcomm.h
+new file mode 100644
+index 0000000..14bf397
+--- /dev/null
++++ b/arch/ppc/syslib/bestcomm/bestcomm.h
+@@ -0,0 +1,473 @@
++/*
++ * arch/ppc/syslib/bestcomm/bestcomm.h
++ *
++ * Driver for MPC52xx processor BestComm peripheral 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.
++ *
++ * HISTORY:
++ *
++ * 2005-08-14	Converted to platform driver by 
++ *		Andrey Volkov <avolkov at varma-el.com>, Varma Electronics Oy
++ */
++
++#ifndef __BESTCOMM_BESTCOMM_H__
++#define __BESTCOMM_BESTCOMM_H__
++
++/* Buffer Descriptor definitions */
++struct sdma_bd {
++	u32 status;
++	void *data;
++};
++
++struct sdma_bd2 {
++	u32 status;
++	void *data1;
++	void *data2;
++};
++
++struct sdma_io {
++	unsigned long			base_reg_addr;
++	struct mpc52xx_sdma __iomem	*io;
++	unsigned long			base_sram_addr;
++	void __iomem			*sram;
++	size_t				sram_size;
++
++	struct sdma_tdt __iomem  	*tdt;
++	u32 __iomem			*var;
++};
++extern struct sdma_io sdma;
++
++#define	sdma_sram_pa(virt)	(((unsigned long)(((void __iomem *)(virt))-sdma.sram))+sdma.base_sram_addr)
++#define	sdma_sram_va(pa)	((void __iomem *)((((unsigned long)(pa))-sdma.base_sram_addr)+((unsigned long)sdma.sram)))
++
++#define	sdma_io_pa(virt)	(((unsigned long)(((void __iomem *)(virt))-((void __iomem *)sdma.io)))+sdma.base_reg_addr)
++#define	sdma_io_va(pa)	((void __iomem *)((((unsigned long)(pa))-sdma.base_reg_addr)+((unsigned long)sdma.io)))
++
++#define SDMA_LEN_BITS		26
++#define SDMA_LEN_MASK		((1 << SDMA_LEN_BITS) - 1)
++
++#define SDMA_BD_READY		0x40000000UL
++
++#define SDMA_FEC_TX_BD_TFD	0x08000000UL	/* transmit frame done */
++#define SDMA_FEC_TX_BD_INT	0x04000000UL	/* Interrupt */
++#define SDMA_FEC_TX_BD_TFD_INIT	(SDMA_BD_READY | SDMA_FEC_TX_BD_TFD | \
++							SDMA_FEC_TX_BD_INT)
++
++struct sdma {
++	union {
++		struct sdma_bd *bd;
++		struct sdma_bd2 *bd2;
++	};
++	void **cookie;
++	u16 index;
++	u16 outdex;
++	u16 num_bd;
++	s16 tasknum;
++	u32 flags;
++};
++
++#define SDMA_FLAGS_NONE		0x0000
++#define SDMA_FLAGS_ENABLE_TASK	0x0001
++#define SDMA_FLAGS_BD2		0x0002
++
++/* Task Descriptor Table Entry */
++struct sdma_tdt {
++	u32 start;
++	u32 stop;
++	u32 var;
++	u32 fdt;
++	u32 exec_status; /* used internally by SmartComm engine */
++	u32 mvtp;		 /* used internally by SmartComm engine */
++	u32 context;
++	u32 litbase;
++};
++
++//extern struct sdma_tdt *sdma_tdt;
++
++#define SDMA_MAX_TASKS		16
++#define SDMA_MAX_VAR		24
++#define SDMA_MAX_INC		8
++#define SDMA_MAX_FDT		64
++#define SDMA_MAX_CONTEXT	20
++#define SDMA_CONTEXT_SIZE	SDMA_MAX_CONTEXT * sizeof(u32)
++#define SDMA_CONTEXT_ALIGN	0x100
++#define SDMA_VAR_SIZE		SDMA_MAX_VAR * sizeof(u32)
++#define SDMA_VAR_ALIGN		0x80
++#define SDMA_INC_SIZE		SDMA_MAX_INC * sizeof(u32)
++#define SDMA_FDT_SIZE		SDMA_MAX_FDT * sizeof(u32)
++#define SDMA_FDT_ALIGN		0x100
++#define SDMA_BD_ALIGN		0x10
++
++#define TASK_ENABLE		0x8000
++
++#ifndef DPRINK
++	#ifdef CONFIG_BESTCOMM_DEBUG
++	#define DPRINTK(a,b...)	printk(KERN_DEBUG "sdma: %s: " a, __FUNCTION__ , ## b)
++	#else
++	#define DPRINTK(a,b...)
++	#endif
++#endif
++
++static inline void sdma_enable_task(int task)
++{
++	DPRINTK("***DMA enable task (%d): tdt = %08x\n",task, sdma.tdt);
++	DPRINTK("***tdt->start   = %08x\n",sdma.tdt[task].start);
++	DPRINTK("***tdt->stop    = %08x\n",sdma.tdt[task].stop);
++	DPRINTK("***tdt->var     = %08x\n",sdma.tdt[task].var);
++	DPRINTK("***tdt->fdt     = %08x\n",sdma.tdt[task].fdt);
++	DPRINTK("***tdt->status  = %08x\n",sdma.tdt[task].exec_status);
++	DPRINTK("***tdt->mvtp    = %08x\n",sdma.tdt[task].mvtp);
++	DPRINTK("***tdt->context = %08x\n",sdma.tdt[task].context);
++	DPRINTK("***tdt->litbase = %08x\n",sdma.tdt[task].litbase);
++	DPRINTK("***--------------\n");
++
++	u16 reg = in_be16(&sdma.io->tcr[task]);
++	DPRINTK("***enable task: &sdma.io->tcr=%08x, reg = %04x\n", &sdma.io->tcr, reg);
++	out_be16(&sdma.io->tcr[task],  reg | TASK_ENABLE);
++}
++
++static inline void sdma_disable_task(int task)
++{
++	u16 reg = in_be16(&sdma.io->tcr[task]);
++	DPRINTK("***disable task(%d): reg = %04x\n", task, reg);
++	out_be16(&sdma.io->tcr[task], reg & ~TASK_ENABLE);
++}
++
++static inline int sdma_irq(struct sdma *s)
++{
++	return MPC52xx_SDMA_IRQ_BASE + s->tasknum;
++}
++
++static inline void sdma_enable(struct sdma *s)
++{
++	sdma_enable_task(s->tasknum);
++}
++
++static inline void sdma_disable(struct sdma *s)
++{
++	sdma_disable_task(s->tasknum);
++}
++
++static inline int sdma_queue_empty(struct sdma *s)
++{
++	return s->index == s->outdex;
++}
++
++static inline void sdma_clear_irq(struct sdma *s)
++{
++	out_be32(&sdma.io->IntPend, 1 << s->tasknum);
++}
++
++static inline int sdma_next_index(struct sdma *s)
++{
++	return ((s->index + 1) == s->num_bd) ? 0 : s->index + 1;
++}
++
++static inline int sdma_next_outdex(struct sdma *s)
++{
++	return ((s->outdex + 1) == s->num_bd) ? 0 : s->outdex + 1;
++}
++
++static inline int sdma_queue_full(struct sdma *s)
++{
++	return s->outdex == sdma_next_index(s);
++}
++
++static inline int sdma_buffer_done(struct sdma *s)
++{
++#ifdef CONFIG_BESTCOMM_DEBUG
++	BUG_ON(s->flags & SDMA_FLAGS_BD2);
++#endif
++	if (sdma_queue_empty(s))
++		return 0;
++	return (s->bd[s->outdex].status & SDMA_BD_READY) == 0;
++}
++
++static inline int sdma_buffer2_done(struct sdma *s)
++{
++#ifdef CONFIG_BESTCOMM_DEBUG
++	BUG_ON(!(s->flags & SDMA_FLAGS_BD2));
++#endif
++	if (sdma_queue_empty(s))
++		return 0;
++
++	return (s->bd2[s->outdex].status & SDMA_BD_READY) == 0;
++}
++
++static inline u32 *sdma_task_desc(int task)
++{
++	return sdma_sram_va(sdma.tdt[task].start);
++}
++
++static inline u32 sdma_task_num_descs(int task)
++{
++	return (sdma.tdt[task].stop - sdma.tdt[task].start)/sizeof(u32) + 1;
++}
++
++static inline u32 *sdma_task_var(int task)
++{
++	return sdma_sram_va(sdma.tdt[task].var);
++}
++
++static inline u32 *sdma_task_inc(int task)
++{
++	return &sdma_task_var(task)[SDMA_MAX_VAR];
++}
++
++static inline void sdma_set_tcr_initiator(int task, int initiator) {
++	u16 *tcr = &sdma.io->tcr[task];
++	out_be16(tcr, (in_be16(tcr) & ~0x1f00) | (initiator << 8));
++}
++
++#define SDMA_DRD_INITIATOR_SHIFT	21
++
++static inline int sdma_desc_initiator(u32 desc)
++{
++	return (desc >> SDMA_DRD_INITIATOR_SHIFT) & 0x1f;
++}
++
++static inline void sdma_set_desc_initiator(u32 *desc, int initiator)
++{
++	*desc = (*desc & ~(0x1f << SDMA_DRD_INITIATOR_SHIFT)) |
++			((initiator << SDMA_DRD_INITIATOR_SHIFT) & 0x1f);
++}
++
++static inline void sdma_submit_buffer(struct sdma *s, void *cookie, void *data,
++								int length)
++{
++#ifdef CONFIG_BESTCOMM_DEBUG
++	BUG_ON(s->flags & SDMA_FLAGS_BD2);
++#endif
++	s->cookie[s->index] = cookie;
++	s->bd[s->index].data = data;
++	s->bd[s->index].status = SDMA_BD_READY | length;
++	s->index = sdma_next_index(s);
++	if (s->flags & SDMA_FLAGS_ENABLE_TASK)
++		sdma_enable_task(s->tasknum);
++}
++
++/*
++ * Special submit_buffer function to submit last buffer of a frame to
++ * the FEC tx task.  tfd means "transmit frame done".
++ */
++static inline void sdma_fec_tfd_submit_buffer(struct sdma *s, void *cookie,
++							void *data, int length)
++{
++#ifdef CONFIG_BESTCOMM_DEBUG
++	BUG_ON(s->flags & SDMA_FLAGS_BD2);
++#endif
++	s->cookie[s->index] = cookie;
++	s->bd[s->index].data = data;
++	s->bd[s->index].status = SDMA_FEC_TX_BD_TFD_INIT | length;
++	s->index = sdma_next_index(s);
++	sdma_enable_task(s->tasknum);
++}
++
++static inline void *sdma_retrieve_buffer(struct sdma *s, int *length)
++{
++	void *cookie = s->cookie[s->outdex];
++
++#ifdef CONFIG_BESTCOMM_DEBUG
++	BUG_ON(s->flags & SDMA_FLAGS_BD2);
++#endif
++	if (length)
++		*length = s->bd[s->outdex].status & SDMA_LEN_MASK;
++	s->outdex = sdma_next_outdex(s);
++	return cookie;
++}
++
++static inline void sdma_submit_buffer2(struct sdma *s, void *cookie,
++					void *data1, void *data2, int length)
++{
++#ifdef CONFIG_BESTCOMM_DEBUG
++	BUG_ON(!(s->flags & SDMA_FLAGS_BD2));
++#endif
++	s->cookie[s->index] = cookie;
++	s->bd2[s->index].data1 = data1;
++	s->bd2[s->index].data2 = data2;
++	s->bd2[s->index].status = SDMA_BD_READY | length;
++	s->index = sdma_next_index(s);
++	if (s->flags & SDMA_FLAGS_ENABLE_TASK)
++		sdma_enable_task(s->tasknum);
++}
++
++static inline void *sdma_retrieve_buffer2(struct sdma *s, int *length)
++{
++	void *cookie = s->cookie[s->outdex];
++
++#ifdef CONFIG_BESTCOMM_DEBUG
++	BUG_ON(!(s->flags & SDMA_FLAGS_BD2));
++#endif
++	if (length)
++		*length = s->bd2[s->outdex].status & SDMA_LEN_MASK;
++	s->outdex = sdma_next_outdex(s);
++	return cookie;
++}
++
++#define SDMA_TASK_MAGIC		0x4243544B	/* 'BCTK' */
++
++/* the size fields are given in number of 32-bit words */
++struct sdma_task_header {
++	u32	magic;
++	u8	desc_size;
++	u8	var_size;
++	u8	inc_size;
++	u8	first_var;
++	u8	reserved[8];
++};
++
++#define SDMA_DESC_NOP		0x000001f8
++#define SDMA_LCD_MASK		0x80000000
++#define SDMA_DRD_EXTENDED	0x40000000
++
++#define sdma_drd_is_extended(desc) ((desc) & SDMA_DRD_EXTENDED)
++
++static inline int sdma_desc_is_drd(u32 desc) {
++	return !(desc & SDMA_LCD_MASK) && desc != SDMA_DESC_NOP;
++};
++
++#define SDMA_PRAGMA_BIT_RSV		7	/* reserved pragma bit */
++#define SDMA_PRAGMA_BIT_PRECISE_INC	6	/* increment 0=when possible, */
++						/*	1=iter end */
++#define SDMA_PRAGMA_BIT_RST_ERROR_NO	5	/* don't reset errors on */
++						/* task enable */
++#define SDMA_PRAGMA_BIT_PACK		4	/* pack data enable */
++#define SDMA_PRAGMA_BIT_INTEGER		3	/* data alignment */
++						/* 0=frac(msb), 1=int(lsb) */
++#define SDMA_PRAGMA_BIT_SPECREAD	2	/* XLB speculative read */
++#define SDMA_PRAGMA_BIT_CW		1	/* write line buffer enable */
++#define SDMA_PRAGMA_BIT_RL		0	/* read line buffer enable */
++
++#define SDMA_STD_PRAGMA		((0 << SDMA_PRAGMA_BIT_RSV)		| \
++				 (0 << SDMA_PRAGMA_BIT_PRECISE_INC)	| \
++				 (0 << SDMA_PRAGMA_BIT_RST_ERROR_NO)	| \
++				 (0 << SDMA_PRAGMA_BIT_PACK)		| \
++				 (0 << SDMA_PRAGMA_BIT_INTEGER)		| \
++				 (1 << SDMA_PRAGMA_BIT_SPECREAD)	| \
++				 (1 << SDMA_PRAGMA_BIT_CW)		| \
++				 (1 << SDMA_PRAGMA_BIT_RL))
++
++#define SDMA_PCI_PRAGMA		((0 << SDMA_PRAGMA_BIT_RSV)		| \
++				 (0 << SDMA_PRAGMA_BIT_PRECISE_INC)	| \
++				 (0 << SDMA_PRAGMA_BIT_RST_ERROR_NO)	| \
++				 (0 << SDMA_PRAGMA_BIT_PACK)		| \
++				 (1 << SDMA_PRAGMA_BIT_INTEGER)		| \
++				 (1 << SDMA_PRAGMA_BIT_SPECREAD)	| \
++				 (1 << SDMA_PRAGMA_BIT_CW)		| \
++				 (1 << SDMA_PRAGMA_BIT_RL))
++
++#define SDMA_ATA_PRAGMA		SDMA_STD_PRAGMA
++#define SDMA_CRC16_DP_0_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_CRC16_DP_1_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_FEC_RX_BD_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_FEC_TX_BD_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_GEN_DP_0_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_GEN_DP_1_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_GEN_DP_2_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_GEN_DP_3_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_GEN_DP_BD_0_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_GEN_DP_BD_1_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_GEN_RX_BD_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_GEN_TX_BD_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_GEN_LPC_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_PCI_RX_PRAGMA	SDMA_PCI_PRAGMA
++#define SDMA_PCI_TX_PRAGMA	SDMA_PCI_PRAGMA
++
++static inline void sdma_set_task_pragma(int task, int pragma)
++{
++	u32 *fdt = &sdma.tdt[task].fdt;
++	*fdt = (*fdt & ~0xff) | pragma;
++}
++
++static inline void sdma_set_task_auto_start(int task, int next_task)
++{
++	u16 *tcr = &sdma.io->tcr[task];
++	out_be16(tcr, (in_be16(tcr) & ~0xff) | 0x00c0 | next_task);
++}
++
++#define SDMA_INITIATOR_ALWAYS	 0
++#define SDMA_INITIATOR_SCTMR_0	 1
++#define SDMA_INITIATOR_SCTMR_1	 2
++#define SDMA_INITIATOR_FEC_RX	 3
++#define SDMA_INITIATOR_FEC_TX	 4
++#define SDMA_INITIATOR_ATA_RX	 5
++#define SDMA_INITIATOR_ATA_TX	 6
++#define SDMA_INITIATOR_SCPCI_RX	 7
++#define SDMA_INITIATOR_SCPCI_TX	 8
++#define SDMA_INITIATOR_PSC3_RX	 9
++#define SDMA_INITIATOR_PSC3_TX	10
++#define SDMA_INITIATOR_PSC2_RX	11
++#define SDMA_INITIATOR_PSC2_TX	12
++#define SDMA_INITIATOR_PSC1_RX	13
++#define SDMA_INITIATOR_PSC1_TX	14
++#define SDMA_INITIATOR_SCTMR_2	15
++#define SDMA_INITIATOR_SCLPC	16
++#define SDMA_INITIATOR_PSC5_RX	17
++#define SDMA_INITIATOR_PSC5_TX	18
++#define SDMA_INITIATOR_PSC4_RX	19
++#define SDMA_INITIATOR_PSC4_TX	20
++#define SDMA_INITIATOR_I2C2_RX	21
++#define SDMA_INITIATOR_I2C2_TX	22
++#define SDMA_INITIATOR_I2C1_RX	23
++#define SDMA_INITIATOR_I2C1_TX	24
++#define SDMA_INITIATOR_PSC6_RX	25
++#define SDMA_INITIATOR_PSC6_TX	26
++#define SDMA_INITIATOR_IRDA_RX	25
++#define SDMA_INITIATOR_IRDA_TX	26
++#define SDMA_INITIATOR_SCTMR_3	27
++#define SDMA_INITIATOR_SCTMR_4	28
++#define SDMA_INITIATOR_SCTMR_5	29
++#define SDMA_INITIATOR_SCTMR_6	30
++#define SDMA_INITIATOR_SCTMR_7	31
++
++#define SDMA_IPR_ALWAYS	7
++#define SDMA_IPR_SCTMR_0 	2
++#define SDMA_IPR_SCTMR_1 	2
++#define SDMA_IPR_FEC_RX 	6
++#define SDMA_IPR_FEC_TX 	5
++#define SDMA_IPR_ATA_RX 	4
++#define SDMA_IPR_ATA_TX 	3
++#define SDMA_IPR_SCPCI_RX	2
++#define SDMA_IPR_SCPCI_TX	2
++#define SDMA_IPR_PSC3_RX	2
++#define SDMA_IPR_PSC3_TX	2
++#define SDMA_IPR_PSC2_RX	2
++#define SDMA_IPR_PSC2_TX	2
++#define SDMA_IPR_PSC1_RX	2
++#define SDMA_IPR_PSC1_TX	2
++#define SDMA_IPR_SCTMR_2	2
++#define SDMA_IPR_SCLPC		2
++#define SDMA_IPR_PSC5_RX	2
++#define SDMA_IPR_PSC5_TX	2
++#define SDMA_IPR_PSC4_RX	2
++#define SDMA_IPR_PSC4_TX	2
++#define SDMA_IPR_I2C2_RX	2
++#define SDMA_IPR_I2C2_TX	2
++#define SDMA_IPR_I2C1_RX	2
++#define SDMA_IPR_I2C1_TX	2
++#define SDMA_IPR_PSC6_RX	2
++#define SDMA_IPR_PSC6_TX	2
++#define SDMA_IPR_IRDA_RX	2
++#define SDMA_IPR_IRDA_TX	2
++#define SDMA_IPR_SCTMR_3	2
++#define SDMA_IPR_SCTMR_4	2
++#define SDMA_IPR_SCTMR_5	2
++#define SDMA_IPR_SCTMR_6	2
++#define SDMA_IPR_SCTMR_7	2
++
++extern struct sdma *sdma_alloc(int request_queue_size);
++extern void sdma_free(struct sdma *sdma_struct);
++extern int sdma_load_task(u32 *task_image);
++extern void *sdma_sram_alloc(int size, int alignment, u32 *dma_handle);
++extern void sdma_init_bd(struct sdma *s);
++extern void sdma_init_bd2(struct sdma *s);
++
++#define FIELD_OFFSET(s,f) ((unsigned long)(&(((struct s*)0)->f)))
++
++#endif  /* __BESTCOMM_BESTCOMM_H__ */
+diff --git a/arch/ppc/syslib/bestcomm/fec.c b/arch/ppc/syslib/bestcomm/fec.c
+new file mode 100644
+index 0000000..8756856
+--- /dev/null
++++ b/arch/ppc/syslib/bestcomm/fec.c
+@@ -0,0 +1,174 @@
++/*
++ * arch/ppc/syslib/bestcomm/fec.c
++ *
++ * Driver for MPC52xx processor BestComm FEC 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.
++ *
++ * HISTORY:
++ *
++ * 2005-08-14	Converted to platform driver by 
++ *		Andrey Volkov <avolkov at varma-el.com>, Varma Electronics Oy
++ */
++
++#include <linux/config.h>
++#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 "fec.h"
++
++/*
++ * Initialize FEC receive task.
++ * Returns task number of FEC receive task.
++ * Returns -1 on failure
++ */
++int sdma_fec_rx_init(struct sdma *s, phys_addr_t fifo, int maxbufsize)
++{
++	struct sdma_fec_rx_var *var;
++	struct sdma_fec_rx_inc *inc;
++
++	static int tasknum = -1;
++	static struct sdma_bd *bd = 0;
++	static u32 bd_pa;
++
++	if (tasknum < 0) {
++		tasknum = sdma_load_task(sdma_fec_rx_task);
++		if (tasknum < 0)
++			return tasknum;
++	}
++
++	if (!bd) 
++		bd = (struct sdma_bd *)sdma_sram_alloc(sizeof(*bd) * s->num_bd,
++								SDMA_BD_ALIGN, &bd_pa);
++	if (!bd)
++		return -ENOMEM;
++
++	sdma_disable_task(tasknum);
++
++	s->tasknum = tasknum;
++	s->bd = bd;
++	s->flags = SDMA_FLAGS_NONE;
++	s->index = 0;
++	s->outdex = 0;
++	memset(bd, 0, sizeof(*bd) * s->num_bd);
++
++	var = (struct sdma_fec_rx_var *)sdma_task_var(tasknum);
++	var->enable			= sdma_io_pa(&sdma.io->tcr[tasknum]);
++	var->fifo			= fifo;
++	var->bd_base		= bd_pa;
++	var->bd_last		= bd_pa + (s->num_bd - 1)*sizeof(struct sdma_bd);
++	var->bd_start		= bd_pa;
++	var->buffer_size	= maxbufsize;
++
++	/* These are constants, they should have been in the image file */
++	inc = (struct sdma_fec_rx_inc *)sdma_task_inc(tasknum);
++	inc->incr_bytes		= -(s16)sizeof(u32);
++	inc->incr_dst		= sizeof(u32);
++	inc->incr_dst_ma	= sizeof(u8);
++
++	sdma_set_task_pragma(tasknum, SDMA_FEC_RX_BD_PRAGMA);
++	sdma_set_task_auto_start(tasknum, tasknum);
++
++	/* clear pending interrupt bits */
++	out_be32(&sdma.io->IntPend, 1<<tasknum);
++
++	out_8(&sdma.io->ipr[SDMA_INITIATOR_FEC_RX], SDMA_IPR_FEC_RX);
++
++	return tasknum;
++}
++
++/*
++ * 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 = sdma_task_num_descs(tasknum);
++	desc = sdma_task_desc(tasknum) + num_descs - 1;
++	drd_count = 0;
++	for (i=0; i<num_descs; i++, desc--)
++		if (sdma_desc_is_drd(*desc) && ++drd_count == 3)
++			break;
++	return desc;
++}
++
++/*
++ * Initialize FEC transmit task.
++ * Returns task number of FEC transmit task.
++ * Returns -1 on failure
++ */
++int sdma_fec_tx_init(struct sdma *s, phys_addr_t fifo)
++{
++	struct sdma_fec_tx_var *var;
++	struct sdma_fec_tx_inc *inc;
++
++	static int tasknum = -1;
++	static struct sdma_bd *bd = 0;
++	static u32 bd_pa;
++
++	if (tasknum < 0) {
++		tasknum = sdma_load_task(sdma_fec_tx_task);
++		if (tasknum < 0)
++			return tasknum;
++	}
++
++	if (!bd)  
++		bd = (struct sdma_bd *)sdma_sram_alloc(sizeof(*bd) * s->num_bd,
++								SDMA_BD_ALIGN, &bd_pa);
++	if (!bd)
++		return -ENOMEM;
++
++	sdma_disable_task(tasknum);
++
++	s->tasknum = tasknum;
++	s->bd = bd;
++	s->flags = SDMA_FLAGS_ENABLE_TASK;
++	s->index = 0;
++	s->outdex = 0;
++	memset(bd, 0, sizeof(*bd) * s->num_bd);
++
++	var = (struct sdma_fec_tx_var *)sdma_task_var(tasknum);
++	var->DRD		= sdma_sram_pa(self_modified_drd(tasknum));
++	var->fifo		= fifo;
++	var->enable		= sdma_io_pa(&sdma.io->tcr[tasknum]);
++	var->bd_base	= bd_pa;
++	var->bd_last	= bd_pa + (s->num_bd - 1)*sizeof(struct sdma_bd);
++	var->bd_start	= bd_pa;
++
++	/* These are constants, they should have been in the image file */
++	inc = (struct sdma_fec_tx_inc *)sdma_task_inc(tasknum);
++	inc->incr_bytes		= -(s16)sizeof(u32);
++	inc->incr_src		= sizeof(u32);
++	inc->incr_src_ma	= sizeof(u8);
++
++	sdma_set_task_pragma(tasknum, SDMA_FEC_TX_BD_PRAGMA);
++	sdma_set_task_auto_start(tasknum, tasknum);
++
++	/* clear pending interrupt bits */
++	out_be32(&sdma.io->IntPend, 1<<tasknum);
++
++	out_8(&sdma.io->ipr[SDMA_INITIATOR_FEC_TX], SDMA_IPR_FEC_TX);
++
++	return tasknum;
++}
++
++EXPORT_SYMBOL(sdma_fec_rx_init);
++EXPORT_SYMBOL(sdma_fec_tx_init);
+diff --git a/arch/ppc/syslib/bestcomm/fec.h b/arch/ppc/syslib/bestcomm/fec.h
+new file mode 100644
+index 0000000..e3abc0f
+--- /dev/null
++++ b/arch/ppc/syslib/bestcomm/fec.h
+@@ -0,0 +1,71 @@
++/*
++ * arch/ppc/syslib/bestcomm/fec.h
++ *
++ * Driver for MPC52xx processor BestComm FEC 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.
++ *
++ * HISTORY:
++ *
++ * 2005-08-14	Converted to platform driver by 
++ *		Andrey Volkov <avolkov at varma-el.com>, Varma Electronics Oy
++ */
++
++#ifndef __BESTCOMM_FEC_H__
++#define __BESTCOMM_FEC_H__
++
++
++/* rx task vars that need to be set before enabling the task */
++struct sdma_fec_rx_var {
++	u32 enable;		/* (u16*) address of task's control register */
++	u32 fifo;		/* (u32*) address of fec's fifo */
++	u32 bd_base;		/* (struct sdma_bd*) beginning of ring buffer */
++	u32 bd_last;		/* (struct sdma_bd*) end of ring buffer */
++	u32 bd_start;		/* (struct sdma_bd*) current bd */
++	u32 buffer_size;	/* size of receive buffer */
++};
++
++/* rx task incs that need to be set before enabling the task */
++struct sdma_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 sdma_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 sdma_bd*) beginning of ring buffer */
++	u32 bd_last;		/* (struct sdma_bd*) end of ring buffer */
++	u32 bd_start;		/* (struct sdma_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 sdma_fec_tx_inc {
++	u16 pad0;
++	s16 incr_bytes;
++	u16 pad1;
++	s16 incr_src;
++	u16 pad2;
++	s16 incr_src_ma;
++};
++
++extern int sdma_fec_rx_init(struct sdma *s, phys_addr_t fifo, int maxbufsize);
++extern int sdma_fec_tx_init(struct sdma *s, phys_addr_t fifo);
++
++extern u32 sdma_fec_rx_task[];
++extern u32 sdma_fec_tx_task[];
++
++
++#endif  /* __BESTCOMM_FEC_H__ */
+diff --git a/arch/ppc/syslib/bestcomm/sdma_fec_rx_task.c b/arch/ppc/syslib/bestcomm/sdma_fec_rx_task.c
+new file mode 100644
+index 0000000..511b036
+--- /dev/null
++++ b/arch/ppc/syslib/bestcomm/sdma_fec_rx_task.c
+@@ -0,0 +1,71 @@
++/*
++ * sdma_fec_rx_task.c
++ *
++ * Automatically created based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex
++ * on Tue Mar 22 11:19:38 2005 GMT
++ */
++
++#include <linux/types.h>
++
++/*
++ * The header consists of the following fields:
++ *	uint32_t	magic;
++ *	uint8_t		desc_size;
++ *	uint8_t		var_size;
++ *	uint8_t		inc_size;
++ *	uint8_t		first_var;
++ *	uint8_t		reserved[8];
++ *
++ * The size fields contain the number of 32-bit words.
++*/
++
++uint32_t sdma_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/ppc/syslib/bestcomm/sdma_fec_tx_task.c b/arch/ppc/syslib/bestcomm/sdma_fec_tx_task.c
+new file mode 100644
+index 0000000..d8d7fd3
+--- /dev/null
++++ b/arch/ppc/syslib/bestcomm/sdma_fec_tx_task.c
+@@ -0,0 +1,84 @@
++/*
++ * sdma_fec_tx_task.c
++ *
++ * Automatically created based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex
++ * on Tue Mar 22 11:19:29 2005 GMT
++ */
++
++#include <linux/types.h>
++
++/*
++ * The header consists of the following fields:
++ *	uint32_t	magic;
++ *	uint8_t		desc_size;
++ *	uint8_t		var_size;
++ *	uint8_t		inc_size;
++ *	uint8_t		first_var;
++ *	uint8_t		reserved[8];
++ *
++ * The size fields contain the number of 32-bit words.
++*/
++
++uint32_t sdma_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/ppc/syslib/mpc52xx_devices.c b/arch/ppc/syslib/mpc52xx_devices.c
+index 7487539..abe6161 100644
+--- a/arch/ppc/syslib/mpc52xx_devices.c
++++ b/arch/ppc/syslib/mpc52xx_devices.c
+@@ -33,6 +33,28 @@ static struct fsl_i2c_platform_data mpc52xx_fsl_i2c_pdata = {
+    possibly using IORESOURCE_DMA. But that's when BestComm is ready ... */
+ 
+ struct platform_device ppc_sys_platform_devices[] = {
++	[MPC52xx_SDMA] = {
++		.name		= "mpc52xx-sdma",
++		.id		= -1,
++		.num_resources	= 3,
++		.resource	= (struct resource[]) {
++			{
++				.start	= 0x1200,
++				.end	= 0x12ff,
++				.flags	= IORESOURCE_MEM,
++			},
++			{
++				.start	= 0x8000,
++				.end	= 0xbfff,
++				.flags	= IORESOURCE_MEM,
++			},
++			{
++				.start	= MPC52xx_SDMA_IRQ,
++				.end	= MPC52xx_SDMA_IRQ,
++				.flags	= IORESOURCE_IRQ,
++			},
++		},
++	},
+ 	[MPC52xx_MSCAN1] = {
+ 		.name		= "mpc52xx-mscan",
+ 		.id		= 0,
+diff --git a/arch/ppc/syslib/mpc52xx_sys.c b/arch/ppc/syslib/mpc52xx_sys.c
+index b4e6f97..a74b19c 100644
+--- a/arch/ppc/syslib/mpc52xx_sys.c
++++ b/arch/ppc/syslib/mpc52xx_sys.c
+@@ -19,10 +19,10 @@ struct ppc_sys_spec ppc_sys_specs[] = {
+ 		.ppc_sys_name	= "5200",
+ 		.mask		= 0xffff0000,
+ 		.value		= 0x80110000,
+-		.num_devices	= 15,
++		.num_devices	= MPC52xx_NUM_DEVICES,
+ 		.device_list	= (enum ppc_sys_devices[])
+ 		{
+-			MPC52xx_MSCAN1, MPC52xx_MSCAN2, MPC52xx_SPI,
++			MPC52xx_SDMA, MPC52xx_MSCAN1, MPC52xx_MSCAN2, MPC52xx_SPI,
+ 			MPC52xx_USB, MPC52xx_BDLC, MPC52xx_PSC1, MPC52xx_PSC2,
+ 			MPC52xx_PSC3, MPC52xx_PSC4, MPC52xx_PSC5, MPC52xx_PSC6,
+ 			MPC52xx_FEC, MPC52xx_ATA, MPC52xx_I2C1, MPC52xx_I2C2,
+diff --git a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h
+index d9d21aa..4856b74 100644
+--- a/include/asm-ppc/mpc52xx.h
++++ b/include/asm-ppc/mpc52xx.h
+@@ -34,6 +34,8 @@ struct pt_regs;
+ /* ======================================================================== */
+ 
+ enum ppc_sys_devices {
++	MPC52xx_SDMA,				 /* Must be first device to probe, 
++									else FEC/ATA will failed */
+ 	MPC52xx_MSCAN1,
+ 	MPC52xx_MSCAN2,
+ 	MPC52xx_SPI,
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0020-Fec-MPC5200-eth-driver.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0020-Fec-MPC5200-eth-driver.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,1783 @@
+From 6b6e09cca4346ea737db427d568843034eb348fa Mon Sep 17 00:00:00 2001
+From: Andrey Volkov <avolkov at varma-el.com>
+Date: Fri, 18 Aug 2006 10:02:29 -0600
+Subject: [PATCH] [PATCH 02/02] Fec MPC5200 eth driver
+
+Second part. Contain only FEC parts.
+Depended on previous bestcomm patch.
+
+Signed-Off-By: Andrey Volkov <avolkov at varma-el.com>
+---
+ drivers/net/Kconfig               |    1 +
+ drivers/net/Makefile              |    1 +
+ drivers/net/fec_mpc52xx/Kconfig   |   23 ++
+ drivers/net/fec_mpc52xx/Makefile  |    2 +
+ drivers/net/fec_mpc52xx/fec.c     |  768 +++++++++++++++++++++++++++++++++++++
+ drivers/net/fec_mpc52xx/fec.h     |  308 +++++++++++++++
+ drivers/net/fec_mpc52xx/fec_phy.c |  526 +++++++++++++++++++++++++
+ drivers/net/fec_mpc52xx/fec_phy.h |   73 ++++
+ 8 files changed, 1702 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
+index 8aa8dd0..0658e92 100644
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -1902,6 +1902,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 4c0d4e5..e6f903d 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_MACB) += macb.o
+ 
+diff --git a/drivers/net/fec_mpc52xx/Kconfig b/drivers/net/fec_mpc52xx/Kconfig
+new file mode 100644
+index 0000000..098c3fa
+--- /dev/null
++++ b/drivers/net/fec_mpc52xx/Kconfig
+@@ -0,0 +1,23 @@
++menu "MPC5200 Networking Options"
++	depends PPC_MPC52xx && NET_ETHERNET
++
++config FEC_MPC52xx
++	bool "FEC Ethernet"
++	depends on NET_ETHERNET
++	select PPC_BESTCOMM
++	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..b8ae05c
+--- /dev/null
++++ b/drivers/net/fec_mpc52xx/Makefile
+@@ -0,0 +1,2 @@
++obj-$(CONFIG_FEC_MPC52xx) 	+= fec.o
++obj-$(CONFIG_USE_MDIO)		+= fec_phy.o
+diff --git a/drivers/net/fec_mpc52xx/fec.c b/drivers/net/fec_mpc52xx/fec.c
+new file mode 100644
+index 0000000..b5f1559
+--- /dev/null
++++ b/drivers/net/fec_mpc52xx/fec.c
+@@ -0,0 +1,768 @@
++/*
++ * drivers/net/fec_mpc52xx/fec.c
++ *
++ * 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.
++ */
++
++#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/io.h>
++#include <asm/delay.h>
++#include <asm/ppcboot.h>
++#include <asm/mpc52xx.h>
++
++#include <syslib/bestcomm/bestcomm.h>
++#include <syslib/bestcomm/fec.h>
++
++#include "fec_phy.h"
++#include "fec.h"
++
++#define DRIVER_NAME "mpc52xx-fec"
++
++static irqreturn_t fec_interrupt(int, void *, struct pt_regs *);
++static irqreturn_t fec_rx_interrupt(int, void *, struct pt_regs *);
++static irqreturn_t fec_tx_interrupt(int, void *, struct pt_regs *);
++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 sdma *s)
++{
++	struct sk_buff *skb;
++
++	while (!sdma_queue_empty(s)) {
++		skb = sdma_retrieve_buffer(s, NULL);
++		kfree_skb(skb);
++	}
++}
++
++static int fec_open(struct net_device *dev)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	struct sk_buff *skb;
++	void *data;
++
++	sdma_fec_rx_init(priv->rx_sdma, priv->rx_fifo, FEC_RX_BUFFER_SIZE);
++	sdma_fec_tx_init(priv->tx_sdma, priv->tx_fifo);
++
++	while (!sdma_queue_full(priv->rx_sdma)) {
++		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);
++		data = (void *)virt_to_phys(skb->data);
++		sdma_submit_buffer(priv->rx_sdma, skb, data, FEC_RX_BUFFER_SIZE);
++	}
++
++	fec_set_paddr(dev, dev->dev_addr);
++
++	if (fec_mii_wait(dev) != 0)
++		return -ENODEV;
++
++	sdma_enable(priv->rx_sdma);
++	sdma_enable(priv->tx_sdma);
++
++	netif_start_queue(dev);
++
++	return 0;
++
++eagain:
++	printk(KERN_ERR "fec_open: failed\n");
++
++	fec_free_rx_buffers(priv->rx_sdma);
++
++	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;
++	void *data;
++
++	if (sdma_queue_full(priv->tx_sdma))
++		panic("MPC52xx transmit queue overrun\n");
++
++	spin_lock_irq(&priv->lock);
++	dev->trans_start = jiffies;
++
++	data = (void *)virt_to_phys(skb->data);
++	sdma_fec_tfd_submit_buffer(priv->tx_sdma, skb, data, skb->len);
++
++	if (sdma_queue_full(priv->tx_sdma)) {
++		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 pt_regs *regs)
++{
++	struct net_device *dev = dev_id;
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	struct sk_buff *skb;
++
++	for (;;) {
++		sdma_clear_irq(priv->tx_sdma);
++		spin_lock(&priv->lock);
++		if (!sdma_buffer_done(priv->tx_sdma)) {
++			spin_unlock(&priv->lock);
++			break;
++		}
++		skb = sdma_retrieve_buffer(priv->tx_sdma, 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 pt_regs *regs)
++{
++	struct net_device *dev = dev_id;
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	struct sk_buff *skb;
++	struct sk_buff *rskb;
++	int status;
++
++	for (;;) {
++		sdma_clear_irq(priv->rx_sdma);
++
++		if (!sdma_buffer_done(priv->rx_sdma))
++			break;
++
++		rskb = sdma_retrieve_buffer(priv->rx_sdma, &status);
++
++		/* Test for errors in received frame */
++		if (status & 0x370000) { 
++			/* Drop packet and reuse the buffer */
++			sdma_submit_buffer(
++				priv->rx_sdma, rskb,
++				(void *)virt_to_phys(rskb->data),
++				FEC_RX_BUFFER_SIZE );
++			
++			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;
++		}
++
++		sdma_submit_buffer( priv->rx_sdma, skb,
++			(void *)virt_to_phys(skb->data), FEC_RX_BUFFER_SIZE );
++	}
++
++	return IRQ_HANDLED;
++}
++
++static irqreturn_t fec_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++	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);
++	out_be32(&fec->ievent, ievent);		/* clear pending events */
++
++	if (ievent & (FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR)) {
++		if (ievent & FEC_IEVENT_RFIFO_ERROR)
++			printk(KERN_WARNING "FEC_IEVENT_RFIFO_ERROR\n");
++		if (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);
++
++	sdma_disable(priv->rx_sdma);		/* disable receive task */
++
++	/* Wait for queues to drain */
++	timeout = jiffies + 2*HZ;
++	while (time_before(jiffies, timeout) &&
++					(!sdma_queue_empty(priv->tx_sdma) ||
++					!sdma_queue_empty(priv->rx_sdma))) {
++		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");
++
++	sdma_disable(priv->tx_sdma);
++
++	fec_free_rx_buffers(priv->rx_sdma);
++
++	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;
++	bd_t *bd = (bd_t *) &__res;
++
++	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 */
++
++	priv->phy_speed = ((bd->bi_ipbfreq >> 20) / 5) << 1;
++
++	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;
++	static void fec_update_stat(struct net_device *);
++
++	netif_stop_queue(dev);
++	out_be32(&fec->imask, 0x0);
++
++	/* Disable the rx and tx tasks. */
++	sdma_disable(priv->rx_sdma);
++	sdma_disable(priv->tx_sdma);
++
++	/* Stop FEC */
++	out_be32(&fec->ecntrl, in_be32(&fec->ecntrl) & ~0x2);
++
++	/* Restart the DMA tasks */
++	sdma_fec_rx_init(priv->rx_sdma, priv->rx_fifo, FEC_RX_BUFFER_SIZE);
++	sdma_fec_tx_init(priv->tx_sdma, priv->tx_fifo);
++	fec_hw_init(dev);
++
++	if (priv->sequence_done) {		 /* redo the fec_open() */
++		fec_free_rx_buffers(priv->rx_sdma);
++		fec_open(dev);
++	}
++	return;
++}
++
++
++/* ======================================================================== */
++/* Platform Driver                                                               */
++/* ======================================================================== */
++
++static int __devinit
++mpc52xx_fec_probe(struct device *dev)
++{
++	int ret;
++	struct platform_device *pdev = to_platform_device(dev);
++	struct net_device *ndev;
++	struct fec_priv *priv = NULL;
++	struct resource *mem;
++
++	volatile int dbg=0;
++	while(dbg)
++		__asm("nop");
++	/* Reserve FEC control zone */
++	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	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",
++									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) {
++		ret = -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->rx_fifo = ndev->base_addr + FIELD_OFFSET(mpc52xx_fec,rfifo_data);
++	priv->tx_fifo = ndev->base_addr + FIELD_OFFSET(mpc52xx_fec,tfifo_data);
++	priv->t_irq = priv->r_irq = ndev->irq = -1; /* 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) {
++		ret = -ENOMEM;
++		goto probe_error;
++	}
++
++	/* SDMA init */
++	priv->rx_sdma = sdma_alloc(FEC_RX_NUM_BD);
++	priv->tx_sdma = sdma_alloc(FEC_TX_NUM_BD);
++	
++	if (!priv->rx_sdma || !priv->tx_sdma) {
++		ret = -ENOMEM;
++		goto probe_error;
++	}
++
++	ret = sdma_fec_rx_init(priv->rx_sdma, priv->rx_fifo,FEC_RX_BUFFER_SIZE);
++	if (ret < 0)
++		goto probe_error;
++
++	ret = sdma_fec_tx_init(priv->tx_sdma, priv->tx_fifo);
++	if (ret < 0)
++		goto probe_error;
++
++	/* Get the IRQ we need one by one */
++		/* Control */
++	ndev->irq = platform_get_irq(pdev, 0);
++	if (request_irq(ndev->irq, &fec_interrupt, SA_INTERRUPT,
++	                DRIVER_NAME "_ctrl", ndev)) {
++		printk(KERN_ERR DRIVER_NAME ": ctrl interrupt request failed\n");
++		ret = -EBUSY;
++		ndev->irq = -1;	/* Don't try to free it */
++		goto probe_error;
++	}
++
++		/* RX */
++	priv->r_irq = sdma_irq(priv->rx_sdma);
++	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");
++		ret = -EBUSY;
++		priv->r_irq = -1;	/* Don't try to free it */
++		goto probe_error;
++	}
++
++		/* TX */
++	priv->t_irq = sdma_irq(priv->tx_sdma);
++	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");
++		ret = -EBUSY;
++		priv->t_irq = -1;	/* 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);
++
++	/* Hardware init */
++	fec_hw_init(ndev);
++
++	/* Register the new network device */
++	ret = register_netdev(ndev);
++	if(ret < 0)
++		goto probe_error;
++
++	/* MII init : After register ???? */
++	fec_mii_init(ndev);
++	
++	/* We're done ! */
++	dev_set_drvdata(dev, ndev);
++
++	return 0;
++
++
++	/* Error handling - free everything that might be allocated */
++probe_error:
++
++	if (ndev) {
++		if (priv->rx_sdma)	sdma_free(priv->rx_sdma);
++		if (priv->tx_sdma)	sdma_free(priv->tx_sdma);
++		
++		if (ndev->irq >= 0)	free_irq(ndev->irq, ndev);
++		if (priv->r_irq >= 0)	free_irq(priv->r_irq, ndev);
++		if (priv->t_irq >= 0)	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 ret;
++}
++
++static int
++mpc52xx_fec_remove(struct device *dev)
++{
++	struct net_device *ndev;
++	struct fec_priv *priv;
++	
++	ndev = (struct net_device *) dev_get_drvdata(dev);
++	if (!ndev)
++		return 0;
++	priv = (struct fec_priv *) ndev->priv;
++
++	unregister_netdev(ndev);
++	
++	free_irq(ndev->irq, ndev);
++	free_irq(priv->r_irq, ndev);
++	free_irq(priv->t_irq, ndev);
++
++	iounmap(priv->fec);
++	
++	release_mem_region(ndev->base_addr, sizeof(struct mpc52xx_fec));
++
++	free_netdev(ndev);
++	
++	dev_set_drvdata(dev, NULL);
++	return 0;
++}
++
++static struct device_driver mpc52xx_fec_driver = {
++	.name	  = DRIVER_NAME,
++	.bus		= &platform_bus_type,
++	.probe		= mpc52xx_fec_probe,
++	.remove		= mpc52xx_fec_remove,
++#ifdef CONFIG_PM
++/*	.suspend	= mpc52xx_fec_suspend,	TODO */
++/*	.resume		= mpc52xx_fec_resume,	TODO */
++#endif
++};
++
++/* ======================================================================== */
++/* Module                                                                   */
++/* ======================================================================== */
++
++static int __init
++mpc52xx_fec_init(void)
++{
++	return driver_register(&mpc52xx_fec_driver);
++}
++
++static void __exit
++mpc52xx_fec_exit(void)
++{
++	driver_unregister(&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..f9eed36
+--- /dev/null
++++ b/drivers/net/fec_mpc52xx/fec.h
+@@ -0,0 +1,308 @@
++/*
++ * 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 sdma *rx_sdma;
++	struct sdma *tx_sdma;
++	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;
++	phys_addr_t rx_fifo;
++	phys_addr_t tx_fifo;
++#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..2a287de
+--- /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 <syslib/bestcomm/bestcomm.h>
++#include <syslib/bestcomm/fec.h>
++#include "fec_phy.h"
++#include "fec.h"
++
++static int mpc52xx_netdev_ethtool_ioctl(struct net_device *dev, void *useraddr);
++
++/* MII processing.  We keep this as simple as possible.  Requests are
++ * placed on the list (if there is room).  When the request is finished
++ * by the MII, an optional function may be called.
++ */
++typedef struct mii_list {
++	uint	mii_regval;
++	void	(*mii_func)(uint val, struct net_device *dev, uint data);
++	struct	mii_list *mii_next;
++	uint	mii_data;
++} mii_list_t;
++
++#define		NMII	20
++mii_list_t	mii_cmds[NMII];
++mii_list_t	*mii_free;
++mii_list_t	*mii_head;
++mii_list_t	*mii_tail;
++
++typedef struct mdio_read_data {
++	__u16 regval;
++	struct task_struct *sleeping_task;
++} mdio_read_data_t;
++
++static int mii_queue(struct net_device *dev, int request,
++		void (*func)(uint, struct net_device *, uint), uint data);
++
++/* Make MII read/write commands for the FEC.
++ * */
++#define mk_mii_read(REG)	(0x60020000 | ((REG & 0x1f) << 18))
++#define mk_mii_write(REG, VAL)	(0x50020000 | ((REG & 0x1f) << 18) | \
++							(VAL & 0xffff))
++#define mk_mii_end	0
++
++/* Register definitions for the PHY.
++*/
++
++#define MII_REG_CR	 0	/* Control Register */
++#define MII_REG_SR	 1	/* Status Register */
++#define MII_REG_PHYIR1	 2	/* PHY Identification Register 1 */
++#define MII_REG_PHYIR2	 3	/* PHY Identification Register 2 */
++#define MII_REG_ANAR	 4	/* A-N Advertisement Register */
++#define MII_REG_ANLPAR	 5	/* A-N Link Partner Ability Register */
++#define MII_REG_ANER	 6	/* A-N Expansion Register */
++#define MII_REG_ANNPTR	 7	/* A-N Next Page Transmit Register */
++#define MII_REG_ANLPRNPR 8	/* A-N Link Partner Received Next Page Reg. */
++
++/* values for phy_status */
++
++#define PHY_CONF_ANE	0x0001	/* 1 auto-negotiation enabled */
++#define PHY_CONF_LOOP	0x0002	/* 1 loopback mode enabled */
++#define PHY_CONF_SPMASK	0x00f0	/* mask for speed */
++#define PHY_CONF_10HDX	0x0010	/* 10 Mbit half duplex supported */
++#define PHY_CONF_10FDX	0x0020	/* 10 Mbit full duplex supported */
++#define PHY_CONF_100HDX	0x0040	/* 100 Mbit half duplex supported */
++#define PHY_CONF_100FDX	0x0080	/* 100 Mbit full duplex supported */
++
++#define PHY_STAT_LINK	0x0100	/* 1 up - 0 down */
++#define PHY_STAT_FAULT	0x0200	/* 1 remote fault */
++#define PHY_STAT_ANC	0x0400	/* 1 auto-negotiation complete	*/
++#define PHY_STAT_SPMASK	0xf000	/* mask for speed */
++#define PHY_STAT_10HDX	0x1000	/* 10 Mbit half duplex selected	*/
++#define PHY_STAT_10FDX	0x2000	/* 10 Mbit full duplex selected	*/
++#define PHY_STAT_100HDX	0x4000	/* 100 Mbit half duplex selected */
++#define PHY_STAT_100FDX	0x8000	/* 100 Mbit full duplex selected */
++
++void fec_mii(struct net_device *dev)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	struct mpc52xx_fec *fec = priv->fec;
++	mii_list_t	*mip;
++	uint		mii_reg;
++
++	mii_reg = in_be32(&fec->mii_data);
++
++	if ((mip = mii_head) == NULL) {
++		printk(KERN_ERR "MII and no head!\n");
++		return;
++	}
++
++	if (mip->mii_func != NULL)
++		(*(mip->mii_func))(mii_reg, dev, mip->mii_data);
++
++	mii_head = mip->mii_next;
++	mip->mii_next = mii_free;
++	mii_free = mip;
++
++	if ((mip = mii_head) != NULL)
++		out_be32(&fec->mii_data, mip->mii_regval);
++}
++
++static int mii_queue(struct net_device *dev, int regval,
++				void (*func)(uint, struct net_device *, uint),
++				uint data)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	struct mpc52xx_fec *fec = priv->fec;
++	mii_list_t	*mip;
++	int		retval;
++
++	/* Add PHY address to register command.
++	*/
++	regval |= priv->phy_addr << 23;
++
++	retval = 0;
++
++	if ((mip = mii_free) != NULL) {
++		mii_free = mip->mii_next;
++		mip->mii_regval = regval;
++		mip->mii_func = func;
++		mip->mii_next = NULL;
++		mip->mii_data = data;
++		if (mii_head) {
++			mii_tail->mii_next = mip;
++			mii_tail = mip;
++		} else {
++			mii_head = mii_tail = mip;
++			out_be32(&fec->mii_data, regval);
++		}
++	} else
++		retval = 1;
++
++	return retval;
++}
++
++static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c)
++{
++	int k;
++
++	if (!c)
++		return;
++
++	for (k = 0; (c+k)->mii_data != mk_mii_end; k++)
++		mii_queue(dev, (c+k)->mii_data, (c+k)->funct, 0);
++}
++
++static void mii_parse_sr(uint mii_reg, struct net_device *dev, uint data)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	uint s = priv->phy_status;
++
++	s &= ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC);
++
++	if (mii_reg & 0x0004)
++		s |= PHY_STAT_LINK;
++	if (mii_reg & 0x0010)
++		s |= PHY_STAT_FAULT;
++	if (mii_reg & 0x0020)
++		s |= PHY_STAT_ANC;
++
++	priv->phy_status = s;
++}
++
++static void mii_parse_cr(uint mii_reg, struct net_device *dev, uint data)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	uint s = priv->phy_status;
++
++	s &= ~(PHY_CONF_ANE | PHY_CONF_LOOP);
++
++	if (mii_reg & 0x1000)
++		s |= PHY_CONF_ANE;
++	if (mii_reg & 0x4000)
++		s |= PHY_CONF_LOOP;
++
++	priv->phy_status = s;
++}
++
++static void mii_parse_anar(uint mii_reg, struct net_device *dev, uint data)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	uint s = priv->phy_status;
++
++	s &= ~(PHY_CONF_SPMASK);
++
++	if (mii_reg & 0x0020)
++		s |= PHY_CONF_10HDX;
++	if (mii_reg & 0x0040)
++		s |= PHY_CONF_10FDX;
++	if (mii_reg & 0x0080)
++		s |= PHY_CONF_100HDX;
++	if (mii_reg & 0x0100)
++		s |= PHY_CONF_100FDX;
++
++	priv->phy_status = s;
++}
++
++/* ------------------------------------------------------------------------- */
++/* Generic PHY support.  Should work for all PHYs, but does not support link
++ * change interrupts.
++ */
++static phy_info_t phy_info_generic = {
++	0x00000000, /* 0-->match any PHY */
++	"GENERIC",
++
++	(const phy_cmd_t []) {	/* config */
++		/* advertise only half-duplex capabilities */
++		{ mk_mii_write(MII_ADVERTISE, MII_ADVERTISE_HALF),
++			mii_parse_anar },
++
++		/* enable auto-negotiation */
++		{ mk_mii_write(MII_BMCR, BMCR_ANENABLE), mii_parse_cr },
++		{ mk_mii_end, }
++	},
++	(const phy_cmd_t []) {	/* startup */
++		/* restart auto-negotiation */
++		{ mk_mii_write(MII_BMCR, (BMCR_ANENABLE | BMCR_ANRESTART)),
++			NULL },
++		{ mk_mii_end, }
++	},
++	(const phy_cmd_t []) { /* ack_int */
++		/* We don't actually use the ack_int table with a generic
++		 * PHY, but putting a reference to mii_parse_sr here keeps
++		 * us from getting a compiler warning about unused static
++		 * functions in the case where we only compile in generic
++		 * PHY support.
++		 */
++		{ mk_mii_read(MII_BMSR), mii_parse_sr },
++		{ mk_mii_end, }
++	},
++	(const phy_cmd_t []) {	/* shutdown */
++		{ mk_mii_end, }
++	},
++};
++/* -------------------------------------------------------------------- */
++
++/* register definitions for the 971 */
++
++#define MII_LXT971_PCR	16	/* Port Control Register	*/
++#define MII_LXT971_SR2	17	/* Status Register 2		*/
++#define MII_LXT971_IER	18	/* Interrupt Enable Register	*/
++#define MII_LXT971_ISR	19	/* Interrupt Status Register	*/
++#define MII_LXT971_LCR	20	/* LED Control Register		*/
++#define MII_LXT971_TCR	30	/* Transmit Control Register	*/
++
++static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev, uint data)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	uint s = priv->phy_status;
++
++	s &= ~(PHY_STAT_SPMASK);
++
++	if (mii_reg & 0x4000) {
++		if (mii_reg & 0x0200)
++			s |= PHY_STAT_100FDX;
++		else
++			s |= PHY_STAT_100HDX;
++	} else {
++		if (mii_reg & 0x0200)
++			s |= PHY_STAT_10FDX;
++		else
++			s |= PHY_STAT_10HDX;
++	}
++	if (mii_reg & 0x0008)
++		s |= PHY_STAT_FAULT;
++
++	priv->phy_status = s;
++}
++
++static phy_info_t phy_info_lxt971 = {
++	0x0001378e,
++	"LXT971",
++
++	(const phy_cmd_t []) {	/* config */
++		{ mk_mii_write(MII_REG_ANAR, 0x0A1), NULL }, /* 10/100, HD */
++		{ mk_mii_read(MII_REG_CR), mii_parse_cr },
++		{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
++		{ mk_mii_end, }
++	},
++	(const phy_cmd_t []) {	/* startup - enable interrupts */
++		{ mk_mii_write(MII_LXT971_IER, 0x00f2), NULL },
++		{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
++
++		/* Somehow does the 971 tell me that the link is down
++		 * the first read after power-up.
++		 * read here to get a valid value in ack_int */
++
++		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
++		{ mk_mii_end, }
++	},
++	(const phy_cmd_t []) { /* ack_int */
++		/* find out the current status */
++
++		{ mk_mii_read(MII_REG_SR), mii_parse_sr },
++		{ mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 },
++
++		/* we only need to read ISR to acknowledge */
++
++		{ mk_mii_read(MII_LXT971_ISR), NULL },
++		{ mk_mii_end, }
++	},
++	(const phy_cmd_t []) {	/* shutdown - disable interrupts */
++		{ mk_mii_write(MII_LXT971_IER, 0x0000), NULL },
++		{ mk_mii_end, }
++	},
++};
++
++static phy_info_t *phy_info[] = {
++	&phy_info_lxt971,
++	/* Generic PHY support.  This must be the last PHY in the table.
++	 * It will be used to support any PHY that doesn't match a previous
++	 * entry in the table.
++	 */
++	&phy_info_generic,
++	NULL
++};
++
++static void mii_display_config(struct net_device *dev)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	uint s = priv->phy_status;
++
++	printk(KERN_INFO "%s: config: auto-negotiation ", dev->name);
++
++	if (s & PHY_CONF_ANE)
++		printk("on");
++	else
++		printk("off");
++
++	if (s & PHY_CONF_100FDX)
++		printk(", 100FDX");
++	if (s & PHY_CONF_100HDX)
++		printk(", 100HDX");
++	if (s & PHY_CONF_10FDX)
++		printk(", 10FDX");
++	if (s & PHY_CONF_10HDX)
++		printk(", 10HDX");
++	if (!(s & PHY_CONF_SPMASK))
++		printk(", No speed/duplex selected?");
++
++	if (s & PHY_CONF_LOOP)
++		printk(", loopback enabled");
++
++	printk(".\n");
++
++	priv->sequence_done = 1;
++}
++
++static void mii_queue_config(uint mii_reg, struct net_device *dev, uint data)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++
++	priv->phy_task.func = (void *)mii_display_config;
++	priv->phy_task.data = (unsigned long)dev;
++	tasklet_schedule(&priv->phy_task);
++}
++
++
++phy_cmd_t phy_cmd_config[] =  { { mk_mii_read(MII_REG_CR), mii_queue_config },
++				{ mk_mii_end, } };
++
++
++/* Read remainder of PHY ID.
++*/
++static void mii_discover_phy3(uint mii_reg, struct net_device *dev, uint data)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	int	i;
++
++	priv->phy_id |= (mii_reg & 0xffff);
++
++	for (i = 0; phy_info[i]; i++) {
++		if (phy_info[i]->id == (priv->phy_id >> 4) || !phy_info[i]->id)
++			break;
++		if (phy_info[i]->id == 0)	/* check generic entry */
++			break;
++	}
++
++	if (!phy_info[i])
++		panic("%s: PHY id 0x%08x is not supported!\n",
++			dev->name, priv->phy_id);
++
++	priv->phy = phy_info[i];
++	priv->phy_id_done = 1;
++
++	printk(KERN_INFO "%s: Phy @ 0x%x, type %s (0x%08x)\n",
++		dev->name, priv->phy_addr, priv->phy->name, priv->phy_id);
++}
++
++/* Scan all of the MII PHY addresses looking for someone to respond
++ * with a valid ID.  This usually happens quickly.
++ */
++static void mii_discover_phy(uint mii_reg, struct net_device *dev, uint data)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	uint	phytype;
++
++	if ((phytype = (mii_reg & 0xffff)) != 0xffff) {
++		/* Got first part of ID, now get remainder.
++		*/
++		priv->phy_id = phytype << 16;
++		mii_queue(dev, mk_mii_read(MII_REG_PHYIR2), mii_discover_phy3,
++									0);
++	} else {
++		priv->phy_addr++;
++		if (priv->phy_addr < 32)
++			mii_queue(dev, mk_mii_read(MII_REG_PHYIR1),
++							mii_discover_phy, 0);
++		else
++			printk(KERN_ERR "fec: No PHY device found.\n");
++	}
++}
++
++static int mpc52xx_netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
++{
++	__u32 ethcmd;
++
++	if (copy_from_user(&ethcmd, useraddr, sizeof ethcmd))
++		return -EFAULT;
++
++	switch (ethcmd) {
++
++		/* Get driver info */
++	case ETHTOOL_GDRVINFO:{
++			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
++			strncpy(info.driver, "MPC5200 FEC",
++				sizeof info.driver - 1);
++			if (copy_to_user(useraddr, &info, sizeof info))
++				return -EFAULT;
++			return 0;
++		}
++		/* get message-level */
++	case ETHTOOL_GMSGLVL:{
++			struct ethtool_value edata = { ETHTOOL_GMSGLVL };
++			edata.data = 0;	/* XXX */
++			if (copy_to_user(useraddr, &edata, sizeof edata))
++				return -EFAULT;
++			return 0;
++		}
++		/* set message-level */
++	case ETHTOOL_SMSGLVL:{
++			struct ethtool_value edata;
++			if (copy_from_user(&edata, useraddr, sizeof edata))
++				return -EFAULT;
++			return 0;
++		}
++	}
++	return -EOPNOTSUPP;
++}
++
++int fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
++{
++	int retval;
++
++	switch (cmd) {
++	case SIOCETHTOOL:
++		retval = mpc52xx_netdev_ethtool_ioctl(
++					dev, (void *) rq->ifr_data);
++		break;
++
++	default:
++		retval = -EOPNOTSUPP;
++		break;
++	}
++	return retval;
++}
++
++void fec_mii_init(struct net_device *dev)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	int i;
++
++	for (i=0; i<NMII-1; i++)
++		mii_cmds[i].mii_next = &mii_cmds[i+1];
++	mii_free = mii_cmds;
++
++	/* Queue up command to detect the PHY and initialize the
++	 * remainder of the interface.
++	 */
++	priv->phy_id_done = 0;
++	priv->phy_addr = 0;
++	mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy, 0);
++
++	priv->old_status = 0;
++}
++
++int fec_mii_wait(struct net_device *dev)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++
++	if (!priv->sequence_done) {
++		if (!priv->phy) {
++			printk("KERN_ERR fec_open: PHY not configured\n");
++			return -ENODEV;		/* No PHY we understand */
++		}
++
++		mii_do_cmd(dev, priv->phy->config);
++		mii_do_cmd(dev, phy_cmd_config); /* display configuration */
++		while(!priv->sequence_done)
++			schedule();
++
++		mii_do_cmd(dev, priv->phy->startup);
++	}
++	return 0;
++}
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Dale Farnsworth");
++MODULE_DESCRIPTION("PHY driver for Motorola MPC52xx FEC");
+diff --git a/drivers/net/fec_mpc52xx/fec_phy.h b/drivers/net/fec_mpc52xx/fec_phy.h
+new file mode 100644
+index 0000000..5c23bff
+--- /dev/null
++++ b/drivers/net/fec_mpc52xx/fec_phy.h
+@@ -0,0 +1,73 @@
++/*
++ * arch/ppc/52xx_io/fec_phy.h
++ *
++ * Driver for the MPC5200 Fast Ethernet Controller
++ * Based heavily on the MII support for the MPC8xx by Dan Malek
++ *
++ * Author: Dale Farnsworth <dfarnsworth at mvista.com>
++ *
++ * 2003-2004 (c) MontaVista, Software, Inc.  This file is licensed under
++ * the terms of the GNU General Public License version 2.  This program
++ * is licensed "as is" without any warranty of any kind, whether express
++ * or implied.
++ */
++
++#ifdef CONFIG_USE_MDIO
++#define MII_ADVERTISE_HALF	(ADVERTISE_100HALF | ADVERTISE_10HALF | \
++				 ADVERTISE_CSMA)
++
++#define MII_ADVERTISE_ALL	(ADVERTISE_100FULL | ADVERTISE_10FULL | \
++				 MII_ADVERTISE_HALF)
++#ifdef PHY_INTERRUPT
++#define MII_ADVERTISE_DEFAULT	MII_ADVERTISE_ALL
++#else
++#define MII_ADVERTISE_DEFAULT	MII_ADVERTISE_HALF
++#endif
++
++#define MII_RCNTL_MODE		FEC_RCNTRL_MII_MODE
++#define set_phy_speed(fec, s)	out_be32(&fec->mii_speed, s)
++#define FEC_IMASK_ENABLE	0xf0fe0000
++
++typedef struct {
++	uint mii_data;
++	void (*funct)(uint mii_reg, struct net_device *dev, uint data);
++} phy_cmd_t;
++
++typedef struct {
++	uint id;
++	char *name;
++
++	const phy_cmd_t *config;
++	const phy_cmd_t *startup;
++	const phy_cmd_t *ack_int;
++	const phy_cmd_t *shutdown;
++} phy_info_t;
++
++#else
++#define MII_RCNTL_MODE		0
++#define set_phy_speed(fec, s)
++#define FEC_IMASK_ENABLE	0xf07e0000
++#define fec_mii_wait(dev)	0
++#define fec_mii(dev)	printk(KERN_WARNING "unexpected FEC_IEVENT_MII\n")
++#define fec_mii_init(dev)
++#endif	/* CONFIG_USE_MDIO */
++
++/* MII-related definitions */
++#define FEC_MII_DATA_ST		0x40000000	/* Start frame */
++#define FEC_MII_DATA_OP_RD	0x20000000	/* Perform read */
++#define FEC_MII_DATA_OP_WR	0x10000000	/* Perform write */
++#define FEC_MII_DATA_PA_MSK	0x0f800000	/* PHY Address mask */
++#define FEC_MII_DATA_RA_MSK	0x007c0000	/* PHY Register mask */
++#define FEC_MII_DATA_TA		0x00020000	/* Turnaround */
++#define FEC_MII_DATA_DATAMSK	0x00000fff	/* PHY data mask */
++
++#define FEC_MII_DATA_RA_SHIFT	0x12		/* MII reg addr bits */
++#define FEC_MII_DATA_PA_SHIFT	0x17		/* MII PHY addr bits */
++
++#define FEC_MII_SPEED		(5 * 2)
++
++extern void fec_mii_init(struct net_device *dev);
++extern int fec_mii_wait(struct net_device *dev);
++extern void fec_mii(struct net_device *dev);
++
++extern int fec_ioctl(struct net_device *, struct ifreq *rq, int cmd);
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0021-POWERPC-Copy-bestcomm-support-files-into-arch-powerpc.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0021-POWERPC-Copy-bestcomm-support-files-into-arch-powerpc.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,1335 @@
+From 50ea8834d3b4c79ddaa8f1df88d285ebe8e71cd4 Mon Sep 17 00:00:00 2001
+From: Grant Likely <grant.likely at secretlab.ca>
+Date: Mon, 4 Dec 2006 22:19:21 -0700
+Subject: [PATCH] [POWERPC] Copy bestcomm support files into arch/powerpc
+
+Signed-off-by: Grant Likely <grant.likely at secretlab.ca>
+---
+ arch/powerpc/platforms/52xx/bestcomm.c         |  408 ++++++++++++++++++++
+ arch/powerpc/platforms/52xx/bestcomm.h         |  473 ++++++++++++++++++++++++
+ arch/powerpc/platforms/52xx/fec.c              |  174 +++++++++
+ arch/powerpc/platforms/52xx/fec.h              |   71 ++++
+ arch/powerpc/platforms/52xx/sdma_fec_rx_task.c |   71 ++++
+ arch/powerpc/platforms/52xx/sdma_fec_tx_task.c |   84 +++++
+ 6 files changed, 1281 insertions(+), 0 deletions(-)
+
+diff --git a/arch/powerpc/platforms/52xx/bestcomm.c b/arch/powerpc/platforms/52xx/bestcomm.c
+new file mode 100644
+index 0000000..ef45e02
+--- /dev/null
++++ b/arch/powerpc/platforms/52xx/bestcomm.c
+@@ -0,0 +1,408 @@
++/*
++ * arch/ppc/syslib/bestcomm/bestcomm.c
++ *
++ * Driver for MPC52xx processor BestComm peripheral 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.
++ *
++ * HISTORY:
++ *
++ * 2005-08-14	Converted to platform driver by 
++ *		Andrey Volkov <avolkov at varma-el.com>, Varma Electronics Oy
++ */
++
++#include <linux/config.h>
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/string.h>
++#include <linux/device.h>
++
++#include <asm/bug.h>
++#include <asm/io.h>
++#include <asm/mpc52xx.h>
++
++#include "bestcomm.h"
++
++#define DRIVER_NAME		"mpc52xx-sdma"
++
++struct sdma_io sdma;
++
++static spinlock_t sdma_lock = SPIN_LOCK_UNLOCKED;
++
++#ifdef CONFIG_BESTCOMM_DEBUG
++void sdma_dump(void)
++{
++	int i;
++	printk("** SDMA registers: pa = %08x, va = %08x\n", sdma.base_reg_addr, sdma.io);
++	printk("**  taskBar = %08x\n", sdma.io->taskBar);
++	printk("**  currentPointer = %08x\n", sdma.io->currentPointer);
++	printk("**  endPointer = %08x\n", sdma.io->endPointer);
++	printk("**  variablePointer = %08x\n", sdma.io->variablePointer);
++
++	printk("**  IntVect1 = %08x\n", sdma.io->IntVect1);
++	printk("**  IntVect2 = %08x\n", sdma.io->IntVect2);
++	printk("**  PtdCntrl = %08x\n", sdma.io->PtdCntrl);
++
++	printk("**  IntPend = %08x\n", sdma.io->IntPend);
++	printk("**  IntMask = %08x\n", sdma.io->IntMask);
++
++	printk("**  TCR dump:");	
++
++	for (i=0;i<16;i++)  {
++		if(i%8 == 0)
++			printk("\n**   %02X:",i);
++		printk(" %04X",sdma.io->tcr[i]);
++	}
++	printk("\n**  IPR dump:");	
++	for (i=0;i<32;i++)  {
++		if(i%16 == 0)
++			printk("\n**   %02X:",i);
++		printk(" %02X",sdma.io->ipr[i]);
++	}
++	printk("\n**  cReqSelect = %08x\n", sdma.io->cReqSelect);
++	printk("**  task_size0 = %08x\n", sdma.io->task_size0);
++	printk("**  task_size1 = %08x\n", sdma.io->task_size1);
++	printk("**  MDEDebug = %08x\n", sdma.io->MDEDebug);
++	printk("**  ADSDebug = %08x\n", sdma.io->ADSDebug);
++	printk("**  Value1 = %08x\n", sdma.io->Value1);
++	printk("**  Value2 = %08x\n", sdma.io->Value2);
++	printk("**  Control = %08x\n", sdma.io->Control);
++	printk("**  Status = %08x\n", sdma.io->Status);
++	printk("**  PTDDebug = %08x\n", sdma.io->PTDDebug);
++}
++#endif
++
++#ifdef CONFIG_BESTCOMM_DEBUG
++#define SDMA_DUMP_REGS()	sdma_dump()
++#else
++#define SDMA_DUMP_REGS()
++#endif
++
++/*
++ * Use a very simple SRAM allocator.
++ * There is no mechanism for freeing space.
++ * In an attempt to minimize internal fragmentation, the SRAM is
++ * divided into two areas.
++ *
++ * Area 1 is at the beginning of SRAM
++ * and is used for allocations requiring alignments of 16 bytes or less.
++ * Successive allocations return higher addresses.
++ *
++ * Area 2 is at the end of SRAM and is used for the remaining allocations.
++ * Successive allocations return lower addresses.
++ *
++ * I've considered adding routines to support the freeing of SRAM allocations,
++ * but the SRAM is so small (16K) that fragmentation can quickly cause the
++ * SRAM to be unusable.  If you can come up with a slick way to free SRAM
++ * memory without the fragmentation problem, please do so.
++ */
++
++static u8 *area1_end;
++static u8 *area2_begin;
++
++void *sdma_sram_alloc(int size, int alignment, u32 *dma_handle)
++{
++	u8 *a;
++
++	spin_lock(&sdma_lock);
++
++	/* alignment must be a power of 2 */
++	BUG_ON(alignment & (alignment - 1));
++
++	if (alignment < 16) {
++		a = (u8 *)(((u32)area1_end + (alignment-1)) & ~(alignment-1));
++		if (a + size <= area2_begin)
++			area1_end = a + size;
++		else
++			a = 0;				/* out of memory */
++	} else {
++		a = (u8 *)(((u32)area2_begin - size) & ~(alignment - 1));
++		if (a >= area1_end)
++			area2_begin = a;
++		else
++			a = 0;				/* out of memory */
++	}
++	if(a && dma_handle)
++		*dma_handle = sdma_sram_pa(a);
++	spin_unlock(&sdma_lock);
++	return (void *)a;
++}
++
++/* this will need to be updated if Freescale changes their task code FDT */
++static u32 fdt_ops[] = {
++	0xa0045670,	/* FDT[48] */
++	0x80045670,	/* FDT[49] */
++	0x21800000,	/* FDT[50] */
++	0x21e00000,	/* FDT[51] */
++	0x21500000,	/* FDT[52] */
++	0x21400000,	/* FDT[53] */
++	0x21500000,	/* FDT[54] */
++	0x20400000,	/* FDT[55] */
++	0x20500000,	/* FDT[56] */
++	0x20800000,	/* FDT[57] */
++	0x20a00000,	/* FDT[58] */
++	0xc0170000,	/* FDT[59] */
++	0xc0145670,	/* FDT[60] */
++	0xc0345670,	/* FDT[61] */
++	0xa0076540,	/* FDT[62] */
++	0xa0000760,	/* FDT[63] */
++};
++
++static int new_task_number(void)
++{
++	struct sdma_tdt *tdt;
++	int i;
++
++	spin_lock(&sdma_lock);
++
++	tdt = sdma.tdt;
++	for (i=0; i<SDMA_MAX_TASKS; i++, tdt++)
++		if (tdt->start == 0)
++			break;
++	if (i == SDMA_MAX_TASKS)
++		i = -1;
++
++	spin_unlock(&sdma_lock);
++
++	return i;
++}
++
++int sdma_load_task(u32 *task_image)
++{
++	struct sdma_task_header *head = (struct sdma_task_header *)task_image;
++	struct sdma_tdt *tdt;
++	int tasknum;
++	u32 *desc;
++	u32 *var_src, *var_dst;
++	u32 *inc_src;
++	void *start;
++
++	BUG_ON(head->magic != SDMA_TASK_MAGIC);
++
++	tasknum = new_task_number();
++	if (tasknum < 0)
++		return -ENOMEM;
++
++	desc = (u32 *)(head + 1);
++	var_src = desc + head->desc_size;
++	inc_src = var_src + head->var_size;
++
++	tdt = &sdma.tdt[tasknum];
++
++	start = sdma_sram_alloc(head->desc_size * sizeof(u32), 4, &tdt->start);
++	if (!start)
++		return -ENOMEM;
++	tdt->stop = tdt->start + (head->desc_size - 1)*sizeof(u32);
++	var_dst = sdma_sram_va(tdt->var);
++
++	memcpy(start, desc, head->desc_size * sizeof(u32));
++	memcpy(&var_dst[head->first_var], var_src, head->var_size * sizeof(u32));
++	memcpy(&var_dst[SDMA_MAX_VAR], inc_src, head->inc_size * sizeof(u32));
++
++	return tasknum;
++}
++
++void sdma_set_initiator(int task, int initiator)
++{
++	int i;
++	int num_descs;
++	u32 *desc;
++	int next_drd_has_initiator;
++
++	sdma_set_tcr_initiator(task, initiator);
++
++	desc = sdma_task_desc(task);
++	next_drd_has_initiator = 1;
++	num_descs = sdma_task_num_descs(task);
++
++	for (i=0; i<num_descs; i++, desc++) {
++		if (!sdma_desc_is_drd(*desc))
++			continue;
++		if (next_drd_has_initiator)
++			if (sdma_desc_initiator(*desc) != SDMA_INITIATOR_ALWAYS)
++				sdma_set_desc_initiator(desc, initiator);
++		next_drd_has_initiator = !sdma_drd_is_extended(*desc);
++	}
++}
++
++struct sdma *sdma_alloc(int queue_size)
++{
++	struct sdma *s = kmalloc(sizeof(*s), GFP_KERNEL);
++	void **cookie;
++
++	if (!s)
++		return NULL;
++
++	memset(s, 0, sizeof(*s));
++
++	if (queue_size) {
++		cookie = kmalloc(sizeof(*cookie) * queue_size, GFP_KERNEL);
++		if (!cookie) {
++			kfree(s);
++			return NULL;
++		}
++		s->cookie = cookie;
++	}
++
++	s->num_bd = queue_size;
++	return s;
++}
++
++void sdma_free(struct sdma *s)
++{
++	if (s->cookie)
++		kfree(s->cookie);
++	kfree(s);
++}
++
++static int __devinit mpc52xx_sdma_probe(struct device *dev)
++{
++	struct platform_device *pdev = to_platform_device(dev);
++	int task;
++	u32 *context;
++	u32 *fdt;
++	struct sdma_tdt *tdt;
++	struct resource *mem_io, *mem_sram;
++	u32 tdt_pa, var_pa, context_pa, fdt_pa; 
++	int ret = -ENODEV;
++
++	mem_io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	mem_sram = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++	if (!mem_io || !mem_sram)
++		goto out;
++
++	if (!request_mem_region(mem_io->start, mem_io->end - mem_io->start + 1, DRIVER_NAME)) {
++		printk(KERN_ERR DRIVER_NAME " - resource unavailable\n");
++		goto out;
++	}
++	sdma.base_reg_addr = mem_io->start;
++
++	sdma.io = ioremap_nocache(mem_io->start, sizeof(struct mpc52xx_sdma));
++
++	if (!sdma.io ) {
++		printk(KERN_ERR DRIVER_NAME " - failed to map sdma regs\n");
++		ret = -ENOMEM;
++		goto map_io_error;
++	}
++
++	SDMA_DUMP_REGS();
++
++	sdma.sram_size = mem_sram->end - mem_sram->start + 1;
++	if (!request_mem_region(mem_sram->start, sdma.sram_size, DRIVER_NAME)) {
++		printk(KERN_ERR DRIVER_NAME " - resource unavailable\n");
++		goto req_sram_error;
++	}
++
++	sdma.base_sram_addr = mem_sram->start;
++	sdma.sram = ioremap_nocache(mem_sram->start, sdma.sram_size);
++	if (!sdma.sram ) {
++		printk(KERN_ERR DRIVER_NAME " - failed to map sdma sram\n");
++		ret = -ENOMEM;
++		goto map_sram_error;
++	}
++
++	area1_end = sdma.sram;
++	area2_begin = area1_end + sdma.sram_size;
++
++	memset(area1_end, 0, sdma.sram_size);
++
++	/* allocate space for task descriptors, contexts, and var tables */
++	sdma.tdt = sdma_sram_alloc(sizeof(struct sdma_tdt) * SDMA_MAX_TASKS, 4, &tdt_pa);
++
++	context = sdma_sram_alloc(SDMA_CONTEXT_SIZE * SDMA_MAX_TASKS,
++							  SDMA_CONTEXT_ALIGN, &context_pa);
++	sdma.var = sdma_sram_alloc( (SDMA_VAR_SIZE + SDMA_INC_SIZE) * SDMA_MAX_TASKS, 
++								SDMA_VAR_ALIGN, &var_pa);
++	fdt = sdma_sram_alloc(SDMA_FDT_SIZE, SDMA_FDT_ALIGN, &fdt_pa);
++	memcpy(&fdt[48], fdt_ops, sizeof(fdt_ops));
++
++	out_be32(&sdma.io->taskBar, tdt_pa);
++
++	tdt = sdma.tdt;
++	for (task=0; task < SDMA_MAX_TASKS; task++) {
++		out_be16(&sdma.io->tcr[task], 0);
++		out_8(&sdma.io->ipr[task], 0);
++
++		tdt->context = context_pa;
++		tdt->var = var_pa;
++		tdt->fdt = fdt_pa;
++		var_pa += (SDMA_MAX_VAR + SDMA_MAX_INC)*sizeof(u32);
++		context_pa += SDMA_MAX_CONTEXT*sizeof(u32);
++		tdt++;
++	}
++
++	out_8(&sdma.io->ipr[SDMA_INITIATOR_ALWAYS], SDMA_IPR_ALWAYS);
++
++	/* Disable COMM Bus Prefetch, apparently it's not reliable yet */
++	out_be16(&sdma.io->PtdCntrl, in_be16(&sdma.io->PtdCntrl) | 1);
++
++	printk(KERN_INFO "MPC52xx BestComm inited\n");
++
++	return 0;
++
++map_sram_error:
++	release_mem_region(mem_sram->start, sdma.sram_size);
++req_sram_error:
++	iounmap(sdma.io);
++map_io_error:
++	release_mem_region(mem_io->start, mem_io->end - mem_io->start + 1);
++out:
++	printk(KERN_ERR "DMA: MPC52xx BestComm init FAILED !!!\n");
++	return ret;
++}
++
++
++static struct device_driver mpc52xx_sdma_driver = {
++	.owner	  = THIS_MODULE,
++	.name	  = DRIVER_NAME,
++	.bus	  = &platform_bus_type,
++	.probe 	  = mpc52xx_sdma_probe,
++/*	.remove	  = mpc52xx_sdma_remove,	TODO */
++#ifdef CONFIG_PM
++/*	.suspend	= mpc52xx_sdma_suspend,	TODO */
++/*	.resume		= mpc52xx_sdma_resume,	TODO */
++#endif
++};
++
++static int __init
++mpc52xx_sdma_init(void)
++{
++	printk(KERN_INFO "DMA: MPC52xx BestComm driver\n");
++	return driver_register(&mpc52xx_sdma_driver);
++}
++
++#ifdef MODULE
++static void __exit
++mpc52xx_sdma_exit(void)
++{
++	driver_unregister(&mpc52xx_sdma_driver);
++}
++#endif
++
++#ifndef MODULE
++ subsys_initcall(mpc52xx_sdma_init);
++#else
++ module_init(mpc52xx_sdma_init);
++ module_exit(mpc52xx_sdma_exit);
++#endif
++
++
++MODULE_DESCRIPTION("Freescale MPC52xx BestComm DMA");
++MODULE_LICENSE("GPL");
++
++EXPORT_SYMBOL(sdma_sram_alloc);
++EXPORT_SYMBOL(sdma_load_task);
++EXPORT_SYMBOL(sdma_set_initiator);
++EXPORT_SYMBOL(sdma_free);
++EXPORT_SYMBOL(sdma);
++
++
+diff --git a/arch/powerpc/platforms/52xx/bestcomm.h b/arch/powerpc/platforms/52xx/bestcomm.h
+new file mode 100644
+index 0000000..14bf397
+--- /dev/null
++++ b/arch/powerpc/platforms/52xx/bestcomm.h
+@@ -0,0 +1,473 @@
++/*
++ * arch/ppc/syslib/bestcomm/bestcomm.h
++ *
++ * Driver for MPC52xx processor BestComm peripheral 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.
++ *
++ * HISTORY:
++ *
++ * 2005-08-14	Converted to platform driver by 
++ *		Andrey Volkov <avolkov at varma-el.com>, Varma Electronics Oy
++ */
++
++#ifndef __BESTCOMM_BESTCOMM_H__
++#define __BESTCOMM_BESTCOMM_H__
++
++/* Buffer Descriptor definitions */
++struct sdma_bd {
++	u32 status;
++	void *data;
++};
++
++struct sdma_bd2 {
++	u32 status;
++	void *data1;
++	void *data2;
++};
++
++struct sdma_io {
++	unsigned long			base_reg_addr;
++	struct mpc52xx_sdma __iomem	*io;
++	unsigned long			base_sram_addr;
++	void __iomem			*sram;
++	size_t				sram_size;
++
++	struct sdma_tdt __iomem  	*tdt;
++	u32 __iomem			*var;
++};
++extern struct sdma_io sdma;
++
++#define	sdma_sram_pa(virt)	(((unsigned long)(((void __iomem *)(virt))-sdma.sram))+sdma.base_sram_addr)
++#define	sdma_sram_va(pa)	((void __iomem *)((((unsigned long)(pa))-sdma.base_sram_addr)+((unsigned long)sdma.sram)))
++
++#define	sdma_io_pa(virt)	(((unsigned long)(((void __iomem *)(virt))-((void __iomem *)sdma.io)))+sdma.base_reg_addr)
++#define	sdma_io_va(pa)	((void __iomem *)((((unsigned long)(pa))-sdma.base_reg_addr)+((unsigned long)sdma.io)))
++
++#define SDMA_LEN_BITS		26
++#define SDMA_LEN_MASK		((1 << SDMA_LEN_BITS) - 1)
++
++#define SDMA_BD_READY		0x40000000UL
++
++#define SDMA_FEC_TX_BD_TFD	0x08000000UL	/* transmit frame done */
++#define SDMA_FEC_TX_BD_INT	0x04000000UL	/* Interrupt */
++#define SDMA_FEC_TX_BD_TFD_INIT	(SDMA_BD_READY | SDMA_FEC_TX_BD_TFD | \
++							SDMA_FEC_TX_BD_INT)
++
++struct sdma {
++	union {
++		struct sdma_bd *bd;
++		struct sdma_bd2 *bd2;
++	};
++	void **cookie;
++	u16 index;
++	u16 outdex;
++	u16 num_bd;
++	s16 tasknum;
++	u32 flags;
++};
++
++#define SDMA_FLAGS_NONE		0x0000
++#define SDMA_FLAGS_ENABLE_TASK	0x0001
++#define SDMA_FLAGS_BD2		0x0002
++
++/* Task Descriptor Table Entry */
++struct sdma_tdt {
++	u32 start;
++	u32 stop;
++	u32 var;
++	u32 fdt;
++	u32 exec_status; /* used internally by SmartComm engine */
++	u32 mvtp;		 /* used internally by SmartComm engine */
++	u32 context;
++	u32 litbase;
++};
++
++//extern struct sdma_tdt *sdma_tdt;
++
++#define SDMA_MAX_TASKS		16
++#define SDMA_MAX_VAR		24
++#define SDMA_MAX_INC		8
++#define SDMA_MAX_FDT		64
++#define SDMA_MAX_CONTEXT	20
++#define SDMA_CONTEXT_SIZE	SDMA_MAX_CONTEXT * sizeof(u32)
++#define SDMA_CONTEXT_ALIGN	0x100
++#define SDMA_VAR_SIZE		SDMA_MAX_VAR * sizeof(u32)
++#define SDMA_VAR_ALIGN		0x80
++#define SDMA_INC_SIZE		SDMA_MAX_INC * sizeof(u32)
++#define SDMA_FDT_SIZE		SDMA_MAX_FDT * sizeof(u32)
++#define SDMA_FDT_ALIGN		0x100
++#define SDMA_BD_ALIGN		0x10
++
++#define TASK_ENABLE		0x8000
++
++#ifndef DPRINK
++	#ifdef CONFIG_BESTCOMM_DEBUG
++	#define DPRINTK(a,b...)	printk(KERN_DEBUG "sdma: %s: " a, __FUNCTION__ , ## b)
++	#else
++	#define DPRINTK(a,b...)
++	#endif
++#endif
++
++static inline void sdma_enable_task(int task)
++{
++	DPRINTK("***DMA enable task (%d): tdt = %08x\n",task, sdma.tdt);
++	DPRINTK("***tdt->start   = %08x\n",sdma.tdt[task].start);
++	DPRINTK("***tdt->stop    = %08x\n",sdma.tdt[task].stop);
++	DPRINTK("***tdt->var     = %08x\n",sdma.tdt[task].var);
++	DPRINTK("***tdt->fdt     = %08x\n",sdma.tdt[task].fdt);
++	DPRINTK("***tdt->status  = %08x\n",sdma.tdt[task].exec_status);
++	DPRINTK("***tdt->mvtp    = %08x\n",sdma.tdt[task].mvtp);
++	DPRINTK("***tdt->context = %08x\n",sdma.tdt[task].context);
++	DPRINTK("***tdt->litbase = %08x\n",sdma.tdt[task].litbase);
++	DPRINTK("***--------------\n");
++
++	u16 reg = in_be16(&sdma.io->tcr[task]);
++	DPRINTK("***enable task: &sdma.io->tcr=%08x, reg = %04x\n", &sdma.io->tcr, reg);
++	out_be16(&sdma.io->tcr[task],  reg | TASK_ENABLE);
++}
++
++static inline void sdma_disable_task(int task)
++{
++	u16 reg = in_be16(&sdma.io->tcr[task]);
++	DPRINTK("***disable task(%d): reg = %04x\n", task, reg);
++	out_be16(&sdma.io->tcr[task], reg & ~TASK_ENABLE);
++}
++
++static inline int sdma_irq(struct sdma *s)
++{
++	return MPC52xx_SDMA_IRQ_BASE + s->tasknum;
++}
++
++static inline void sdma_enable(struct sdma *s)
++{
++	sdma_enable_task(s->tasknum);
++}
++
++static inline void sdma_disable(struct sdma *s)
++{
++	sdma_disable_task(s->tasknum);
++}
++
++static inline int sdma_queue_empty(struct sdma *s)
++{
++	return s->index == s->outdex;
++}
++
++static inline void sdma_clear_irq(struct sdma *s)
++{
++	out_be32(&sdma.io->IntPend, 1 << s->tasknum);
++}
++
++static inline int sdma_next_index(struct sdma *s)
++{
++	return ((s->index + 1) == s->num_bd) ? 0 : s->index + 1;
++}
++
++static inline int sdma_next_outdex(struct sdma *s)
++{
++	return ((s->outdex + 1) == s->num_bd) ? 0 : s->outdex + 1;
++}
++
++static inline int sdma_queue_full(struct sdma *s)
++{
++	return s->outdex == sdma_next_index(s);
++}
++
++static inline int sdma_buffer_done(struct sdma *s)
++{
++#ifdef CONFIG_BESTCOMM_DEBUG
++	BUG_ON(s->flags & SDMA_FLAGS_BD2);
++#endif
++	if (sdma_queue_empty(s))
++		return 0;
++	return (s->bd[s->outdex].status & SDMA_BD_READY) == 0;
++}
++
++static inline int sdma_buffer2_done(struct sdma *s)
++{
++#ifdef CONFIG_BESTCOMM_DEBUG
++	BUG_ON(!(s->flags & SDMA_FLAGS_BD2));
++#endif
++	if (sdma_queue_empty(s))
++		return 0;
++
++	return (s->bd2[s->outdex].status & SDMA_BD_READY) == 0;
++}
++
++static inline u32 *sdma_task_desc(int task)
++{
++	return sdma_sram_va(sdma.tdt[task].start);
++}
++
++static inline u32 sdma_task_num_descs(int task)
++{
++	return (sdma.tdt[task].stop - sdma.tdt[task].start)/sizeof(u32) + 1;
++}
++
++static inline u32 *sdma_task_var(int task)
++{
++	return sdma_sram_va(sdma.tdt[task].var);
++}
++
++static inline u32 *sdma_task_inc(int task)
++{
++	return &sdma_task_var(task)[SDMA_MAX_VAR];
++}
++
++static inline void sdma_set_tcr_initiator(int task, int initiator) {
++	u16 *tcr = &sdma.io->tcr[task];
++	out_be16(tcr, (in_be16(tcr) & ~0x1f00) | (initiator << 8));
++}
++
++#define SDMA_DRD_INITIATOR_SHIFT	21
++
++static inline int sdma_desc_initiator(u32 desc)
++{
++	return (desc >> SDMA_DRD_INITIATOR_SHIFT) & 0x1f;
++}
++
++static inline void sdma_set_desc_initiator(u32 *desc, int initiator)
++{
++	*desc = (*desc & ~(0x1f << SDMA_DRD_INITIATOR_SHIFT)) |
++			((initiator << SDMA_DRD_INITIATOR_SHIFT) & 0x1f);
++}
++
++static inline void sdma_submit_buffer(struct sdma *s, void *cookie, void *data,
++								int length)
++{
++#ifdef CONFIG_BESTCOMM_DEBUG
++	BUG_ON(s->flags & SDMA_FLAGS_BD2);
++#endif
++	s->cookie[s->index] = cookie;
++	s->bd[s->index].data = data;
++	s->bd[s->index].status = SDMA_BD_READY | length;
++	s->index = sdma_next_index(s);
++	if (s->flags & SDMA_FLAGS_ENABLE_TASK)
++		sdma_enable_task(s->tasknum);
++}
++
++/*
++ * Special submit_buffer function to submit last buffer of a frame to
++ * the FEC tx task.  tfd means "transmit frame done".
++ */
++static inline void sdma_fec_tfd_submit_buffer(struct sdma *s, void *cookie,
++							void *data, int length)
++{
++#ifdef CONFIG_BESTCOMM_DEBUG
++	BUG_ON(s->flags & SDMA_FLAGS_BD2);
++#endif
++	s->cookie[s->index] = cookie;
++	s->bd[s->index].data = data;
++	s->bd[s->index].status = SDMA_FEC_TX_BD_TFD_INIT | length;
++	s->index = sdma_next_index(s);
++	sdma_enable_task(s->tasknum);
++}
++
++static inline void *sdma_retrieve_buffer(struct sdma *s, int *length)
++{
++	void *cookie = s->cookie[s->outdex];
++
++#ifdef CONFIG_BESTCOMM_DEBUG
++	BUG_ON(s->flags & SDMA_FLAGS_BD2);
++#endif
++	if (length)
++		*length = s->bd[s->outdex].status & SDMA_LEN_MASK;
++	s->outdex = sdma_next_outdex(s);
++	return cookie;
++}
++
++static inline void sdma_submit_buffer2(struct sdma *s, void *cookie,
++					void *data1, void *data2, int length)
++{
++#ifdef CONFIG_BESTCOMM_DEBUG
++	BUG_ON(!(s->flags & SDMA_FLAGS_BD2));
++#endif
++	s->cookie[s->index] = cookie;
++	s->bd2[s->index].data1 = data1;
++	s->bd2[s->index].data2 = data2;
++	s->bd2[s->index].status = SDMA_BD_READY | length;
++	s->index = sdma_next_index(s);
++	if (s->flags & SDMA_FLAGS_ENABLE_TASK)
++		sdma_enable_task(s->tasknum);
++}
++
++static inline void *sdma_retrieve_buffer2(struct sdma *s, int *length)
++{
++	void *cookie = s->cookie[s->outdex];
++
++#ifdef CONFIG_BESTCOMM_DEBUG
++	BUG_ON(!(s->flags & SDMA_FLAGS_BD2));
++#endif
++	if (length)
++		*length = s->bd2[s->outdex].status & SDMA_LEN_MASK;
++	s->outdex = sdma_next_outdex(s);
++	return cookie;
++}
++
++#define SDMA_TASK_MAGIC		0x4243544B	/* 'BCTK' */
++
++/* the size fields are given in number of 32-bit words */
++struct sdma_task_header {
++	u32	magic;
++	u8	desc_size;
++	u8	var_size;
++	u8	inc_size;
++	u8	first_var;
++	u8	reserved[8];
++};
++
++#define SDMA_DESC_NOP		0x000001f8
++#define SDMA_LCD_MASK		0x80000000
++#define SDMA_DRD_EXTENDED	0x40000000
++
++#define sdma_drd_is_extended(desc) ((desc) & SDMA_DRD_EXTENDED)
++
++static inline int sdma_desc_is_drd(u32 desc) {
++	return !(desc & SDMA_LCD_MASK) && desc != SDMA_DESC_NOP;
++};
++
++#define SDMA_PRAGMA_BIT_RSV		7	/* reserved pragma bit */
++#define SDMA_PRAGMA_BIT_PRECISE_INC	6	/* increment 0=when possible, */
++						/*	1=iter end */
++#define SDMA_PRAGMA_BIT_RST_ERROR_NO	5	/* don't reset errors on */
++						/* task enable */
++#define SDMA_PRAGMA_BIT_PACK		4	/* pack data enable */
++#define SDMA_PRAGMA_BIT_INTEGER		3	/* data alignment */
++						/* 0=frac(msb), 1=int(lsb) */
++#define SDMA_PRAGMA_BIT_SPECREAD	2	/* XLB speculative read */
++#define SDMA_PRAGMA_BIT_CW		1	/* write line buffer enable */
++#define SDMA_PRAGMA_BIT_RL		0	/* read line buffer enable */
++
++#define SDMA_STD_PRAGMA		((0 << SDMA_PRAGMA_BIT_RSV)		| \
++				 (0 << SDMA_PRAGMA_BIT_PRECISE_INC)	| \
++				 (0 << SDMA_PRAGMA_BIT_RST_ERROR_NO)	| \
++				 (0 << SDMA_PRAGMA_BIT_PACK)		| \
++				 (0 << SDMA_PRAGMA_BIT_INTEGER)		| \
++				 (1 << SDMA_PRAGMA_BIT_SPECREAD)	| \
++				 (1 << SDMA_PRAGMA_BIT_CW)		| \
++				 (1 << SDMA_PRAGMA_BIT_RL))
++
++#define SDMA_PCI_PRAGMA		((0 << SDMA_PRAGMA_BIT_RSV)		| \
++				 (0 << SDMA_PRAGMA_BIT_PRECISE_INC)	| \
++				 (0 << SDMA_PRAGMA_BIT_RST_ERROR_NO)	| \
++				 (0 << SDMA_PRAGMA_BIT_PACK)		| \
++				 (1 << SDMA_PRAGMA_BIT_INTEGER)		| \
++				 (1 << SDMA_PRAGMA_BIT_SPECREAD)	| \
++				 (1 << SDMA_PRAGMA_BIT_CW)		| \
++				 (1 << SDMA_PRAGMA_BIT_RL))
++
++#define SDMA_ATA_PRAGMA		SDMA_STD_PRAGMA
++#define SDMA_CRC16_DP_0_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_CRC16_DP_1_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_FEC_RX_BD_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_FEC_TX_BD_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_GEN_DP_0_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_GEN_DP_1_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_GEN_DP_2_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_GEN_DP_3_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_GEN_DP_BD_0_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_GEN_DP_BD_1_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_GEN_RX_BD_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_GEN_TX_BD_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_GEN_LPC_PRAGMA	SDMA_STD_PRAGMA
++#define SDMA_PCI_RX_PRAGMA	SDMA_PCI_PRAGMA
++#define SDMA_PCI_TX_PRAGMA	SDMA_PCI_PRAGMA
++
++static inline void sdma_set_task_pragma(int task, int pragma)
++{
++	u32 *fdt = &sdma.tdt[task].fdt;
++	*fdt = (*fdt & ~0xff) | pragma;
++}
++
++static inline void sdma_set_task_auto_start(int task, int next_task)
++{
++	u16 *tcr = &sdma.io->tcr[task];
++	out_be16(tcr, (in_be16(tcr) & ~0xff) | 0x00c0 | next_task);
++}
++
++#define SDMA_INITIATOR_ALWAYS	 0
++#define SDMA_INITIATOR_SCTMR_0	 1
++#define SDMA_INITIATOR_SCTMR_1	 2
++#define SDMA_INITIATOR_FEC_RX	 3
++#define SDMA_INITIATOR_FEC_TX	 4
++#define SDMA_INITIATOR_ATA_RX	 5
++#define SDMA_INITIATOR_ATA_TX	 6
++#define SDMA_INITIATOR_SCPCI_RX	 7
++#define SDMA_INITIATOR_SCPCI_TX	 8
++#define SDMA_INITIATOR_PSC3_RX	 9
++#define SDMA_INITIATOR_PSC3_TX	10
++#define SDMA_INITIATOR_PSC2_RX	11
++#define SDMA_INITIATOR_PSC2_TX	12
++#define SDMA_INITIATOR_PSC1_RX	13
++#define SDMA_INITIATOR_PSC1_TX	14
++#define SDMA_INITIATOR_SCTMR_2	15
++#define SDMA_INITIATOR_SCLPC	16
++#define SDMA_INITIATOR_PSC5_RX	17
++#define SDMA_INITIATOR_PSC5_TX	18
++#define SDMA_INITIATOR_PSC4_RX	19
++#define SDMA_INITIATOR_PSC4_TX	20
++#define SDMA_INITIATOR_I2C2_RX	21
++#define SDMA_INITIATOR_I2C2_TX	22
++#define SDMA_INITIATOR_I2C1_RX	23
++#define SDMA_INITIATOR_I2C1_TX	24
++#define SDMA_INITIATOR_PSC6_RX	25
++#define SDMA_INITIATOR_PSC6_TX	26
++#define SDMA_INITIATOR_IRDA_RX	25
++#define SDMA_INITIATOR_IRDA_TX	26
++#define SDMA_INITIATOR_SCTMR_3	27
++#define SDMA_INITIATOR_SCTMR_4	28
++#define SDMA_INITIATOR_SCTMR_5	29
++#define SDMA_INITIATOR_SCTMR_6	30
++#define SDMA_INITIATOR_SCTMR_7	31
++
++#define SDMA_IPR_ALWAYS	7
++#define SDMA_IPR_SCTMR_0 	2
++#define SDMA_IPR_SCTMR_1 	2
++#define SDMA_IPR_FEC_RX 	6
++#define SDMA_IPR_FEC_TX 	5
++#define SDMA_IPR_ATA_RX 	4
++#define SDMA_IPR_ATA_TX 	3
++#define SDMA_IPR_SCPCI_RX	2
++#define SDMA_IPR_SCPCI_TX	2
++#define SDMA_IPR_PSC3_RX	2
++#define SDMA_IPR_PSC3_TX	2
++#define SDMA_IPR_PSC2_RX	2
++#define SDMA_IPR_PSC2_TX	2
++#define SDMA_IPR_PSC1_RX	2
++#define SDMA_IPR_PSC1_TX	2
++#define SDMA_IPR_SCTMR_2	2
++#define SDMA_IPR_SCLPC		2
++#define SDMA_IPR_PSC5_RX	2
++#define SDMA_IPR_PSC5_TX	2
++#define SDMA_IPR_PSC4_RX	2
++#define SDMA_IPR_PSC4_TX	2
++#define SDMA_IPR_I2C2_RX	2
++#define SDMA_IPR_I2C2_TX	2
++#define SDMA_IPR_I2C1_RX	2
++#define SDMA_IPR_I2C1_TX	2
++#define SDMA_IPR_PSC6_RX	2
++#define SDMA_IPR_PSC6_TX	2
++#define SDMA_IPR_IRDA_RX	2
++#define SDMA_IPR_IRDA_TX	2
++#define SDMA_IPR_SCTMR_3	2
++#define SDMA_IPR_SCTMR_4	2
++#define SDMA_IPR_SCTMR_5	2
++#define SDMA_IPR_SCTMR_6	2
++#define SDMA_IPR_SCTMR_7	2
++
++extern struct sdma *sdma_alloc(int request_queue_size);
++extern void sdma_free(struct sdma *sdma_struct);
++extern int sdma_load_task(u32 *task_image);
++extern void *sdma_sram_alloc(int size, int alignment, u32 *dma_handle);
++extern void sdma_init_bd(struct sdma *s);
++extern void sdma_init_bd2(struct sdma *s);
++
++#define FIELD_OFFSET(s,f) ((unsigned long)(&(((struct s*)0)->f)))
++
++#endif  /* __BESTCOMM_BESTCOMM_H__ */
+diff --git a/arch/powerpc/platforms/52xx/fec.c b/arch/powerpc/platforms/52xx/fec.c
+new file mode 100644
+index 0000000..8756856
+--- /dev/null
++++ b/arch/powerpc/platforms/52xx/fec.c
+@@ -0,0 +1,174 @@
++/*
++ * arch/ppc/syslib/bestcomm/fec.c
++ *
++ * Driver for MPC52xx processor BestComm FEC 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.
++ *
++ * HISTORY:
++ *
++ * 2005-08-14	Converted to platform driver by 
++ *		Andrey Volkov <avolkov at varma-el.com>, Varma Electronics Oy
++ */
++
++#include <linux/config.h>
++#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 "fec.h"
++
++/*
++ * Initialize FEC receive task.
++ * Returns task number of FEC receive task.
++ * Returns -1 on failure
++ */
++int sdma_fec_rx_init(struct sdma *s, phys_addr_t fifo, int maxbufsize)
++{
++	struct sdma_fec_rx_var *var;
++	struct sdma_fec_rx_inc *inc;
++
++	static int tasknum = -1;
++	static struct sdma_bd *bd = 0;
++	static u32 bd_pa;
++
++	if (tasknum < 0) {
++		tasknum = sdma_load_task(sdma_fec_rx_task);
++		if (tasknum < 0)
++			return tasknum;
++	}
++
++	if (!bd) 
++		bd = (struct sdma_bd *)sdma_sram_alloc(sizeof(*bd) * s->num_bd,
++								SDMA_BD_ALIGN, &bd_pa);
++	if (!bd)
++		return -ENOMEM;
++
++	sdma_disable_task(tasknum);
++
++	s->tasknum = tasknum;
++	s->bd = bd;
++	s->flags = SDMA_FLAGS_NONE;
++	s->index = 0;
++	s->outdex = 0;
++	memset(bd, 0, sizeof(*bd) * s->num_bd);
++
++	var = (struct sdma_fec_rx_var *)sdma_task_var(tasknum);
++	var->enable			= sdma_io_pa(&sdma.io->tcr[tasknum]);
++	var->fifo			= fifo;
++	var->bd_base		= bd_pa;
++	var->bd_last		= bd_pa + (s->num_bd - 1)*sizeof(struct sdma_bd);
++	var->bd_start		= bd_pa;
++	var->buffer_size	= maxbufsize;
++
++	/* These are constants, they should have been in the image file */
++	inc = (struct sdma_fec_rx_inc *)sdma_task_inc(tasknum);
++	inc->incr_bytes		= -(s16)sizeof(u32);
++	inc->incr_dst		= sizeof(u32);
++	inc->incr_dst_ma	= sizeof(u8);
++
++	sdma_set_task_pragma(tasknum, SDMA_FEC_RX_BD_PRAGMA);
++	sdma_set_task_auto_start(tasknum, tasknum);
++
++	/* clear pending interrupt bits */
++	out_be32(&sdma.io->IntPend, 1<<tasknum);
++
++	out_8(&sdma.io->ipr[SDMA_INITIATOR_FEC_RX], SDMA_IPR_FEC_RX);
++
++	return tasknum;
++}
++
++/*
++ * 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 = sdma_task_num_descs(tasknum);
++	desc = sdma_task_desc(tasknum) + num_descs - 1;
++	drd_count = 0;
++	for (i=0; i<num_descs; i++, desc--)
++		if (sdma_desc_is_drd(*desc) && ++drd_count == 3)
++			break;
++	return desc;
++}
++
++/*
++ * Initialize FEC transmit task.
++ * Returns task number of FEC transmit task.
++ * Returns -1 on failure
++ */
++int sdma_fec_tx_init(struct sdma *s, phys_addr_t fifo)
++{
++	struct sdma_fec_tx_var *var;
++	struct sdma_fec_tx_inc *inc;
++
++	static int tasknum = -1;
++	static struct sdma_bd *bd = 0;
++	static u32 bd_pa;
++
++	if (tasknum < 0) {
++		tasknum = sdma_load_task(sdma_fec_tx_task);
++		if (tasknum < 0)
++			return tasknum;
++	}
++
++	if (!bd)  
++		bd = (struct sdma_bd *)sdma_sram_alloc(sizeof(*bd) * s->num_bd,
++								SDMA_BD_ALIGN, &bd_pa);
++	if (!bd)
++		return -ENOMEM;
++
++	sdma_disable_task(tasknum);
++
++	s->tasknum = tasknum;
++	s->bd = bd;
++	s->flags = SDMA_FLAGS_ENABLE_TASK;
++	s->index = 0;
++	s->outdex = 0;
++	memset(bd, 0, sizeof(*bd) * s->num_bd);
++
++	var = (struct sdma_fec_tx_var *)sdma_task_var(tasknum);
++	var->DRD		= sdma_sram_pa(self_modified_drd(tasknum));
++	var->fifo		= fifo;
++	var->enable		= sdma_io_pa(&sdma.io->tcr[tasknum]);
++	var->bd_base	= bd_pa;
++	var->bd_last	= bd_pa + (s->num_bd - 1)*sizeof(struct sdma_bd);
++	var->bd_start	= bd_pa;
++
++	/* These are constants, they should have been in the image file */
++	inc = (struct sdma_fec_tx_inc *)sdma_task_inc(tasknum);
++	inc->incr_bytes		= -(s16)sizeof(u32);
++	inc->incr_src		= sizeof(u32);
++	inc->incr_src_ma	= sizeof(u8);
++
++	sdma_set_task_pragma(tasknum, SDMA_FEC_TX_BD_PRAGMA);
++	sdma_set_task_auto_start(tasknum, tasknum);
++
++	/* clear pending interrupt bits */
++	out_be32(&sdma.io->IntPend, 1<<tasknum);
++
++	out_8(&sdma.io->ipr[SDMA_INITIATOR_FEC_TX], SDMA_IPR_FEC_TX);
++
++	return tasknum;
++}
++
++EXPORT_SYMBOL(sdma_fec_rx_init);
++EXPORT_SYMBOL(sdma_fec_tx_init);
+diff --git a/arch/powerpc/platforms/52xx/fec.h b/arch/powerpc/platforms/52xx/fec.h
+new file mode 100644
+index 0000000..e3abc0f
+--- /dev/null
++++ b/arch/powerpc/platforms/52xx/fec.h
+@@ -0,0 +1,71 @@
++/*
++ * arch/ppc/syslib/bestcomm/fec.h
++ *
++ * Driver for MPC52xx processor BestComm FEC 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.
++ *
++ * HISTORY:
++ *
++ * 2005-08-14	Converted to platform driver by 
++ *		Andrey Volkov <avolkov at varma-el.com>, Varma Electronics Oy
++ */
++
++#ifndef __BESTCOMM_FEC_H__
++#define __BESTCOMM_FEC_H__
++
++
++/* rx task vars that need to be set before enabling the task */
++struct sdma_fec_rx_var {
++	u32 enable;		/* (u16*) address of task's control register */
++	u32 fifo;		/* (u32*) address of fec's fifo */
++	u32 bd_base;		/* (struct sdma_bd*) beginning of ring buffer */
++	u32 bd_last;		/* (struct sdma_bd*) end of ring buffer */
++	u32 bd_start;		/* (struct sdma_bd*) current bd */
++	u32 buffer_size;	/* size of receive buffer */
++};
++
++/* rx task incs that need to be set before enabling the task */
++struct sdma_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 sdma_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 sdma_bd*) beginning of ring buffer */
++	u32 bd_last;		/* (struct sdma_bd*) end of ring buffer */
++	u32 bd_start;		/* (struct sdma_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 sdma_fec_tx_inc {
++	u16 pad0;
++	s16 incr_bytes;
++	u16 pad1;
++	s16 incr_src;
++	u16 pad2;
++	s16 incr_src_ma;
++};
++
++extern int sdma_fec_rx_init(struct sdma *s, phys_addr_t fifo, int maxbufsize);
++extern int sdma_fec_tx_init(struct sdma *s, phys_addr_t fifo);
++
++extern u32 sdma_fec_rx_task[];
++extern u32 sdma_fec_tx_task[];
++
++
++#endif  /* __BESTCOMM_FEC_H__ */
+diff --git a/arch/powerpc/platforms/52xx/sdma_fec_rx_task.c b/arch/powerpc/platforms/52xx/sdma_fec_rx_task.c
+new file mode 100644
+index 0000000..511b036
+--- /dev/null
++++ b/arch/powerpc/platforms/52xx/sdma_fec_rx_task.c
+@@ -0,0 +1,71 @@
++/*
++ * sdma_fec_rx_task.c
++ *
++ * Automatically created based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex
++ * on Tue Mar 22 11:19:38 2005 GMT
++ */
++
++#include <linux/types.h>
++
++/*
++ * The header consists of the following fields:
++ *	uint32_t	magic;
++ *	uint8_t		desc_size;
++ *	uint8_t		var_size;
++ *	uint8_t		inc_size;
++ *	uint8_t		first_var;
++ *	uint8_t		reserved[8];
++ *
++ * The size fields contain the number of 32-bit words.
++*/
++
++uint32_t sdma_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/platforms/52xx/sdma_fec_tx_task.c b/arch/powerpc/platforms/52xx/sdma_fec_tx_task.c
+new file mode 100644
+index 0000000..d8d7fd3
+--- /dev/null
++++ b/arch/powerpc/platforms/52xx/sdma_fec_tx_task.c
+@@ -0,0 +1,84 @@
++/*
++ * sdma_fec_tx_task.c
++ *
++ * Automatically created based on BestCommAPI-2.2/code_dma/image_rtos1/dma_image.hex
++ * on Tue Mar 22 11:19:29 2005 GMT
++ */
++
++#include <linux/types.h>
++
++/*
++ * The header consists of the following fields:
++ *	uint32_t	magic;
++ *	uint8_t		desc_size;
++ *	uint8_t		var_size;
++ *	uint8_t		inc_size;
++ *	uint8_t		first_var;
++ *	uint8_t		reserved[8];
++ *
++ * The size fields contain the number of 32-bit words.
++*/
++
++uint32_t sdma_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,
++};
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0022-MPC52xx-PCI-now-working-on-lite5200.-ugly-but-working.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0022-MPC52xx-PCI-now-working-on-lite5200.-ugly-but-working.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,464 @@
+From c4c2f5cb57335b1b47aa8007b0cfce48cc46fa06 Mon Sep 17 00:00:00 2001
+From: Grant Likely <grant.likely at secretlab.ca>
+Date: Tue, 21 Nov 2006 14:41:59 -0700
+Subject: [PATCH] [MPC52xx] PCI now working on lite5200... ugly, but working
+
+Signed-off-by: Grant Likely <grant.likely at secretlab.ca>
+---
+ arch/powerpc/platforms/52xx/mpc52xx_pci.c |  334 +++++++++++++++++++++++++++++
+ arch/powerpc/platforms/52xx/mpc52xx_pci.h |  104 +++++++++
+ 2 files changed, 438 insertions(+), 0 deletions(-)
+
+diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
+new file mode 100644
+index 0000000..07dce3c
+--- /dev/null
++++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
+@@ -0,0 +1,334 @@
++/*
++ * PCI code for the Freescale MPC52xx embedded CPU.
++ *
++ * Copyright (C) 2004 Secret Lab Technologies Ltd.
++ *                        Grant Likely <grant.likely at secretlab.ca>
++ * Copyright (C) 2004 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 <asm/pci.h>
++#include <asm/mpc52xx.h>
++#include "mpc52xx_pci.h"
++#include <asm/delay.h>
++#include <asm/machdep.h>
++#include <linux/kernel.h>
++
++
++/* This macro is defined to activate the workaround for the bug
++   435 of the MPC5200 (L25R). With it activated, we don't do any
++   32 bits configuration access during type-1 cycles */
++#define MPC5200_BUG_435_WORKAROUND
++
++
++static int
++mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
++				int offset, int len, u32 *val)
++{
++	struct pci_controller *hose = bus->sysdata;
++	u32 value;
++
++	if (ppc_md.pci_exclude_device)
++		if (ppc_md.pci_exclude_device(bus->number, devfn))
++			return PCIBIOS_DEVICE_NOT_FOUND;
++
++	out_be32(hose->cfg_addr,
++		(1 << 31) |
++		((bus->number - hose->bus_offset) << 16) |
++		(devfn << 8) |
++		(offset & 0xfc));
++	mb();
++
++#ifdef MPC5200_BUG_435_WORKAROUND
++	if (bus->number != hose->bus_offset) {
++		switch (len) {
++		      case 1:
++			value = in_8(((u8 __iomem *)hose->cfg_data) +
++			             (offset & 3));
++			break;
++		      case 2:
++			value = in_le16(((u16 __iomem *)hose->cfg_data) +
++			                ((offset>>1) & 1));
++			break;
++
++		      default:
++			value = in_le16((u16 __iomem *)hose->cfg_data) |
++				(in_le16(((u16 __iomem *)hose->cfg_data) + 1) << 16);
++			break;
++		}
++	}
++	else
++#endif
++	{
++		value = in_le32(hose->cfg_data);
++
++		if (len != 4) {
++			value >>= ((offset & 0x3) << 3);
++			value &= 0xffffffff >> (32 - (len << 3));
++		}
++	}
++
++	*val = value;
++
++	out_be32(hose->cfg_addr, 0);
++	mb();
++
++	return PCIBIOS_SUCCESSFUL;
++}
++
++static int
++mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
++				int offset, int len, u32 val)
++{
++	struct pci_controller *hose = bus->sysdata;
++	u32 value, mask;
++
++	if (ppc_md.pci_exclude_device)
++		if (ppc_md.pci_exclude_device(bus->number, devfn))
++			return PCIBIOS_DEVICE_NOT_FOUND;
++
++	out_be32(hose->cfg_addr,
++		(1 << 31) |
++		((bus->number - hose->bus_offset) << 16) |
++		(devfn << 8) |
++		(offset & 0xfc));
++	mb();
++
++#ifdef MPC5200_BUG_435_WORKAROUND
++	if (bus->number != hose->bus_offset) {
++		switch (len) {
++		      case 1:
++			out_8(((u8 __iomem *)hose->cfg_data) +
++				(offset & 3), val);
++			break;
++		      case 2:
++			out_le16(((u16 __iomem *)hose->cfg_data) +
++				((offset>>1) & 1), val);
++			break;
++
++		      default:
++			out_le16((u16 __iomem *)hose->cfg_data,
++				(u16)val);
++			out_le16(((u16 __iomem *)hose->cfg_data) + 1,
++				(u16)(val>>16));
++			break;
++		}
++	}
++	else
++#endif
++	{
++		if (len != 4) {
++			value = in_le32(hose->cfg_data);
++
++			offset = (offset & 0x3) << 3;
++			mask = (0xffffffff >> (32 - (len << 3)));
++			mask <<= offset;
++
++			value &= ~mask;
++			val = value | ((val << offset) & mask);
++		}
++
++		out_le32(hose->cfg_data, val);
++	}
++	mb();
++
++	out_be32(hose->cfg_addr, 0);
++	mb();
++
++	return PCIBIOS_SUCCESSFUL;
++}
++
++static struct pci_ops mpc52xx_pci_ops = {
++	.read  = mpc52xx_pci_read_config,
++	.write = mpc52xx_pci_write_config
++};
++
++
++static void __init
++mpc52xx_pci_setup(struct pci_controller *hose,
++                  struct mpc52xx_pci __iomem *pci_regs)
++{
++	struct resource *res;
++	u32 tmp;
++	int iwcr0 = 0, iwcr1 = 0, iwcr2 = 0;
++
++	pr_debug("mpc52xx_pci_setup()\n");
++
++	pr_debug("iw0btar=%x iw1btar=%x iw2btar=%x iwcr=%x\n",
++	         in_be32(&pci_regs->iw0btar), in_be32(&pci_regs->iw1btar),
++	         in_be32(&pci_regs->iw2btar), in_be32(&pci_regs->iwcr));
++	pr_debug("tbatr0=%x tbatr1=%x tcr=%x gscr=%x\n",
++	         in_be32(&pci_regs->tbatr0), in_be32(&pci_regs->tbatr1),
++	         in_be32(&pci_regs->tcr), in_be32(&pci_regs->gscr));
++
++	/* Setup control regs */
++	tmp = in_be32(&pci_regs->scr);
++	tmp |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
++	out_be32(&pci_regs->scr, tmp);
++
++	/* Setup windows */
++	res = &hose->mem_resources[0];
++	if (res->flags) {
++		pr_debug("mem_resource[0] = {.start=%x, .end=%x, .flags=%lx}\n",
++		         res->start, res->end, res->flags);
++		out_be32(&pci_regs->iw0btar,
++		         MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start,
++		                  res->end - res->start + 1));
++		iwcr0 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM;
++		if (res->flags & IORESOURCE_PREFETCH)
++			iwcr0 |= MPC52xx_PCI_IWCR_READ_MULTI;
++		else
++			iwcr0 |= MPC52xx_PCI_IWCR_READ;
++	}
++
++	res = &hose->mem_resources[1];
++	if (res->flags) {
++		pr_debug("mem_resource[1] = {.start=%x, .end=%x, .flags=%lx}\n",
++		         res->start, res->end, res->flags);
++		out_be32(&pci_regs->iw1btar,
++		         MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start,
++		                  res->end - res->start + 1));
++		iwcr1 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM;
++		if (res->flags & IORESOURCE_PREFETCH)
++			iwcr1 |= MPC52xx_PCI_IWCR_READ_MULTI;
++		else
++			iwcr1 |= MPC52xx_PCI_IWCR_READ;
++	}
++
++	res = &hose->io_resource;
++	if (!res) {
++		printk(KERN_ERR "%s: Didn't find IO resources\n", __FILE__);
++		return;
++	}
++	pr_debug(".io_resource={.start=%x,.end=%x,.flags=%lx} "
++	         ".io_base_phys=%lx\n",
++	         res->start, res->end, res->flags, hose->io_base_phys);
++	out_be32(&pci_regs->iw2btar,
++	         MPC52xx_PCI_IWBTAR_TRANSLATION(hose->io_base_phys,
++	                                        res->start,
++	                                        res->end - res->start + 1));
++	iwcr2 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_IO;
++
++	pr_debug("iwcr0=%x iwcr1=%x iwcr2=%x iwcr=%x old_iwcr=%x\n",
++		 iwcr0, iwcr1, iwcr2,
++		 MPC52xx_PCI_IWCR_PACK(iwcr0, iwcr1, iwcr2),
++		 in_be32(&pci_regs->iwcr));
++	out_be32(&pci_regs->iwcr, MPC52xx_PCI_IWCR_PACK(iwcr0, iwcr1, iwcr2));
++
++	out_be32(&pci_regs->tbatr0,
++		MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_IO );
++	out_be32(&pci_regs->tbatr1,
++		MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_MEM );
++
++	out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD);
++
++	/* Reset the exteral bus ( internal PCI controller is NOT resetted ) */
++	/* Not necessary and can be a bad thing if for example the bootloader
++	   is displaying a splash screen or ... Just left here for
++	   documentation purpose if anyone need it */
++	tmp = in_be32(&pci_regs->gscr);
++#if 0
++	out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR);
++	udelay(50);
++#endif
++	out_be32(&pci_regs->gscr, tmp & ~MPC52xx_PCI_GSCR_PR);
++
++	pr_debug("iw0btar=%x iw1btar=%x iw2btar=%x iwcr=%x\n",
++	         in_be32(&pci_regs->iw0btar), in_be32(&pci_regs->iw1btar),
++	         in_be32(&pci_regs->iw2btar), in_be32(&pci_regs->iwcr));
++	pr_debug("tbatr0=%x tbatr1=%x tcr=%x gscr=%x\n",
++	         in_be32(&pci_regs->tbatr0), in_be32(&pci_regs->tbatr1),
++	         in_be32(&pci_regs->tcr), in_be32(&pci_regs->gscr));
++}
++
++static void
++mpc52xx_pci_fixup_resources(struct pci_dev *dev)
++{
++	int i;
++
++	pr_debug("mpc52xx_pci_fixup_resources() %.4x:%.4x\n",
++	         dev->vendor, dev->device);
++
++	/* We don't rely on boot loader for PCI and resets all
++	   devices */
++	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
++		struct resource *res = &dev->resource[i];
++		if (res->end > res->start) {	/* Only valid resources */
++			res->end -= res->start;
++			res->start = 0;
++			res->flags |= IORESOURCE_UNSET;
++		}
++	}
++
++	/* The PCI Host bridge of MPC52xx has a prefetch memory resource
++	   fixed to 1Gb. Doesn't fit in the resource system so we remove it */
++	if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
++	     (   dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200
++	      || dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) {
++		struct resource *res = &dev->resource[1];
++		res->start = res->end = res->flags = 0;
++	}
++}
++
++int __init
++mpc52xx_add_bridge(struct device_node *node)
++{
++	int len;
++	struct mpc52xx_pci __iomem *pci_regs;
++	struct pci_controller *hose;
++	const int *bus_range;
++	struct resource rsrc;
++
++	pr_debug("Adding PCI host bridge %s\n", node->full_name);
++
++	pci_assign_all_buses = 1;
++
++	if (of_address_to_resource(node, 0, &rsrc) != 0) {
++		printk(KERN_ERR "Can't get %s resources\n", node->full_name);
++		return -EINVAL;
++	}
++
++	bus_range = get_property(node, "bus-range", &len);
++	if (bus_range == NULL || len < 2 * sizeof(int)) {
++		printk(KERN_WARNING "Can't get bus-range for %s, assume"
++		        " bus 0\n", node->full_name);
++	}
++
++	hose = pcibios_alloc_controller();
++	if (!hose)
++		return -ENOMEM;
++
++	ppc_md.pcibios_fixup_resources = mpc52xx_pci_fixup_resources;
++
++	hose->arch_data = node;
++	hose->set_cfg_type = 1;
++
++	hose->first_busno = bus_range ? bus_range[0] : 0;
++	hose->last_busno = bus_range ? bus_range[1] : 0xff;
++
++	hose->bus_offset = 0;
++	hose->ops = &mpc52xx_pci_ops;
++
++	pci_regs = ioremap(rsrc.start, rsrc.end - rsrc.start + 1);
++	if (!pci_regs)
++		return -ENOMEM;
++
++	pci_process_bridge_OF_ranges(hose, node, 0);
++
++	hose->cfg_addr = &pci_regs->car;
++
++	hose->cfg_data = hose->io_base_virt;
++	hose->io_base_virt = ioremap(hose->io_base_phys,
++	                             hose->io_resource.end + 1 -
++	                             hose->io_resource.start);
++	isa_io_base = (unsigned long) hose->io_base_virt;
++
++	mpc52xx_pci_setup(hose, pci_regs);
++
++	return 0;
++}
+diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.h b/arch/powerpc/platforms/52xx/mpc52xx_pci.h
+new file mode 100644
+index 0000000..07a659e
+--- /dev/null
++++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.h
+@@ -0,0 +1,104 @@
++/*
++ * PCI Include file the Freescale MPC52xx embedded cpu chips
++ *
++ * Inspired from code written by Dale Farnsworth <dfarnsworth at mvista.com>
++ * for the 2.4 kernel.
++ *
++ * Copyright (C) 2004 Sylvain Munaut <tnt at 246tNt.com>
++ * Copyright (C) 2003 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 __SYSLIB_MPC52xx_PCI_H__
++#define __SYSLIB_MPC52xx_PCI_H__
++
++/* ======================================================================== */
++/* PCI windows config                                                       */
++/* ======================================================================== */
++
++#define MPC52xx_PCI_TARGET_IO	0xf0000000
++#define MPC52xx_PCI_TARGET_MEM	0x00000000
++
++
++/* ======================================================================== */
++/* Structures mapping & Defines for PCI Unit                                */
++/* ======================================================================== */
++
++#define MPC52xx_PCI_GSCR_BM		0x40000000
++#define MPC52xx_PCI_GSCR_PE		0x20000000
++#define MPC52xx_PCI_GSCR_SE		0x10000000
++#define MPC52xx_PCI_GSCR_XLB2PCI_MASK	0x07000000
++#define MPC52xx_PCI_GSCR_XLB2PCI_SHIFT	24
++#define MPC52xx_PCI_GSCR_IPG2PCI_MASK	0x00070000
++#define MPC52xx_PCI_GSCR_IPG2PCI_SHIFT	16
++#define MPC52xx_PCI_GSCR_BME		0x00004000
++#define MPC52xx_PCI_GSCR_PEE		0x00002000
++#define MPC52xx_PCI_GSCR_SEE		0x00001000
++#define MPC52xx_PCI_GSCR_PR		0x00000001
++
++
++#define MPC52xx_PCI_IWBTAR_TRANSLATION(proc_ad,pci_ad,size)	  \
++		( ( (proc_ad) & 0xff000000 )			| \
++		  ( (((size) - 1) >> 8) & 0x00ff0000 )		| \
++		  ( ((pci_ad) >> 16) & 0x0000ff00 ) )
++
++#define MPC52xx_PCI_IWCR_PACK(win0,win1,win2)	(((win0) << 24) | \
++						 ((win1) << 16) | \
++						 ((win2) <<  8))
++
++#define MPC52xx_PCI_IWCR_DISABLE	0x0
++#define MPC52xx_PCI_IWCR_ENABLE		0x1
++#define MPC52xx_PCI_IWCR_READ		0x0
++#define MPC52xx_PCI_IWCR_READ_LINE	0x2
++#define MPC52xx_PCI_IWCR_READ_MULTI	0x4
++#define MPC52xx_PCI_IWCR_MEM		0x0
++#define MPC52xx_PCI_IWCR_IO		0x8
++
++#define MPC52xx_PCI_TCR_P		0x01000000
++#define MPC52xx_PCI_TCR_LD		0x00010000
++
++#define MPC52xx_PCI_TBATR_DISABLE	0x0
++#define MPC52xx_PCI_TBATR_ENABLE	0x1
++
++
++#ifndef __ASSEMBLY__
++
++struct mpc52xx_pci {
++	u32	idr;		/* PCI + 0x00 */
++	u32	scr;		/* PCI + 0x04 */
++	u32	ccrir;		/* PCI + 0x08 */
++	u32	cr1;		/* PCI + 0x0C */
++	u32	bar0;		/* PCI + 0x10 */
++	u32	bar1;		/* PCI + 0x14 */
++	u8	reserved1[16];	/* PCI + 0x18 */
++	u32	ccpr;		/* PCI + 0x28 */
++	u32	sid;		/* PCI + 0x2C */
++	u32	erbar;		/* PCI + 0x30 */
++	u32	cpr;		/* PCI + 0x34 */
++	u8	reserved2[4];	/* PCI + 0x38 */
++	u32	cr2;		/* PCI + 0x3C */
++	u8	reserved3[32];	/* PCI + 0x40 */
++	u32	gscr;		/* PCI + 0x60 */
++	u32	tbatr0;		/* PCI + 0x64 */
++	u32	tbatr1;		/* PCI + 0x68 */
++	u32	tcr;		/* PCI + 0x6C */
++	u32	iw0btar;	/* PCI + 0x70 */
++	u32	iw1btar;	/* PCI + 0x74 */
++	u32	iw2btar;	/* PCI + 0x78 */
++	u8	reserved4[4];	/* PCI + 0x7C */
++	u32	iwcr;		/* PCI + 0x80 */
++	u32	icr;		/* PCI + 0x84 */
++	u32	isr;		/* PCI + 0x88 */
++	u32	arb;		/* PCI + 0x8C */
++	u8	reserved5[104];	/* PCI + 0x90 */
++	u32	car;		/* PCI + 0xF8 */
++	u8	reserved6[4];	/* PCI + 0xFC */
++};
++
++#endif  /* __ASSEMBLY__ */
++
++
++#endif  /* __SYSLIB_MPC52xx_PCI_H__ */
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0023-POWERPC-Make-FEC-work-on-the-lite5200.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0023-POWERPC-Make-FEC-work-on-the-lite5200.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,700 @@
+From 3c687b616fee5d7097e965fce80f8f8b2b6e14cf Mon Sep 17 00:00:00 2001
+From: Grant Likely <grant.likely at secretlab.ca>
+Date: Mon, 4 Dec 2006 22:29:03 -0700
+Subject: [PATCH] [POWERPC] Make FEC work on the lite5200
+
+This patch may very well break Eth support on the Efika, and it's not
+very pretty.  But is works well enough for an NFS rootfs.  This also
+makes major bestcomm changes by removing Efika-specific bestcomm
+support and porting the arch/ppc bestcomm support driver which
+was posted to linuxppc-embedded about a year ago.
+
+Signed-off-by: Grant Likely <grant.likely at secretlab.ca>
+---
+ arch/powerpc/Kconfig                   |    5 +
+ arch/powerpc/platforms/52xx/Makefile   |    3 +
+ arch/powerpc/platforms/52xx/bestcomm.c |   98 ++++++++++-------------
+ arch/powerpc/platforms/52xx/bestcomm.h |   13 ++-
+ arch/powerpc/platforms/52xx/fec.c      |    1 -
+ arch/powerpc/platforms/52xx/lite5200.c |    9 ++
+ drivers/net/fec_mpc52xx/Kconfig        |    2 +-
+ drivers/net/fec_mpc52xx/fec.c          |  137 +++++++++++++++++++++++++++----
+ drivers/net/fec_mpc52xx/fec_phy.c      |    6 ++
+ 9 files changed, 196 insertions(+), 78 deletions(-)
+
+diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
+index 8699dad..23d7d73 100644
+--- a/arch/powerpc/Kconfig
++++ b/arch/powerpc/Kconfig
+@@ -429,6 +429,11 @@ config PPC_MPC52xx
+ 	bool
+ 	default n
+ 
++config PPC_BESTCOMM
++	bool
++	depends on PPC_MPC52xx
++	default y
++
+ config PPC_EFIKA
+ 	bool "bPlan Efika 5k2. MPC5200B based computer"
+ 	depends on PPC_MULTIPLATFORM && PPC32
+diff --git a/arch/powerpc/platforms/52xx/Makefile b/arch/powerpc/platforms/52xx/Makefile
+index a46184a..d85ea04 100644
+--- a/arch/powerpc/platforms/52xx/Makefile
++++ b/arch/powerpc/platforms/52xx/Makefile
+@@ -3,6 +3,9 @@
+ #
+ ifeq ($(CONFIG_PPC_MERGE),y)
+ obj-y				+= mpc52xx_pic.o mpc52xx_common.o
++obj-$(CONFIG_PCI)		+= mpc52xx_pci.o
++obj-$(CONFIG_PPC_BESTCOMM) 	+= bestcomm.o
++obj-$(CONFIG_FEC_MPC52xx)	+= sdma_fec_rx_task.o sdma_fec_tx_task.o fec.o
+ endif
+ 
+ obj-$(CONFIG_PPC_EFIKA)		+= efika-setup.o efika-pci.o
+diff --git a/arch/powerpc/platforms/52xx/bestcomm.c b/arch/powerpc/platforms/52xx/bestcomm.c
+index ef45e02..9935b01 100644
+--- a/arch/powerpc/platforms/52xx/bestcomm.c
++++ b/arch/powerpc/platforms/52xx/bestcomm.c
+@@ -16,7 +16,6 @@
+  *		Andrey Volkov <avolkov at varma-el.com>, Varma Electronics Oy
+  */
+ 
+-#include <linux/config.h>
+ #include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+@@ -24,17 +23,19 @@
+ #include <linux/slab.h>
+ #include <linux/spinlock.h>
+ #include <linux/string.h>
+-#include <linux/device.h>
+ 
+ #include <asm/bug.h>
+ #include <asm/io.h>
+ #include <asm/mpc52xx.h>
++#include <asm/of_platform.h>
+ 
+ #include "bestcomm.h"
+ 
+-#define DRIVER_NAME		"mpc52xx-sdma"
++#define DRIVER_NAME "mpc52xx-bestcomm"
+ 
+ struct sdma_io sdma;
++struct device_node *sdma_node;
++struct device_node *sram_node;
+ 
+ static spinlock_t sdma_lock = SPIN_LOCK_UNLOCKED;
+ 
+@@ -42,7 +43,8 @@ static spinlock_t sdma_lock = SPIN_LOCK_UNLOCKED;
+ void sdma_dump(void)
+ {
+ 	int i;
+-	printk("** SDMA registers: pa = %08x, va = %08x\n", sdma.base_reg_addr, sdma.io);
++	printk("** SDMA registers: pa = %.8lx, va = %p\n",
++	       sdma.base_reg_addr, sdma.io);
+ 	printk("**  taskBar = %08x\n", sdma.io->taskBar);
+ 	printk("**  currentPointer = %08x\n", sdma.io->currentPointer);
+ 	printk("**  endPointer = %08x\n", sdma.io->endPointer);
+@@ -254,6 +256,7 @@ struct sdma *sdma_alloc(int queue_size)
+ 	}
+ 
+ 	s->num_bd = queue_size;
++	s->node = sdma_node;
+ 	return s;
+ }
+ 
+@@ -264,29 +267,49 @@ void sdma_free(struct sdma *s)
+ 	kfree(s);
+ }
+ 
+-static int __devinit mpc52xx_sdma_probe(struct device *dev)
++static int __init mpc52xx_sdma_init(void)
+ {
+-	struct platform_device *pdev = to_platform_device(dev);
+ 	int task;
+ 	u32 *context;
+ 	u32 *fdt;
+ 	struct sdma_tdt *tdt;
+-	struct resource *mem_io, *mem_sram;
+-	u32 tdt_pa, var_pa, context_pa, fdt_pa; 
++	struct resource mem_io, mem_sram;
++	u32 tdt_pa, var_pa, context_pa, fdt_pa;
+ 	int ret = -ENODEV;
+ 
+-	mem_io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-	mem_sram = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+-	if (!mem_io || !mem_sram)
++	/* Find SDMA registers */
++	sdma_node = of_find_compatible_node(NULL, "dma-controller", "mpc52xx-bestcomm");
++	if (!sdma_node) {
++		printk (KERN_ERR DRIVER_NAME ": could not locate SDRAM controller\n");
+ 		goto out;
++	}
++
++	if ((ret = of_address_to_resource(sdma_node, 0, &mem_io)) != 0) {
++		printk(KERN_ERR "Could not get address of SDMA controller\n");
++		goto out;
++	}
++
++	/* Find SRAM location */
++	sram_node = of_find_compatible_node(NULL, "sram", "mpc52xx-sram");
++	if (!sram_node) {
++		printk (KERN_ERR DRIVER_NAME ": could not locate SRAM\n");
++		goto out;
++	}
++
++	if ((ret = of_address_to_resource(sram_node, 0, &mem_sram)) != 0) {
++		printk(KERN_ERR "Could not get address of SRAM\n");
++		goto out;
++	}
+ 
+-	if (!request_mem_region(mem_io->start, mem_io->end - mem_io->start + 1, DRIVER_NAME)) {
++	/* Map register regions */
++	if (!request_mem_region(mem_io.start, mem_io.end - mem_io.start + 1,
++	                        DRIVER_NAME)) {
+ 		printk(KERN_ERR DRIVER_NAME " - resource unavailable\n");
+ 		goto out;
+ 	}
+-	sdma.base_reg_addr = mem_io->start;
++	sdma.base_reg_addr = mem_io.start;
+ 
+-	sdma.io = ioremap_nocache(mem_io->start, sizeof(struct mpc52xx_sdma));
++	sdma.io = ioremap_nocache(mem_io.start, sizeof(struct mpc52xx_sdma));
+ 
+ 	if (!sdma.io ) {
+ 		printk(KERN_ERR DRIVER_NAME " - failed to map sdma regs\n");
+@@ -296,14 +319,14 @@ static int __devinit mpc52xx_sdma_probe(struct device *dev)
+ 
+ 	SDMA_DUMP_REGS();
+ 
+-	sdma.sram_size = mem_sram->end - mem_sram->start + 1;
+-	if (!request_mem_region(mem_sram->start, sdma.sram_size, DRIVER_NAME)) {
++	sdma.sram_size = mem_sram.end - mem_sram.start + 1;
++	if (!request_mem_region(mem_sram.start, sdma.sram_size, DRIVER_NAME)) {
+ 		printk(KERN_ERR DRIVER_NAME " - resource unavailable\n");
+ 		goto req_sram_error;
+ 	}
+ 
+-	sdma.base_sram_addr = mem_sram->start;
+-	sdma.sram = ioremap_nocache(mem_sram->start, sdma.sram_size);
++	sdma.base_sram_addr = mem_sram.start;
++	sdma.sram = ioremap_nocache(mem_sram.start, sdma.sram_size);
+ 	if (!sdma.sram ) {
+ 		printk(KERN_ERR DRIVER_NAME " - failed to map sdma sram\n");
+ 		ret = -ENOMEM;
+@@ -350,50 +373,17 @@ static int __devinit mpc52xx_sdma_probe(struct device *dev)
+ 	return 0;
+ 
+ map_sram_error:
+-	release_mem_region(mem_sram->start, sdma.sram_size);
++	release_mem_region(mem_sram.start, sdma.sram_size);
+ req_sram_error:
+ 	iounmap(sdma.io);
+ map_io_error:
+-	release_mem_region(mem_io->start, mem_io->end - mem_io->start + 1);
++	release_mem_region(mem_io.start, mem_io.end - mem_io.start + 1);
+ out:
+ 	printk(KERN_ERR "DMA: MPC52xx BestComm init FAILED !!!\n");
+ 	return ret;
+ }
+ 
+-
+-static struct device_driver mpc52xx_sdma_driver = {
+-	.owner	  = THIS_MODULE,
+-	.name	  = DRIVER_NAME,
+-	.bus	  = &platform_bus_type,
+-	.probe 	  = mpc52xx_sdma_probe,
+-/*	.remove	  = mpc52xx_sdma_remove,	TODO */
+-#ifdef CONFIG_PM
+-/*	.suspend	= mpc52xx_sdma_suspend,	TODO */
+-/*	.resume		= mpc52xx_sdma_resume,	TODO */
+-#endif
+-};
+-
+-static int __init
+-mpc52xx_sdma_init(void)
+-{
+-	printk(KERN_INFO "DMA: MPC52xx BestComm driver\n");
+-	return driver_register(&mpc52xx_sdma_driver);
+-}
+-
+-#ifdef MODULE
+-static void __exit
+-mpc52xx_sdma_exit(void)
+-{
+-	driver_unregister(&mpc52xx_sdma_driver);
+-}
+-#endif
+-
+-#ifndef MODULE
+- subsys_initcall(mpc52xx_sdma_init);
+-#else
+- module_init(mpc52xx_sdma_init);
+- module_exit(mpc52xx_sdma_exit);
+-#endif
++subsys_initcall(mpc52xx_sdma_init);
+ 
+ 
+ MODULE_DESCRIPTION("Freescale MPC52xx BestComm DMA");
+diff --git a/arch/powerpc/platforms/52xx/bestcomm.h b/arch/powerpc/platforms/52xx/bestcomm.h
+index 14bf397..bd2619d 100644
+--- a/arch/powerpc/platforms/52xx/bestcomm.h
++++ b/arch/powerpc/platforms/52xx/bestcomm.h
+@@ -19,6 +19,8 @@
+ #ifndef __BESTCOMM_BESTCOMM_H__
+ #define __BESTCOMM_BESTCOMM_H__
+ 
++#include "mpc52xx_pic.h"
++
+ /* Buffer Descriptor definitions */
+ struct sdma_bd {
+ 	u32 status;
+@@ -70,6 +72,7 @@ struct sdma {
+ 	u16 num_bd;
+ 	s16 tasknum;
+ 	u32 flags;
++	struct device_node *node;
+ };
+ 
+ #define SDMA_FLAGS_NONE		0x0000
+@@ -116,7 +119,9 @@ struct sdma_tdt {
+ 
+ static inline void sdma_enable_task(int task)
+ {
+-	DPRINTK("***DMA enable task (%d): tdt = %08x\n",task, sdma.tdt);
++	u16 reg;
++
++	DPRINTK("***DMA enable task (%d): tdt = %p\n",task, sdma.tdt);
+ 	DPRINTK("***tdt->start   = %08x\n",sdma.tdt[task].start);
+ 	DPRINTK("***tdt->stop    = %08x\n",sdma.tdt[task].stop);
+ 	DPRINTK("***tdt->var     = %08x\n",sdma.tdt[task].var);
+@@ -127,8 +132,8 @@ static inline void sdma_enable_task(int task)
+ 	DPRINTK("***tdt->litbase = %08x\n",sdma.tdt[task].litbase);
+ 	DPRINTK("***--------------\n");
+ 
+-	u16 reg = in_be16(&sdma.io->tcr[task]);
+-	DPRINTK("***enable task: &sdma.io->tcr=%08x, reg = %04x\n", &sdma.io->tcr, reg);
++	reg = in_be16(&sdma.io->tcr[task]);
++	DPRINTK("***enable task: &sdma.io->tcr=%p, reg = %04x\n", &sdma.io->tcr, reg);
+ 	out_be16(&sdma.io->tcr[task],  reg | TASK_ENABLE);
+ }
+ 
+@@ -141,7 +146,7 @@ static inline void sdma_disable_task(int task)
+ 
+ static inline int sdma_irq(struct sdma *s)
+ {
+-	return MPC52xx_SDMA_IRQ_BASE + s->tasknum;
++	return irq_of_parse_and_map(s->node, s->tasknum);
+ }
+ 
+ static inline void sdma_enable(struct sdma *s)
+diff --git a/arch/powerpc/platforms/52xx/fec.c b/arch/powerpc/platforms/52xx/fec.c
+index 8756856..90df6f4 100644
+--- a/arch/powerpc/platforms/52xx/fec.c
++++ b/arch/powerpc/platforms/52xx/fec.c
+@@ -16,7 +16,6 @@
+  *		Andrey Volkov <avolkov at varma-el.com>, Varma Electronics Oy
+  */
+ 
+-#include <linux/config.h>
+ #include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c
+index 0f21bab..f1bbe24 100644
+--- a/arch/powerpc/platforms/52xx/lite5200.c
++++ b/arch/powerpc/platforms/52xx/lite5200.c
+@@ -107,6 +107,15 @@ static void __init lite52xx_setup_arch(void)
+ 	mpc52xx_setup_cpu();	/* Generic */
+ 	lite52xx_setup_cpu();	/* Platorm specific */
+ 
++#ifdef CONFIG_PCI
++	np = of_find_node_by_type(np, "pci");
++	if (np)
++		mpc52xx_add_bridge(np);
++
++	//ppc_md.pci_swizzle = common_swizzle;
++	//ppc_md.pci_exclude_device = mpc52xx_exclude_device;
++#endif
++
+ #ifdef CONFIG_BLK_DEV_INITRD
+ 	if (initrd_start)
+ 		ROOT_DEV = Root_RAM0;
+diff --git a/drivers/net/fec_mpc52xx/Kconfig b/drivers/net/fec_mpc52xx/Kconfig
+index 098c3fa..b6bce55 100644
+--- a/drivers/net/fec_mpc52xx/Kconfig
++++ b/drivers/net/fec_mpc52xx/Kconfig
+@@ -11,7 +11,7 @@ config FEC_MPC52xx
+ 	  Fast Ethernet Controller
+ 
+ config USE_MDIO
+-	bool "  Use external Ethernet MII PHY"
++	bool "Use external Ethernet MII PHY"
+ 	select MII
+ 	depends FEC_MPC52xx
+ 	---help---
+diff --git a/drivers/net/fec_mpc52xx/fec.c b/drivers/net/fec_mpc52xx/fec.c
+index b5f1559..894da79 100644
+--- a/drivers/net/fec_mpc52xx/fec.c
++++ b/drivers/net/fec_mpc52xx/fec.c
+@@ -30,17 +30,24 @@
+ #include <asm/ppcboot.h>
+ #include <asm/mpc52xx.h>
+ 
++#if defined(CONFIG_PPC_MERGE)
++#include <asm/of_device.h>
++#include <asm/of_platform.h>
++#include <platforms/52xx/bestcomm.h>
++#include <platforms/52xx/fec.h>
++#else
+ #include <syslib/bestcomm/bestcomm.h>
+ #include <syslib/bestcomm/fec.h>
++#endif
+ 
+ #include "fec_phy.h"
+ #include "fec.h"
+ 
+ #define DRIVER_NAME "mpc52xx-fec"
+ 
+-static irqreturn_t fec_interrupt(int, void *, struct pt_regs *);
+-static irqreturn_t fec_rx_interrupt(int, void *, struct pt_regs *);
+-static irqreturn_t fec_tx_interrupt(int, void *, struct pt_regs *);
++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);
+@@ -233,7 +240,7 @@ static int fec_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ 
+ /* This handles BestComm transmit task interrupts
+  */
+-static irqreturn_t fec_tx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++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;
+@@ -259,7 +266,7 @@ static irqreturn_t fec_tx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ 	return IRQ_HANDLED;
+ }
+ 
+-static irqreturn_t fec_rx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++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;
+@@ -316,7 +323,7 @@ static irqreturn_t fec_rx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ 	return IRQ_HANDLED;
+ }
+ 
+-static irqreturn_t fec_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++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;
+@@ -324,13 +331,18 @@ static irqreturn_t fec_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ 	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 (ievent & FEC_IEVENT_RFIFO_ERROR)
+-			printk(KERN_WARNING "FEC_IEVENT_RFIFO_ERROR\n");
+-		if (ievent & FEC_IEVENT_XFIFO_ERROR)
+-			printk(KERN_WARNING "FEC_IEVENT_XFIFO_ERROR\n");
++		if (net_ratelimit() && (ievent & FEC_IEVENT_RFIFO_ERROR))
++			printk(KERN_WARNING "FEC_IEVENT_RFIFO_ERROR (%.8x)\n",
++			       ievent);
++		if (net_ratelimit() && (ievent & FEC_IEVENT_XFIFO_ERROR))
++			printk(KERN_WARNING "FEC_IEVENT_XFIFO_ERROR (%.8x)\n",
++			       ievent);
+ 		fec_reinit(dev);
+ 	}
+ 	else if (ievent & FEC_IEVENT_MII)
+@@ -495,7 +507,9 @@ static void fec_hw_init(struct net_device *dev)
+ {
+ 	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+ 	struct mpc52xx_fec *fec = priv->fec;
++#if !defined(CONFIG_PPC_MERGE)
+ 	bd_t *bd = (bd_t *) &__res;
++#endif
+ 
+ 	out_be32(&fec->op_pause, 0x00010020);
+ 	out_be32(&fec->rfifo_cntrl, 0x0f000000);
+@@ -507,7 +521,9 @@ static void fec_hw_init(struct net_device *dev)
+ 	out_be32(&fec->iaddr1, 0x00000000);	/* No individual filter */
+ 	out_be32(&fec->iaddr2, 0x00000000);	/* No individual filter */
+ 
++#if !defined(CONFIG_PPC_MERGE)
+ 	priv->phy_speed = ((bd->bi_ipbfreq >> 20) / 5) << 1;
++#endif
+ 
+ 	fec_restart(dev, 0);	/* always use half duplex mode only */
+ 	/*
+@@ -522,7 +538,6 @@ static void fec_reinit(struct net_device *dev)
+ {
+ 	struct fec_priv *priv = (struct fec_priv *)dev->priv;
+ 	struct mpc52xx_fec *fec = priv->fec;
+-	static void fec_update_stat(struct net_device *);
+ 
+ 	netif_stop_queue(dev);
+ 	out_be32(&fec->imask, 0x0);
+@@ -551,19 +566,38 @@ static void fec_reinit(struct net_device *dev)
+ /* Platform Driver                                                               */
+ /* ======================================================================== */
+ 
++#if defined(CONFIG_PPC_MERGE)
++static int __devinit
++mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
++#else
+ static int __devinit
+ mpc52xx_fec_probe(struct device *dev)
++#endif
+ {
+ 	int ret;
++#if defined(CONFIG_PPC_MERGE)
++	int rv;
++	struct resource __mem;
++	struct resource *mem = &__mem;
++#else
+ 	struct platform_device *pdev = to_platform_device(dev);
++	struct resource *mem;
++#endif
+ 	struct net_device *ndev;
+ 	struct fec_priv *priv = NULL;
+-	struct resource *mem;
+ 
+ 	volatile int dbg=0;
+ 	while(dbg)
+ 		__asm("nop");
+ 	/* Reserve FEC control zone */
++#if defined(CONFIG_PPC_MERGE)
++	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;
++	}
++#else
+ 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ 	if ((mem->end - mem->start + 1) != sizeof(struct mpc52xx_fec)) {
+ 		printk(KERN_ERR DRIVER_NAME 
+@@ -571,7 +605,8 @@ mpc52xx_fec_probe(struct device *dev)
+ 									mem->end - mem->start + 1, sizeof(struct mpc52xx_fec));
+ 		return -EINVAL;
+ 	}
+-	
++#endif
++
+ 	if (!request_mem_region(mem->start, sizeof(struct mpc52xx_fec),
+ 	                        DRIVER_NAME))
+ 		return -EBUSY;
+@@ -579,6 +614,8 @@ mpc52xx_fec_probe(struct device *dev)
+ 	/* Get the ether ndev & it's private zone */
+ 	ndev = alloc_etherdev(sizeof(struct fec_priv));
+ 	if (!ndev) {
++		printk(KERN_ERR DRIVER_NAME ": "
++			"Can not allocate the ethernet device\n" );
+ 		ret = -ENOMEM;
+ 		goto probe_error;
+ 	}
+@@ -609,6 +646,8 @@ mpc52xx_fec_probe(struct device *dev)
+ 		ioremap(mem->start, sizeof(struct mpc52xx_fec));
+ 	
+ 	if (!priv->fec) {
++		printk(KERN_ERR DRIVER_NAME ": "
++			"Can not remap IO memory at 0x%8.8x\n", mem->start );
+ 		ret = -ENOMEM;
+ 		goto probe_error;
+ 	}
+@@ -618,6 +657,8 @@ mpc52xx_fec_probe(struct device *dev)
+ 	priv->tx_sdma = sdma_alloc(FEC_TX_NUM_BD);
+ 	
+ 	if (!priv->rx_sdma || !priv->tx_sdma) {
++		printk(KERN_ERR DRIVER_NAME ": "
++			"Can not init SDMA tasks\n" );
+ 		ret = -ENOMEM;
+ 		goto probe_error;
+ 	}
+@@ -631,8 +672,13 @@ mpc52xx_fec_probe(struct device *dev)
+ 		goto probe_error;
+ 
+ 	/* Get the IRQ we need one by one */
+-		/* Control */
++	/* Control */
++#if defined(CONFIG_PPC_MERGE)
++	ndev->irq = irq_of_parse_and_map(op->node, 0);
++#else
+ 	ndev->irq = platform_get_irq(pdev, 0);
++#endif
++
+ 	if (request_irq(ndev->irq, &fec_interrupt, SA_INTERRUPT,
+ 	                DRIVER_NAME "_ctrl", ndev)) {
+ 		printk(KERN_ERR DRIVER_NAME ": ctrl interrupt request failed\n");
+@@ -641,26 +687,32 @@ mpc52xx_fec_probe(struct device *dev)
+ 		goto probe_error;
+ 	}
+ 
+-		/* RX */
++	/* RX */
+ 	priv->r_irq = sdma_irq(priv->rx_sdma);
+ 	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");
++		printk(KERN_ERR DRIVER_NAME ": rx request_irq(0x%x) failed\n",
++		       priv->r_irq);
+ 		ret = -EBUSY;
+ 		priv->r_irq = -1;	/* Don't try to free it */
+ 		goto probe_error;
+ 	}
+ 
+-		/* TX */
++	/* TX */
+ 	priv->t_irq = sdma_irq(priv->tx_sdma);
+ 	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");
++		printk(KERN_ERR DRIVER_NAME ": tx request_irq(0x%x) failed\n",
++		       priv->t_irq);
+ 		ret = -EBUSY;
+ 		priv->t_irq = -1;	/* Don't try to free it */
+ 		goto probe_error;
+ 	}
+ 
++#if defined(CONFIG_PPC_MERGE)
++	priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1;
++#endif
++
+ 	/* MAC address init */
+ 	if (memcmp(mpc52xx_fec_mac_addr, null_mac, 6) != 0)
+ 		memcpy(ndev->dev_addr, mpc52xx_fec_mac_addr, 6);
+@@ -679,7 +731,11 @@ mpc52xx_fec_probe(struct device *dev)
+ 	fec_mii_init(ndev);
+ 	
+ 	/* We're done ! */
++#if defined(CONFIG_PPC_MERGE)
++	dev_set_drvdata(&op->dev, ndev);
++#else
+ 	dev_set_drvdata(dev, ndev);
++#endif
+ 
+ 	return 0;
+ 
+@@ -705,13 +761,22 @@ probe_error:
+ 	return ret;
+ }
+ 
++#if defined(CONFIG_PPC_MERGE)
++static int
++mpc52xx_fec_remove(struct of_device *op)
++#else
+ static int
+ mpc52xx_fec_remove(struct device *dev)
++#endif
+ {
+ 	struct net_device *ndev;
+ 	struct fec_priv *priv;
+ 	
++#if defined(CONFIG_PPC_MERGE)
++	ndev = (struct net_device *) dev_get_drvdata(&op->dev);
++#else
+ 	ndev = (struct net_device *) dev_get_drvdata(dev);
++#endif
+ 	if (!ndev)
+ 		return 0;
+ 	priv = (struct fec_priv *) ndev->priv;
+@@ -728,10 +793,37 @@ mpc52xx_fec_remove(struct device *dev)
+ 
+ 	free_netdev(ndev);
+ 	
++#if defined(CONFIG_PPC_MERGE)
++	dev_set_drvdata(&op->dev, NULL);
++#else
+ 	dev_set_drvdata(dev, NULL);
++#endif
+ 	return 0;
+ }
+ 
++#if defined(CONFIG_PPC_MERGE)
++static struct of_device_id mpc52xx_fec_of_match[] = {
++	{ .compatible = "mpc5200-ethernet", },
++	{ .compatible = "mpc52xx-fec", },
++	{},
++};
++
++static struct of_platform_driver mpc52xx_fec_driver = {
++	.name = DRIVER_NAME,
++	.owner = THIS_MODULE,
++	.match_table = mpc52xx_fec_of_match,
++	.probe = mpc52xx_fec_probe,
++	.remove = mpc52xx_fec_remove,
++#ifdef CONFIG_PM
++/*	.suspend = mpc52xx_fec_suspend, TODO */
++/*	.resume = mpc52xx_fec_resume, TODO */
++#endif
++	.driver = {
++		.name = DRIVER_NAME,
++		.owner = THIS_MODULE,
++	},
++};
++#else
+ static struct device_driver mpc52xx_fec_driver = {
+ 	.name	  = DRIVER_NAME,
+ 	.bus		= &platform_bus_type,
+@@ -742,6 +834,7 @@ static struct device_driver mpc52xx_fec_driver = {
+ /*	.resume		= mpc52xx_fec_resume,	TODO */
+ #endif
+ };
++#endif
+ 
+ /* ======================================================================== */
+ /* Module                                                                   */
+@@ -750,13 +843,21 @@ static struct device_driver mpc52xx_fec_driver = {
+ static int __init
+ mpc52xx_fec_init(void)
+ {
++#if defined(CONFIG_PPC_MERGE)
++	return of_register_platform_driver(&mpc52xx_fec_driver);
++#else
+ 	return driver_register(&mpc52xx_fec_driver);
++#endif
+ }
+ 
+ static void __exit
+ mpc52xx_fec_exit(void)
+ {
++#if defined(CONFIG_PPC_MERGE)
++	of_unregister_platform_driver(&mpc52xx_fec_driver);
++#else
+ 	driver_unregister(&mpc52xx_fec_driver);
++#endif
+ }
+ 
+ 
+diff --git a/drivers/net/fec_mpc52xx/fec_phy.c b/drivers/net/fec_mpc52xx/fec_phy.c
+index 2a287de..25e0409 100644
+--- a/drivers/net/fec_mpc52xx/fec_phy.c
++++ b/drivers/net/fec_mpc52xx/fec_phy.c
+@@ -20,8 +20,14 @@
+ #include <linux/mii.h>
+ #include <asm/io.h>
+ #include <asm/mpc52xx.h>
++
++#ifdef CONFIG_PPC_MERGE
++#include <platforms/52xx/bestcomm.h>
++#else
+ #include <syslib/bestcomm/bestcomm.h>
+ #include <syslib/bestcomm/fec.h>
++#endif
++
+ #include "fec_phy.h"
+ #include "fec.h"
+ 
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0024-Add-missing-function-prototype.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0024-Add-missing-function-prototype.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,26 @@
+From 4ad1395745f590eba1b5220c8dd3ca6541f49db7 Mon Sep 17 00:00:00 2001
+From: Grant Likely <grant.likely at secretlab.ca>
+Date: Mon, 4 Dec 2006 22:55:49 -0700
+Subject: [PATCH] Add missing function prototype
+
+Signed-off-by: Grant Likely <grant.likely at secretlab.ca>
+---
+ include/asm-powerpc/mpc52xx.h |    2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/include/asm-powerpc/mpc52xx.h b/include/asm-powerpc/mpc52xx.h
+index 4560d72..7afd5bf 100644
+--- a/include/asm-powerpc/mpc52xx.h
++++ b/include/asm-powerpc/mpc52xx.h
+@@ -249,6 +249,8 @@ extern void mpc52xx_declare_of_platform_devices(void);
+ extern void mpc52xx_init_irq(void);
+ extern unsigned int mpc52xx_get_irq(void);
+ 
++extern int __init mpc52xx_add_bridge(struct device_node *node);
++
+ #endif /* __ASSEMBLY__ */
+ 
+ #endif /* __ASM_POWERPC_MPC52xx_H__ */
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0025-POWERPC-Misc-EFIKA-fixups-for-rtas-chrp.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0025-POWERPC-Misc-EFIKA-fixups-for-rtas-chrp.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,133 @@
+From 95f80c44731c46261b0ba334b35ee803f21ef60b Mon Sep 17 00:00:00 2001
+From: Grant Likely <grant.likely at secretlab.ca>
+Date: Mon, 4 Dec 2006 23:01:13 -0700
+Subject: [PATCH] [POWERPC] Misc EFIKA fixups for rtas/chrp
+
+---
+ arch/powerpc/kernel/proc_ppc64.c    |    9 --------
+ arch/powerpc/kernel/rtas-proc.c     |   36 +++++++++++++++++++++++++---------
+ arch/powerpc/platforms/chrp/setup.c |    9 ++++++++
+ 3 files changed, 35 insertions(+), 19 deletions(-)
+
+diff --git a/arch/powerpc/kernel/proc_ppc64.c b/arch/powerpc/kernel/proc_ppc64.c
+index dd7001c..fa54220 100644
+--- a/arch/powerpc/kernel/proc_ppc64.c
++++ b/arch/powerpc/kernel/proc_ppc64.c
+@@ -51,15 +51,6 @@ static int __init proc_ppc64_create(void)
+ 	if (!root)
+ 		return 1;
+ 
+-	if (!of_find_node_by_path("/rtas"))
+-		return 0;
+-
+-	if (!proc_mkdir("rtas", root))
+-		return 1;
+-
+-	if (!proc_symlink("rtas", NULL, "ppc64/rtas"))
+-		return 1;
+-
+ 	return 0;
+ }
+ core_initcall(proc_ppc64_create);
+diff --git a/arch/powerpc/kernel/rtas-proc.c b/arch/powerpc/kernel/rtas-proc.c
+index 2fe82ab..4c06c32 100644
+--- a/arch/powerpc/kernel/rtas-proc.c
++++ b/arch/powerpc/kernel/rtas-proc.c
+@@ -253,43 +253,59 @@ static void get_location_code(struct seq_file *m,
+ static void check_location_string(struct seq_file *m, const char *c);
+ static void check_location(struct seq_file *m, const char *c);
+ 
++static int __init proc_rtas_create(void)
++{
++        struct proc_dir_entry *root;
++
++        root = proc_mkdir("rtas" , NULL);
++        if (!root)
++                return -1;
++
++#ifdef CONFIG_PPC64
++        if (!proc_symlink("rtas", NULL, "ppc64/rtas"))
++                return -1;
++#endif
++
++        return 0;
++}
++
+ static int __init proc_rtas_init(void)
+ {
+ 	struct proc_dir_entry *entry;
+ 
+-	if (!machine_is(pseries))
+-		return -ENODEV;
+-
+ 	rtas_node = of_find_node_by_name(NULL, "rtas");
+ 	if (rtas_node == NULL)
+ 		return -ENODEV;
+ 
+-	entry = create_proc_entry("ppc64/rtas/progress", S_IRUGO|S_IWUSR, NULL);
++	if (proc_rtas_create() != 0)
++		return -ENODEV;
++
++	entry = create_proc_entry("rtas/progress", S_IRUGO|S_IWUSR, NULL);
+ 	if (entry)
+ 		entry->proc_fops = &ppc_rtas_progress_operations;
+ 
+-	entry = create_proc_entry("ppc64/rtas/clock", S_IRUGO|S_IWUSR, NULL);
++	entry = create_proc_entry("rtas/clock", S_IRUGO|S_IWUSR, NULL);
+ 	if (entry)
+ 		entry->proc_fops = &ppc_rtas_clock_operations;
+ 
+-	entry = create_proc_entry("ppc64/rtas/poweron", S_IWUSR|S_IRUGO, NULL);
++	entry = create_proc_entry("rtas/poweron", S_IWUSR|S_IRUGO, NULL);
+ 	if (entry)
+ 		entry->proc_fops = &ppc_rtas_poweron_operations;
+ 
+-	entry = create_proc_entry("ppc64/rtas/sensors", S_IRUGO, NULL);
++	entry = create_proc_entry("rtas/sensors", S_IRUGO, NULL);
+ 	if (entry)
+ 		entry->proc_fops = &ppc_rtas_sensors_operations;
+ 
+-	entry = create_proc_entry("ppc64/rtas/frequency", S_IWUSR|S_IRUGO,
++	entry = create_proc_entry("rtas/frequency", S_IWUSR|S_IRUGO,
+ 				  NULL);
+ 	if (entry)
+ 		entry->proc_fops = &ppc_rtas_tone_freq_operations;
+ 
+-	entry = create_proc_entry("ppc64/rtas/volume", S_IWUSR|S_IRUGO, NULL);
++	entry = create_proc_entry("rtas/volume", S_IWUSR|S_IRUGO, NULL);
+ 	if (entry)
+ 		entry->proc_fops = &ppc_rtas_tone_volume_operations;
+ 
+-	entry = create_proc_entry("ppc64/rtas/rmo_buffer", S_IRUSR, NULL);
++	entry = create_proc_entry("rtas/rmo_buffer", S_IRUSR, NULL);
+ 	if (entry)
+ 		entry->proc_fops = &ppc_rtas_rmo_buf_ops;
+ 
+diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
+index e1f51d4..ec4515c 100644
+--- a/arch/powerpc/platforms/chrp/setup.c
++++ b/arch/powerpc/platforms/chrp/setup.c
+@@ -580,11 +580,20 @@ static int __init chrp_probe(void)
+ {
+  	char *dtype = of_get_flat_dt_prop(of_get_flat_dt_root(),
+  					  "device_type", NULL);
++
++ 	char *model = of_get_flat_dt_prop(of_get_flat_dt_root(),
++ 					  "model", NULL);
+  	if (dtype == NULL)
+  		return 0;
+  	if (strcmp(dtype, "chrp"))
+ 		return 0;
+ 
++	/*
++	 * Filter out efika because it has its own platform
++	*/
++	if (model && (strcmp(model, "EFIKA5K2") == 0) )
++		return 0;
++
+ 	ISA_DMA_THRESHOLD = ~0L;
+ 	DMA_MODE_READ = 0x44;
+ 	DMA_MODE_WRITE = 0x48;
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0026-POWERPC-Cleanup-mpc52xx-PCI-support.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0026-POWERPC-Cleanup-mpc52xx-PCI-support.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,911 @@
+From 78aaa3476bf62a50d85a9753bf1ef82fd296ca73 Mon Sep 17 00:00:00 2001
+From: Grant Likely <grant.likely at secretlab.ca>
+Date: Mon, 11 Dec 2006 22:41:49 -0700
+Subject: [PATCH] [POWERPC] Cleanup mpc52xx PCI support
+
+Signed-off-by: Grant Likely <grant.likely at secretlab.ca>
+---
+ arch/powerpc/Kconfig                      |   17 ++-
+ arch/powerpc/platforms/52xx/mpc52xx_pci.c |  334 ------------------------
+ arch/powerpc/platforms/52xx/mpc52xx_pci.h |  104 --------
+ arch/powerpc/platforms/52xx/pci.c         |  404 +++++++++++++++++++++++++++++
+ 4 files changed, 420 insertions(+), 439 deletions(-)
+
+diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
+index 23d7d73..ec17225 100644
+--- a/arch/powerpc/Kconfig
++++ b/arch/powerpc/Kconfig
+@@ -429,6 +429,21 @@ config PPC_MPC52xx
+ 	bool
+ 	default n
+ 
++config PPC_MPC5200
++	bool
++	select PPC_MPC52xx
++	default n
++
++config PPC_MPC5200_BUGFIX
++	bool "MPC5200 (L25R) bugfix support"
++	depends on PPC_MPC5200
++	default n
++	help
++	  Enable workarounds for original MPC5200 errata.  This is not required
++	  for MPC5200B based boards.
++
++	  It is safe to say 'Y' here
++
+ config PPC_BESTCOMM
+ 	bool
+ 	depends on PPC_MPC52xx
+@@ -446,7 +461,7 @@ config PPC_EFIKA
+ config PPC_LITE5200
+ 	bool "Freescale Lite5200 Eval Board"
+ 	depends on PPC_MULTIPLATFORM && PPC32
+-	select PPC_MPC52xx
++	select PPC_MPC5200
+ 	default n
+ 
+ config PPC_PMAC
+diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
+deleted file mode 100644
+index 07dce3c..0000000
+--- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c
++++ /dev/null
+@@ -1,334 +0,0 @@
+-/*
+- * PCI code for the Freescale MPC52xx embedded CPU.
+- *
+- * Copyright (C) 2004 Secret Lab Technologies Ltd.
+- *                        Grant Likely <grant.likely at secretlab.ca>
+- * Copyright (C) 2004 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 <asm/pci.h>
+-#include <asm/mpc52xx.h>
+-#include "mpc52xx_pci.h"
+-#include <asm/delay.h>
+-#include <asm/machdep.h>
+-#include <linux/kernel.h>
+-
+-
+-/* This macro is defined to activate the workaround for the bug
+-   435 of the MPC5200 (L25R). With it activated, we don't do any
+-   32 bits configuration access during type-1 cycles */
+-#define MPC5200_BUG_435_WORKAROUND
+-
+-
+-static int
+-mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
+-				int offset, int len, u32 *val)
+-{
+-	struct pci_controller *hose = bus->sysdata;
+-	u32 value;
+-
+-	if (ppc_md.pci_exclude_device)
+-		if (ppc_md.pci_exclude_device(bus->number, devfn))
+-			return PCIBIOS_DEVICE_NOT_FOUND;
+-
+-	out_be32(hose->cfg_addr,
+-		(1 << 31) |
+-		((bus->number - hose->bus_offset) << 16) |
+-		(devfn << 8) |
+-		(offset & 0xfc));
+-	mb();
+-
+-#ifdef MPC5200_BUG_435_WORKAROUND
+-	if (bus->number != hose->bus_offset) {
+-		switch (len) {
+-		      case 1:
+-			value = in_8(((u8 __iomem *)hose->cfg_data) +
+-			             (offset & 3));
+-			break;
+-		      case 2:
+-			value = in_le16(((u16 __iomem *)hose->cfg_data) +
+-			                ((offset>>1) & 1));
+-			break;
+-
+-		      default:
+-			value = in_le16((u16 __iomem *)hose->cfg_data) |
+-				(in_le16(((u16 __iomem *)hose->cfg_data) + 1) << 16);
+-			break;
+-		}
+-	}
+-	else
+-#endif
+-	{
+-		value = in_le32(hose->cfg_data);
+-
+-		if (len != 4) {
+-			value >>= ((offset & 0x3) << 3);
+-			value &= 0xffffffff >> (32 - (len << 3));
+-		}
+-	}
+-
+-	*val = value;
+-
+-	out_be32(hose->cfg_addr, 0);
+-	mb();
+-
+-	return PCIBIOS_SUCCESSFUL;
+-}
+-
+-static int
+-mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
+-				int offset, int len, u32 val)
+-{
+-	struct pci_controller *hose = bus->sysdata;
+-	u32 value, mask;
+-
+-	if (ppc_md.pci_exclude_device)
+-		if (ppc_md.pci_exclude_device(bus->number, devfn))
+-			return PCIBIOS_DEVICE_NOT_FOUND;
+-
+-	out_be32(hose->cfg_addr,
+-		(1 << 31) |
+-		((bus->number - hose->bus_offset) << 16) |
+-		(devfn << 8) |
+-		(offset & 0xfc));
+-	mb();
+-
+-#ifdef MPC5200_BUG_435_WORKAROUND
+-	if (bus->number != hose->bus_offset) {
+-		switch (len) {
+-		      case 1:
+-			out_8(((u8 __iomem *)hose->cfg_data) +
+-				(offset & 3), val);
+-			break;
+-		      case 2:
+-			out_le16(((u16 __iomem *)hose->cfg_data) +
+-				((offset>>1) & 1), val);
+-			break;
+-
+-		      default:
+-			out_le16((u16 __iomem *)hose->cfg_data,
+-				(u16)val);
+-			out_le16(((u16 __iomem *)hose->cfg_data) + 1,
+-				(u16)(val>>16));
+-			break;
+-		}
+-	}
+-	else
+-#endif
+-	{
+-		if (len != 4) {
+-			value = in_le32(hose->cfg_data);
+-
+-			offset = (offset & 0x3) << 3;
+-			mask = (0xffffffff >> (32 - (len << 3)));
+-			mask <<= offset;
+-
+-			value &= ~mask;
+-			val = value | ((val << offset) & mask);
+-		}
+-
+-		out_le32(hose->cfg_data, val);
+-	}
+-	mb();
+-
+-	out_be32(hose->cfg_addr, 0);
+-	mb();
+-
+-	return PCIBIOS_SUCCESSFUL;
+-}
+-
+-static struct pci_ops mpc52xx_pci_ops = {
+-	.read  = mpc52xx_pci_read_config,
+-	.write = mpc52xx_pci_write_config
+-};
+-
+-
+-static void __init
+-mpc52xx_pci_setup(struct pci_controller *hose,
+-                  struct mpc52xx_pci __iomem *pci_regs)
+-{
+-	struct resource *res;
+-	u32 tmp;
+-	int iwcr0 = 0, iwcr1 = 0, iwcr2 = 0;
+-
+-	pr_debug("mpc52xx_pci_setup()\n");
+-
+-	pr_debug("iw0btar=%x iw1btar=%x iw2btar=%x iwcr=%x\n",
+-	         in_be32(&pci_regs->iw0btar), in_be32(&pci_regs->iw1btar),
+-	         in_be32(&pci_regs->iw2btar), in_be32(&pci_regs->iwcr));
+-	pr_debug("tbatr0=%x tbatr1=%x tcr=%x gscr=%x\n",
+-	         in_be32(&pci_regs->tbatr0), in_be32(&pci_regs->tbatr1),
+-	         in_be32(&pci_regs->tcr), in_be32(&pci_regs->gscr));
+-
+-	/* Setup control regs */
+-	tmp = in_be32(&pci_regs->scr);
+-	tmp |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+-	out_be32(&pci_regs->scr, tmp);
+-
+-	/* Setup windows */
+-	res = &hose->mem_resources[0];
+-	if (res->flags) {
+-		pr_debug("mem_resource[0] = {.start=%x, .end=%x, .flags=%lx}\n",
+-		         res->start, res->end, res->flags);
+-		out_be32(&pci_regs->iw0btar,
+-		         MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start,
+-		                  res->end - res->start + 1));
+-		iwcr0 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM;
+-		if (res->flags & IORESOURCE_PREFETCH)
+-			iwcr0 |= MPC52xx_PCI_IWCR_READ_MULTI;
+-		else
+-			iwcr0 |= MPC52xx_PCI_IWCR_READ;
+-	}
+-
+-	res = &hose->mem_resources[1];
+-	if (res->flags) {
+-		pr_debug("mem_resource[1] = {.start=%x, .end=%x, .flags=%lx}\n",
+-		         res->start, res->end, res->flags);
+-		out_be32(&pci_regs->iw1btar,
+-		         MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start,
+-		                  res->end - res->start + 1));
+-		iwcr1 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM;
+-		if (res->flags & IORESOURCE_PREFETCH)
+-			iwcr1 |= MPC52xx_PCI_IWCR_READ_MULTI;
+-		else
+-			iwcr1 |= MPC52xx_PCI_IWCR_READ;
+-	}
+-
+-	res = &hose->io_resource;
+-	if (!res) {
+-		printk(KERN_ERR "%s: Didn't find IO resources\n", __FILE__);
+-		return;
+-	}
+-	pr_debug(".io_resource={.start=%x,.end=%x,.flags=%lx} "
+-	         ".io_base_phys=%lx\n",
+-	         res->start, res->end, res->flags, hose->io_base_phys);
+-	out_be32(&pci_regs->iw2btar,
+-	         MPC52xx_PCI_IWBTAR_TRANSLATION(hose->io_base_phys,
+-	                                        res->start,
+-	                                        res->end - res->start + 1));
+-	iwcr2 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_IO;
+-
+-	pr_debug("iwcr0=%x iwcr1=%x iwcr2=%x iwcr=%x old_iwcr=%x\n",
+-		 iwcr0, iwcr1, iwcr2,
+-		 MPC52xx_PCI_IWCR_PACK(iwcr0, iwcr1, iwcr2),
+-		 in_be32(&pci_regs->iwcr));
+-	out_be32(&pci_regs->iwcr, MPC52xx_PCI_IWCR_PACK(iwcr0, iwcr1, iwcr2));
+-
+-	out_be32(&pci_regs->tbatr0,
+-		MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_IO );
+-	out_be32(&pci_regs->tbatr1,
+-		MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_MEM );
+-
+-	out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD);
+-
+-	/* Reset the exteral bus ( internal PCI controller is NOT resetted ) */
+-	/* Not necessary and can be a bad thing if for example the bootloader
+-	   is displaying a splash screen or ... Just left here for
+-	   documentation purpose if anyone need it */
+-	tmp = in_be32(&pci_regs->gscr);
+-#if 0
+-	out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR);
+-	udelay(50);
+-#endif
+-	out_be32(&pci_regs->gscr, tmp & ~MPC52xx_PCI_GSCR_PR);
+-
+-	pr_debug("iw0btar=%x iw1btar=%x iw2btar=%x iwcr=%x\n",
+-	         in_be32(&pci_regs->iw0btar), in_be32(&pci_regs->iw1btar),
+-	         in_be32(&pci_regs->iw2btar), in_be32(&pci_regs->iwcr));
+-	pr_debug("tbatr0=%x tbatr1=%x tcr=%x gscr=%x\n",
+-	         in_be32(&pci_regs->tbatr0), in_be32(&pci_regs->tbatr1),
+-	         in_be32(&pci_regs->tcr), in_be32(&pci_regs->gscr));
+-}
+-
+-static void
+-mpc52xx_pci_fixup_resources(struct pci_dev *dev)
+-{
+-	int i;
+-
+-	pr_debug("mpc52xx_pci_fixup_resources() %.4x:%.4x\n",
+-	         dev->vendor, dev->device);
+-
+-	/* We don't rely on boot loader for PCI and resets all
+-	   devices */
+-	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+-		struct resource *res = &dev->resource[i];
+-		if (res->end > res->start) {	/* Only valid resources */
+-			res->end -= res->start;
+-			res->start = 0;
+-			res->flags |= IORESOURCE_UNSET;
+-		}
+-	}
+-
+-	/* The PCI Host bridge of MPC52xx has a prefetch memory resource
+-	   fixed to 1Gb. Doesn't fit in the resource system so we remove it */
+-	if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
+-	     (   dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200
+-	      || dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) {
+-		struct resource *res = &dev->resource[1];
+-		res->start = res->end = res->flags = 0;
+-	}
+-}
+-
+-int __init
+-mpc52xx_add_bridge(struct device_node *node)
+-{
+-	int len;
+-	struct mpc52xx_pci __iomem *pci_regs;
+-	struct pci_controller *hose;
+-	const int *bus_range;
+-	struct resource rsrc;
+-
+-	pr_debug("Adding PCI host bridge %s\n", node->full_name);
+-
+-	pci_assign_all_buses = 1;
+-
+-	if (of_address_to_resource(node, 0, &rsrc) != 0) {
+-		printk(KERN_ERR "Can't get %s resources\n", node->full_name);
+-		return -EINVAL;
+-	}
+-
+-	bus_range = get_property(node, "bus-range", &len);
+-	if (bus_range == NULL || len < 2 * sizeof(int)) {
+-		printk(KERN_WARNING "Can't get bus-range for %s, assume"
+-		        " bus 0\n", node->full_name);
+-	}
+-
+-	hose = pcibios_alloc_controller();
+-	if (!hose)
+-		return -ENOMEM;
+-
+-	ppc_md.pcibios_fixup_resources = mpc52xx_pci_fixup_resources;
+-
+-	hose->arch_data = node;
+-	hose->set_cfg_type = 1;
+-
+-	hose->first_busno = bus_range ? bus_range[0] : 0;
+-	hose->last_busno = bus_range ? bus_range[1] : 0xff;
+-
+-	hose->bus_offset = 0;
+-	hose->ops = &mpc52xx_pci_ops;
+-
+-	pci_regs = ioremap(rsrc.start, rsrc.end - rsrc.start + 1);
+-	if (!pci_regs)
+-		return -ENOMEM;
+-
+-	pci_process_bridge_OF_ranges(hose, node, 0);
+-
+-	hose->cfg_addr = &pci_regs->car;
+-
+-	hose->cfg_data = hose->io_base_virt;
+-	hose->io_base_virt = ioremap(hose->io_base_phys,
+-	                             hose->io_resource.end + 1 -
+-	                             hose->io_resource.start);
+-	isa_io_base = (unsigned long) hose->io_base_virt;
+-
+-	mpc52xx_pci_setup(hose, pci_regs);
+-
+-	return 0;
+-}
+diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.h b/arch/powerpc/platforms/52xx/mpc52xx_pci.h
+deleted file mode 100644
+index 07a659e..0000000
+--- a/arch/powerpc/platforms/52xx/mpc52xx_pci.h
++++ /dev/null
+@@ -1,104 +0,0 @@
+-/*
+- * PCI Include file the Freescale MPC52xx embedded cpu chips
+- *
+- * Inspired from code written by Dale Farnsworth <dfarnsworth at mvista.com>
+- * for the 2.4 kernel.
+- *
+- * Copyright (C) 2004 Sylvain Munaut <tnt at 246tNt.com>
+- * Copyright (C) 2003 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 __SYSLIB_MPC52xx_PCI_H__
+-#define __SYSLIB_MPC52xx_PCI_H__
+-
+-/* ======================================================================== */
+-/* PCI windows config                                                       */
+-/* ======================================================================== */
+-
+-#define MPC52xx_PCI_TARGET_IO	0xf0000000
+-#define MPC52xx_PCI_TARGET_MEM	0x00000000
+-
+-
+-/* ======================================================================== */
+-/* Structures mapping & Defines for PCI Unit                                */
+-/* ======================================================================== */
+-
+-#define MPC52xx_PCI_GSCR_BM		0x40000000
+-#define MPC52xx_PCI_GSCR_PE		0x20000000
+-#define MPC52xx_PCI_GSCR_SE		0x10000000
+-#define MPC52xx_PCI_GSCR_XLB2PCI_MASK	0x07000000
+-#define MPC52xx_PCI_GSCR_XLB2PCI_SHIFT	24
+-#define MPC52xx_PCI_GSCR_IPG2PCI_MASK	0x00070000
+-#define MPC52xx_PCI_GSCR_IPG2PCI_SHIFT	16
+-#define MPC52xx_PCI_GSCR_BME		0x00004000
+-#define MPC52xx_PCI_GSCR_PEE		0x00002000
+-#define MPC52xx_PCI_GSCR_SEE		0x00001000
+-#define MPC52xx_PCI_GSCR_PR		0x00000001
+-
+-
+-#define MPC52xx_PCI_IWBTAR_TRANSLATION(proc_ad,pci_ad,size)	  \
+-		( ( (proc_ad) & 0xff000000 )			| \
+-		  ( (((size) - 1) >> 8) & 0x00ff0000 )		| \
+-		  ( ((pci_ad) >> 16) & 0x0000ff00 ) )
+-
+-#define MPC52xx_PCI_IWCR_PACK(win0,win1,win2)	(((win0) << 24) | \
+-						 ((win1) << 16) | \
+-						 ((win2) <<  8))
+-
+-#define MPC52xx_PCI_IWCR_DISABLE	0x0
+-#define MPC52xx_PCI_IWCR_ENABLE		0x1
+-#define MPC52xx_PCI_IWCR_READ		0x0
+-#define MPC52xx_PCI_IWCR_READ_LINE	0x2
+-#define MPC52xx_PCI_IWCR_READ_MULTI	0x4
+-#define MPC52xx_PCI_IWCR_MEM		0x0
+-#define MPC52xx_PCI_IWCR_IO		0x8
+-
+-#define MPC52xx_PCI_TCR_P		0x01000000
+-#define MPC52xx_PCI_TCR_LD		0x00010000
+-
+-#define MPC52xx_PCI_TBATR_DISABLE	0x0
+-#define MPC52xx_PCI_TBATR_ENABLE	0x1
+-
+-
+-#ifndef __ASSEMBLY__
+-
+-struct mpc52xx_pci {
+-	u32	idr;		/* PCI + 0x00 */
+-	u32	scr;		/* PCI + 0x04 */
+-	u32	ccrir;		/* PCI + 0x08 */
+-	u32	cr1;		/* PCI + 0x0C */
+-	u32	bar0;		/* PCI + 0x10 */
+-	u32	bar1;		/* PCI + 0x14 */
+-	u8	reserved1[16];	/* PCI + 0x18 */
+-	u32	ccpr;		/* PCI + 0x28 */
+-	u32	sid;		/* PCI + 0x2C */
+-	u32	erbar;		/* PCI + 0x30 */
+-	u32	cpr;		/* PCI + 0x34 */
+-	u8	reserved2[4];	/* PCI + 0x38 */
+-	u32	cr2;		/* PCI + 0x3C */
+-	u8	reserved3[32];	/* PCI + 0x40 */
+-	u32	gscr;		/* PCI + 0x60 */
+-	u32	tbatr0;		/* PCI + 0x64 */
+-	u32	tbatr1;		/* PCI + 0x68 */
+-	u32	tcr;		/* PCI + 0x6C */
+-	u32	iw0btar;	/* PCI + 0x70 */
+-	u32	iw1btar;	/* PCI + 0x74 */
+-	u32	iw2btar;	/* PCI + 0x78 */
+-	u8	reserved4[4];	/* PCI + 0x7C */
+-	u32	iwcr;		/* PCI + 0x80 */
+-	u32	icr;		/* PCI + 0x84 */
+-	u32	isr;		/* PCI + 0x88 */
+-	u32	arb;		/* PCI + 0x8C */
+-	u8	reserved5[104];	/* PCI + 0x90 */
+-	u32	car;		/* PCI + 0xF8 */
+-	u8	reserved6[4];	/* PCI + 0xFC */
+-};
+-
+-#endif  /* __ASSEMBLY__ */
+-
+-
+-#endif  /* __SYSLIB_MPC52xx_PCI_H__ */
+diff --git a/arch/powerpc/platforms/52xx/pci.c b/arch/powerpc/platforms/52xx/pci.c
+new file mode 100644
+index 0000000..14940af
+--- /dev/null
++++ b/arch/powerpc/platforms/52xx/pci.c
+@@ -0,0 +1,404 @@
++/*
++ * PCI code for the Freescale MPC52xx embedded CPU.
++ *
++ * Copyright (C) 2004 Secret Lab Technologies Ltd.
++ *                        Grant Likely <grant.likely at secretlab.ca>
++ * Copyright (C) 2004 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.
++ */
++
++#undef DEBUG
++
++#include <asm/pci.h>
++#include <asm/mpc52xx.h>
++#include <asm/delay.h>
++#include <asm/machdep.h>
++#include <linux/kernel.h>
++
++
++/* ======================================================================== */
++/* PCI windows config                                                       */
++/* ======================================================================== */
++
++#define MPC52xx_PCI_TARGET_IO	0xf0000000
++#define MPC52xx_PCI_TARGET_MEM	0x00000000
++
++/* ======================================================================== */
++/* Structures mapping & Defines for PCI Unit                                */
++/* ======================================================================== */
++
++#define MPC52xx_PCI_GSCR_BM		0x40000000
++#define MPC52xx_PCI_GSCR_PE		0x20000000
++#define MPC52xx_PCI_GSCR_SE		0x10000000
++#define MPC52xx_PCI_GSCR_XLB2PCI_MASK	0x07000000
++#define MPC52xx_PCI_GSCR_XLB2PCI_SHIFT	24
++#define MPC52xx_PCI_GSCR_IPG2PCI_MASK	0x00070000
++#define MPC52xx_PCI_GSCR_IPG2PCI_SHIFT	16
++#define MPC52xx_PCI_GSCR_BME		0x00004000
++#define MPC52xx_PCI_GSCR_PEE		0x00002000
++#define MPC52xx_PCI_GSCR_SEE		0x00001000
++#define MPC52xx_PCI_GSCR_PR		0x00000001
++
++
++#define MPC52xx_PCI_IWBTAR_TRANSLATION(proc_ad,pci_ad,size)	  \
++		( ( (proc_ad) & 0xff000000 )			| \
++		  ( (((size) - 1) >> 8) & 0x00ff0000 )		| \
++		  ( ((pci_ad) >> 16) & 0x0000ff00 ) )
++
++#define MPC52xx_PCI_IWCR_PACK(win0,win1,win2)	(((win0) << 24) | \
++						 ((win1) << 16) | \
++						 ((win2) <<  8))
++
++#define MPC52xx_PCI_IWCR_DISABLE	0x0
++#define MPC52xx_PCI_IWCR_ENABLE		0x1
++#define MPC52xx_PCI_IWCR_READ		0x0
++#define MPC52xx_PCI_IWCR_READ_LINE	0x2
++#define MPC52xx_PCI_IWCR_READ_MULTI	0x4
++#define MPC52xx_PCI_IWCR_MEM		0x0
++#define MPC52xx_PCI_IWCR_IO		0x8
++
++#define MPC52xx_PCI_TCR_P		0x01000000
++#define MPC52xx_PCI_TCR_LD		0x00010000
++
++#define MPC52xx_PCI_TBATR_DISABLE	0x0
++#define MPC52xx_PCI_TBATR_ENABLE	0x1
++
++struct mpc52xx_pci {
++	u32	idr;		/* PCI + 0x00 */
++	u32	scr;		/* PCI + 0x04 */
++	u32	ccrir;		/* PCI + 0x08 */
++	u32	cr1;		/* PCI + 0x0C */
++	u32	bar0;		/* PCI + 0x10 */
++	u32	bar1;		/* PCI + 0x14 */
++	u8	reserved1[16];	/* PCI + 0x18 */
++	u32	ccpr;		/* PCI + 0x28 */
++	u32	sid;		/* PCI + 0x2C */
++	u32	erbar;		/* PCI + 0x30 */
++	u32	cpr;		/* PCI + 0x34 */
++	u8	reserved2[4];	/* PCI + 0x38 */
++	u32	cr2;		/* PCI + 0x3C */
++	u8	reserved3[32];	/* PCI + 0x40 */
++	u32	gscr;		/* PCI + 0x60 */
++	u32	tbatr0;		/* PCI + 0x64 */
++	u32	tbatr1;		/* PCI + 0x68 */
++	u32	tcr;		/* PCI + 0x6C */
++	u32	iw0btar;	/* PCI + 0x70 */
++	u32	iw1btar;	/* PCI + 0x74 */
++	u32	iw2btar;	/* PCI + 0x78 */
++	u8	reserved4[4];	/* PCI + 0x7C */
++	u32	iwcr;		/* PCI + 0x80 */
++	u32	icr;		/* PCI + 0x84 */
++	u32	isr;		/* PCI + 0x88 */
++	u32	arb;		/* PCI + 0x8C */
++	u8	reserved5[104];	/* PCI + 0x90 */
++	u32	car;		/* PCI + 0xF8 */
++	u8	reserved6[4];	/* PCI + 0xFC */
++};
++
++static int
++mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
++				int offset, int len, u32 *val)
++{
++	struct pci_controller *hose = bus->sysdata;
++	u32 value;
++
++	if (ppc_md.pci_exclude_device)
++		if (ppc_md.pci_exclude_device(bus->number, devfn))
++			return PCIBIOS_DEVICE_NOT_FOUND;
++
++	out_be32(hose->cfg_addr,
++		(1 << 31) |
++		((bus->number - hose->bus_offset) << 16) |
++		(devfn << 8) |
++		(offset & 0xfc));
++	mb();
++
++#if defined(CONFIG_PPC_MPC5200_BUGFIX)
++	if (bus->number != hose->bus_offset) {
++		/* workaround for the bug 435 of the MPC5200 (L25R);
++		 * Don't do 32 bits config access during type-1 cycles */
++		switch (len) {
++		      case 1:
++			value = in_8(((u8 __iomem *)hose->cfg_data) +
++			             (offset & 3));
++			break;
++		      case 2:
++			value = in_le16(((u16 __iomem *)hose->cfg_data) +
++			                ((offset>>1) & 1));
++			break;
++
++		      default:
++			value = in_le16((u16 __iomem *)hose->cfg_data) |
++				(in_le16(((u16 __iomem *)hose->cfg_data) + 1) << 16);
++			break;
++		}
++	}
++	else
++#endif
++	{
++		value = in_le32(hose->cfg_data);
++
++		if (len != 4) {
++			value >>= ((offset & 0x3) << 3);
++			value &= 0xffffffff >> (32 - (len << 3));
++		}
++	}
++
++	*val = value;
++
++	out_be32(hose->cfg_addr, 0);
++	mb();
++
++	return PCIBIOS_SUCCESSFUL;
++}
++
++static int
++mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
++				int offset, int len, u32 val)
++{
++	struct pci_controller *hose = bus->sysdata;
++	u32 value, mask;
++
++	if (ppc_md.pci_exclude_device)
++		if (ppc_md.pci_exclude_device(bus->number, devfn))
++			return PCIBIOS_DEVICE_NOT_FOUND;
++
++	out_be32(hose->cfg_addr,
++		(1 << 31) |
++		((bus->number - hose->bus_offset) << 16) |
++		(devfn << 8) |
++		(offset & 0xfc));
++	mb();
++
++#if defined(CONFIG_PPC_MPC5200_BUGFIX)
++	if (bus->number != hose->bus_offset) {
++		/* workaround for the bug 435 of the MPC5200 (L25R);
++		 * Don't do 32 bits config access during type-1 cycles */
++		switch (len) {
++		      case 1:
++			out_8(((u8 __iomem *)hose->cfg_data) +
++				(offset & 3), val);
++			break;
++		      case 2:
++			out_le16(((u16 __iomem *)hose->cfg_data) +
++				((offset>>1) & 1), val);
++			break;
++
++		      default:
++			out_le16((u16 __iomem *)hose->cfg_data,
++				(u16)val);
++			out_le16(((u16 __iomem *)hose->cfg_data) + 1,
++				(u16)(val>>16));
++			break;
++		}
++	}
++	else
++#endif
++	{
++		if (len != 4) {
++			value = in_le32(hose->cfg_data);
++
++			offset = (offset & 0x3) << 3;
++			mask = (0xffffffff >> (32 - (len << 3)));
++			mask <<= offset;
++
++			value &= ~mask;
++			val = value | ((val << offset) & mask);
++		}
++
++		out_le32(hose->cfg_data, val);
++	}
++	mb();
++
++	out_be32(hose->cfg_addr, 0);
++	mb();
++
++	return PCIBIOS_SUCCESSFUL;
++}
++
++static struct pci_ops mpc52xx_pci_ops = {
++	.read  = mpc52xx_pci_read_config,
++	.write = mpc52xx_pci_write_config
++};
++
++
++static void __init
++mpc52xx_pci_setup(struct pci_controller *hose,
++                  struct mpc52xx_pci __iomem *pci_regs)
++{
++	struct resource *res;
++	u32 tmp;
++	int iwcr0 = 0, iwcr1 = 0, iwcr2 = 0;
++
++	pr_debug("mpc52xx_pci_setup(hose=%p, pci_regs=%p)\n", hose, pci_regs);
++
++	/* pci_process_bridge_OF_ranges() found all our addresses for us;
++	 * now store them in the right places */
++	hose->cfg_addr = &pci_regs->car;
++	hose->cfg_data = hose->io_base_virt;
++	hose->io_base_virt = ioremap(hose->io_base_phys,
++	                             hose->io_resource.end + 1 -
++	                             hose->io_resource.start);
++	isa_io_base = (unsigned long) hose->io_base_virt;
++
++	/* Control regs */
++	tmp = in_be32(&pci_regs->scr);
++	tmp |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
++	out_be32(&pci_regs->scr, tmp);
++
++	/* Memory windows */
++	res = &hose->mem_resources[0];
++	if (res->flags) {
++		pr_debug("mem_resource[0] = {.start=%x, .end=%x, .flags=%lx}\n",
++		         res->start, res->end, res->flags);
++		out_be32(&pci_regs->iw0btar,
++		         MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start,
++		                  res->end - res->start + 1));
++		iwcr0 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM;
++		if (res->flags & IORESOURCE_PREFETCH)
++			iwcr0 |= MPC52xx_PCI_IWCR_READ_MULTI;
++		else
++			iwcr0 |= MPC52xx_PCI_IWCR_READ;
++	}
++
++	res = &hose->mem_resources[1];
++	if (res->flags) {
++		pr_debug("mem_resource[1] = {.start=%x, .end=%x, .flags=%lx}\n",
++		         res->start, res->end, res->flags);
++		out_be32(&pci_regs->iw1btar,
++		         MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start,
++		                  res->end - res->start + 1));
++		iwcr1 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM;
++		if (res->flags & IORESOURCE_PREFETCH)
++			iwcr1 |= MPC52xx_PCI_IWCR_READ_MULTI;
++		else
++			iwcr1 |= MPC52xx_PCI_IWCR_READ;
++	}
++
++	/* IO resources */
++	res = &hose->io_resource;
++	if (!res) {
++		printk(KERN_ERR "%s: Didn't find IO resources\n", __FILE__);
++		return;
++	}
++	pr_debug(".io_resource={.start=%x,.end=%x,.flags=%lx} "
++	         ".io_base_phys=%lx\n",
++	         res->start, res->end, res->flags, hose->io_base_phys);
++	out_be32(&pci_regs->iw2btar,
++	         MPC52xx_PCI_IWBTAR_TRANSLATION(hose->io_base_phys,
++	                                        res->start,
++	                                        res->end - res->start + 1));
++	iwcr2 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_IO;
++
++	/* Set all the IWCR fields at once; they're in the same reg */
++	out_be32(&pci_regs->iwcr, MPC52xx_PCI_IWCR_PACK(iwcr0, iwcr1, iwcr2));
++
++	out_be32(&pci_regs->tbatr0,
++		MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_IO );
++	out_be32(&pci_regs->tbatr1,
++		MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_MEM );
++
++	out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD);
++
++#if 0
++	/* Reset the exteral bus ( internal PCI controller is NOT resetted ) */
++	/* Not necessary and can be a bad thing if for example the bootloader
++	   is displaying a splash screen or ... Just left here for
++	   documentation purpose if anyone need it */
++	tmp = in_be32(&pci_regs->gscr);
++	out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR);
++	udelay(50);
++	out_be32(&pci_regs->gscr, tmp & ~MPC52xx_PCI_GSCR_PR);
++#endif
++}
++
++static void
++mpc52xx_pci_fixup_resources(struct pci_dev *dev)
++{
++	int i;
++
++	pr_debug("mpc52xx_pci_fixup_resources() %.4x:%.4x\n",
++	         dev->vendor, dev->device);
++
++	/* We don't rely on boot loader for PCI and resets all
++	   devices */
++	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
++		struct resource *res = &dev->resource[i];
++		if (res->end > res->start) {	/* Only valid resources */
++			res->end -= res->start;
++			res->start = 0;
++			res->flags |= IORESOURCE_UNSET;
++		}
++	}
++
++	/* The PCI Host bridge of MPC52xx has a prefetch memory resource
++	   fixed to 1Gb. Doesn't fit in the resource system so we remove it */
++	if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
++	     (   dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200
++	      || dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) {
++		struct resource *res = &dev->resource[1];
++		res->start = res->end = res->flags = 0;
++	}
++}
++
++int __init
++mpc52xx_add_bridge(struct device_node *node)
++{
++	int len;
++	struct mpc52xx_pci __iomem *pci_regs;
++	struct pci_controller *hose;
++	const int *bus_range;
++	struct resource rsrc;
++
++	pr_debug("Adding MPC52xx PCI host bridge %s\n", node->full_name);
++
++	pci_assign_all_buses = 1;
++
++	if (of_address_to_resource(node, 0, &rsrc) != 0) {
++		printk(KERN_ERR "Can't get %s resources\n", node->full_name);
++		return -EINVAL;
++	}
++
++	bus_range = get_property(node, "bus-range", &len);
++	if (bus_range == NULL || len < 2 * sizeof(int)) {
++		printk(KERN_WARNING "Can't get %s bus-range, assume bus 0\n",
++		       node->full_name);
++		bus_range = NULL;
++	}
++
++	/* There are some PCI quirks on the 52xx, register the hook to
++	 * fix them. */
++	ppc_md.pcibios_fixup_resources = mpc52xx_pci_fixup_resources;
++
++	/* Alloc and initialize the pci controller.  Values in the device
++	 * tree are needed to configure the 52xx PCI controller.  Rather
++	 * than parse the tree here, let pci_process_bridge_OF_ranges()
++	 * do it for us and extract the values after the fact */
++	hose = pcibios_alloc_controller();
++	if (!hose)
++		return -ENOMEM;
++
++	hose->arch_data = node;
++	hose->set_cfg_type = 1;
++
++	hose->first_busno = bus_range ? bus_range[0] : 0;
++	hose->last_busno = bus_range ? bus_range[1] : 0xff;
++
++	hose->bus_offset = 0;
++	hose->ops = &mpc52xx_pci_ops;
++
++	pci_regs = ioremap(rsrc.start, rsrc.end - rsrc.start + 1);
++	if (!pci_regs)
++		return -ENOMEM;
++
++	pci_process_bridge_OF_ranges(hose, node, 0);
++
++	/* Finish setting up PCI using values obtained by
++	 * pci_proces_bridge_OF_ranges */
++	mpc52xx_pci_setup(hose, pci_regs);
++
++	return 0;
++}
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0027-POWERPC-Change-name-of-mpc52xx-pci-support-file-in-Makefile.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0027-POWERPC-Change-name-of-mpc52xx-pci-support-file-in-Makefile.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,28 @@
+From 5145742e15b45e96c623f571dee421306dc95a3e Mon Sep 17 00:00:00 2001
+From: Grant Likely <grant.likely at secretlab.ca>
+Date: Mon, 11 Dec 2006 22:45:39 -0700
+Subject: [PATCH] [POWERPC] Change name of mpc52xx pci support file in Makefile
+
+Oops, missed a bit in the previous patch
+
+Signed-off-by: Grant Likely <grant.likely at secretlab.ca>
+---
+ arch/powerpc/platforms/52xx/Makefile |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/arch/powerpc/platforms/52xx/Makefile b/arch/powerpc/platforms/52xx/Makefile
+index d85ea04..a7c646a 100644
+--- a/arch/powerpc/platforms/52xx/Makefile
++++ b/arch/powerpc/platforms/52xx/Makefile
+@@ -3,7 +3,7 @@
+ #
+ ifeq ($(CONFIG_PPC_MERGE),y)
+ obj-y				+= mpc52xx_pic.o mpc52xx_common.o
+-obj-$(CONFIG_PCI)		+= mpc52xx_pci.o
++obj-$(CONFIG_PCI)		+= pci.o
+ obj-$(CONFIG_PPC_BESTCOMM) 	+= bestcomm.o
+ obj-$(CONFIG_FEC_MPC52xx)	+= sdma_fec_rx_task.o sdma_fec_tx_task.o fec.o
+ endif
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0028-POWERPC-Change-link-order-so-mpc52xx-fec-always-shows-up-as-eth0.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0028-POWERPC-Change-link-order-so-mpc52xx-fec-always-shows-up-as-eth0.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,47 @@
+From 2086d309f8b8de0b41119596d43f2a7bfe028a89 Mon Sep 17 00:00:00 2001
+From: Grant Likely <grant.likely at secretlab.ca>
+Date: Mon, 11 Dec 2006 22:46:59 -0700
+Subject: [PATCH] [POWERPC] Change link order so mpc52xx-fec always shows up as eth0
+
+Signed-off-by: Grant Likely <grant.likely at secretlab.ca>
+---
+ drivers/net/Makefile          |    2 +-
+ drivers/net/fec_mpc52xx/fec.c |    2 ++
+ 2 files changed, 3 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/net/Makefile b/drivers/net/Makefile
+index e6f903d..95f0963 100644
+--- a/drivers/net/Makefile
++++ b/drivers/net/Makefile
+@@ -24,6 +24,7 @@ ucc_geth_driver-objs := ucc_geth.o ucc_geth_phy.o
+ obj-$(CONFIG_PLIP) += plip.o
+ 
+ obj-$(CONFIG_ROADRUNNER) += rrunner.o
++obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx/
+ 
+ obj-$(CONFIG_HAPPYMEAL) += sunhme.o
+ obj-$(CONFIG_SUNLANCE) += sunlance.o
+@@ -196,7 +197,6 @@ 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_MACB) += macb.o
+ 
+diff --git a/drivers/net/fec_mpc52xx/fec.c b/drivers/net/fec_mpc52xx/fec.c
+index 894da79..30cef2b 100644
+--- a/drivers/net/fec_mpc52xx/fec.c
++++ b/drivers/net/fec_mpc52xx/fec.c
+@@ -731,6 +731,8 @@ mpc52xx_fec_probe(struct device *dev)
+ 	fec_mii_init(ndev);
+ 	
+ 	/* We're done ! */
++	printk(KERN_INFO "%s: mpc52xx-fec at %#lx,",
++	       ndev->name, (long)mem->start);
+ #if defined(CONFIG_PPC_MERGE)
+ 	dev_set_drvdata(&op->dev, ndev);
+ #else
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0029-POWERPC-Fixup-pr_print-format-for-mpc52xx-pci-support.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0029-POWERPC-Fixup-pr_print-format-for-mpc52xx-pci-support.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,28 @@
+From 08bb999d4f8b866a570775db5788cd84edafd3f5 Mon Sep 17 00:00:00 2001
+From: Grant Likely <grant.likely at secretlab.ca>
+Date: Mon, 11 Dec 2006 23:00:24 -0700
+Subject: [PATCH] [POWERPC] Fixup pr_print format for mpc52xx pci support
+
+Signed-off-by: Grant Likely <grant.likely at secretlab.ca>
+---
+ arch/powerpc/platforms/52xx/pci.c |    4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/powerpc/platforms/52xx/pci.c b/arch/powerpc/platforms/52xx/pci.c
+index 14940af..b732fdc 100644
+--- a/arch/powerpc/platforms/52xx/pci.c
++++ b/arch/powerpc/platforms/52xx/pci.c
+@@ -285,8 +285,8 @@ mpc52xx_pci_setup(struct pci_controller *hose,
+ 		return;
+ 	}
+ 	pr_debug(".io_resource={.start=%x,.end=%x,.flags=%lx} "
+-	         ".io_base_phys=%lx\n",
+-	         res->start, res->end, res->flags, hose->io_base_phys);
++	         ".io_base_phys=0x%p\n",
++	         res->start, res->end, res->flags, (void*)hose->io_base_phys);
+ 	out_be32(&pci_regs->iw2btar,
+ 	         MPC52xx_PCI_IWBTAR_TRANSLATION(hose->io_base_phys,
+ 	                                        res->start,
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0030-POWERPC-Add-mpc52xx-lite5200-PCI-support.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0030-POWERPC-Add-mpc52xx-lite5200-PCI-support.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,871 @@
+From 56aad819c662c854466a8c454c948e79dd2f0777 Mon Sep 17 00:00:00 2001
+From: Grant Likely <grant.likely at secretlab.ca>
+Date: Mon, 11 Dec 2006 23:23:40 -0700
+Subject: [PATCH] [POWERPC] Add mpc52xx/lite5200 PCI support
+
+Signed-off-by: Grant Likely <grant.likely at secretlab.ca>
+---
+ arch/powerpc/platforms/52xx/Makefile      |    2 +-
+ arch/powerpc/platforms/52xx/lite5200.c    |    3 -
+ arch/powerpc/platforms/52xx/mpc52xx_pci.c |  412 +++++++++++++++++++++++++++++
+ arch/powerpc/platforms/52xx/pci.c         |  404 ----------------------------
+ 4 files changed, 413 insertions(+), 408 deletions(-)
+
+diff --git a/arch/powerpc/platforms/52xx/Makefile b/arch/powerpc/platforms/52xx/Makefile
+index a7c646a..d85ea04 100644
+--- a/arch/powerpc/platforms/52xx/Makefile
++++ b/arch/powerpc/platforms/52xx/Makefile
+@@ -3,7 +3,7 @@
+ #
+ ifeq ($(CONFIG_PPC_MERGE),y)
+ obj-y				+= mpc52xx_pic.o mpc52xx_common.o
+-obj-$(CONFIG_PCI)		+= pci.o
++obj-$(CONFIG_PCI)		+= mpc52xx_pci.o
+ obj-$(CONFIG_PPC_BESTCOMM) 	+= bestcomm.o
+ obj-$(CONFIG_FEC_MPC52xx)	+= sdma_fec_rx_task.o sdma_fec_tx_task.o fec.o
+ endif
+diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c
+index f1bbe24..cdb16bf 100644
+--- a/arch/powerpc/platforms/52xx/lite5200.c
++++ b/arch/powerpc/platforms/52xx/lite5200.c
+@@ -111,9 +111,6 @@ static void __init lite52xx_setup_arch(void)
+ 	np = of_find_node_by_type(np, "pci");
+ 	if (np)
+ 		mpc52xx_add_bridge(np);
+-
+-	//ppc_md.pci_swizzle = common_swizzle;
+-	//ppc_md.pci_exclude_device = mpc52xx_exclude_device;
+ #endif
+ 
+ #ifdef CONFIG_BLK_DEV_INITRD
+diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
+new file mode 100644
+index 0000000..faf161b
+--- /dev/null
++++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
+@@ -0,0 +1,412 @@
++/*
++ * PCI code for the Freescale MPC52xx embedded CPU.
++ *
++ * Copyright (C) 2006 Secret Lab Technologies Ltd.
++ *                        Grant Likely <grant.likely at secretlab.ca>
++ * Copyright (C) 2004 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.
++ */
++
++#undef DEBUG
++
++#include <asm/pci.h>
++#include <asm/mpc52xx.h>
++#include <asm/delay.h>
++#include <asm/machdep.h>
++#include <linux/kernel.h>
++
++
++/* ======================================================================== */
++/* PCI windows config                                                       */
++/* ======================================================================== */
++
++#define MPC52xx_PCI_TARGET_IO	0xf0000000
++#define MPC52xx_PCI_TARGET_MEM	0x00000000
++
++
++/* ======================================================================== */
++/* Structures mapping & Defines for PCI Unit                                */
++/* ======================================================================== */
++
++#define MPC52xx_PCI_GSCR_BM		0x40000000
++#define MPC52xx_PCI_GSCR_PE		0x20000000
++#define MPC52xx_PCI_GSCR_SE		0x10000000
++#define MPC52xx_PCI_GSCR_XLB2PCI_MASK	0x07000000
++#define MPC52xx_PCI_GSCR_XLB2PCI_SHIFT	24
++#define MPC52xx_PCI_GSCR_IPG2PCI_MASK	0x00070000
++#define MPC52xx_PCI_GSCR_IPG2PCI_SHIFT	16
++#define MPC52xx_PCI_GSCR_BME		0x00004000
++#define MPC52xx_PCI_GSCR_PEE		0x00002000
++#define MPC52xx_PCI_GSCR_SEE		0x00001000
++#define MPC52xx_PCI_GSCR_PR		0x00000001
++
++
++#define MPC52xx_PCI_IWBTAR_TRANSLATION(proc_ad,pci_ad,size)	  \
++		( ( (proc_ad) & 0xff000000 )			| \
++		  ( (((size) - 1) >> 8) & 0x00ff0000 )		| \
++		  ( ((pci_ad) >> 16) & 0x0000ff00 ) )
++
++#define MPC52xx_PCI_IWCR_PACK(win0,win1,win2)	(((win0) << 24) | \
++						 ((win1) << 16) | \
++						 ((win2) <<  8))
++
++#define MPC52xx_PCI_IWCR_DISABLE	0x0
++#define MPC52xx_PCI_IWCR_ENABLE		0x1
++#define MPC52xx_PCI_IWCR_READ		0x0
++#define MPC52xx_PCI_IWCR_READ_LINE	0x2
++#define MPC52xx_PCI_IWCR_READ_MULTI	0x4
++#define MPC52xx_PCI_IWCR_MEM		0x0
++#define MPC52xx_PCI_IWCR_IO		0x8
++
++#define MPC52xx_PCI_TCR_P		0x01000000
++#define MPC52xx_PCI_TCR_LD		0x00010000
++
++#define MPC52xx_PCI_TBATR_DISABLE	0x0
++#define MPC52xx_PCI_TBATR_ENABLE	0x1
++
++struct mpc52xx_pci {
++	u32	idr;		/* PCI + 0x00 */
++	u32	scr;		/* PCI + 0x04 */
++	u32	ccrir;		/* PCI + 0x08 */
++	u32	cr1;		/* PCI + 0x0C */
++	u32	bar0;		/* PCI + 0x10 */
++	u32	bar1;		/* PCI + 0x14 */
++	u8	reserved1[16];	/* PCI + 0x18 */
++	u32	ccpr;		/* PCI + 0x28 */
++	u32	sid;		/* PCI + 0x2C */
++	u32	erbar;		/* PCI + 0x30 */
++	u32	cpr;		/* PCI + 0x34 */
++	u8	reserved2[4];	/* PCI + 0x38 */
++	u32	cr2;		/* PCI + 0x3C */
++	u8	reserved3[32];	/* PCI + 0x40 */
++	u32	gscr;		/* PCI + 0x60 */
++	u32	tbatr0;		/* PCI + 0x64 */
++	u32	tbatr1;		/* PCI + 0x68 */
++	u32	tcr;		/* PCI + 0x6C */
++	u32	iw0btar;	/* PCI + 0x70 */
++	u32	iw1btar;	/* PCI + 0x74 */
++	u32	iw2btar;	/* PCI + 0x78 */
++	u8	reserved4[4];	/* PCI + 0x7C */
++	u32	iwcr;		/* PCI + 0x80 */
++	u32	icr;		/* PCI + 0x84 */
++	u32	isr;		/* PCI + 0x88 */
++	u32	arb;		/* PCI + 0x8C */
++	u8	reserved5[104];	/* PCI + 0x90 */
++	u32	car;		/* PCI + 0xF8 */
++	u8	reserved6[4];	/* PCI + 0xFC */
++};
++
++
++/* ======================================================================== */
++/* PCI configuration acess                                                  */
++/* ======================================================================== */
++
++static int
++mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
++				int offset, int len, u32 *val)
++{
++	struct pci_controller *hose = bus->sysdata;
++	u32 value;
++
++	if (ppc_md.pci_exclude_device)
++		if (ppc_md.pci_exclude_device(bus->number, devfn))
++			return PCIBIOS_DEVICE_NOT_FOUND;
++
++	out_be32(hose->cfg_addr,
++		(1 << 31) |
++		((bus->number - hose->bus_offset) << 16) |
++		(devfn << 8) |
++		(offset & 0xfc));
++	mb();
++
++#if defined(CONFIG_PPC_MPC5200_BUGFIX)
++	if (bus->number != hose->bus_offset) {
++		/* workaround for the bug 435 of the MPC5200 (L25R);
++		 * Don't do 32 bits config access during type-1 cycles */
++		switch (len) {
++		      case 1:
++			value = in_8(((u8 __iomem *)hose->cfg_data) +
++			             (offset & 3));
++			break;
++		      case 2:
++			value = in_le16(((u16 __iomem *)hose->cfg_data) +
++			                ((offset>>1) & 1));
++			break;
++
++		      default:
++			value = in_le16((u16 __iomem *)hose->cfg_data) |
++				(in_le16(((u16 __iomem *)hose->cfg_data) + 1) << 16);
++			break;
++		}
++	}
++	else
++#endif
++	{
++		value = in_le32(hose->cfg_data);
++
++		if (len != 4) {
++			value >>= ((offset & 0x3) << 3);
++			value &= 0xffffffff >> (32 - (len << 3));
++		}
++	}
++
++	*val = value;
++
++	out_be32(hose->cfg_addr, 0);
++	mb();
++
++	return PCIBIOS_SUCCESSFUL;
++}
++
++static int
++mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
++				int offset, int len, u32 val)
++{
++	struct pci_controller *hose = bus->sysdata;
++	u32 value, mask;
++
++	if (ppc_md.pci_exclude_device)
++		if (ppc_md.pci_exclude_device(bus->number, devfn))
++			return PCIBIOS_DEVICE_NOT_FOUND;
++
++	out_be32(hose->cfg_addr,
++		(1 << 31) |
++		((bus->number - hose->bus_offset) << 16) |
++		(devfn << 8) |
++		(offset & 0xfc));
++	mb();
++
++#if defined(CONFIG_PPC_MPC5200_BUGFIX)
++	if (bus->number != hose->bus_offset) {
++		/* workaround for the bug 435 of the MPC5200 (L25R);
++		 * Don't do 32 bits config access during type-1 cycles */
++		switch (len) {
++		      case 1:
++			out_8(((u8 __iomem *)hose->cfg_data) +
++				(offset & 3), val);
++			break;
++		      case 2:
++			out_le16(((u16 __iomem *)hose->cfg_data) +
++				((offset>>1) & 1), val);
++			break;
++
++		      default:
++			out_le16((u16 __iomem *)hose->cfg_data,
++				(u16)val);
++			out_le16(((u16 __iomem *)hose->cfg_data) + 1,
++				(u16)(val>>16));
++			break;
++		}
++	}
++	else
++#endif
++	{
++		if (len != 4) {
++			value = in_le32(hose->cfg_data);
++
++			offset = (offset & 0x3) << 3;
++			mask = (0xffffffff >> (32 - (len << 3)));
++			mask <<= offset;
++
++			value &= ~mask;
++			val = value | ((val << offset) & mask);
++		}
++
++		out_le32(hose->cfg_data, val);
++	}
++	mb();
++
++	out_be32(hose->cfg_addr, 0);
++	mb();
++
++	return PCIBIOS_SUCCESSFUL;
++}
++
++static struct pci_ops mpc52xx_pci_ops = {
++	.read  = mpc52xx_pci_read_config,
++	.write = mpc52xx_pci_write_config
++};
++
++
++/* ======================================================================== */
++/* PCI setup                                                                */
++/* ======================================================================== */
++
++static void __init
++mpc52xx_pci_setup(struct pci_controller *hose,
++                  struct mpc52xx_pci __iomem *pci_regs)
++{
++	struct resource *res;
++	u32 tmp;
++	int iwcr0 = 0, iwcr1 = 0, iwcr2 = 0;
++
++	pr_debug("mpc52xx_pci_setup(hose=%p, pci_regs=%p)\n", hose, pci_regs);
++
++	/* pci_process_bridge_OF_ranges() found all our addresses for us;
++	 * now store them in the right places */
++	hose->cfg_addr = &pci_regs->car;
++	hose->cfg_data = hose->io_base_virt;
++
++	/* Control regs */
++	tmp = in_be32(&pci_regs->scr);
++	tmp |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
++	out_be32(&pci_regs->scr, tmp);
++
++	/* Memory windows */
++	res = &hose->mem_resources[0];
++	if (res->flags) {
++		pr_debug("mem_resource[0] = {.start=%x, .end=%x, .flags=%lx}\n",
++		         res->start, res->end, res->flags);
++		out_be32(&pci_regs->iw0btar,
++		         MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start,
++		                  res->end - res->start + 1));
++		iwcr0 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM;
++		if (res->flags & IORESOURCE_PREFETCH)
++			iwcr0 |= MPC52xx_PCI_IWCR_READ_MULTI;
++		else
++			iwcr0 |= MPC52xx_PCI_IWCR_READ;
++	}
++
++	res = &hose->mem_resources[1];
++	if (res->flags) {
++		pr_debug("mem_resource[1] = {.start=%x, .end=%x, .flags=%lx}\n",
++		         res->start, res->end, res->flags);
++		out_be32(&pci_regs->iw1btar,
++		         MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start,
++		                  res->end - res->start + 1));
++		iwcr1 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM;
++		if (res->flags & IORESOURCE_PREFETCH)
++			iwcr1 |= MPC52xx_PCI_IWCR_READ_MULTI;
++		else
++			iwcr1 |= MPC52xx_PCI_IWCR_READ;
++	}
++
++	/* IO resources */
++	res = &hose->io_resource;
++	if (!res) {
++		printk(KERN_ERR "%s: Didn't find IO resources\n", __FILE__);
++		return;
++	}
++	pr_debug(".io_resource={.start=%x,.end=%x,.flags=%lx} "
++	         ".io_base_phys=0x%p\n",
++	         res->start, res->end, res->flags, (void*)hose->io_base_phys);
++	out_be32(&pci_regs->iw2btar,
++	         MPC52xx_PCI_IWBTAR_TRANSLATION(hose->io_base_phys,
++	                                        res->start,
++	                                        res->end - res->start + 1));
++	iwcr2 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_IO;
++
++	/* Set all the IWCR fields at once; they're in the same reg */
++	out_be32(&pci_regs->iwcr, MPC52xx_PCI_IWCR_PACK(iwcr0, iwcr1, iwcr2));
++
++	out_be32(&pci_regs->tbatr0,
++		MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_IO );
++	out_be32(&pci_regs->tbatr1,
++		MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_MEM );
++
++	out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD);
++
++	tmp = in_be32(&pci_regs->gscr);
++#if 0
++	/* Reset the exteral bus ( internal PCI controller is NOT resetted ) */
++	/* Not necessary and can be a bad thing if for example the bootloader
++	   is displaying a splash screen or ... Just left here for
++	   documentation purpose if anyone need it */
++	out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR);
++	udelay(50);
++#endif
++
++	/* Make sure the PCI bridge is out of reset */
++	out_be32(&pci_regs->gscr, tmp & ~MPC52xx_PCI_GSCR_PR);
++}
++
++static void
++mpc52xx_pci_fixup_resources(struct pci_dev *dev)
++{
++	int i;
++
++	pr_debug("mpc52xx_pci_fixup_resources() %.4x:%.4x\n",
++	         dev->vendor, dev->device);
++
++	/* We don't rely on boot loader for PCI and resets all
++	   devices */
++	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
++		struct resource *res = &dev->resource[i];
++		if (res->end > res->start) {	/* Only valid resources */
++			res->end -= res->start;
++			res->start = 0;
++			res->flags |= IORESOURCE_UNSET;
++		}
++	}
++
++	/* The PCI Host bridge of MPC52xx has a prefetch memory resource
++	   fixed to 1Gb. Doesn't fit in the resource system so we remove it */
++	if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
++	     (   dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200
++	      || dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) {
++		struct resource *res = &dev->resource[1];
++		res->start = res->end = res->flags = 0;
++	}
++}
++
++int __init
++mpc52xx_add_bridge(struct device_node *node)
++{
++	int len;
++	struct mpc52xx_pci __iomem *pci_regs;
++	struct pci_controller *hose;
++	const int *bus_range;
++	struct resource rsrc;
++
++	pr_debug("Adding MPC52xx PCI host bridge %s\n", node->full_name);
++
++	pci_assign_all_buses = 1;
++
++	if (of_address_to_resource(node, 0, &rsrc) != 0) {
++		printk(KERN_ERR "Can't get %s resources\n", node->full_name);
++		return -EINVAL;
++	}
++
++	bus_range = get_property(node, "bus-range", &len);
++	if (bus_range == NULL || len < 2 * sizeof(int)) {
++		printk(KERN_WARNING "Can't get %s bus-range, assume bus 0\n",
++		       node->full_name);
++		bus_range = NULL;
++	}
++
++	/* There are some PCI quirks on the 52xx, register the hook to
++	 * fix them. */
++	ppc_md.pcibios_fixup_resources = mpc52xx_pci_fixup_resources;
++
++	/* Alloc and initialize the pci controller.  Values in the device
++	 * tree are needed to configure the 52xx PCI controller.  Rather
++	 * than parse the tree here, let pci_process_bridge_OF_ranges()
++	 * do it for us and extract the values after the fact */
++	hose = pcibios_alloc_controller();
++	if (!hose)
++		return -ENOMEM;
++
++	hose->arch_data = node;
++	hose->set_cfg_type = 1;
++
++	hose->first_busno = bus_range ? bus_range[0] : 0;
++	hose->last_busno = bus_range ? bus_range[1] : 0xff;
++
++	hose->bus_offset = 0;
++	hose->ops = &mpc52xx_pci_ops;
++
++	pci_regs = ioremap(rsrc.start, rsrc.end - rsrc.start + 1);
++	if (!pci_regs)
++		return -ENOMEM;
++
++	pci_process_bridge_OF_ranges(hose, node, 1);
++
++	/* Finish setting up PCI using values obtained by
++	 * pci_proces_bridge_OF_ranges */
++	mpc52xx_pci_setup(hose, pci_regs);
++
++	return 0;
++}
+diff --git a/arch/powerpc/platforms/52xx/pci.c b/arch/powerpc/platforms/52xx/pci.c
+deleted file mode 100644
+index b732fdc..0000000
+--- a/arch/powerpc/platforms/52xx/pci.c
++++ /dev/null
+@@ -1,404 +0,0 @@
+-/*
+- * PCI code for the Freescale MPC52xx embedded CPU.
+- *
+- * Copyright (C) 2004 Secret Lab Technologies Ltd.
+- *                        Grant Likely <grant.likely at secretlab.ca>
+- * Copyright (C) 2004 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.
+- */
+-
+-#undef DEBUG
+-
+-#include <asm/pci.h>
+-#include <asm/mpc52xx.h>
+-#include <asm/delay.h>
+-#include <asm/machdep.h>
+-#include <linux/kernel.h>
+-
+-
+-/* ======================================================================== */
+-/* PCI windows config                                                       */
+-/* ======================================================================== */
+-
+-#define MPC52xx_PCI_TARGET_IO	0xf0000000
+-#define MPC52xx_PCI_TARGET_MEM	0x00000000
+-
+-/* ======================================================================== */
+-/* Structures mapping & Defines for PCI Unit                                */
+-/* ======================================================================== */
+-
+-#define MPC52xx_PCI_GSCR_BM		0x40000000
+-#define MPC52xx_PCI_GSCR_PE		0x20000000
+-#define MPC52xx_PCI_GSCR_SE		0x10000000
+-#define MPC52xx_PCI_GSCR_XLB2PCI_MASK	0x07000000
+-#define MPC52xx_PCI_GSCR_XLB2PCI_SHIFT	24
+-#define MPC52xx_PCI_GSCR_IPG2PCI_MASK	0x00070000
+-#define MPC52xx_PCI_GSCR_IPG2PCI_SHIFT	16
+-#define MPC52xx_PCI_GSCR_BME		0x00004000
+-#define MPC52xx_PCI_GSCR_PEE		0x00002000
+-#define MPC52xx_PCI_GSCR_SEE		0x00001000
+-#define MPC52xx_PCI_GSCR_PR		0x00000001
+-
+-
+-#define MPC52xx_PCI_IWBTAR_TRANSLATION(proc_ad,pci_ad,size)	  \
+-		( ( (proc_ad) & 0xff000000 )			| \
+-		  ( (((size) - 1) >> 8) & 0x00ff0000 )		| \
+-		  ( ((pci_ad) >> 16) & 0x0000ff00 ) )
+-
+-#define MPC52xx_PCI_IWCR_PACK(win0,win1,win2)	(((win0) << 24) | \
+-						 ((win1) << 16) | \
+-						 ((win2) <<  8))
+-
+-#define MPC52xx_PCI_IWCR_DISABLE	0x0
+-#define MPC52xx_PCI_IWCR_ENABLE		0x1
+-#define MPC52xx_PCI_IWCR_READ		0x0
+-#define MPC52xx_PCI_IWCR_READ_LINE	0x2
+-#define MPC52xx_PCI_IWCR_READ_MULTI	0x4
+-#define MPC52xx_PCI_IWCR_MEM		0x0
+-#define MPC52xx_PCI_IWCR_IO		0x8
+-
+-#define MPC52xx_PCI_TCR_P		0x01000000
+-#define MPC52xx_PCI_TCR_LD		0x00010000
+-
+-#define MPC52xx_PCI_TBATR_DISABLE	0x0
+-#define MPC52xx_PCI_TBATR_ENABLE	0x1
+-
+-struct mpc52xx_pci {
+-	u32	idr;		/* PCI + 0x00 */
+-	u32	scr;		/* PCI + 0x04 */
+-	u32	ccrir;		/* PCI + 0x08 */
+-	u32	cr1;		/* PCI + 0x0C */
+-	u32	bar0;		/* PCI + 0x10 */
+-	u32	bar1;		/* PCI + 0x14 */
+-	u8	reserved1[16];	/* PCI + 0x18 */
+-	u32	ccpr;		/* PCI + 0x28 */
+-	u32	sid;		/* PCI + 0x2C */
+-	u32	erbar;		/* PCI + 0x30 */
+-	u32	cpr;		/* PCI + 0x34 */
+-	u8	reserved2[4];	/* PCI + 0x38 */
+-	u32	cr2;		/* PCI + 0x3C */
+-	u8	reserved3[32];	/* PCI + 0x40 */
+-	u32	gscr;		/* PCI + 0x60 */
+-	u32	tbatr0;		/* PCI + 0x64 */
+-	u32	tbatr1;		/* PCI + 0x68 */
+-	u32	tcr;		/* PCI + 0x6C */
+-	u32	iw0btar;	/* PCI + 0x70 */
+-	u32	iw1btar;	/* PCI + 0x74 */
+-	u32	iw2btar;	/* PCI + 0x78 */
+-	u8	reserved4[4];	/* PCI + 0x7C */
+-	u32	iwcr;		/* PCI + 0x80 */
+-	u32	icr;		/* PCI + 0x84 */
+-	u32	isr;		/* PCI + 0x88 */
+-	u32	arb;		/* PCI + 0x8C */
+-	u8	reserved5[104];	/* PCI + 0x90 */
+-	u32	car;		/* PCI + 0xF8 */
+-	u8	reserved6[4];	/* PCI + 0xFC */
+-};
+-
+-static int
+-mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
+-				int offset, int len, u32 *val)
+-{
+-	struct pci_controller *hose = bus->sysdata;
+-	u32 value;
+-
+-	if (ppc_md.pci_exclude_device)
+-		if (ppc_md.pci_exclude_device(bus->number, devfn))
+-			return PCIBIOS_DEVICE_NOT_FOUND;
+-
+-	out_be32(hose->cfg_addr,
+-		(1 << 31) |
+-		((bus->number - hose->bus_offset) << 16) |
+-		(devfn << 8) |
+-		(offset & 0xfc));
+-	mb();
+-
+-#if defined(CONFIG_PPC_MPC5200_BUGFIX)
+-	if (bus->number != hose->bus_offset) {
+-		/* workaround for the bug 435 of the MPC5200 (L25R);
+-		 * Don't do 32 bits config access during type-1 cycles */
+-		switch (len) {
+-		      case 1:
+-			value = in_8(((u8 __iomem *)hose->cfg_data) +
+-			             (offset & 3));
+-			break;
+-		      case 2:
+-			value = in_le16(((u16 __iomem *)hose->cfg_data) +
+-			                ((offset>>1) & 1));
+-			break;
+-
+-		      default:
+-			value = in_le16((u16 __iomem *)hose->cfg_data) |
+-				(in_le16(((u16 __iomem *)hose->cfg_data) + 1) << 16);
+-			break;
+-		}
+-	}
+-	else
+-#endif
+-	{
+-		value = in_le32(hose->cfg_data);
+-
+-		if (len != 4) {
+-			value >>= ((offset & 0x3) << 3);
+-			value &= 0xffffffff >> (32 - (len << 3));
+-		}
+-	}
+-
+-	*val = value;
+-
+-	out_be32(hose->cfg_addr, 0);
+-	mb();
+-
+-	return PCIBIOS_SUCCESSFUL;
+-}
+-
+-static int
+-mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
+-				int offset, int len, u32 val)
+-{
+-	struct pci_controller *hose = bus->sysdata;
+-	u32 value, mask;
+-
+-	if (ppc_md.pci_exclude_device)
+-		if (ppc_md.pci_exclude_device(bus->number, devfn))
+-			return PCIBIOS_DEVICE_NOT_FOUND;
+-
+-	out_be32(hose->cfg_addr,
+-		(1 << 31) |
+-		((bus->number - hose->bus_offset) << 16) |
+-		(devfn << 8) |
+-		(offset & 0xfc));
+-	mb();
+-
+-#if defined(CONFIG_PPC_MPC5200_BUGFIX)
+-	if (bus->number != hose->bus_offset) {
+-		/* workaround for the bug 435 of the MPC5200 (L25R);
+-		 * Don't do 32 bits config access during type-1 cycles */
+-		switch (len) {
+-		      case 1:
+-			out_8(((u8 __iomem *)hose->cfg_data) +
+-				(offset & 3), val);
+-			break;
+-		      case 2:
+-			out_le16(((u16 __iomem *)hose->cfg_data) +
+-				((offset>>1) & 1), val);
+-			break;
+-
+-		      default:
+-			out_le16((u16 __iomem *)hose->cfg_data,
+-				(u16)val);
+-			out_le16(((u16 __iomem *)hose->cfg_data) + 1,
+-				(u16)(val>>16));
+-			break;
+-		}
+-	}
+-	else
+-#endif
+-	{
+-		if (len != 4) {
+-			value = in_le32(hose->cfg_data);
+-
+-			offset = (offset & 0x3) << 3;
+-			mask = (0xffffffff >> (32 - (len << 3)));
+-			mask <<= offset;
+-
+-			value &= ~mask;
+-			val = value | ((val << offset) & mask);
+-		}
+-
+-		out_le32(hose->cfg_data, val);
+-	}
+-	mb();
+-
+-	out_be32(hose->cfg_addr, 0);
+-	mb();
+-
+-	return PCIBIOS_SUCCESSFUL;
+-}
+-
+-static struct pci_ops mpc52xx_pci_ops = {
+-	.read  = mpc52xx_pci_read_config,
+-	.write = mpc52xx_pci_write_config
+-};
+-
+-
+-static void __init
+-mpc52xx_pci_setup(struct pci_controller *hose,
+-                  struct mpc52xx_pci __iomem *pci_regs)
+-{
+-	struct resource *res;
+-	u32 tmp;
+-	int iwcr0 = 0, iwcr1 = 0, iwcr2 = 0;
+-
+-	pr_debug("mpc52xx_pci_setup(hose=%p, pci_regs=%p)\n", hose, pci_regs);
+-
+-	/* pci_process_bridge_OF_ranges() found all our addresses for us;
+-	 * now store them in the right places */
+-	hose->cfg_addr = &pci_regs->car;
+-	hose->cfg_data = hose->io_base_virt;
+-	hose->io_base_virt = ioremap(hose->io_base_phys,
+-	                             hose->io_resource.end + 1 -
+-	                             hose->io_resource.start);
+-	isa_io_base = (unsigned long) hose->io_base_virt;
+-
+-	/* Control regs */
+-	tmp = in_be32(&pci_regs->scr);
+-	tmp |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+-	out_be32(&pci_regs->scr, tmp);
+-
+-	/* Memory windows */
+-	res = &hose->mem_resources[0];
+-	if (res->flags) {
+-		pr_debug("mem_resource[0] = {.start=%x, .end=%x, .flags=%lx}\n",
+-		         res->start, res->end, res->flags);
+-		out_be32(&pci_regs->iw0btar,
+-		         MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start,
+-		                  res->end - res->start + 1));
+-		iwcr0 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM;
+-		if (res->flags & IORESOURCE_PREFETCH)
+-			iwcr0 |= MPC52xx_PCI_IWCR_READ_MULTI;
+-		else
+-			iwcr0 |= MPC52xx_PCI_IWCR_READ;
+-	}
+-
+-	res = &hose->mem_resources[1];
+-	if (res->flags) {
+-		pr_debug("mem_resource[1] = {.start=%x, .end=%x, .flags=%lx}\n",
+-		         res->start, res->end, res->flags);
+-		out_be32(&pci_regs->iw1btar,
+-		         MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start,
+-		                  res->end - res->start + 1));
+-		iwcr1 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM;
+-		if (res->flags & IORESOURCE_PREFETCH)
+-			iwcr1 |= MPC52xx_PCI_IWCR_READ_MULTI;
+-		else
+-			iwcr1 |= MPC52xx_PCI_IWCR_READ;
+-	}
+-
+-	/* IO resources */
+-	res = &hose->io_resource;
+-	if (!res) {
+-		printk(KERN_ERR "%s: Didn't find IO resources\n", __FILE__);
+-		return;
+-	}
+-	pr_debug(".io_resource={.start=%x,.end=%x,.flags=%lx} "
+-	         ".io_base_phys=0x%p\n",
+-	         res->start, res->end, res->flags, (void*)hose->io_base_phys);
+-	out_be32(&pci_regs->iw2btar,
+-	         MPC52xx_PCI_IWBTAR_TRANSLATION(hose->io_base_phys,
+-	                                        res->start,
+-	                                        res->end - res->start + 1));
+-	iwcr2 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_IO;
+-
+-	/* Set all the IWCR fields at once; they're in the same reg */
+-	out_be32(&pci_regs->iwcr, MPC52xx_PCI_IWCR_PACK(iwcr0, iwcr1, iwcr2));
+-
+-	out_be32(&pci_regs->tbatr0,
+-		MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_IO );
+-	out_be32(&pci_regs->tbatr1,
+-		MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_MEM );
+-
+-	out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD);
+-
+-#if 0
+-	/* Reset the exteral bus ( internal PCI controller is NOT resetted ) */
+-	/* Not necessary and can be a bad thing if for example the bootloader
+-	   is displaying a splash screen or ... Just left here for
+-	   documentation purpose if anyone need it */
+-	tmp = in_be32(&pci_regs->gscr);
+-	out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR);
+-	udelay(50);
+-	out_be32(&pci_regs->gscr, tmp & ~MPC52xx_PCI_GSCR_PR);
+-#endif
+-}
+-
+-static void
+-mpc52xx_pci_fixup_resources(struct pci_dev *dev)
+-{
+-	int i;
+-
+-	pr_debug("mpc52xx_pci_fixup_resources() %.4x:%.4x\n",
+-	         dev->vendor, dev->device);
+-
+-	/* We don't rely on boot loader for PCI and resets all
+-	   devices */
+-	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+-		struct resource *res = &dev->resource[i];
+-		if (res->end > res->start) {	/* Only valid resources */
+-			res->end -= res->start;
+-			res->start = 0;
+-			res->flags |= IORESOURCE_UNSET;
+-		}
+-	}
+-
+-	/* The PCI Host bridge of MPC52xx has a prefetch memory resource
+-	   fixed to 1Gb. Doesn't fit in the resource system so we remove it */
+-	if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
+-	     (   dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200
+-	      || dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) {
+-		struct resource *res = &dev->resource[1];
+-		res->start = res->end = res->flags = 0;
+-	}
+-}
+-
+-int __init
+-mpc52xx_add_bridge(struct device_node *node)
+-{
+-	int len;
+-	struct mpc52xx_pci __iomem *pci_regs;
+-	struct pci_controller *hose;
+-	const int *bus_range;
+-	struct resource rsrc;
+-
+-	pr_debug("Adding MPC52xx PCI host bridge %s\n", node->full_name);
+-
+-	pci_assign_all_buses = 1;
+-
+-	if (of_address_to_resource(node, 0, &rsrc) != 0) {
+-		printk(KERN_ERR "Can't get %s resources\n", node->full_name);
+-		return -EINVAL;
+-	}
+-
+-	bus_range = get_property(node, "bus-range", &len);
+-	if (bus_range == NULL || len < 2 * sizeof(int)) {
+-		printk(KERN_WARNING "Can't get %s bus-range, assume bus 0\n",
+-		       node->full_name);
+-		bus_range = NULL;
+-	}
+-
+-	/* There are some PCI quirks on the 52xx, register the hook to
+-	 * fix them. */
+-	ppc_md.pcibios_fixup_resources = mpc52xx_pci_fixup_resources;
+-
+-	/* Alloc and initialize the pci controller.  Values in the device
+-	 * tree are needed to configure the 52xx PCI controller.  Rather
+-	 * than parse the tree here, let pci_process_bridge_OF_ranges()
+-	 * do it for us and extract the values after the fact */
+-	hose = pcibios_alloc_controller();
+-	if (!hose)
+-		return -ENOMEM;
+-
+-	hose->arch_data = node;
+-	hose->set_cfg_type = 1;
+-
+-	hose->first_busno = bus_range ? bus_range[0] : 0;
+-	hose->last_busno = bus_range ? bus_range[1] : 0xff;
+-
+-	hose->bus_offset = 0;
+-	hose->ops = &mpc52xx_pci_ops;
+-
+-	pci_regs = ioremap(rsrc.start, rsrc.end - rsrc.start + 1);
+-	if (!pci_regs)
+-		return -ENOMEM;
+-
+-	pci_process_bridge_OF_ranges(hose, node, 0);
+-
+-	/* Finish setting up PCI using values obtained by
+-	 * pci_proces_bridge_OF_ranges */
+-	mpc52xx_pci_setup(hose, pci_regs);
+-
+-	return 0;
+-}
+-- 
+1.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0031-sound-Add-support-for-the-MPC52xx-PSC-AC97-Link.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0031-sound-Add-support-for-the-MPC52xx-PSC-AC97-Link.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,828 @@
+From 46e8903e34759728afd11dd11c481e6a94e6b06d Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt at 246tNt.com>
+Date: Mon, 18 Dec 2006 22:51:38 +0100
+Subject: [PATCH] [PATCH] sound: Add support for the MPC52xx PSC AC97 Link
+
+Messy driver, to be cleaned ... a lot ...
+
+Signed-off-by: Sylvain Munaut <tnt at 246tNt.com>
+---
+ include/asm-ppc/mpc52xx_psc.h |   10 +-
+ sound/ppc/Kconfig             |   16 +
+ sound/ppc/Makefile            |    3 +
+ sound/ppc/mpc52xx_ac97.c      |  738 +++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 765 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 */
+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..a4f008e
+--- /dev/null
++++ b/sound/ppc/mpc52xx_ac97.c
+@@ -0,0 +1,738 @@
++/*
++ * 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 <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 <asm/mpc52xx_psc.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 snd_card *card;
++	struct snd_pcm *pcm;
++	struct snd_ac97 *ac97;
++
++	struct snd_pcm_substream *substream_playback;
++	unsigned int buf_pos;
++};
++
++/* 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
++
++
++
++/* ======================================================================== */
++/* ISR routine                                                              */
++/* ======================================================================== */
++
++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 0
++	if ((icnt++) > 50000)
++		out_be16(&priv->psc->mpc52xx_psc_imr, 0);
++	#endif
++
++	/* Copy 64 data into the buffer */
++	if (in_be16(&priv->psc->mpc52xx_psc_imr) & 0x0100) {
++		if (priv->substream_playback) {
++			struct snd_pcm_runtime *rt;
++
++			rt = priv->substream_playback->runtime;
++
++			if (snd_pcm_playback_hw_avail(rt) < bytes_to_frames(rt,128)) {
++				int i;
++				/* Push silence */
++				for (i=0; i<64; i++)
++					out_be32(&priv->psc->mpc52xx_psc_buffer_32, 0x00000800);
++				printk(KERN_DEBUG "pushed silence ...\n");
++			} else {
++				int i;
++				unsigned short *data;
++
++				data = (unsigned short *)
++					(&rt->dma_area[frames_to_bytes(rt, priv->buf_pos)]);
++
++				for (i=0; i<64; i++)
++					out_be32(&priv->psc->mpc52xx_psc_buffer_32,
++						(((unsigned int)data[i]) << 16) | 0x00000000);
++							/* Setting the sof bit looks useless */
++
++				priv->buf_pos += bytes_to_frames(rt,128);;
++				if (priv->buf_pos >= rt->buffer_size)
++					priv->buf_pos = 0;
++
++				snd_pcm_period_elapsed(priv->substream_playback);
++			}
++		} else {
++			out_be16(&priv->psc->mpc52xx_psc_imr, 0);
++			printk(KERN_DEBUG "Interrupt with no stream ...\n");
++		}
++	} else {
++		printk(KERN_ERR "Spurious int\n");
++	}
++
++	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_S16_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	= 128*1024,
++	.period_bytes_min	= 128, /* 32, */
++	.period_bytes_max	= 128, /* 16*1024, */
++	.periods_min		= 8,
++	.periods_max		= 256,
++	.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;
++	priv->buf_pos = 0;	/* FIXME Do that where ? */
++
++	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;
++	}
++
++	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);
++
++	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 interrupt */
++			out_be16(&priv->psc->mpc52xx_psc_imr, 0x0100); // 0x0100
++
++			break;
++
++		case SNDRV_PCM_TRIGGER_STOP:
++			/* Disable TX interrupt */
++			out_be16(&priv->psc->mpc52xx_psc_imr, 0x0000);
++
++			break;
++
++		default:
++			rv = -EINVAL;
++	}
++
++	/* FIXME */
++	return rv;
++}
++
++static snd_pcm_uframes_t
++mpc52xx_ac97_pointer(struct snd_pcm_substream *substream)
++{
++	struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
++
++//	dev_dbg(priv->dev, "mpc52xx_ac97_pointer(%p)\n", substream);
++
++	if (substream->runtime->channels == 1)
++		return priv->buf_pos;	/* FIXME */
++	else
++		return priv->buf_pos >> 1;	/* FIXME */
++}
++
++
++/* 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;
++	}
++
++	/* 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;
++	}
++
++	/* 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(priv->irq, priv);
++err_irqreq:
++	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 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		= "ac97",	FIXME Efika ... */
++		.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.4.4.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0033-Fix-the-bestcomm-interrupt-property-fixes-the-ethernet-driver.txt
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0033-Fix-the-bestcomm-interrupt-property-fixes-the-ethernet-driver.txt	Thu Jan 11 15:19:52 2007
@@ -0,0 +1,113 @@
+From 49029f815b10175dcec09152929d53efe0ed510c Mon Sep 17 00:00:00 2001
+From: Sven Luther <sven at tael.(none)>
+Date: Tue, 9 Jan 2007 11:12:51 +0100
+Subject: [PATCH] Fix the bestcomm interrupt property, fixes the ethernet driver.
+
+---
+ arch/powerpc/kernel/prom_init.c |   85 +++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 85 insertions(+), 0 deletions(-)
+
+diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
+index 520ef42..a1cf18e 100644
+--- a/arch/powerpc/kernel/prom_init.c
++++ b/arch/powerpc/kernel/prom_init.c
+@@ -2117,11 +2117,96 @@ static void __init fixup_device_tree_pmac(void)
+ #define fixup_device_tree_pmac()
+ #endif
+ 
++#ifdef CONFIG_PPC_EFIKA
++/* The current fw of the Efika has a device tree needs quite a few
++ * fixups to be compliant with the mpc52xx bindings. It's currently
++ * unknown if it will ever be compliant (come on bPlan ...) so we do fixups.
++ * NOTE that we (barely) tolerate it because the EFIKA was out before
++ * the bindings were finished, for any new boards -> RTFM ! */
++
++struct subst_entry {
++	char *path;
++	char *property;
++	void *value;
++	int value_len;
++};
++
++static void __init fixup_device_tree_efika(void)
++{
++	/* Substitution table */
++	#define prop_cstr(x) x, sizeof(x)
++	int prop_sound_irq[3] = { 2, 2, 0 };
++	int prop_bcomm_irq[48];
++	struct subst_entry efika_subst_table[] = {
++		{ "/",			"device_type",	prop_cstr("efika") },
++		{ "/builtin",		"compatible",	prop_cstr("soc") },
++		{ "/builtin/ata",	"compatible",	prop_cstr("mpc5200b-ata\0mpc52xx-ata"), },
++		{ "/builtin/bestcomm",	"compatible",	prop_cstr("mpc5200b-bestcomm\0mpc52xx-bestcomm") },
++		{ "/builtin/bestcomm",	"interrupts",	prop_bcomm_irq, sizeof(prop_bcomm_irq) },
++		{ "/builtin/ethernet",	"compatible",	prop_cstr("mpc5200b-fec\0mpc52xx-fec") },
++		{ "/builtin/pic",	"compatible",	prop_cstr("mpc5200b-pic\0mpc52xx-pic") },
++		{ "/builtin/serial",	"compatible",	prop_cstr("mpc5200b-psc-uart\0mpc52xx-psc-uart") },
++		{ "/builtin/sound",	"compatible",	prop_cstr("mpc5200b-psc-ac97\0mpc52xx-psc-ac97") },
++		{ "/builtin/sound",	"interrupts",	prop_sound_irq, sizeof(prop_sound_irq) },
++		{ "/builtin/sram",	"compatible",	prop_cstr("mpc5200b-sram\0mpc52xx-sram") },
++		{ "/builtin/sram",	"device_type",	prop_cstr("sram") },
++		{}
++	};
++	#undef prop_cstr
++
++	/* Vars */
++	u32 node;
++	char prop[64];
++	int rv, i;
++
++	/* Check if we're really running on a EFIKA */
++	node = call_prom("finddevice", 1, 1, ADDR("/"));
++	if (!PHANDLE_VALID(node))
++		return;
++
++	rv = prom_getprop(node, "model", prop, sizeof(prop));
++	if (rv == PROM_ERROR)
++		return;
++	if (strcmp(prop, "EFIKA5K2"))
++		return;
++
++	prom_printf("Applying EFIKA device tree fixups\n");
++
++	/* Fill the prop_bcomm_irq */
++	for (i=0; i<16; i++) {
++		prop_bcomm_irq[3*i  ] = 3;
++		prop_bcomm_irq[3*i+1] = i;
++		prop_bcomm_irq[3*i+2] = 0;
++	}
++
++	/* Process substitution table */
++	for (i=0; efika_subst_table[i].path; i++) {
++		struct subst_entry *se = &efika_subst_table[i];
++
++		node = call_prom("finddevice", 1, 1, ADDR(se->path));
++		if (!PHANDLE_VALID(node)) {
++			prom_printf("fixup_device_tree_efika: ",
++				"skipped entry %x - not found\n", i);
++			continue;
++		}
++
++		rv = prom_setprop(node, se->path, se->property,
++					se->value, se->value_len );
++		if (rv == PROM_ERROR)
++			prom_printf("fixup_device_tree_efika: ",
++				"skipped entry %x - setprop error\n", i);
++	}
++}
++#else
++#define fixup_device_tree_efika()
++#endif
++
+ static void __init fixup_device_tree(void)
+ {
+ 	fixup_device_tree_maple();
+ 	fixup_device_tree_chrp();
+ 	fixup_device_tree_pmac();
++	fixup_device_tree_efika();
+ }
+ 
+ static void __init prom_find_boot_cpu(void)
+-- 
+1.4.4.2
+

Modified: dists/trunk/linux-2.6/debian/patches/series/1~experimental.1
==============================================================================
--- dists/trunk/linux-2.6/debian/patches/series/1~experimental.1	(original)
+++ dists/trunk/linux-2.6/debian/patches/series/1~experimental.1	Thu Jan 11 15:19:52 2007
@@ -2,8 +2,8 @@
 + debian/kernelvariables.patch
 + debian/doc-build-parallel.patch
 + debian/scripts-kconfig-reportoldconfig.patch
-#+ debian/powerpc-mkvmlinuz-support-ppc.patch
-#+ debian/powerpc-mkvmlinuz-support-powerpc.patch
++ debian/powerpc-mkvmlinuz-support-ppc.patch
++ debian/powerpc-mkvmlinuz-support-powerpc.patch
 
 + bugfix/powerpc/build-links.patch
 + bugfix/powerpc/mv643xx-hotplug-support.patch
@@ -26,3 +26,35 @@
 + features/arm/ixp4xx-net-driver-improve-mac-handling.patch
 + bugfix/Makefile-localversion-backup.patch
 + bugfix/drivers-bus_to_virt.patch
+
++ features/powerpc/efika/0001-powerpc-serial-Dispose-irq-mapping-when-done-in-mpc52xx_serial.c.txt
++ features/powerpc/efika/0002-powerpc-52xx-Don-t-use-device_initcall-to-probe-of_platform_bus.txt
++ features/powerpc/efika/0004-powerpc-Use-common-52xx-of_platform-probe-code-for-EFIKA.txt
++ features/powerpc/efika/0005-powerpc-Restore-proper-link-order-in-platform.txt
++ features/powerpc/efika/0006-Rework-the-OHCI-quirk-mecanism-as-suggested-by-David.txt
++ features/powerpc/efika/0007-Implement-support-for-split-endian-OHCI.txt
++ features/powerpc/efika/0008-ohci-Rework-bus-glue-integration-to-allow-several-at-once.txt
++ features/powerpc/efika/0009-ohci-Add-support-for-OHCI-controller-on-the-of_platform-bus.txt
++ features/powerpc/efika/0010-libata-Add-support-for-the-MPC52xx-ATA-controller.txt
++ features/powerpc/efika/0011-ohci-Whitespace-and-typo-fix-in-ohci-ppc-of.c.txt
++ features/powerpc/efika/0012-ata-Fix-pata_mpc52xx.c-compatible-list.txt
++ features/powerpc/efika/0013-powerpc-serial-Fix-mpc52xx_uart.c-compatible-list.txt
++ features/powerpc/efika/0014-powerpc-Small-cleanup-of-EFIKA-platform.txt
++ features/powerpc/efika/0015-powerpc-Add-a-unified-uevent-handler-for-bus-based-on-of_device.txt
++ features/powerpc/efika/0016-macintosh-Use-the-new-of_device-common-uevent-handler.txt
++ features/powerpc/efika/0017-powerpc-Add-uevent-handler-for-of_platform_bus.txt
++ features/powerpc/efika/0018-powerpc-Add-uevent-handler-for-ibmebus.txt
++ features/powerpc/efika/0019-MPC5200-Bestcomm-platform-driver.txt
++ features/powerpc/efika/0020-Fec-MPC5200-eth-driver.txt
++ features/powerpc/efika/0021-POWERPC-Copy-bestcomm-support-files-into-arch-powerpc.txt
++ features/powerpc/efika/0022-MPC52xx-PCI-now-working-on-lite5200.-ugly-but-working.txt
++ features/powerpc/efika/0023-POWERPC-Make-FEC-work-on-the-lite5200.txt
++ features/powerpc/efika/0024-Add-missing-function-prototype.txt
++ features/powerpc/efika/0025-POWERPC-Misc-EFIKA-fixups-for-rtas-chrp.txt
++ features/powerpc/efika/0026-POWERPC-Cleanup-mpc52xx-PCI-support.txt
++ features/powerpc/efika/0027-POWERPC-Change-name-of-mpc52xx-pci-support-file-in-Makefile.txt
++ features/powerpc/efika/0028-POWERPC-Change-link-order-so-mpc52xx-fec-always-shows-up-as-eth0.txt
++ features/powerpc/efika/0029-POWERPC-Fixup-pr_print-format-for-mpc52xx-pci-support.txt
++ features/powerpc/efika/0030-POWERPC-Add-mpc52xx-lite5200-PCI-support.txt
++ features/powerpc/efika/0031-sound-Add-support-for-the-MPC52xx-PSC-AC97-Link.txt
++ features/powerpc/efika/0033-Fix-the-bestcomm-interrupt-property-fixes-the-ethernet-driver.txt



More information about the Kernel-svn-changes mailing list