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

Sven Luther luther at alioth.debian.org
Sat Nov 25 16:21:54 UTC 2006


Author: luther
Date: Sat Nov 25 17:21:50 2006
New Revision: 7873

Added:
   dists/trunk/linux-2.6/debian/patches/features/powerpc/
   dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/
   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/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/changelog
   dists/trunk/linux-2.6/debian/patches/debian/powerpc-mkvmlinuz-support-powerpc.patch
   dists/trunk/linux-2.6/debian/patches/features/all/fs-asfs.patch
   dists/trunk/linux-2.6/debian/patches/series/1~experimental.1
Log:
Cleaned powerpc patches, re-added those that are needed, and removed the single not needed one.
Cleaned the fs-asfs patch.
Added support for the genesi/efika board, patches scheduled for merge in 2.6.20.
Note: the 0002-Add-USB-OHCI-glue-for-OpenFirmware-devices.diff patch seems a bit ugly,
and may have an impact on modular usb/ohci build. I am monitoring for fixes of this problem, 
but if one doesn' t come soon, it should be disabled for 2.6.19 or 2.6.19-rc6 uploads.


Modified: dists/trunk/linux-2.6/debian/changelog
==============================================================================
--- dists/trunk/linux-2.6/debian/changelog	(original)
+++ dists/trunk/linux-2.6/debian/changelog	Sat Nov 25 17:21:50 2006
@@ -8,6 +8,9 @@
   * arm/footbridge: Unset SATA.
   * arm/s3c2410: Likewise.
 
+  [ Sven Luther ]
+  * [powerpc] Added Genesi Efika support patch
+
  -- Bastian Blank <waldi at debian.org>  Sun, 19 Nov 2006 12:05:33 +0100
 
 linux-2.6 (2.6.18-6) UNRELEASED; urgency=low

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	Sat Nov 25 17:21:50 2006
@@ -18,29 +18,29 @@
 # Upstream status: This patch stays a debian specific patch for now,
 # but it is not in a form where it could go upstream.
 #
---- linux-2.6.17/arch/powerpc/Makefile.orig	2006-04-12 16:57:16.000000000 +0000
-+++ linux-2.6.17/arch/powerpc/Makefile	2006-04-12 16:58:53.000000000 +0000
-@@ -147,7 +147,7 @@
+--- linux-2.6.19-rc6/arch/powerpc/Makefile.orig	2006-11-24 17:43:15.000000000 +0100
++++ linux-2.6.19-rc6/arch/powerpc/Makefile	2006-11-24 17:44:32.000000000 +0100
+@@ -148,7 +148,7 @@
  
  CPPFLAGS_vmlinux.lds	:= -Upowerpc
  
--BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm uImage vmlinux.bin
-+BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm uImage vmlinux.bin mkvmlinuz_support_install
+-BOOT_TARGETS = zImage zImage.initrd uImage
++BOOT_TARGETS = zImage zImage.initrd uImage mkvmlinuz_support_install
  
  PHONY += $(BOOT_TARGETS)
  
---- linux-2.6.16/arch/powerpc/boot/Makefile.orig	2006-04-12 16:40:11.000000000 +0000
-+++ linux-2.6.16/arch/powerpc/boot/Makefile	2006-04-12 19:23:06.000000000 +0000
-@@ -213,3 +213,23 @@
- 	sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" "$(BOOTIMAGE)"
+--- linux-2.6.19-rc6/arch/powerpc/boot/Makefile.orig	2006-11-24 17:42:40.000000000 +0100
++++ linux-2.6.19-rc6/arch/powerpc/boot/Makefile	2006-11-24 17:45:45.000000000 +0100
+@@ -176,3 +176,23 @@
  
- clean-files += $(addprefix $(objtree)/, $(obj-boot) vmlinux.strip)
+ clean-files += $(addprefix $(objtree)/, $(obj-boot) vmlinux.strip.gz)
+ clean-files += $(addprefix $(objtree)/, $(obj-boot) vmlinux.bin.gz)
 +
 +#-----------------------------------------------------------
 +# install mkvmlinuz support files
 +#-----------------------------------------------------------
 +quiet_cmd_mkvmlinuz = INSTALL mkvmlinuz support files
-+      cmd_mkvmlinuz = cp -f $? $(INSTALL_MKVMLINUZ)
++	cmd_mkvmlinuz = cp -f $? $(INSTALL_MKVMLINUZ)
 +
 +mkvmlinuz-obj-sec = $(foreach section, $(1), $(patsubst %,$(obj)/mkvmlinuz-kernel-%.o, $(section)))
 +mkvmlinuz-src-sec = $(foreach section, $(1), $(patsubst %,$(obj)/mkvmlinuz-kernel-%.c, $(section)))

Modified: dists/trunk/linux-2.6/debian/patches/features/all/fs-asfs.patch
==============================================================================
--- dists/trunk/linux-2.6/debian/patches/features/all/fs-asfs.patch	(original)
+++ dists/trunk/linux-2.6/debian/patches/features/all/fs-asfs.patch	Sat Nov 25 17:21:50 2006
@@ -6,9 +6,9 @@
 ## DP: Upstream status: submitted but no reply. Submitted again on 2005.03.22.
 ## DP: Reference: http://home.elka.pw.edu.pl/~mszyprow/programy/asfs/
 
-diff -urN linux-2.6.18/Documentation/filesystems/00-INDEX linux-2.6.18-asfs-1.0b11/Documentation/filesystems/00-INDEX
---- linux-2.6.18/Documentation/filesystems/00-INDEX	2006-09-22 22:47:41.000000000 +0200
-+++ linux-2.6.18-asfs-1.0b11/Documentation/filesystems/00-INDEX	2006-09-22 22:53:21.000000000 +0200
+diff -Nur linux-2.6.19-rc6/Documentation/filesystems/00-INDEX linux-2.6.19-rc6/Documentation/filesystems/00-INDEX
+--- linux-2.6.19-rc6/Documentation/filesystems/00-INDEX	2006-11-16 05:03:40.000000000 +0100
++++ linux-2.6.19-rc6/Documentation/filesystems/00-INDEX	2006-11-24 18:19:03.000000000 +0100
 @@ -10,6 +10,8 @@
  	- info and examples for the distributed AFS (Andrew File System) fs.
  affs.txt
@@ -18,9 +18,9 @@
  automount-support.txt
  	- information about filesystem automount support.
  befs.txt
-diff -urN linux-2.6.18/Documentation/filesystems/asfs.txt linux-2.6.18-asfs-1.0b11/Documentation/filesystems/asfs.txt
---- linux-2.6.18/Documentation/filesystems/asfs.txt	1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-asfs-1.0b11/Documentation/filesystems/asfs.txt	2006-09-22 22:52:37.000000000 +0200
+diff -Nur linux-2.6.19-rc6/Documentation/filesystems/asfs.txt linux-2.6.19-rc6/Documentation/filesystems/asfs.txt
+--- linux-2.6.19-rc6/Documentation/filesystems/asfs.txt	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.19-rc6/Documentation/filesystems/asfs.txt	2006-11-24 18:19:03.000000000 +0100
 @@ -0,0 +1,161 @@
 +
 +Amiga SmartFileSystem, Linux implementation
@@ -183,9 +183,209 @@
 +The ASFS driver is realased under the terms of of the GNU General 
 +Public License. See source code for more details.
 +
-diff -urN linux-2.6.18/fs/asfs/adminspace.c linux-2.6.18-asfs-1.0b11/fs/asfs/adminspace.c
---- linux-2.6.18/fs/asfs/adminspace.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-asfs-1.0b11/fs/asfs/adminspace.c	2006-09-22 22:52:37.000000000 +0200
+diff -Nur linux-2.6.19-rc6/fs/Kconfig linux-2.6.19-rc6/fs/Kconfig
+--- linux-2.6.19-rc6/fs/Kconfig	2006-11-16 05:03:40.000000000 +0100
++++ linux-2.6.19-rc6/fs/Kconfig	2006-11-24 18:19:03.000000000 +0100
+@@ -1111,6 +1111,53 @@
+ 	  To compile this file system support as a module, choose M here: the
+ 	  module will be called ecryptfs.
+ 
++config ASFS_FS
++	tristate "Amiga SFS file system support (EXPERIMENTAL)"
++	select NLS
++	depends on EXPERIMENTAL
++	help
++
++	  The Amiga Smart FileSystem (SFS) is the file system used on hard 
++	  disks by Amiga(tm) and MorphOS(tm) systems.  Say Y if you want 
++	  to be able to read files from an Amiga SFS partition on your hard 
++	  drive.
++
++	  For more information read <file:Documentation/filesystems/asfs.txt>
++
++	  To compile this file system support as a module, choose M here: the
++	  module will be called asfs.
++
++	  If unsure, say N.
++
++config ASFS_DEFAULT_CODEPAGE
++	string "Default codepage for SFS"
++	depends on ASFS_FS
++	default ""
++	help
++	  This option should be set to the codepage of your SFS filesystems.
++	  It can be overridden with the 'codepage' mount option. Leave it blank 
++	  or enter 'none' to disable filename converting.
++
++	  Use full codepage name (for example 'cp1251' instead of '1251') here, 
++	  this allows to specify any character set, not only numbered one (like 
++	  'iso8859-2').
++
++	  If unsure, leave it blank.
++
++config ASFS_RW
++	bool "Amiga SFS write support (DANGEROUS)"
++	depends on ASFS_FS
++	help
++
++	  If you say Y here, you will be able to write to ASFS file
++	  systems as well as read from them. The read-write support in ASFS
++	  is in beta stage. This means that useing it to write files to SFS 
++	  partitions is DANGEROUS and COULD corrupt the filesystem.
++
++	  For more information read <file:Documentation/filesystems/asfs.txt>
++
++	  If unsure, say N.
++
+ config HFS_FS
+ 	tristate "Apple Macintosh file system support (EXPERIMENTAL)"
+ 	depends on BLOCK && EXPERIMENTAL
+diff -Nur linux-2.6.19-rc6/fs/Makefile linux-2.6.19-rc6/fs/Makefile
+--- linux-2.6.19-rc6/fs/Makefile	2006-11-16 05:03:40.000000000 +0100
++++ linux-2.6.19-rc6/fs/Makefile	2006-11-24 18:19:03.000000000 +0100
+@@ -96,6 +96,7 @@
+ obj-$(CONFIG_JFFS_FS)		+= jffs/
+ obj-$(CONFIG_JFFS2_FS)		+= jffs2/
+ obj-$(CONFIG_AFFS_FS)		+= affs/
++obj-$(CONFIG_ASFS_FS)		+= asfs/
+ obj-$(CONFIG_ROMFS_FS)		+= romfs/
+ obj-$(CONFIG_QNX4FS_FS)		+= qnx4/
+ obj-$(CONFIG_AUTOFS_FS)		+= autofs/
+diff -Nur linux-2.6.19-rc6/fs/asfs/Changes linux-2.6.19-rc6/fs/asfs/Changes
+--- linux-2.6.19-rc6/fs/asfs/Changes	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.19-rc6/fs/asfs/Changes	2006-11-24 18:19:03.000000000 +0100
+@@ -0,0 +1,116 @@
++
++Amiga Smart File System, Linux implementation
++
++Please direct bug reports to: marek at amiga.pl
++
++History:
++
++v1.0beta11 (22.09.2006)
++- adapted to 2.6.18 kernel VFS changes
++- made some functions static to reduce overhead in kernel namespace
++
++v1.0beta10 (13.06.2005)
++- fixed ugly bug introduced in beta9 that caused kernel crash on x86
++  (thanks to Emiliano for reporting it!)
++
++v1.0beta9 (17.03.2005)
++- added NLS support (thanks to Pavel Fedin!)
++
++v1.0beta8 (07.01.2005)
++- adapted to 2.6.10 kernel VFS changes
++- added workaround for buggy Mandrake kernel headers
++
++v1.0beta7 (25.06.2004)
++- small changes in documentation
++- code clean up: bitfuncs.c, super.c, inode.c, *.h, Makefile, added 
++  asfs_ prefix to function names, made some functions static
++  (big thanks to Christoph Hellwig for advice!)
++- fixed minor bugs (inode leak in super.c, not-realesed buffer during 
++  object renaming in inode.c)
++- now files/dirs are created with global ownership/permission bits
++
++v1.0beta6 (04.06.2004)
++- fixed: ASFS_SB(sb)->flags was always zero in 2.6.x code
++
++v1.0beta5 (07.05.2004)
++- finally fixed a problem with file size attrib. not being written
++  to disk
++- fixed some problems with GCC 3.x and debug enabled
++
++v1.0beta4 (12.04.2004)
++- removed dummy asfs_notify_change (this fixes major bug introduced
++  in 1.0beta3 - file size wasn't written to disk) until it will 
++  be implemented completely
++
++v1.0beta3 (22.03.2004) - still beta
++- updated for 2.6.x kernels VFS changes
++- code clean-up 
++- added dummy asfs_notify_change (chmod now returns no errors)
++- added symlinks write support
++- fixed: ASFS_SB(sb)->flags was always zero
++
++v1.0beta2 (11.01.2004) - special version for Pegasos][ kernel
++- separated read and write functions, can be compiled also
++  as read-only fs
++
++v1.0beta1 (02.12.2003) - first public beta with write support
++- added dentry hashing/comparing routines
++- code clean-up
++
++v1.0aplha4 (30.11.2003) - preparing for first public beta
++- fixed some problems with renaming/moving files
++- fixed two major bugs, which didn't occur when fs was mounted
++  on loopback device (newly allocated blocks were not written to
++  disk and state bits were not set correctly on newly mapped file
++  blocks)
++- fixed many small bugs in io code (some buffers were not freed)
++- added/modified sb locks in asfs_lookup and asfs_getblock
++- fixed serious bug in file block allocation routines
++
++v1.0aplha3 (23.11.2003)
++- added (hopefully) all byteswap code, should now work again on 
++  little-endian systems (also with write support!)
++- updated documentation
++
++v1.0alpha2 (13.11.2003) 
++- now alocates file blocks in chunks during one request
++- fixed some dead-locks, other fixes
++
++v1.0alpha (02.11.2003) - first working version with full write support
++- too much to list it here ;)
++
++... (working on write support)
++
++v0.7 (12.10.2003) - internal realase
++- added asfs_breadcheck, modified asfs_get_node, asfs_search_BTree, 
++  no more from_be32/16 macros, other...
++- code splitted into several files
++
++v0.6 (04.09.2003) - final read-only version
++- added support for HashTables, directory scaning should be
++  MUCH faster now
++- added checking of block IDs before reading any data from block
++
++v0.5 (19.07.2003)
++- added simple but effective extent cache - real speed-up 
++  in reading large files
++- added read support for symlinks - based on AFFS symlinks
++
++v0.4 (10.07.2003)
++- third code clean-up (thanks to Roman Zippel for advice)
++- now uses generic readpage and readinode routines
++
++v0.3beta (17.06.2003)
++- second code clean-up
++
++v0.2beta2 (15.06.2003)
++- fixed yet another stupid bug - driver can't read root block on little-endian systems
++v0.2beta (15.06.2003)
++- fixed stupid bug - now files have 'file' flag (S_IFREG) set...
++- added mount options to set uid, gid and mode of files and dirs
++- made hidden files & dirs really hidden (= not listed in directories)
++- code clean-up
++
++v0.1beta (11.06.2003) 
++- after many kernel crashes, finally got it! 
++- first working read-only filesystem driver
+diff -Nur linux-2.6.19-rc6/fs/asfs/Makefile linux-2.6.19-rc6/fs/asfs/Makefile
+--- linux-2.6.19-rc6/fs/asfs/Makefile	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.19-rc6/fs/asfs/Makefile	2006-11-24 18:19:03.000000000 +0100
+@@ -0,0 +1,8 @@
++#
++# Makefile for the linux asfs filesystem routines.
++#
++
++obj-$(CONFIG_ASFS_FS) += asfs.o
++
++asfs-y += dir.o extents.o file.o inode.o namei.o nodes.o objects.o super.o symlink.o
++asfs-$(CONFIG_ASFS_RW) += adminspace.o bitfuncs.o 
+diff -Nur linux-2.6.19-rc6/fs/asfs/adminspace.c linux-2.6.19-rc6/fs/asfs/adminspace.c
+--- linux-2.6.19-rc6/fs/asfs/adminspace.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.19-rc6/fs/asfs/adminspace.c	2006-11-24 18:19:03.000000000 +0100
 @@ -0,0 +1,446 @@
 +/*
 + *
@@ -633,9 +833,9 @@
 +}
 +
 +#endif
-diff -urN linux-2.6.18/fs/asfs/asfs_fs.h linux-2.6.18-asfs-1.0b11/fs/asfs/asfs_fs.h
---- linux-2.6.18/fs/asfs/asfs_fs.h	1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-asfs-1.0b11/fs/asfs/asfs_fs.h	2006-09-22 23:18:03.000000000 +0200
+diff -Nur linux-2.6.19-rc6/fs/asfs/asfs_fs.h linux-2.6.19-rc6/fs/asfs/asfs_fs.h
+--- linux-2.6.19-rc6/fs/asfs/asfs_fs.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.19-rc6/fs/asfs/asfs_fs.h	2006-11-24 18:19:03.000000000 +0100
 @@ -0,0 +1,217 @@
 +#ifndef __LINUX_ASFS_FS_H
 +#define __LINUX_ASFS_FS_H
@@ -854,10 +1054,9 @@
 +int asfs_write_symlink(struct inode *symfile, const char *symname);
 +
 +#endif
-Pliki binarne linux-2.6.18/fs/asfs/asfs.ko i linux-2.6.18-asfs-1.0b11/fs/asfs/asfs.ko siê ró¿ni±
-diff -urN linux-2.6.18/fs/asfs/bitfuncs.c linux-2.6.18-asfs-1.0b11/fs/asfs/bitfuncs.c
---- linux-2.6.18/fs/asfs/bitfuncs.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-asfs-1.0b11/fs/asfs/bitfuncs.c	2006-09-22 22:52:37.000000000 +0200
+diff -Nur linux-2.6.19-rc6/fs/asfs/bitfuncs.c linux-2.6.19-rc6/fs/asfs/bitfuncs.c
+--- linux-2.6.19-rc6/fs/asfs/bitfuncs.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.19-rc6/fs/asfs/bitfuncs.c	2006-11-24 18:19:03.000000000 +0100
 @@ -0,0 +1,171 @@
 +/*
 + *
@@ -1030,9 +1229,9 @@
 +	}
 +	return (orgbits - bits);
 +}
-diff -urN linux-2.6.18/fs/asfs/bitfuncs.h linux-2.6.18-asfs-1.0b11/fs/asfs/bitfuncs.h
---- linux-2.6.18/fs/asfs/bitfuncs.h	1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-asfs-1.0b11/fs/asfs/bitfuncs.h	2006-09-22 22:52:37.000000000 +0200
+diff -Nur linux-2.6.19-rc6/fs/asfs/bitfuncs.h linux-2.6.19-rc6/fs/asfs/bitfuncs.h
+--- linux-2.6.19-rc6/fs/asfs/bitfuncs.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.19-rc6/fs/asfs/bitfuncs.h	2006-11-24 18:19:03.000000000 +0100
 @@ -0,0 +1,59 @@
 +/*
 + *
@@ -1093,129 +1292,9 @@
 +int bmset(u32 *, int, int, int);
 +
 +#endif
-diff -urN linux-2.6.18/fs/asfs/Changes linux-2.6.18-asfs-1.0b11/fs/asfs/Changes
---- linux-2.6.18/fs/asfs/Changes	1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-asfs-1.0b11/fs/asfs/Changes	2006-09-22 23:24:31.000000000 +0200
-@@ -0,0 +1,116 @@
-+
-+Amiga Smart File System, Linux implementation
-+
-+Please direct bug reports to: marek at amiga.pl
-+
-+History:
-+
-+v1.0beta11 (22.09.2006)
-+- adapted to 2.6.18 kernel VFS changes
-+- made some functions static to reduce overhead in kernel namespace
-+
-+v1.0beta10 (13.06.2005)
-+- fixed ugly bug introduced in beta9 that caused kernel crash on x86
-+  (thanks to Emiliano for reporting it!)
-+
-+v1.0beta9 (17.03.2005)
-+- added NLS support (thanks to Pavel Fedin!)
-+
-+v1.0beta8 (07.01.2005)
-+- adapted to 2.6.10 kernel VFS changes
-+- added workaround for buggy Mandrake kernel headers
-+
-+v1.0beta7 (25.06.2004)
-+- small changes in documentation
-+- code clean up: bitfuncs.c, super.c, inode.c, *.h, Makefile, added 
-+  asfs_ prefix to function names, made some functions static
-+  (big thanks to Christoph Hellwig for advice!)
-+- fixed minor bugs (inode leak in super.c, not-realesed buffer during 
-+  object renaming in inode.c)
-+- now files/dirs are created with global ownership/permission bits
-+
-+v1.0beta6 (04.06.2004)
-+- fixed: ASFS_SB(sb)->flags was always zero in 2.6.x code
-+
-+v1.0beta5 (07.05.2004)
-+- finally fixed a problem with file size attrib. not being written
-+  to disk
-+- fixed some problems with GCC 3.x and debug enabled
-+
-+v1.0beta4 (12.04.2004)
-+- removed dummy asfs_notify_change (this fixes major bug introduced
-+  in 1.0beta3 - file size wasn't written to disk) until it will 
-+  be implemented completely
-+
-+v1.0beta3 (22.03.2004) - still beta
-+- updated for 2.6.x kernels VFS changes
-+- code clean-up 
-+- added dummy asfs_notify_change (chmod now returns no errors)
-+- added symlinks write support
-+- fixed: ASFS_SB(sb)->flags was always zero
-+
-+v1.0beta2 (11.01.2004) - special version for Pegasos][ kernel
-+- separated read and write functions, can be compiled also
-+  as read-only fs
-+
-+v1.0beta1 (02.12.2003) - first public beta with write support
-+- added dentry hashing/comparing routines
-+- code clean-up
-+
-+v1.0aplha4 (30.11.2003) - preparing for first public beta
-+- fixed some problems with renaming/moving files
-+- fixed two major bugs, which didn't occur when fs was mounted
-+  on loopback device (newly allocated blocks were not written to
-+  disk and state bits were not set correctly on newly mapped file
-+  blocks)
-+- fixed many small bugs in io code (some buffers were not freed)
-+- added/modified sb locks in asfs_lookup and asfs_getblock
-+- fixed serious bug in file block allocation routines
-+
-+v1.0aplha3 (23.11.2003)
-+- added (hopefully) all byteswap code, should now work again on 
-+  little-endian systems (also with write support!)
-+- updated documentation
-+
-+v1.0alpha2 (13.11.2003) 
-+- now alocates file blocks in chunks during one request
-+- fixed some dead-locks, other fixes
-+
-+v1.0alpha (02.11.2003) - first working version with full write support
-+- too much to list it here ;)
-+
-+... (working on write support)
-+
-+v0.7 (12.10.2003) - internal realase
-+- added asfs_breadcheck, modified asfs_get_node, asfs_search_BTree, 
-+  no more from_be32/16 macros, other...
-+- code splitted into several files
-+
-+v0.6 (04.09.2003) - final read-only version
-+- added support for HashTables, directory scaning should be
-+  MUCH faster now
-+- added checking of block IDs before reading any data from block
-+
-+v0.5 (19.07.2003)
-+- added simple but effective extent cache - real speed-up 
-+  in reading large files
-+- added read support for symlinks - based on AFFS symlinks
-+
-+v0.4 (10.07.2003)
-+- third code clean-up (thanks to Roman Zippel for advice)
-+- now uses generic readpage and readinode routines
-+
-+v0.3beta (17.06.2003)
-+- second code clean-up
-+
-+v0.2beta2 (15.06.2003)
-+- fixed yet another stupid bug - driver can't read root block on little-endian systems
-+v0.2beta (15.06.2003)
-+- fixed stupid bug - now files have 'file' flag (S_IFREG) set...
-+- added mount options to set uid, gid and mode of files and dirs
-+- made hidden files & dirs really hidden (= not listed in directories)
-+- code clean-up
-+
-+v0.1beta (11.06.2003) 
-+- after many kernel crashes, finally got it! 
-+- first working read-only filesystem driver
-diff -urN linux-2.6.18/fs/asfs/dir.c linux-2.6.18-asfs-1.0b11/fs/asfs/dir.c
---- linux-2.6.18/fs/asfs/dir.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-asfs-1.0b11/fs/asfs/dir.c	2006-09-22 22:52:37.000000000 +0200
+diff -Nur linux-2.6.19-rc6/fs/asfs/dir.c linux-2.6.19-rc6/fs/asfs/dir.c
+--- linux-2.6.19-rc6/fs/asfs/dir.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.19-rc6/fs/asfs/dir.c	2006-11-24 18:19:03.000000000 +0100
 @@ -0,0 +1,240 @@
 +/*
 + *
@@ -1457,9 +1536,9 @@
 +	d_add(dentry, inode);
 +	return ERR_PTR(res);
 +}
-diff -urN linux-2.6.18/fs/asfs/extents.c linux-2.6.18-asfs-1.0b11/fs/asfs/extents.c
---- linux-2.6.18/fs/asfs/extents.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-asfs-1.0b11/fs/asfs/extents.c	2006-09-22 23:22:48.000000000 +0200
+diff -Nur linux-2.6.19-rc6/fs/asfs/extents.c linux-2.6.19-rc6/fs/asfs/extents.c
+--- linux-2.6.19-rc6/fs/asfs/extents.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.19-rc6/fs/asfs/extents.c	2006-11-24 18:19:03.000000000 +0100
 @@ -0,0 +1,586 @@
 +/*
 + *
@@ -2047,9 +2126,9 @@
 +	return errorcode;
 +}
 +#endif
-diff -urN linux-2.6.18/fs/asfs/file.c linux-2.6.18-asfs-1.0b11/fs/asfs/file.c
---- linux-2.6.18/fs/asfs/file.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-asfs-1.0b11/fs/asfs/file.c	2006-09-22 22:52:37.000000000 +0200
+diff -Nur linux-2.6.19-rc6/fs/asfs/file.c linux-2.6.19-rc6/fs/asfs/file.c
+--- linux-2.6.19-rc6/fs/asfs/file.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.19-rc6/fs/asfs/file.c	2006-11-24 18:19:03.000000000 +0100
 @@ -0,0 +1,251 @@
 +/*
 + *
@@ -2302,9 +2381,9 @@
 +}
 +
 +#endif
-diff -urN linux-2.6.18/fs/asfs/inode.c linux-2.6.18-asfs-1.0b11/fs/asfs/inode.c
---- linux-2.6.18/fs/asfs/inode.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-asfs-1.0b11/fs/asfs/inode.c	2006-09-22 23:22:35.000000000 +0200
+diff -Nur linux-2.6.19-rc6/fs/asfs/inode.c linux-2.6.19-rc6/fs/asfs/inode.c
+--- linux-2.6.19-rc6/fs/asfs/inode.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.19-rc6/fs/asfs/inode.c	2006-11-24 18:19:03.000000000 +0100
 @@ -0,0 +1,436 @@
 +/*
 + *
@@ -2742,21 +2821,9 @@
 +}
 +*/
 +#endif
-diff -urN linux-2.6.18/fs/asfs/Makefile linux-2.6.18-asfs-1.0b11/fs/asfs/Makefile
---- linux-2.6.18/fs/asfs/Makefile	1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-asfs-1.0b11/fs/asfs/Makefile	2006-09-22 22:52:37.000000000 +0200
-@@ -0,0 +1,8 @@
-+#
-+# Makefile for the linux asfs filesystem routines.
-+#
-+
-+obj-$(CONFIG_ASFS_FS) += asfs.o
-+
-+asfs-y += dir.o extents.o file.o inode.o namei.o nodes.o objects.o super.o symlink.o
-+asfs-$(CONFIG_ASFS_RW) += adminspace.o bitfuncs.o 
-diff -urN linux-2.6.18/fs/asfs/namei.c linux-2.6.18-asfs-1.0b11/fs/asfs/namei.c
---- linux-2.6.18/fs/asfs/namei.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-asfs-1.0b11/fs/asfs/namei.c	2006-09-22 22:52:37.000000000 +0200
+diff -Nur linux-2.6.19-rc6/fs/asfs/namei.c linux-2.6.19-rc6/fs/asfs/namei.c
+--- linux-2.6.19-rc6/fs/asfs/namei.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.19-rc6/fs/asfs/namei.c	2006-11-24 18:19:03.000000000 +0100
 @@ -0,0 +1,197 @@
 +/*
 + *
@@ -2955,9 +3022,9 @@
 +		to[limit-1] = '\0';
 +	}
 +}
-diff -urN linux-2.6.18/fs/asfs/nodes.c linux-2.6.18-asfs-1.0b11/fs/asfs/nodes.c
---- linux-2.6.18/fs/asfs/nodes.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-asfs-1.0b11/fs/asfs/nodes.c	2006-09-22 22:52:37.000000000 +0200
+diff -Nur linux-2.6.19-rc6/fs/asfs/nodes.c linux-2.6.19-rc6/fs/asfs/nodes.c
+--- linux-2.6.19-rc6/fs/asfs/nodes.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.19-rc6/fs/asfs/nodes.c	2006-11-24 18:19:03.000000000 +0100
 @@ -0,0 +1,455 @@
 +/*
 + *
@@ -3414,9 +3481,9 @@
 +}
 +
 +#endif
-diff -urN linux-2.6.18/fs/asfs/objects.c linux-2.6.18-asfs-1.0b11/fs/asfs/objects.c
---- linux-2.6.18/fs/asfs/objects.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-asfs-1.0b11/fs/asfs/objects.c	2006-09-22 23:22:42.000000000 +0200
+diff -Nur linux-2.6.19-rc6/fs/asfs/objects.c linux-2.6.19-rc6/fs/asfs/objects.c
+--- linux-2.6.19-rc6/fs/asfs/objects.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.19-rc6/fs/asfs/objects.c	2006-11-24 18:19:03.000000000 +0100
 @@ -0,0 +1,765 @@
 +/*
 + *
@@ -4183,9 +4250,9 @@
 +	return 0;
 +}
 +#endif
-diff -urN linux-2.6.18/fs/asfs/super.c linux-2.6.18-asfs-1.0b11/fs/asfs/super.c
---- linux-2.6.18/fs/asfs/super.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-asfs-1.0b11/fs/asfs/super.c	2006-09-22 23:22:22.000000000 +0200
+diff -Nur linux-2.6.19-rc6/fs/asfs/super.c linux-2.6.19-rc6/fs/asfs/super.c
+--- linux-2.6.19-rc6/fs/asfs/super.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.19-rc6/fs/asfs/super.c	2006-11-24 18:19:03.000000000 +0100
 @@ -0,0 +1,497 @@
 +/*
 + *
@@ -4684,9 +4751,9 @@
 +
 +module_init(init_asfs_fs)
 +module_exit(exit_asfs_fs)
-diff -urN linux-2.6.18/fs/asfs/symlink.c linux-2.6.18-asfs-1.0b11/fs/asfs/symlink.c
---- linux-2.6.18/fs/asfs/symlink.c	1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-asfs-1.0b11/fs/asfs/symlink.c	2006-09-22 22:52:37.000000000 +0200
+diff -Nur linux-2.6.19-rc6/fs/asfs/symlink.c linux-2.6.19-rc6/fs/asfs/symlink.c
+--- linux-2.6.19-rc6/fs/asfs/symlink.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.19-rc6/fs/asfs/symlink.c	2006-11-24 18:19:03.000000000 +0100
 @@ -0,0 +1,235 @@
 +/*
 + *
@@ -4923,77 +4990,8 @@
 +}
 +
 +#endif
-diff -urN linux-2.6.18/fs/Kconfig linux-2.6.18-asfs-1.0b11/fs/Kconfig
---- linux-2.6.18/fs/Kconfig	2006-09-22 22:48:22.000000000 +0200
-+++ linux-2.6.18-asfs-1.0b11/fs/Kconfig	2006-09-22 22:52:37.000000000 +0200
-@@ -955,6 +955,53 @@
- 	  To compile this file system support as a module, choose M here: the
- 	  module will be called affs.  If unsure, say N.
- 
-+config ASFS_FS
-+	tristate "Amiga SFS file system support (EXPERIMENTAL)"
-+	select NLS
-+	depends on EXPERIMENTAL
-+	help
-+
-+	  The Amiga Smart FileSystem (SFS) is the file system used on hard 
-+	  disks by Amiga(tm) and MorphOS(tm) systems.  Say Y if you want 
-+	  to be able to read files from an Amiga SFS partition on your hard 
-+	  drive.
-+
-+	  For more information read <file:Documentation/filesystems/asfs.txt>
-+
-+	  To compile this file system support as a module, choose M here: the
-+	  module will be called asfs.
-+
-+	  If unsure, say N.
-+
-+config ASFS_DEFAULT_CODEPAGE
-+	string "Default codepage for SFS"
-+	depends on ASFS_FS
-+	default ""
-+	help
-+	  This option should be set to the codepage of your SFS filesystems.
-+	  It can be overridden with the 'codepage' mount option. Leave it blank 
-+	  or enter 'none' to disable filename converting.
-+
-+	  Use full codepage name (for example 'cp1251' instead of '1251') here, 
-+	  this allows to specify any character set, not only numbered one (like 
-+	  'iso8859-2').
-+
-+	  If unsure, leave it blank.
-+
-+config ASFS_RW
-+	bool "Amiga SFS write support (DANGEROUS)"
-+	depends on ASFS_FS
-+	help
-+
-+	  If you say Y here, you will be able to write to ASFS file
-+	  systems as well as read from them. The read-write support in ASFS
-+	  is in beta stage. This means that useing it to write files to SFS 
-+	  partitions is DANGEROUS and COULD corrupt the filesystem.
-+
-+	  For more information read <file:Documentation/filesystems/asfs.txt>
-+
-+	  If unsure, say N.
-+
- config HFS_FS
- 	tristate "Apple Macintosh file system support (EXPERIMENTAL)"
- 	depends on EXPERIMENTAL
-diff -urN linux-2.6.18/fs/Makefile linux-2.6.18-asfs-1.0b11/fs/Makefile
---- linux-2.6.18/fs/Makefile	2006-09-22 22:48:22.000000000 +0200
-+++ linux-2.6.18-asfs-1.0b11/fs/Makefile	2006-09-22 22:52:37.000000000 +0200
-@@ -85,6 +85,7 @@
- obj-$(CONFIG_JFFS_FS)		+= jffs/
- obj-$(CONFIG_JFFS2_FS)		+= jffs2/
- obj-$(CONFIG_AFFS_FS)		+= affs/
-+obj-$(CONFIG_ASFS_FS)		+= asfs/
- obj-$(CONFIG_ROMFS_FS)		+= romfs/
- obj-$(CONFIG_QNX4FS_FS)		+= qnx4/
- obj-$(CONFIG_AUTOFS_FS)		+= autofs/
-diff -urN linux-2.6.18/include/linux/amigasfs.h linux-2.6.18-asfs-1.0b11/include/linux/amigasfs.h
---- linux-2.6.18/include/linux/amigasfs.h	1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-asfs-1.0b11/include/linux/amigasfs.h	2006-09-22 22:52:37.000000000 +0200
+--- linux-2.6.19-rc6/include/linux/amigasfs.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.19-rc6/include/linux/amigasfs.h	2006-11-24 18:19:03.000000000 +0100
 @@ -0,0 +1,276 @@
 +#ifndef __LINUX_AMIGASFS_H
 +#define __LINUX_AMIGASFS_H
@@ -5271,6 +5269,3 @@
 +};
 +
 +#endif
-
-
-

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0001-Fix-compilation-issue-when-PPC_MPC52xx-and-PPC_MERGE-are-selected.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0001-Fix-compilation-issue-when-PPC_MPC52xx-and-PPC_MERGE-are-selected.diff	Sat Nov 25 17:21:50 2006
@@ -0,0 +1,26 @@
+From 9f3ff0ffed7c1fc1dbf3c0628f1a22a20d0846ce Mon Sep 17 00:00:00 2001
+From: Nicolas DET <nd at bplan-gmbh.de>
+Date: Fri, 24 Nov 2006 12:40:48 +0100
+Subject: [PATCH] Fix compilation issue when PPC_MPC52xx and PPC_MERGE are selected
+
+Signed-off-by: Nicolas DET <nd at bplan-gmbh.de>
+---
+ include/asm-ppc/io.h |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h
+index a4c411b..8ed380c 100644
+--- a/include/asm-ppc/io.h
++++ b/include/asm-ppc/io.h
+@@ -26,7 +26,7 @@ #define PREP_PCI_DRAM_OFFSET 	0x80000000
+ 
+ #if defined(CONFIG_4xx)
+ #include <asm/ibm4xx.h>
+-#elif defined(CONFIG_PPC_MPC52xx)
++#elif defined(CONFIG_PPC_MPC52xx) && !defined(CONFIG_PPC_MERGE)
+ #include <asm/mpc52xx.h>
+ #elif defined(CONFIG_8xx)
+ #include <asm/mpc8xx.h>
+-- 
+1.4.3.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0002-Add-USB-OHCI-glue-for-OpenFirmware-devices.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0002-Add-USB-OHCI-glue-for-OpenFirmware-devices.diff	Sat Nov 25 17:21:50 2006
@@ -0,0 +1,360 @@
+From bc515daf6d0845b0ddb739f3ba822b66f84344a7 Mon Sep 17 00:00:00 2001
+From: Nicolas DET <nd at bplan-gmbh.de>
+Date: Fri, 24 Nov 2006 12:55:37 +0100
+Subject: [PATCH] Add USB/OHCI glue for OpenFirmware devices
+
+Signed-off-by: Nicolas DET <nd at bplan-gmbh.de>
+---
+ drivers/usb/host/Kconfig       |   19 +++
+ drivers/usb/host/ohci-hcd.c    |    6 +
+ drivers/usb/host/ohci-ppc-of.c |  285 ++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 310 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
+index cf10cbc..f5ef6f5 100644
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -106,6 +106,25 @@ 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 for OpenFirmware platform"
++	depends on USB_OHCI_HCD && PPC_OF
++	default y
++	---help---
++	  Enables support for the USB controller PowerPC OpenFirmware platform
++
++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
++
++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)
+diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
+index 9be6b30..04413b6 100644
+--- a/drivers/usb/host/ohci-hcd.c
++++ b/drivers/usb/host/ohci-hcd.c
+@@ -930,6 +930,10 @@ #ifdef CONFIG_USB_OHCI_HCD_PPC_SOC
+ #include "ohci-ppc-soc.c"
+ #endif
+ 
++#ifdef CONFIG_USB_OHCI_HCD_PPC_OF
++#include "ohci-ppc-of.c"
++#endif
++
+ #if defined(CONFIG_ARCH_AT91RM9200) || defined(CONFIG_ARCH_AT91SAM9261)
+ #include "ohci-at91.c"
+ #endif
+@@ -950,6 +954,8 @@ #if !(defined(CONFIG_PCI) \
+       || defined (CONFIG_ARCH_AT91RM9200) \
+       || defined (CONFIG_ARCH_AT91SAM9261) \
+       || defined (CONFIG_ARCH_PNX4008) \
++      || defined (CONFIG_USB_OHCI_HCD_PPC_OF_LE) \
++      || defined (CONFIG_USB_OHCI_HCD_PPC_OF_BE) \
+ 	)
+ #error "missing bus glue for ohci-hcd"
+ #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..30ce520
+--- /dev/null
++++ b/drivers/usb/host/ohci-ppc-of.c
+@@ -0,0 +1,285 @@
++/*
++ * 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 2003-2005 MontaVista Software Inc.
++ *
++ * Probe and init OHCI Big endian HC from OpenFirmware device tree
++ * Tested on Efika 5k2
++ *
++ * Modified by Dale Farnsworth <dale at farnsworth.org> from ohci-sa1111.c
++ *
++ * This file is licenced under the GPL.
++ */
++
++#include <linux/signal.h>
++
++#include <asm/of_device.h>
++#include <asm/of_platform.h>
++#include <asm/prom.h>
++
++/* configure so an HC device and id are always provided */
++/* always called with process context; sleeping is OK */
++
++/*
++ * usb_hcd_ppc_of_probe - initialize On-Chip HCDs
++ * Context: !in_interrupt()
++ *
++ * Allocates basic resources for this USB host controller.
++ *
++ * Store this function in the HCD's struct pci_driver as probe().
++ */
++static int usb_hcd_ppc_of_probe(const struct hc_driver *driver,
++			  struct of_device *dev, int is_bigendian)
++{
++	int retval;
++	struct usb_hcd *hcd;
++	struct ohci_hcd	*ohci;
++	struct resource res;
++	int irq;
++	int ret;
++
++	pr_debug("initializing PPC-OF USB Controller\n");
++
++	if ((ret = of_address_to_resource(dev->node, 0, &res)) != 0)
++		return ret;
++
++	hcd = usb_create_hcd(driver, &dev->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)) {
++		pr_debug(__FILE__ ": request_mem_region failed\n");
++		retval = -EBUSY;
++		goto err1;
++	}
++
++	irq = irq_of_parse_and_map(dev->node, 0);
++	if (irq == NO_IRQ) {
++		retval = -EBUSY;
++		goto err2;
++	}
++
++	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
++	if (!hcd->regs) {
++		pr_debug(__FILE__ ": ioremap failed\n");
++		retval = -ENOMEM;
++		goto err2;
++	}
++
++	ohci = hcd_to_ohci(hcd);
++	if (is_bigendian)
++		ohci->flags |= OHCI_BIG_ENDIAN;
++
++	ohci_hcd_init(ohci);
++
++	retval = usb_add_hcd(hcd, irq, 0);
++	if (retval == 0)
++		return retval;
++
++	pr_debug("Removing PPC-OF USB Controller\n");
++
++	iounmap(hcd->regs);
++ err2:
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++ err1:
++ 	usb_put_hcd(hcd);
++	return retval;
++}
++
++
++/* may be called without controller electrically present */
++/* may be called with controller, bus, and devices active */
++
++/*
++ * usb_hcd_ppc_of_remove - shutdown processing for On-Chip HCDs
++ * @pdev: USB Host Controller being removed
++ * Context: !in_interrupt()
++ *
++ * Reverses the effect of usb_hcd_ppc_of_probe().
++ * It is always called from a thread
++ * context, normally "rmmod", "apmd", or something similar.
++ *
++ */
++static void usb_hcd_ppc_of_remove(struct usb_hcd *hcd,
++		struct of_device *op)
++{
++	usb_remove_hcd(hcd);
++
++	pr_debug("stopping PPC-OF USB Controller\n");
++
++	iounmap(hcd->regs);
++	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++	usb_put_hcd(hcd);
++}
++
++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,
++	.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 ohci_hcd_ppc_of_drv_remove(struct of_device *op)
++{
++	struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
++	dev_set_drvdata(&op->dev, NULL);
++
++	usb_hcd_ppc_of_remove(hcd, op);
++	return 0;
++}
++
++static int ohci_hcd_ppc_of_drv_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
++	{},
++};
++
++static int __devinit
++ohci_hcd_ppc_of_drv_probe(struct of_device *op, const struct of_device_id *match)
++{
++	struct device_node *dev;
++	int ret;
++	int is_bigendian;
++
++	if (usb_disabled())
++		return -ENODEV;
++
++	dev = op->node;
++	is_bigendian = 0;
++
++	if ( device_is_compatible(dev, "ohci-bigendian") )
++		is_bigendian = 1;
++
++	if ( device_is_compatible(dev, "ohci-be") )
++		is_bigendian = 1;
++
++	ret = usb_hcd_ppc_of_probe(&ohci_ppc_of_hc_driver, op, is_bigendian);
++	return ret;
++}
++
++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_drv_probe,
++	.remove		= ohci_hcd_ppc_of_drv_remove,
++	.shutdown 	= ohci_hcd_ppc_of_drv_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,
++	},
++};
++
++static int __init ohci_hcd_ppc_of_init(void)
++{
++	pr_debug(DRIVER_INFO " (PPC OF)\n");
++	pr_debug("block sizes: ed %d td %d\n", sizeof(struct ed),
++							sizeof(struct td));
++
++	return of_register_platform_driver(&ohci_hcd_ppc_of_driver);
++}
++
++static void __exit ohci_hcd_ppc_of_cleanup(void)
++{
++	of_unregister_platform_driver(&ohci_hcd_ppc_of_driver);
++}
++
++module_init(ohci_hcd_ppc_of_init);
++module_exit(ohci_hcd_ppc_of_cleanup);
++
+-- 
+1.4.3.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0003-Add-MPC5200-serial-driver.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0003-Add-MPC5200-serial-driver.diff	Sat Nov 25 17:21:50 2006
@@ -0,0 +1,719 @@
+From 0ac70faf67a7e5e3f24a841ace4658336f8f98df Mon Sep 17 00:00:00 2001
+From: Nicolas DET <nd at bplan-gmbh.de>
+Date: Fri, 24 Nov 2006 13:00:06 +0100
+Subject: [PATCH] Add MPC5200 serial driver
+
+Signed-off-by: Nicolas DET <nd at bplan-gmbh.de>
+---
+ drivers/serial/mpc52xx_uart.c |  287 +++++++++++++++++++++++++----------------
+ 1 files changed, 178 insertions(+), 109 deletions(-)
+
+diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
+index 4f80c5b..debcd7b 100644
+--- a/drivers/serial/mpc52xx_uart.c
++++ b/drivers/serial/mpc52xx_uart.c
+@@ -1,6 +1,4 @@
+ /*
+- * drivers/serial/mpc52xx_uart.c
+- *
+  * Driver for the PSC of the Freescale MPC52xx PSCs configured as UARTs.
+  *
+  * FIXME According to the usermanual the status bits in the status register
+@@ -14,18 +12,18 @@
+  *
+  *
+  * Maintainer : Sylvain Munaut <tnt at 246tNt.com>
+- * 
++ *
+  * Some of the code has been inspired/copied from the 2.4 code written
+  * by Dale Farnsworth <dfarnsworth at mvista.com>.
+- * 
++ *
+  * Copyright (C) 2004-2005 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.
+  */
+- 
++
+ /* Platform device Usage :
+  *
+  * Since PSCs can have multiple function, the correct driver for each one
+@@ -44,7 +42,8 @@
+  * will be mapped to.
+  */
+ 
+-#include <linux/platform_device.h>
++#define DEBUG
++
+ #include <linux/module.h>
+ #include <linux/tty.h>
+ #include <linux/serial.h>
+@@ -53,6 +52,8 @@ #include <linux/console.h>
+ 
+ #include <asm/delay.h>
+ #include <asm/io.h>
++#include <asm/of_device.h>
++#include <asm/of_platform.h>
+ 
+ #include <asm/mpc52xx.h>
+ #include <asm/mpc52xx_psc.h>
+@@ -96,32 +97,43 @@ #else
+ #define uart_console(port)	(0)
+ #endif
+ 
++static struct of_device_id mpc52xx_uart_match[] = {
++	{
++		.type = "serial",
++		.compatible = "mpc52xx-psc-uart",
++	},
++	{
++		.type = "serial",
++		.compatible = "mpc5200-psc",
++	},	
++	{},
++};
+ 
+ /* ======================================================================== */
+ /* UART operations                                                          */
+ /* ======================================================================== */
+ 
+-static unsigned int 
++static unsigned int
+ mpc52xx_uart_tx_empty(struct uart_port *port)
+ {
+ 	int status = in_be16(&PSC(port)->mpc52xx_psc_status);
+ 	return (status & MPC52xx_PSC_SR_TXEMP) ? TIOCSER_TEMT : 0;
+ }
+ 
+-static void 
++static void
+ mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+ {
+ 	/* Not implemented */
+ }
+ 
+-static unsigned int 
++static unsigned int
+ mpc52xx_uart_get_mctrl(struct uart_port *port)
+ {
+ 	/* Not implemented */
+ 	return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+ }
+ 
+-static void 
++static void
+ mpc52xx_uart_stop_tx(struct uart_port *port)
+ {
+ 	/* port->lock taken by caller */
+@@ -129,7 +141,7 @@ mpc52xx_uart_stop_tx(struct uart_port *p
+ 	out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
+ }
+ 
+-static void 
++static void
+ mpc52xx_uart_start_tx(struct uart_port *port)
+ {
+ 	/* port->lock taken by caller */
+@@ -137,12 +149,12 @@ mpc52xx_uart_start_tx(struct uart_port *
+ 	out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
+ }
+ 
+-static void 
++static void
+ mpc52xx_uart_send_xchar(struct uart_port *port, char ch)
+ {
+ 	unsigned long flags;
+ 	spin_lock_irqsave(&port->lock, flags);
+-	
++
+ 	port->x_char = ch;
+ 	if (ch) {
+ 		/* Make sure tx interrupts are on */
+@@ -150,7 +162,7 @@ mpc52xx_uart_send_xchar(struct uart_port
+ 		port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
+ 		out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);
+ 	}
+-	
++
+ 	spin_unlock_irqrestore(&port->lock, flags);
+ }
+ 
+@@ -178,7 +190,7 @@ mpc52xx_uart_break_ctl(struct uart_port
+ 		out_8(&PSC(port)->command,MPC52xx_PSC_START_BRK);
+ 	else
+ 		out_8(&PSC(port)->command,MPC52xx_PSC_STOP_BRK);
+-	
++
+ 	spin_unlock_irqrestore(&port->lock, flags);
+ }
+ 
+@@ -197,11 +209,11 @@ mpc52xx_uart_startup(struct uart_port *p
+ 	/* Reset/activate the port, clear and enable interrupts */
+ 	out_8(&psc->command,MPC52xx_PSC_RST_RX);
+ 	out_8(&psc->command,MPC52xx_PSC_RST_TX);
+-	
++
+ 	out_be32(&psc->sicr,0);	/* UART mode DCD ignored */
+ 
+ 	out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /16 prescaler on */
+-	
++
+ 	out_8(&psc->rfcntl, 0x00);
+ 	out_be16(&psc->rfalarm, 0x1ff);
+ 	out_8(&psc->tfcntl, 0x07);
+@@ -209,10 +221,10 @@ mpc52xx_uart_startup(struct uart_port *p
+ 
+ 	port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY;
+ 	out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask);
+-	
++
+ 	out_8(&psc->command,MPC52xx_PSC_TX_ENABLE);
+ 	out_8(&psc->command,MPC52xx_PSC_RX_ENABLE);
+-		
++
+ 	return 0;
+ }
+ 
+@@ -220,19 +232,19 @@ static void
+ mpc52xx_uart_shutdown(struct uart_port *port)
+ {
+ 	struct mpc52xx_psc __iomem *psc = PSC(port);
+-	
++
+ 	/* Shut down the port, interrupt and all */
+ 	out_8(&psc->command,MPC52xx_PSC_RST_RX);
+ 	out_8(&psc->command,MPC52xx_PSC_RST_TX);
+-	
+-	port->read_status_mask = 0; 
++
++	port->read_status_mask = 0;
+ 	out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask);
+ 
+ 	/* Release interrupt */
+ 	free_irq(port->irq, port);
+ }
+ 
+-static void 
++static void
+ mpc52xx_uart_set_termios(struct uart_port *port, struct termios *new,
+                          struct termios *old)
+ {
+@@ -241,10 +253,10 @@ mpc52xx_uart_set_termios(struct uart_por
+ 	unsigned char mr1, mr2;
+ 	unsigned short ctr;
+ 	unsigned int j, baud, quot;
+-	
++
+ 	/* Prepare what we're gonna write */
+ 	mr1 = 0;
+-	
++
+ 	switch (new->c_cflag & CSIZE) {
+ 		case CS5:	mr1 |= MPC52xx_PSC_MODE_5_BITS;
+ 				break;
+@@ -261,8 +273,8 @@ mpc52xx_uart_set_termios(struct uart_por
+ 			MPC52xx_PSC_MODE_PARODD : MPC52xx_PSC_MODE_PAREVEN;
+ 	} else
+ 		mr1 |= MPC52xx_PSC_MODE_PARNONE;
+-	
+-	
++
++
+ 	mr2 = 0;
+ 
+ 	if (new->c_cflag & CSTOPB)
+@@ -276,7 +288,7 @@ mpc52xx_uart_set_termios(struct uart_por
+ 	baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
+ 	quot = uart_get_divisor(port, baud);
+ 	ctr = quot & 0xffff;
+-	
++
+ 	/* Get the lock */
+ 	spin_lock_irqsave(&port->lock, flags);
+ 
+@@ -290,14 +302,14 @@ mpc52xx_uart_set_termios(struct uart_por
+ 	 * boot for the console, all stuff is not yet ready to receive at that
+ 	 * time and that just makes the kernel oops */
+ 	/* while (j-- && mpc52xx_uart_int_rx_chars(port)); */
+-	while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) && 
++	while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) &&
+ 	       --j)
+ 		udelay(1);
+ 
+ 	if (!j)
+ 		printk(	KERN_ERR "mpc52xx_uart.c: "
+ 			"Unable to flush RX & TX fifos in-time in set_termios."
+-			"Some chars may have been lost.\n" ); 
++			"Some chars may have been lost.\n" );
+ 
+ 	/* Reset the TX & RX */
+ 	out_8(&psc->command,MPC52xx_PSC_RST_RX);
+@@ -309,7 +321,7 @@ mpc52xx_uart_set_termios(struct uart_por
+ 	out_8(&psc->mode,mr2);
+ 	out_8(&psc->ctur,ctr >> 8);
+ 	out_8(&psc->ctlr,ctr & 0xff);
+-	
++
+ 	/* Reenable TX & RX */
+ 	out_8(&psc->command,MPC52xx_PSC_TX_ENABLE);
+ 	out_8(&psc->command,MPC52xx_PSC_RX_ENABLE);
+@@ -332,7 +344,7 @@ mpc52xx_uart_release_port(struct uart_po
+ 		port->membase = NULL;
+ 	}
+ 
+-	release_mem_region(port->mapbase, MPC52xx_PSC_SIZE);
++	release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));
+ }
+ 
+ static int
+@@ -341,12 +353,13 @@ mpc52xx_uart_request_port(struct uart_po
+ 	int err;
+ 
+ 	if (port->flags & UPF_IOREMAP) /* Need to remap ? */
+-		port->membase = ioremap(port->mapbase, MPC52xx_PSC_SIZE);
++		port->membase = ioremap(port->mapbase,
++		                        sizeof(struct mpc52xx_psc));
+ 
+ 	if (!port->membase)
+ 		return -EINVAL;
+ 
+-	err = request_mem_region(port->mapbase, MPC52xx_PSC_SIZE,
++	err = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc),
+ 			"mpc52xx_psc_uart") != NULL ? 0 : -EBUSY;
+ 
+ 	if (err && (port->flags & UPF_IOREMAP)) {
+@@ -373,7 +386,7 @@ mpc52xx_uart_verify_port(struct uart_por
+ 
+ 	if ( (ser->irq != port->irq) ||
+ 	     (ser->io_type != SERIAL_IO_MEM) ||
+-	     (ser->baud_base != port->uartclk)  || 
++	     (ser->baud_base != port->uartclk) ||
+ 	     (ser->iomem_base != (void*)port->mapbase) ||
+ 	     (ser->hub6 != 0 ) )
+ 		return -EINVAL;
+@@ -404,11 +417,11 @@ static struct uart_ops mpc52xx_uart_ops
+ 	.verify_port	= mpc52xx_uart_verify_port
+ };
+ 
+-	
++
+ /* ======================================================================== */
+ /* Interrupt handling                                                       */
+ /* ======================================================================== */
+-	
++
+ static inline int
+ mpc52xx_uart_int_rx_chars(struct uart_port *port)
+ {
+@@ -435,11 +448,11 @@ #endif
+ 
+ 		flag = TTY_NORMAL;
+ 		port->icount.rx++;
+-	
++
+ 		if ( status & (MPC52xx_PSC_SR_PE |
+ 		               MPC52xx_PSC_SR_FE |
+ 		               MPC52xx_PSC_SR_RB) ) {
+-			
++
+ 			if (status & MPC52xx_PSC_SR_RB) {
+ 				flag = TTY_BREAK;
+ 				uart_handle_break(port);
+@@ -464,7 +477,7 @@ #endif
+ 	}
+ 
+ 	tty_flip_buffer_push(tty);
+-	
++
+ 	return in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY;
+ }
+ 
+@@ -509,25 +522,25 @@ mpc52xx_uart_int_tx_chars(struct uart_po
+ 	return 1;
+ }
+ 
+-static irqreturn_t 
++static irqreturn_t
+ mpc52xx_uart_int(int irq, void *dev_id)
+ {
+ 	struct uart_port *port = dev_id;
+ 	unsigned long pass = ISR_PASS_LIMIT;
+ 	unsigned int keepgoing;
+ 	unsigned short status;
+-	
++
+ 	spin_lock(&port->lock);
+-	
++
+ 	/* While we have stuff to do, we continue */
+ 	do {
+ 		/* If we don't find anything to do, we stop */
+-		keepgoing = 0; 
+-		
++		keepgoing = 0;
++
+ 		/* Read status */
+ 		status = in_be16(&PSC(port)->mpc52xx_psc_isr);
+ 		status &= port->read_status_mask;
+-			
++
+ 		/* Do we need to receive chars ? */
+ 		/* For this RX interrupts must be on and some chars waiting */
+ 		if ( status & MPC52xx_PSC_IMR_RXRDY )
+@@ -537,15 +550,15 @@ mpc52xx_uart_int(int irq, void *dev_id)
+ 		/* For this, TX must be ready and TX interrupt enabled */
+ 		if ( status & MPC52xx_PSC_IMR_TXRDY )
+ 			keepgoing |= mpc52xx_uart_int_tx_chars(port);
+-		
++
+ 		/* Limit number of iteration */
+ 		if ( !(--pass) )
+ 			keepgoing = 0;
+ 
+ 	} while (keepgoing);
+-	
++
+ 	spin_unlock(&port->lock);
+-	
++
+ 	return IRQ_HANDLED;
+ }
+ 
+@@ -563,13 +576,13 @@ mpc52xx_console_get_options(struct uart_
+ 	struct mpc52xx_psc __iomem *psc = PSC(port);
+ 	unsigned char mr1;
+ 
++	pr_debug("mpc52xx_console_get_options(port=%p)\n", port);
+ 	/* Read the mode registers */
+ 	out_8(&psc->command,MPC52xx_PSC_SEL_MODE_REG_1);
+ 	mr1 = in_8(&psc->mode);
+-	
++
+ 	/* CT{U,L}R are write-only ! */
+-	*baud = __res.bi_baudrate ?
+-		__res.bi_baudrate : CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
++	*baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
+ 
+ 	/* Parse them */
+ 	switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) {
+@@ -579,26 +592,26 @@ mpc52xx_console_get_options(struct uart_
+ 		case MPC52xx_PSC_MODE_8_BITS:
+ 		default:			*bits = 8;
+ 	}
+-	
++
+ 	if (mr1 & MPC52xx_PSC_MODE_PARNONE)
+ 		*parity = 'n';
+ 	else
+ 		*parity = mr1 & MPC52xx_PSC_MODE_PARODD ? 'o' : 'e';
+ }
+ 
+-static void  
++static void
+ mpc52xx_console_write(struct console *co, const char *s, unsigned int count)
+ {
+ 	struct uart_port *port = &mpc52xx_uart_ports[co->index];
+ 	struct mpc52xx_psc __iomem *psc = PSC(port);
+ 	unsigned int i, j;
+-	
++
+ 	/* Disable interrupts */
+ 	out_be16(&psc->mpc52xx_psc_imr, 0);
+ 
+ 	/* Wait the TX buffer to be empty */
+-	j = 5000000;	/* Maximum wait */	
+-	while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) && 
++	j = 5000000;	/* Maximum wait */
++	while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) &&
+ 	       --j)
+ 		udelay(1);
+ 
+@@ -606,14 +619,14 @@ mpc52xx_console_write(struct console *co
+ 	for (i = 0; i < count; i++, s++) {
+ 		/* Line return handling */
+ 		if (*s == '\n')
+-			out_8(&psc->mpc52xx_psc_buffer_8, '\r');
+-		
++			out_8(&psc->buffer.buffer_8, '\r');
++
+ 		/* Send the char */
+-		out_8(&psc->mpc52xx_psc_buffer_8, *s);
++		out_8(&psc->buffer.buffer_8, *s);
+ 
+ 		/* Wait the TX buffer to be empty */
+-		j = 20000;	/* Maximum wait */	
+-		while (!(in_be16(&psc->mpc52xx_psc_status) & 
++		j = 20000;	/* Maximum wait */
++		while (!(in_be16(&psc->mpc52xx_psc_status) &
+ 		         MPC52xx_PSC_SR_TXEMP) && --j)
+ 			udelay(1);
+ 	}
+@@ -626,33 +639,77 @@ static int __init
+ mpc52xx_console_setup(struct console *co, char *options)
+ {
+ 	struct uart_port *port = &mpc52xx_uart_ports[co->index];
++	struct device_node *np = NULL;
++	const struct of_device_id *dev_id = NULL;
++	struct device_node *np_idx;
++	const void *pp = NULL;
++	struct resource res;
++	int index = 0;
++	int ret;
+ 
+ 	int baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
+ 	int bits = 8;
+ 	int parity = 'n';
+ 	int flow = 'n';
+ 
+-	if (co->index < 0 || co->index >= MPC52xx_PSC_MAXNUM)
++	pr_debug("mpc52xx_console_setup co=%p, options=%s, index=%i\n",
++		 co, options, co->index);
++
++	for_each_node_by_type(np, "serial")
++	{
++		dev_id = of_match_node(mpc52xx_uart_match, np);
++		if (dev_id)
++			if (index++ == co->index)
++				break;
++	}
++ 
++	if (!np) {
++		pr_debug("PSC%x not found in device tree\n", co->index);
++		return -EINVAL;
++	}
++
++	/* Fetch register locations */
++	if ((ret = of_address_to_resource(np, 0, &res)) != 0) {
++		pr_debug("Could not get resources for PSC%x\n", index);
++		return ret;
++	}
++
++	/* Search for bus-frequency property in this node or a parent */
++	np_idx = np;
++	while (np_idx) {
++		if ((pp = get_property(np_idx, "bus-frequency", NULL)) != NULL)
++			break;
++		np_idx = of_get_parent(np_idx);
++	}
++	if (!pp) {
++		pr_debug("Could not find bus-frequency property!\n");
+ 		return -EINVAL;
+-	
++	}
++
+ 	/* Basic port init. Needed since we use some uart_??? func before
+ 	 * real init for early access */
+ 	spin_lock_init(&port->lock);
+-	port->uartclk	= __res.bi_ipbfreq / 2; /* Look at CTLR doc */
++	port->uartclk	= *(const u32*)pp / 2;
+ 	port->ops	= &mpc52xx_uart_ops;
+-	port->mapbase	= MPC52xx_PA(MPC52xx_PSCx_OFFSET(co->index+1));
++	port->mapbase = res.start;
++	port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc));
++	port->irq = irq_of_parse_and_map(np, 0);
+ 
+-	/* We ioremap ourself */
+-	port->membase = ioremap(port->mapbase, MPC52xx_PSC_SIZE);
+ 	if (port->membase == NULL)
+ 		return -EINVAL;
+ 
++	pr_debug("mpc52xx_psc at %lx mapped to %p; irq=%x freq=%i\n",
++	         port->mapbase, port->membase, port->irq, port->uartclk);
++
+ 	/* Setup the port parameters accoding to options */
+ 	if (options)
+ 		uart_parse_options(options, &baud, &parity, &bits, &flow);
+ 	else
+ 		mpc52xx_console_get_options(port, &baud, &parity, &bits, &flow);
+ 
++	pr_debug("Setting console parameters: %i %i%c1 flow=%c\n",
++	         baud, bits, parity, flow);
++
+ 	return uart_set_options(port, co, baud, parity, bits, flow);
+ }
+ 
+@@ -669,8 +726,8 @@ static struct console mpc52xx_console =
+ 	.data	= &mpc52xx_uart_driver,
+ };
+ 
+-	
+-static int __init 
++
++static int __init
+ mpc52xx_console_init(void)
+ {
+ 	register_console(&mpc52xx_console);
+@@ -705,28 +762,23 @@ static struct uart_driver mpc52xx_uart_d
+ /* ======================================================================== */
+ 
+ static int __devinit
+-mpc52xx_uart_probe(struct platform_device *dev)
++mpc52xx_uart_probe(struct of_device *op, const struct of_device_id *match)
+ {
+-	struct resource *res = dev->resource;
+-
++	static int idx = 0;
+ 	struct uart_port *port = NULL;
+-	int i, idx, ret;
++	struct resource res;
++	int ret;
++
++	dev_dbg(&op->dev, "mpc52xx_uart_probe(op=%p, match=%p)\n", op, match);
+ 
+ 	/* Check validity & presence */
+-	idx = dev->id;
+-	if (idx < 0 || idx >= MPC52xx_PSC_MAXNUM)
++	if (idx >= MPC52xx_PSC_MAXNUM)
+ 		return -EINVAL;
+ 
+-	if (!mpc52xx_match_psc_function(idx,"uart"))
+-		return -ENODEV;
+-
+ 	/* Init the port structure */
+ 	port = &mpc52xx_uart_ports[idx];
+ 
+-	memset(port, 0x00, sizeof(struct uart_port));
+-
+ 	spin_lock_init(&port->lock);
+-	port->uartclk	= __res.bi_ipbfreq / 2; /* Look at CTLR doc */
+ 	port->fifosize	= 512;
+ 	port->iotype	= UPIO_MEM;
+ 	port->flags	= UPF_BOOT_AUTOCONF |
+@@ -735,29 +787,36 @@ mpc52xx_uart_probe(struct platform_devic
+ 	port->ops	= &mpc52xx_uart_ops;
+ 
+ 	/* Search for IRQ and mapbase */
+-	for (i=0 ; i<dev->num_resources ; i++, res++) {
+-		if (res->flags & IORESOURCE_MEM)
+-			port->mapbase = res->start;
+-		else if (res->flags & IORESOURCE_IRQ)
+-			port->irq = res->start;
+-	}
+-	if (!port->irq || !port->mapbase)
++	if ((ret = of_address_to_resource(op->node, 0, &res)) != 0)
++		return ret;
++
++	port->mapbase = res.start;
++	port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc));
++	port->irq = irq_of_parse_and_map(op->node, 0);
++
++	dev_dbg(&op->dev, "mpc52xx-psc UART at %lx. mapped to %p, irq %x\n",
++	         port->mapbase, port->membase, port->irq);
++
++	//if (!port->irq || !port->mapbase) {
++	if (!port->mapbase) {
++		printk(KERN_ERR "Could not allocate resources for PSC\n");
+ 		return -EINVAL;
++	}
+ 
+ 	/* Add the port to the uart sub-system */
+ 	ret = uart_add_one_port(&mpc52xx_uart_driver, port);
+ 	if (!ret)
+-		platform_set_drvdata(dev, (void*)port);
++		dev_set_drvdata(&op->dev, (void*)port);
+ 
++	idx++;
+ 	return ret;
+ }
+ 
+ static int
+-mpc52xx_uart_remove(struct platform_device *dev)
++mpc52xx_uart_remove(struct of_device *op)
+ {
+-	struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev);
+-
+-	platform_set_drvdata(dev, NULL);
++	struct uart_port *port = dev_get_drvdata(&op->dev);
++	dev_set_drvdata(&op->dev, NULL);
+ 
+ 	if (port)
+ 		uart_remove_one_port(&mpc52xx_uart_driver, port);
+@@ -767,20 +826,20 @@ mpc52xx_uart_remove(struct platform_devi
+ 
+ #ifdef CONFIG_PM
+ static int
+-mpc52xx_uart_suspend(struct platform_device *dev, pm_message_t state)
++mpc52xx_uart_suspend(struct of_device *op, pm_message_t state)
+ {
+-	struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev);
++	struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev);
+ 
+-	if (sport)
++	if (port)
+ 		uart_suspend_port(&mpc52xx_uart_driver, port);
+ 
+ 	return 0;
+ }
+ 
+ static int
+-mpc52xx_uart_resume(struct platform_device *dev)
++mpc52xx_uart_resume(struct of_device *op)
+ {
+-	struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev);
++	struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev);
+ 
+ 	if (port)
+ 		uart_resume_port(&mpc52xx_uart_driver, port);
+@@ -789,7 +848,13 @@ mpc52xx_uart_resume(struct platform_devi
+ }
+ #endif
+ 
+-static struct platform_driver mpc52xx_uart_platform_driver = {
++
++MODULE_DEVICE_TABLE(of, mpc52xx_uart_match);
++
++static struct of_platform_driver mpc52xx_uart_of_driver = {
++	.owner		= THIS_MODULE,
++	.name		= "mpc52xx-uart",
++	.match_table	= mpc52xx_uart_match,
+ 	.probe		= mpc52xx_uart_probe,
+ 	.remove		= mpc52xx_uart_remove,
+ #ifdef CONFIG_PM
+@@ -804,7 +869,7 @@ #endif
+ 
+ /* ======================================================================== */
+ /* Module                                                                   */
+-/* ======================================================================== */
++ /* ======================================================================== */
+ 
+ static int __init
+ mpc52xx_uart_init(void)
+@@ -813,20 +878,24 @@ mpc52xx_uart_init(void)
+ 
+ 	printk(KERN_INFO "Serial: MPC52xx PSC driver\n");
+ 
+-	ret = uart_register_driver(&mpc52xx_uart_driver);
+-	if (ret == 0) {
+-		ret = platform_driver_register(&mpc52xx_uart_platform_driver);
+-		if (ret)
+-			uart_unregister_driver(&mpc52xx_uart_driver);
++	if ((ret = uart_register_driver(&mpc52xx_uart_driver)) != 0) {
++		printk(KERN_ERR "Could not register mpc52xx uart driver\n");
++		return ret;
+ 	}
+ 
+-	return ret;
++	if ((ret = of_register_platform_driver(&mpc52xx_uart_of_driver)) != 0) {
++		printk(KERN_ERR "Could not register mpc52xx of driver\n");
++		uart_unregister_driver(&mpc52xx_uart_driver);
++		return ret;
++	}
++
++	return 0;
+ }
+ 
+ static void __exit
+ mpc52xx_uart_exit(void)
+ {
+-	platform_driver_unregister(&mpc52xx_uart_platform_driver);
++	of_unregister_platform_driver(&mpc52xx_uart_of_driver);
+ 	uart_unregister_driver(&mpc52xx_uart_driver);
+ }
+ 
+-- 
+1.4.3.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0004-Add-MPC5200-CPU-PIO-driver-using-libata.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0004-Add-MPC5200-CPU-PIO-driver-using-libata.diff	Sat Nov 25 17:21:50 2006
@@ -0,0 +1,677 @@
+From bb6dea9b9a251e42efcec030af2d5272d5d5714a Mon Sep 17 00:00:00 2001
+From: Nicolas DET <nd at bplan-gmbh.de>
+Date: Fri, 24 Nov 2006 13:01:30 +0100
+Subject: [PATCH] Add MPC5200 CPU/PIO driver using libata
+
+Signed-off-by: Nicolas DET <nd at bplan-gmbh.de>
+---
+ drivers/ata/Kconfig        |    9 +
+ drivers/ata/Makefile       |    1 +
+ drivers/ata/pata_mpc52xx.c |  510 ++++++++++++++++++++++++++++++++++++++++++++
+ drivers/ata/pata_mpc52xx.h |  107 +++++++++
+ 4 files changed, 627 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
+index 03f6338..be01ddf 100644
+--- a/drivers/ata/Kconfig
++++ b/drivers/ata/Kconfig
+@@ -328,6 +328,15 @@ config PATA_TRIFLEX
+ 
+ 	  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 72243a6..e3a741c 100644
+--- a/drivers/ata/Makefile
++++ b/drivers/ata/Makefile
+@@ -38,6 +38,7 @@ obj-$(CONFIG_PATA_NETCELL)	+= pata_netce
+ 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_MPIIX)	+= pata_mpiix.o
+ obj-$(CONFIG_PATA_OLDPIIX)	+= pata_oldpiix.o
+ obj-$(CONFIG_PATA_PCMCIA)	+= pata_pcmcia.o
+diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
+new file mode 100644
+index 0000000..c75d4c9
+--- /dev/null
++++ b/drivers/ata/pata_mpc52xx.c
+@@ -0,0 +1,510 @@
++/*
++ * 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/libata.h>
++
++#include <asm/io.h>
++#include <asm/prom.h>
++#include <asm/of_platform.h>
++#include <asm/mpc52xx.h>
++
++#include "pata_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)))
++
++
++/* ======================================================================== */
++/* Aux fns                                                                  */
++/* ======================================================================== */
++
++
++/* OF device tree */
++
++static unsigned int
++mpc52xx_find_ipb_freq(struct device_node *on)
++{
++	struct device_node *onp;
++	const unsigned int *p_ipb_freq = NULL;
++
++	of_node_get(on);
++	while (on) {
++		p_ipb_freq = get_property(on, "bus-frequency", NULL);
++
++		if (p_ipb_freq)
++			break;
++
++		onp = of_get_parent(on);
++		of_node_put(on);
++		on = onp;
++	}
++
++	if (on)
++		of_node_put(on);
++
++	return p_ipb_freq ? *p_ipb_freq : 0;
++}
++
++
++/* 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);
++
+diff --git a/drivers/ata/pata_mpc52xx.h b/drivers/ata/pata_mpc52xx.h
+new file mode 100644
+index 0000000..2430ae2
+--- /dev/null
++++ b/drivers/ata/pata_mpc52xx.h
+@@ -0,0 +1,107 @@
++/*
++ * drivers/ata/pata_mpc52xx.h
++ *
++ * Definitions 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.
++ */
++
++#ifndef __PATA_MPC52xx_H__
++#define __PATA_MPC52xx_H__
++
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/ide.h>
++#include <asm/types.h>
++#include <asm/io.h>
++
++
++
++/* 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];
++};
++
++#endif /* __PATA_MPC52xx_H__ */
++
+-- 
+1.4.3.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0005-Add-MPC5200-specific-header.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0005-Add-MPC5200-specific-header.diff	Sat Nov 25 17:21:50 2006
@@ -0,0 +1,306 @@
+From e63b95820892f44ac7eec431900378763a83ae9d Mon Sep 17 00:00:00 2001
+From: Nicolas DET <nd at bplan-gmbh.de>
+Date: Fri, 24 Nov 2006 13:05:34 +0100
+Subject: [PATCH] Add MPC5200 specific header
+
+Signed-off-by: Nicolas DET <nd at bplan-gmbh.de>
+---
+ include/asm-powerpc/mpc52xx.h |  287 +++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 287 insertions(+), 0 deletions(-)
+
+diff --git a/include/asm-powerpc/mpc52xx.h b/include/asm-powerpc/mpc52xx.h
+new file mode 100644
+index 0000000..e9aa622
+--- /dev/null
++++ b/include/asm-powerpc/mpc52xx.h
+@@ -0,0 +1,287 @@
++/*
++ * Prototypes, etc. for the Freescale MPC52xx embedded cpu chips
++ * May need to be cleaned as the port goes on ...
++ *
++ * Copyright (C) 2004-2005 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 __ASM_POWERPC_MPC52xx_H__
++#define __ASM_POWERPC_MPC52xx_H__
++
++#ifndef __ASSEMBLY__
++#include <asm/types.h>
++#include <asm/prom.h>
++#endif /* __ASSEMBLY__ */
++
++
++/* ======================================================================== */
++/* HW IRQ mapping                                                           */
++/* ======================================================================== */
++
++#define MPC52xx_IRQ_L1_CRIT		(0)
++#define MPC52xx_IRQ_L1_MAIN		(1)
++#define MPC52xx_IRQ_L1_PERP		(2)
++#define MPC52xx_IRQ_L1_SDMA		(3)
++
++#define MPC52xx_IRQ_L1_OFFSET		(6)
++#define MPC52xx_IRQ_L1_MASK		(0xc0)
++
++#define MPC52xx_IRQ_L2_OFFSET		(0)
++#define MPC52xx_IRQ_L2_MASK		(0x3f)
++
++#define MPC52xx_IRQ_HIGHTESTHWIRQ	(0xd0)
++
++
++/* ======================================================================== */
++/* Structures mapping of some unit register set                             */
++/* ======================================================================== */
++
++#ifndef __ASSEMBLY__
++
++/* Interrupt controller Register set */
++struct mpc52xx_intr {
++	u32 per_mask;		/* INTR + 0x00 */
++	u32 per_pri1;		/* INTR + 0x04 */
++	u32 per_pri2;		/* INTR + 0x08 */
++	u32 per_pri3;		/* INTR + 0x0c */
++	u32 ctrl;		/* INTR + 0x10 */
++	u32 main_mask;		/* INTR + 0x14 */
++	u32 main_pri1;		/* INTR + 0x18 */
++	u32 main_pri2;		/* INTR + 0x1c */
++	u32 reserved1;		/* INTR + 0x20 */
++	u32 enc_status;		/* INTR + 0x24 */
++	u32 crit_status;	/* INTR + 0x28 */
++	u32 main_status;	/* INTR + 0x2c */
++	u32 per_status;		/* INTR + 0x30 */
++	u32 reserved2;		/* INTR + 0x34 */
++	u32 per_error;		/* INTR + 0x38 */
++};
++
++/* Memory Mapping Control */
++struct mpc52xx_mmap_ctl {
++	u32 mbar;		/* MMAP_CTRL + 0x00 */
++
++	u32 cs0_start;		/* MMAP_CTRL + 0x04 */
++	u32 cs0_stop;		/* MMAP_CTRL + 0x08 */
++	u32 cs1_start;		/* MMAP_CTRL + 0x0c */
++	u32 cs1_stop;		/* MMAP_CTRL + 0x10 */
++	u32 cs2_start;		/* MMAP_CTRL + 0x14 */
++	u32 cs2_stop;		/* MMAP_CTRL + 0x18 */
++	u32 cs3_start;		/* MMAP_CTRL + 0x1c */
++	u32 cs3_stop;		/* MMAP_CTRL + 0x20 */
++	u32 cs4_start;		/* MMAP_CTRL + 0x24 */
++	u32 cs4_stop;		/* MMAP_CTRL + 0x28 */
++	u32 cs5_start;		/* MMAP_CTRL + 0x2c */
++	u32 cs5_stop;		/* MMAP_CTRL + 0x30 */
++
++	u32 sdram0;		/* MMAP_CTRL + 0x34 */
++	u32 sdram1;		/* MMAP_CTRL + 0X38 */
++
++	u32 reserved[4];	/* MMAP_CTRL + 0x3c .. 0x48 */
++
++	u32 boot_start;		/* MMAP_CTRL + 0x4c */
++	u32 boot_stop;		/* MMAP_CTRL + 0x50 */
++
++	u32 ipbi_ws_ctrl;	/* MMAP_CTRL + 0x54 */
++
++	u32 cs6_start;		/* MMAP_CTRL + 0x58 */
++	u32 cs6_stop;		/* MMAP_CTRL + 0x5c */
++	u32 cs7_start;		/* MMAP_CTRL + 0x60 */
++	u32 cs7_stop;		/* MMAP_CTRL + 0x64 */
++};
++
++/* SDRAM control */
++struct mpc52xx_sdram {
++	u32 mode;		/* SDRAM + 0x00 */
++	u32 ctrl;		/* SDRAM + 0x04 */
++	u32 config1;		/* SDRAM + 0x08 */
++	u32 config2;		/* SDRAM + 0x0c */
++};
++
++/* SDMA */
++struct mpc52xx_sdma {
++	u32 taskBar;		/* SDMA + 0x00 */
++	u32 currentPointer;	/* SDMA + 0x04 */
++	u32 endPointer;		/* SDMA + 0x08 */
++	u32 variablePointer;	/* SDMA + 0x0c */
++
++	u8 IntVect1;		/* SDMA + 0x10 */
++	u8 IntVect2;		/* SDMA + 0x11 */
++	u16 PtdCntrl;		/* SDMA + 0x12 */
++
++	u32 IntPend;		/* SDMA + 0x14 */
++	u32 IntMask;		/* SDMA + 0x18 */
++
++	u16 tcr[16];		/* SDMA + 0x1c .. 0x3a */
++
++	u8 ipr[32];		/* SDMA + 0x3c .. 0x5b */
++
++	u32 cReqSelect;		/* SDMA + 0x5c */
++	u32 task_size0;		/* SDMA + 0x60 */
++	u32 task_size1;		/* SDMA + 0x64 */
++	u32 MDEDebug;		/* SDMA + 0x68 */
++	u32 ADSDebug;		/* SDMA + 0x6c */
++	u32 Value1;		/* SDMA + 0x70 */
++	u32 Value2;		/* SDMA + 0x74 */
++	u32 Control;		/* SDMA + 0x78 */
++	u32 Status;		/* SDMA + 0x7c */
++	u32 PTDDebug;		/* SDMA + 0x80 */
++};
++
++/* GPT */
++struct mpc52xx_gpt {
++	u32 mode;		/* GPTx + 0x00 */
++	u32 count;		/* GPTx + 0x04 */
++	u32 pwm;		/* GPTx + 0x08 */
++	u32 status;		/* GPTx + 0X0c */
++};
++
++/* GPIO */
++struct mpc52xx_gpio {
++	u32 port_config;	/* GPIO + 0x00 */
++	u32 simple_gpioe;	/* GPIO + 0x04 */
++	u32 simple_ode;		/* GPIO + 0x08 */
++	u32 simple_ddr;		/* GPIO + 0x0c */
++	u32 simple_dvo;		/* GPIO + 0x10 */
++	u32 simple_ival;	/* GPIO + 0x14 */
++	u8 outo_gpioe;		/* GPIO + 0x18 */
++	u8 reserved1[3];	/* GPIO + 0x19 */
++	u8 outo_dvo;		/* GPIO + 0x1c */
++	u8 reserved2[3];	/* GPIO + 0x1d */
++	u8 sint_gpioe;		/* GPIO + 0x20 */
++	u8 reserved3[3];	/* GPIO + 0x21 */
++	u8 sint_ode;		/* GPIO + 0x24 */
++	u8 reserved4[3];	/* GPIO + 0x25 */
++	u8 sint_ddr;		/* GPIO + 0x28 */
++	u8 reserved5[3];	/* GPIO + 0x29 */
++	u8 sint_dvo;		/* GPIO + 0x2c */
++	u8 reserved6[3];	/* GPIO + 0x2d */
++	u8 sint_inten;		/* GPIO + 0x30 */
++	u8 reserved7[3];	/* GPIO + 0x31 */
++	u16 sint_itype;		/* GPIO + 0x34 */
++	u16 reserved8;		/* GPIO + 0x36 */
++	u8 gpio_control;	/* GPIO + 0x38 */
++	u8 reserved9[3];	/* GPIO + 0x39 */
++	u8 sint_istat;		/* GPIO + 0x3c */
++	u8 sint_ival;		/* GPIO + 0x3d */
++	u8 bus_errs;		/* GPIO + 0x3e */
++	u8 reserved10;		/* GPIO + 0x3f */
++};
++
++#define MPC52xx_GPIO_PSC_CONFIG_UART_WITHOUT_CD	4
++#define MPC52xx_GPIO_PSC_CONFIG_UART_WITH_CD	5
++#define MPC52xx_GPIO_PCI_DIS			(1<<15)
++
++/* GPIO with WakeUp*/
++struct mpc52xx_gpio_wkup {
++	u8 wkup_gpioe;		/* GPIO_WKUP + 0x00 */
++	u8 reserved1[3];	/* GPIO_WKUP + 0x03 */
++	u8 wkup_ode;		/* GPIO_WKUP + 0x04 */
++	u8 reserved2[3];	/* GPIO_WKUP + 0x05 */
++	u8 wkup_ddr;		/* GPIO_WKUP + 0x08 */
++	u8 reserved3[3];	/* GPIO_WKUP + 0x09 */
++	u8 wkup_dvo;		/* GPIO_WKUP + 0x0C */
++	u8 reserved4[3];	/* GPIO_WKUP + 0x0D */
++	u8 wkup_inten;		/* GPIO_WKUP + 0x10 */
++	u8 reserved5[3];	/* GPIO_WKUP + 0x11 */
++	u8 wkup_iinten;		/* GPIO_WKUP + 0x14 */
++	u8 reserved6[3];	/* GPIO_WKUP + 0x15 */
++	u16 wkup_itype;		/* GPIO_WKUP + 0x18 */
++	u8 reserved7[2];	/* GPIO_WKUP + 0x1A */
++	u8 wkup_maste;		/* GPIO_WKUP + 0x1C */
++	u8 reserved8[3];	/* GPIO_WKUP + 0x1D */
++	u8 wkup_ival;		/* GPIO_WKUP + 0x20 */
++	u8 reserved9[3];	/* GPIO_WKUP + 0x21 */
++	u8 wkup_istat;		/* GPIO_WKUP + 0x24 */
++	u8 reserved10[3];	/* GPIO_WKUP + 0x25 */
++};
++
++/* XLB Bus control */
++struct mpc52xx_xlb {
++	u8 reserved[0x40];
++	u32 config;		/* XLB + 0x40 */
++	u32 version;		/* XLB + 0x44 */
++	u32 status;		/* XLB + 0x48 */
++	u32 int_enable;		/* XLB + 0x4c */
++	u32 addr_capture;	/* XLB + 0x50 */
++	u32 bus_sig_capture;	/* XLB + 0x54 */
++	u32 addr_timeout;	/* XLB + 0x58 */
++	u32 data_timeout;	/* XLB + 0x5c */
++	u32 bus_act_timeout;	/* XLB + 0x60 */
++	u32 master_pri_enable;	/* XLB + 0x64 */
++	u32 master_priority;	/* XLB + 0x68 */
++	u32 base_address;	/* XLB + 0x6c */
++	u32 snoop_window;	/* XLB + 0x70 */
++};
++
++#define MPC52xx_XLB_CFG_PLDIS		(1 << 31)
++#define MPC52xx_XLB_CFG_SNOOP		(1 << 15)
++
++/* Clock Distribution control */
++struct mpc52xx_cdm {
++	u32 jtag_id;		/* CDM + 0x00  reg0 read only */
++	u32 rstcfg;		/* CDM + 0x04  reg1 read only */
++	u32 breadcrumb;		/* CDM + 0x08  reg2 */
++
++	u8 mem_clk_sel;		/* CDM + 0x0c  reg3 byte0 */
++	u8 xlb_clk_sel;		/* CDM + 0x0d  reg3 byte1 read only */
++	u8 ipb_clk_sel;		/* CDM + 0x0e  reg3 byte2 */
++	u8 pci_clk_sel;		/* CDM + 0x0f  reg3 byte3 */
++
++	u8 ext_48mhz_en;	/* CDM + 0x10  reg4 byte0 */
++	u8 fd_enable;		/* CDM + 0x11  reg4 byte1 */
++	u16 fd_counters;	/* CDM + 0x12  reg4 byte2,3 */
++
++	u32 clk_enables;	/* CDM + 0x14  reg5 */
++
++	u8 osc_disable;		/* CDM + 0x18  reg6 byte0 */
++	u8 reserved0[3];	/* CDM + 0x19  reg6 byte1,2,3 */
++
++	u8 ccs_sleep_enable;	/* CDM + 0x1c  reg7 byte0 */
++	u8 osc_sleep_enable;	/* CDM + 0x1d  reg7 byte1 */
++	u8 reserved1;		/* CDM + 0x1e  reg7 byte2 */
++	u8 ccs_qreq_test;	/* CDM + 0x1f  reg7 byte3 */
++
++	u8 soft_reset;		/* CDM + 0x20  u8 byte0 */
++	u8 no_ckstp;		/* CDM + 0x21  u8 byte0 */
++	u8 reserved2[2];	/* CDM + 0x22  u8 byte1,2,3 */
++
++	u8 pll_lock;		/* CDM + 0x24  reg9 byte0 */
++	u8 pll_looselock;	/* CDM + 0x25  reg9 byte1 */
++	u8 pll_sm_lockwin;	/* CDM + 0x26  reg9 byte2 */
++	u8 reserved3;		/* CDM + 0x27  reg9 byte3 */
++
++	u16 reserved4;		/* CDM + 0x28  reg10 byte0,1 */
++	u16 mclken_div_psc1;	/* CDM + 0x2a  reg10 byte2,3 */
++
++	u16 reserved5;		/* CDM + 0x2c  reg11 byte0,1 */
++	u16 mclken_div_psc2;	/* CDM + 0x2e  reg11 byte2,3 */
++
++	u16 reserved6;		/* CDM + 0x30  reg12 byte0,1 */
++	u16 mclken_div_psc3;	/* CDM + 0x32  reg12 byte2,3 */
++
++	u16 reserved7;		/* CDM + 0x34  reg13 byte0,1 */
++	u16 mclken_div_psc6;	/* CDM + 0x36  reg13 byte2,3 */
++};
++
++#endif /* __ASSEMBLY__ */
++
++
++/* ========================================================================= */
++/* Prototypes for MPC52xx sysdev                                             */
++/* ========================================================================= */
++
++#ifndef __ASSEMBLY__
++
++extern void mpc52xx_init_irq(void);
++extern unsigned int mpc52xx_get_irq(void);
++
++#endif /* __ASSEMBLY__ */
++
++#endif /* __ASM_POWERPC_MPC52xx_H__ */
++
+-- 
+1.4.3.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0006-Add-MPC5200-interrupt-controller-driver.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0006-Add-MPC5200-interrupt-controller-driver.diff	Sat Nov 25 17:21:50 2006
@@ -0,0 +1,570 @@
+From b20c97e6f809bff52b864db1352a866c66a2bbd1 Mon Sep 17 00:00:00 2001
+From: Nicolas DET <nd at bplan-gmbh.de>
+Date: Fri, 24 Nov 2006 13:06:28 +0100
+Subject: [PATCH] Add MPC5200 interrupt controller driver
+
+Signed-off-by: Nicolas DET <nd at bplan-gmbh.de>
+---
+ arch/powerpc/sysdev/Makefile      |    1 +
+ arch/powerpc/sysdev/mpc52xx_pic.c |  538 +++++++++++++++++++++++++++++++++++++
+ 2 files changed, 539 insertions(+), 0 deletions(-)
+
+diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
+index 91f052d..5b5b61e 100644
+--- a/arch/powerpc/sysdev/Makefile
++++ b/arch/powerpc/sysdev/Makefile
+@@ -13,6 +13,7 @@ obj-$(CONFIG_FSL_SOC)		+= fsl_soc.o
+ obj-$(CONFIG_PPC_TODC)		+= todc.o
+ obj-$(CONFIG_TSI108_BRIDGE)	+= tsi108_pci.o tsi108_dev.o
+ obj-$(CONFIG_QUICC_ENGINE)	+= qe_lib/
++obj-$(CONFIG_PPC_MPC52xx)       += mpc52xx_pic.o
+ 
+ ifeq ($(CONFIG_PPC_MERGE),y)
+ obj-$(CONFIG_PPC_I8259)		+= i8259.o
+diff --git a/arch/powerpc/sysdev/mpc52xx_pic.c b/arch/powerpc/sysdev/mpc52xx_pic.c
+new file mode 100644
+index 0000000..6df51f0
+--- /dev/null
++++ b/arch/powerpc/sysdev/mpc52xx_pic.c
+@@ -0,0 +1,538 @@
++/*
++ *
++ * Programmable Interrupt Controller functions for the Freescale MPC52xx.
++ *
++ * Copyright (C) 2006 bplan GmbH
++ *
++ * Based on the code from the 2.4 kernel by
++ * Dale Farnsworth <dfarnsworth at mvista.com> and Kent Borg.
++ *
++ * 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.
++ *
++ */
++
++#undef DEBUG
++
++#include <linux/stddef.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/signal.h>
++#include <linux/stddef.h>
++#include <linux/delay.h>
++#include <linux/irq.h>
++#include <linux/hardirq.h>
++
++#include <asm/io.h>
++#include <asm/processor.h>
++#include <asm/system.h>
++#include <asm/irq.h>
++#include <asm/prom.h>
++#include <asm/mpc52xx.h>
++
++/*
++ *
++*/
++
++static struct mpc52xx_intr __iomem *intr;
++static struct mpc52xx_sdma __iomem *sdma;
++static struct irq_host *mpc52xx_irqhost = NULL;
++
++static unsigned char mpc52xx_map_senses[4] = {
++	IRQ_TYPE_LEVEL_HIGH,
++	IRQ_TYPE_EDGE_RISING,
++	IRQ_TYPE_EDGE_FALLING,
++	IRQ_TYPE_LEVEL_LOW,
++};
++
++/*
++ *
++*/
++
++static inline void io_be_setbit(u32 __iomem * addr, int bitno)
++{
++	out_be32(addr, in_be32(addr) | (1 << bitno));
++}
++
++static inline void io_be_clrbit(u32 __iomem * addr, int bitno)
++{
++	out_be32(addr, in_be32(addr) & ~(1 << bitno));
++}
++
++/*
++ * IRQ[0-3] interrupt irq_chip
++*/
++
++static void mpc52xx_extirq_mask(unsigned int virq)
++{
++	int irq;
++	int l2irq;
++
++	irq = irq_map[virq].hwirq;
++	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
++
++	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
++
++	io_be_clrbit(&intr->ctrl, 11 - l2irq);
++}
++
++static void mpc52xx_extirq_unmask(unsigned int virq)
++{
++	int irq;
++	int l2irq;
++
++	irq = irq_map[virq].hwirq;
++	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
++
++	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
++
++	io_be_setbit(&intr->ctrl, 11 - l2irq);
++}
++
++static void mpc52xx_extirq_ack(unsigned int virq)
++{
++	int irq;
++	int l2irq;
++
++	irq = irq_map[virq].hwirq;
++	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
++
++	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
++
++	io_be_setbit(&intr->ctrl, 27 - l2irq);
++}
++
++static struct irq_chip mpc52xx_extirq_irqchip = {
++	.typename = " MPC52xx IRQ[0-3] ",
++	.mask = mpc52xx_extirq_mask,
++	.unmask = mpc52xx_extirq_unmask,
++	.ack = mpc52xx_extirq_ack,
++};
++
++/*
++ * Main interrupt irq_chip
++*/
++
++static void mpc52xx_main_mask(unsigned int virq)
++{
++	int irq;
++	int l2irq;
++
++	irq = irq_map[virq].hwirq;
++	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
++
++	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
++
++	io_be_setbit(&intr->main_mask, 15 - l2irq);
++}
++
++static void mpc52xx_main_unmask(unsigned int virq)
++{
++	int irq;
++	int l2irq;
++
++	irq = irq_map[virq].hwirq;
++	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
++
++	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
++
++	io_be_clrbit(&intr->main_mask, 15 - l2irq);
++}
++
++static struct irq_chip mpc52xx_main_irqchip = {
++	.typename = "MPC52xx Main",
++	.mask = mpc52xx_main_mask,
++	.mask_ack = mpc52xx_main_mask,
++	.unmask = mpc52xx_main_unmask,
++};
++
++/*
++ * Peripherals interrupt irq_chip
++*/
++
++static void mpc52xx_periph_mask(unsigned int virq)
++{
++	int irq;
++	int l2irq;
++
++	irq = irq_map[virq].hwirq;
++	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
++
++	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
++
++	io_be_setbit(&intr->per_mask, 31 - l2irq);
++}
++
++static void mpc52xx_periph_unmask(unsigned int virq)
++{
++	int irq;
++	int l2irq;
++
++	irq = irq_map[virq].hwirq;
++	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
++
++	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
++
++	io_be_clrbit(&intr->per_mask, 31 - l2irq);
++}
++
++static struct irq_chip mpc52xx_periph_irqchip = {
++	.typename = "MPC52xx Peripherals",
++	.mask = mpc52xx_periph_mask,
++	.mask_ack = mpc52xx_periph_mask,
++	.unmask = mpc52xx_periph_unmask,
++};
++
++/*
++ * SDMA interrupt irq_chip
++*/
++
++static void mpc52xx_sdma_mask(unsigned int virq)
++{
++	int irq;
++	int l2irq;
++
++	irq = irq_map[virq].hwirq;
++	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
++
++	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
++
++	io_be_setbit(&sdma->IntMask, l2irq);
++}
++
++static void mpc52xx_sdma_unmask(unsigned int virq)
++{
++	int irq;
++	int l2irq;
++
++	irq = irq_map[virq].hwirq;
++	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
++
++	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
++
++	io_be_clrbit(&sdma->IntMask, l2irq);
++}
++
++static void mpc52xx_sdma_ack(unsigned int virq)
++{
++	int irq;
++	int l2irq;
++
++	irq = irq_map[virq].hwirq;
++	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
++
++	pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq);
++
++	out_be32(&sdma->IntPend, 1 << l2irq);
++}
++
++static struct irq_chip mpc52xx_sdma_irqchip = {
++	.typename = "MPC52xx SDMA",
++	.mask = mpc52xx_sdma_mask,
++	.unmask = mpc52xx_sdma_unmask,
++	.ack = mpc52xx_sdma_ack,
++};
++
++/*
++ * irq_host
++*/
++
++static int mpc52xx_irqhost_match(struct irq_host *h, struct device_node *node)
++{
++	pr_debug("%s: node=%p\n", __func__, node);
++	return mpc52xx_irqhost->host_data == node;
++}
++
++static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct,
++				 u32 * intspec, unsigned int intsize,
++				 irq_hw_number_t * out_hwirq,
++				 unsigned int *out_flags)
++{
++	int intrvect_l1;
++	int intrvect_l2;
++	int intrvect_type;
++	int intrvect_linux;
++
++	if (intsize != 3)
++		return -1;
++
++	intrvect_l1 = (int)intspec[0];
++	intrvect_l2 = (int)intspec[1];
++	intrvect_type = (int)intspec[2];
++
++	intrvect_linux =
++	    (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) & MPC52xx_IRQ_L1_MASK;
++	intrvect_linux |=
++	    (intrvect_l2 << MPC52xx_IRQ_L2_OFFSET) & MPC52xx_IRQ_L2_MASK;
++
++	pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1,
++		 intrvect_l2);
++
++	*out_hwirq = intrvect_linux;
++	*out_flags = mpc52xx_map_senses[intrvect_type];
++
++	return 0;
++}
++
++/*
++ * this function retrieves the correct IRQ type out
++ * of the MPC regs
++ * Only externals IRQs needs this
++*/
++static int mpc52xx_irqx_gettype(int irq)
++{
++	int type;
++	u32 ctrl_reg;
++
++	ctrl_reg = in_be32(&intr->ctrl);
++	type = (ctrl_reg >> (22 - irq * 2)) & 0x3;
++
++	return mpc52xx_map_senses[type];
++}
++
++static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq,
++			       irq_hw_number_t irq)
++{
++	int l1irq;
++	int l2irq;
++	struct irq_chip *good_irqchip;
++	void *good_handle;
++	int type;
++
++	l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET;
++	l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET;
++
++	/*
++	 * Most of ours IRQs will be level low
++	 * Only external IRQs on some platform may be others
++	 */
++	type = IRQ_TYPE_LEVEL_LOW;
++
++	switch (l1irq) {
++	case MPC52xx_IRQ_L1_CRIT:
++		pr_debug("%s: Critical. l2=%x\n", __func__, l2irq);
++
++		BUG_ON(l2irq != 0);
++
++		type = mpc52xx_irqx_gettype(l2irq);
++		good_irqchip = &mpc52xx_extirq_irqchip;
++		break;
++
++	case MPC52xx_IRQ_L1_MAIN:
++		pr_debug("%s: Main IRQ[1-3] l2=%x\n", __func__, l2irq);
++
++		if ((l2irq >= 1) && (l2irq <= 3)) {
++			type = mpc52xx_irqx_gettype(l2irq);
++			good_irqchip = &mpc52xx_extirq_irqchip;
++		} else {
++			good_irqchip = &mpc52xx_main_irqchip;
++		}
++		break;
++
++	case MPC52xx_IRQ_L1_PERP:
++		pr_debug("%s: Peripherals. l2=%x\n", __func__, l2irq);
++		good_irqchip = &mpc52xx_periph_irqchip;
++		break;
++
++	case MPC52xx_IRQ_L1_SDMA:
++		pr_debug("%s: SDMA. l2=%x\n", __func__, l2irq);
++		good_irqchip = &mpc52xx_sdma_irqchip;
++		break;
++
++	default:
++		pr_debug("%s: Error, unknown L1 IRQ (0x%x)\n", __func__, l1irq);
++		printk(KERN_ERR "Unknow IRQ!\n");
++		return -EINVAL;
++	}
++
++	switch (type) {
++	case IRQ_TYPE_EDGE_FALLING:
++	case IRQ_TYPE_EDGE_RISING:
++		good_handle = handle_edge_irq;
++		break;
++	default:
++		good_handle = handle_level_irq;
++	}
++
++	set_irq_chip_and_handler(virq, good_irqchip, good_handle);
++
++	pr_debug("%s: virq=%x, hw=%x. type=%x\n", __func__, virq,
++		 (int)irq, type);
++
++	return 0;
++}
++
++static struct irq_host_ops mpc52xx_irqhost_ops = {
++	.match = mpc52xx_irqhost_match,
++	.xlate = mpc52xx_irqhost_xlate,
++	.map = mpc52xx_irqhost_map,
++};
++
++/*
++ * init (public)
++*/
++
++void __init mpc52xx_init_irq(void)
++{
++	struct device_node *picnode = NULL;
++	int picnode_regsize;
++	u32 picnode_regoffset;
++
++	struct device_node *sdmanode = NULL;
++	int sdmanode_regsize;
++	u32 sdmanode_regoffset;
++
++	u64 size64;
++	int flags;
++
++	u32 intr_ctrl;
++
++	picnode = of_find_compatible_node(NULL, "interrupt-controller",
++						"mpc5200-pic");
++	if (picnode == NULL) {
++		printk(KERN_ERR "MPC52xx PIC: "
++			"Unable to find the interrupt controller "
++			"in the OpenFirmware device tree\n");
++		goto end;
++	}
++
++	sdmanode = of_find_compatible_node(NULL, "dma-controller",
++						 "mpc5200-bestcomm");
++	if (sdmanode == NULL) {
++		printk(KERN_ERR "MPC52xx PIC"
++			"Unable to find the Bestcomm DMA controller device "
++			"in the OpenFirmware device tree\n");
++		goto end;
++	}
++
++	/* Retrieve PIC ressources */
++	picnode_regoffset = (u32) of_get_address(picnode, 0, &size64, &flags);
++	if (picnode_regoffset == 0) {
++		printk(KERN_ERR "MPC52xx PIC"
++			"Unable to get the interrupt controller address\n");
++		goto end;
++	}
++
++	picnode_regoffset =
++		of_translate_address(picnode, (u32 *) picnode_regoffset);
++	picnode_regsize = (int)size64;
++
++	/* Retrieve SDMA ressources */
++	sdmanode_regoffset = (u32) of_get_address(sdmanode, 0, &size64, &flags);
++	if (sdmanode_regoffset == 0) {
++		printk(KERN_ERR "MPC52xx PIC: "
++			"Unable to get the Bestcomm DMA controller address\n");
++		goto end;
++	}
++
++	sdmanode_regoffset =
++	    of_translate_address(sdmanode, (u32 *) sdmanode_regoffset);
++	sdmanode_regsize = (int)size64;
++
++	/* Remap the necessary zones */
++	intr = ioremap(picnode_regoffset, picnode_regsize);
++	if (intr == NULL) {
++		printk(KERN_ERR "MPC52xx PIC: "
++			"Unable to ioremap interrupt controller registers!\n");
++		goto end;
++	}
++
++	sdma = ioremap(sdmanode_regoffset, sdmanode_regsize);
++	if (sdma == NULL) {
++		iounmap(intr);
++		printk(KERN_ERR "MPC52xx PIC: "
++			"Unable to ioremap Bestcomm DMA registers!\n");
++		goto end;
++	}
++
++	printk(KERN_INFO "MPC52xx PIC: MPC52xx PIC Remapped at 0x%8.8x\n",
++		picnode_regoffset);
++	printk(KERN_INFO "MPC52xx PIC: MPC52xx SDMA Remapped at 0x%8.8x\n",
++		sdmanode_regoffset);
++
++	/* Disable all interrupt sources. */
++	out_be32(&sdma->IntPend, 0xffffffff);	/* 1 means clear pending */
++	out_be32(&sdma->IntMask, 0xffffffff);	/* 1 means disabled */
++	out_be32(&intr->per_mask, 0x7ffffc00);	/* 1 means disabled */
++	out_be32(&intr->main_mask, 0x00010fff);	/* 1 means disabled */
++	intr_ctrl = in_be32(&intr->ctrl);
++	intr_ctrl &= 0x00ff0000;	/* Keeps IRQ[0-3] config */
++	intr_ctrl |=	0x0f000000 |	/* clear IRQ 0-3 */
++			0x00001000 |	/* MEE master external enable */
++			0x00000000 |	/* 0 means disable IRQ 0-3 */
++			0x00000001;	/* CEb route critical normally */
++	out_be32(&intr->ctrl, intr_ctrl);
++
++	/* Zero a bunch of the priority settings. */
++	out_be32(&intr->per_pri1, 0);
++	out_be32(&intr->per_pri2, 0);
++	out_be32(&intr->per_pri3, 0);
++	out_be32(&intr->main_pri1, 0);
++	out_be32(&intr->main_pri2, 0);
++
++	/*
++	 * As last step, add an irq host to translate the real
++	 * hw irq information provided by the ofw to linux virq
++	 */
++
++	mpc52xx_irqhost =
++	    irq_alloc_host(IRQ_HOST_MAP_LINEAR, MPC52xx_IRQ_HIGHTESTHWIRQ,
++			   &mpc52xx_irqhost_ops, -1);
++
++	if (mpc52xx_irqhost) {
++		mpc52xx_irqhost->host_data = picnode;
++		printk(KERN_INFO "MPC52xx PIC is up and running!\n");
++	} else {
++		printk(KERN_ERR
++			"MPC52xx PIC: Unable to allocate the IRQ host\n");
++	}
++
++end:
++	of_node_put(picnode);
++	of_node_put(sdmanode);
++}
++
++/*
++ * get_irq (public)
++*/
++unsigned int mpc52xx_get_irq(void)
++{
++	u32 status;
++	int irq = NO_IRQ_IGNORE;
++
++	status = in_be32(&intr->enc_status);
++	if (status & 0x00000400) {	/* critical */
++		irq = (status >> 8) & 0x3;
++		if (irq == 2)	/* high priority peripheral */
++			goto peripheral;
++		irq |=	(MPC52xx_IRQ_L1_CRIT << MPC52xx_IRQ_L1_OFFSET) &
++			MPC52xx_IRQ_L1_MASK;
++	} else if (status & 0x00200000) {	/* main */
++		irq = (status >> 16) & 0x1f;
++		if (irq == 4)	/* low priority peripheral */
++			goto peripheral;
++		irq |=	(MPC52xx_IRQ_L1_MAIN << MPC52xx_IRQ_L1_OFFSET) &
++			MPC52xx_IRQ_L1_MASK;
++	} else if (status & 0x20000000) {	/* peripheral */
++	      peripheral:
++		irq = (status >> 24) & 0x1f;
++		if (irq == 0) {	/* bestcomm */
++			status = in_be32(&sdma->IntPend);
++			irq = ffs(status) - 1;
++			irq |=	(MPC52xx_IRQ_L1_SDMA << MPC52xx_IRQ_L1_OFFSET) &
++				MPC52xx_IRQ_L1_MASK;
++		} else
++			irq |=	(MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET) &
++				MPC52xx_IRQ_L1_MASK;
++	}
++
++	pr_debug("%s: irq=%x. virq=%d\n", __func__, irq,
++		 irq_linear_revmap(mpc52xx_irqhost, irq));
++
++	return irq_linear_revmap(mpc52xx_irqhost, irq);
++}
++
+-- 
+1.4.3.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0007-Add-MPC5200-ethernet-driver.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0007-Add-MPC5200-ethernet-driver.diff	Sat Nov 25 17:21:50 2006
@@ -0,0 +1,1834 @@
+From 0eae8b0fed7d8342c027e15d2a6d52eae10366e1 Mon Sep 17 00:00:00 2001
+From: Nicolas DET <nd at bplan-gmbh.de>
+Date: Fri, 24 Nov 2006 13:09:04 +0100
+Subject: [PATCH] Add MPC5200 ethernet driver
+
+Signed-off-by: Nicolas DET <nd at bplan-gmbh.de>
+---
+ drivers/net/Kconfig               |    1 +
+ drivers/net/Makefile              |    1 +
+ drivers/net/fec_mpc52xx/Kconfig   |   22 +
+ drivers/net/fec_mpc52xx/Makefile  |    2 +
+ drivers/net/fec_mpc52xx/fec.c     |  817 +++++++++++++++++++++++++++++++++++++
+ drivers/net/fec_mpc52xx/fec.h     |  308 ++++++++++++++
+ drivers/net/fec_mpc52xx/fec_phy.c |  532 ++++++++++++++++++++++++
+ drivers/net/fec_mpc52xx/fec_phy.h |   73 ++++
+ 8 files changed, 1756 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
+index 6e863aa..c0bf347 100644
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -1892,6 +1892,7 @@ config NE_H8300
+ 
+ source "drivers/net/fec_8xx/Kconfig"
+ source "drivers/net/fs_enet/Kconfig"
++source "drivers/net/fec_mpc52xx/Kconfig"
+ 
+ endmenu
+ 
+diff --git a/drivers/net/Makefile b/drivers/net/Makefile
+index f270bc4..a39a931 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_ARM) += arm/
+ obj-$(CONFIG_DEV_APPLETALK) += appletalk/
+diff --git a/drivers/net/fec_mpc52xx/Kconfig b/drivers/net/fec_mpc52xx/Kconfig
+new file mode 100644
+index 0000000..dc3fee6
+--- /dev/null
++++ b/drivers/net/fec_mpc52xx/Kconfig
+@@ -0,0 +1,22 @@
++menu "MPC5200 Networking Options"
++	depends (PPC_CHRP || PPC_MPC52xx) && NET_ETHERNET
++
++config FEC_MPC52xx
++	bool "FEC Ethernet"
++	depends on NET_ETHERNET
++	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..5591bb7
+--- /dev/null
++++ b/drivers/net/fec_mpc52xx/fec.c
+@@ -0,0 +1,817 @@
++/*
++ * 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/mpc52xx.h>
++#include <asm/of_device.h>
++#include <asm/of_platform.h>
++
++#ifdef CONFIG_PPC_EFIKA
++#include <platforms/efika/bestcomm.h>
++#else
++#include <syslib/bestcomm/bestcomm.h>
++#include <syslib/bestcomm/fec.h>
++#endif
++
++/******************/
++/******************/
++static unsigned long get_ipbfreq(void)
++{
++#ifdef CONFIG_PPC_EFIKA
++	return (132*1000*1000);
++#else
++	bd_t *bd = (bd_t *)&__res;
++	return bd->bi_ipbfreq
++#endif
++}
++
++/******************/
++/******************/
++
++#include "fec_phy.h"
++#include "fec.h"
++
++#define DRIVER_NAME "mpc52xx-fec"
++
++static irqreturn_t fec_interrupt(int, void *);
++static irqreturn_t fec_rx_interrupt(int, void *);
++static irqreturn_t fec_tx_interrupt(int, void *);
++static struct net_device_stats *fec_get_stats(struct net_device *);
++static void fec_set_multicast_list(struct net_device *dev);
++static void fec_reinit(struct net_device *dev);
++
++static u8 mpc52xx_fec_mac_addr[6];
++static u8 null_mac[6];
++
++static void fec_tx_timeout(struct net_device *dev)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++
++	priv->stats.tx_errors++;
++
++	if (!priv->tx_full)
++		netif_wake_queue(dev);
++}
++
++static void fec_set_paddr(struct net_device *dev, u8 *mac)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	struct mpc52xx_fec *fec = priv->fec;
++
++	out_be32(&fec->paddr1, *(u32*)(&mac[0]));
++	out_be32(&fec->paddr2, (*(u16*)(&mac[4]) << 16) | 0x8808);
++}
++
++static void fec_get_paddr(struct net_device *dev, u8 *mac)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	struct mpc52xx_fec *fec = priv->fec;
++
++	*(u32*)(&mac[0]) = in_be32(&fec->paddr1);
++	*(u16*)(&mac[4]) = in_be32(&fec->paddr2) >> 16;
++}
++
++static int fec_set_mac_address(struct net_device *dev, void *addr)
++{
++	struct sockaddr *sock = (struct sockaddr *)addr;
++
++	memcpy(dev->dev_addr, sock->sa_data, dev->addr_len);
++
++	fec_set_paddr(dev, sock->sa_data);
++	return 0;
++}
++
++/* This function is called to start or restart the FEC during a link
++ * change.  This happens on fifo errors or when switching between half
++ * and full duplex.
++ */
++static void fec_restart(struct net_device *dev, int duplex)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	struct mpc52xx_fec *fec = priv->fec;
++	u32 rcntrl;
++	u32 tcntrl;
++	int i;
++
++	out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status) & 0x700000);
++	out_be32(&fec->tfifo_status, in_be32(&fec->tfifo_status) & 0x700000);
++	out_be32(&fec->reset_cntrl, 0x1000000);
++
++	/* Whack a reset.  We should wait for this. */
++	out_be32(&fec->ecntrl, FEC_ECNTRL_RESET);
++	for (i = 0; i < FEC_RESET_DELAY; ++i) {
++		if ((in_be32(&fec->ecntrl) & FEC_ECNTRL_RESET) == 0)
++			break;
++		udelay(1);
++	}
++	if (i == FEC_RESET_DELAY)
++		printk (KERN_ERR DRIVER_NAME ": FEC Reset timeout!\n");
++
++	/* Set station address. */
++	fec_set_paddr(dev, dev->dev_addr);
++
++	fec_set_multicast_list(dev);
++
++	rcntrl = FEC_RX_BUFFER_SIZE << 16;	/* max frame length */
++	rcntrl |= FEC_RCNTRL_FCE;
++	rcntrl |= MII_RCNTL_MODE;
++	if (duplex)
++		tcntrl = FEC_TCNTRL_FDEN;		/* FD enable */
++	else {
++		rcntrl |= FEC_RCNTRL_DRT;
++		tcntrl = 0;
++	}
++	out_be32(&fec->r_cntrl, rcntrl);
++	out_be32(&fec->x_cntrl, tcntrl);
++
++	set_phy_speed(fec, priv->phy_speed);
++
++	priv->full_duplex = duplex;
++
++	/* Clear any outstanding interrupt. */
++	out_be32(&fec->ievent, 0xffffffff);	/* clear intr events */
++
++	/* Enable interrupts we wish to service.
++	*/
++	out_be32(&fec->imask, FEC_IMASK_ENABLE);
++
++	/* And last, enable the transmit and receive processing.
++	*/
++	out_be32(&fec->ecntrl, FEC_ECNTRL_ETHER_EN);
++	out_be32(&fec->r_des_active, 0x01000000);
++
++	/* The tx ring is no longer full. */
++	if (priv->tx_full)
++	{
++		priv->tx_full = 0;
++		netif_wake_queue(dev);
++	}
++}
++
++static void fec_free_rx_buffers(struct 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 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 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 net_device *dev = (struct net_device *)dev_id;
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	struct mpc52xx_fec *fec = priv->fec;
++	int ievent;
++
++	ievent = in_be32(&fec->ievent);
++	if (!ievent)
++	  return IRQ_NONE;
++
++	out_be32(&fec->ievent, ievent);		/* clear pending events */
++
++	if (ievent & (FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR)) {
++		if ( net_ratelimit() )
++		{
++		  if (ievent & FEC_IEVENT_RFIFO_ERROR)
++			printk(KERN_WARNING "FEC_IEVENT_RFIFO_ERROR (%8.8x)\n", ievent);
++		  if (ievent & FEC_IEVENT_XFIFO_ERROR)
++			printk(KERN_WARNING "FEC_IEVENT_XFIFO_ERROR (%8.8x)\n", ievent);
++		}
++		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;
++	
++	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 = ((get_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_update_stat(struct net_device *);
++static void fec_reinit(struct net_device *dev)
++{
++	struct fec_priv *priv = (struct fec_priv *)dev->priv;
++	struct mpc52xx_fec *fec = priv->fec;
++	
++	netif_stop_queue(dev);
++	out_be32(&fec->imask, 0x0);
++
++	/* Disable the rx and tx tasks. */
++	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 of_device *op, const struct of_device_id *match)
++{
++	int ret;
++	int rv;
++	struct net_device *ndev;
++	struct fec_priv *priv = NULL;
++	struct resource mem;
++
++	/* Reserve FEC control zone */
++	rv = of_address_to_resource(op->node, 0, &mem);
++	if (rv) {
++		printk(KERN_ERR DRIVER_NAME ": "
++			"Error while parsing device node resource\n" );
++		return rv;
++	}
++	
++	if (!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) {
++		printk(KERN_ERR DRIVER_NAME ": "
++			"Can not allocate the ethernet device\n" );
++		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) {
++		printk(KERN_ERR DRIVER_NAME ": "
++			"Can not remap IO memory at 0x%8.8x\n", mem.start );
++		ret = -ENOMEM;
++		goto probe_error;
++	}
++
++	/* SDMA init */
++#ifdef CONFIG_PPC_EFIKA
++	priv->rx_sdma = sdma_fex_rx_preinit(FEC_RX_NUM_BD);
++	priv->tx_sdma = sdma_fex_tx_preinit(FEC_TX_NUM_BD);
++#else
++	priv->rx_sdma = sdma_alloc(FEC_RX_NUM_BD);
++	priv->tx_sdma = sdma_alloc(FEC_TX_NUM_BD);
++#endif
++	
++	if (!priv->rx_sdma || !priv->tx_sdma) {
++		printk(KERN_ERR DRIVER_NAME ": "
++			"Can not init SDMA tasks\n" );
++		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 = irq_of_parse_and_map(op->node, 0);
++
++	if (request_irq(ndev->irq, &fec_interrupt, SA_INTERRUPT,
++	                DRIVER_NAME "_ctrl", ndev)) {
++		printk(KERN_ERR DRIVER_NAME ": ctrl interrupt request failed\n");
++		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(&op->dev, ndev);
++
++	return 0;
++
++	/* Errorx 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 of_device *op)
++{
++	struct net_device *ndev;
++	struct fec_priv *priv;
++	
++	ndev = (struct net_device *) dev_get_drvdata(&op->dev);
++	if (!ndev)
++		return 0;
++	priv = (struct fec_priv *) ndev->priv;
++
++	unregister_netdev(ndev);
++	
++	free_irq(ndev->irq, ndev);
++	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(&op->dev, NULL);
++	return 0;
++}
++
++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,
++	},
++};
++
++/* ======================================================================== */
++/* Module                                                                   */
++/* ======================================================================== */
++
++static int __init
++mpc52xx_fec_init(void)
++{
++	return of_register_platform_driver(&mpc52xx_fec_driver);
++}
++
++static void __exit
++mpc52xx_fec_exit(void)
++{
++	of_unregister_platform_driver(&mpc52xx_fec_driver);
++}
++
++
++module_init(mpc52xx_fec_init);
++module_exit(mpc52xx_fec_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Dale Farnsworth");
++MODULE_DESCRIPTION("Ethernet driver for the Freescale MPC52xx FEC");
+diff --git a/drivers/net/fec_mpc52xx/fec.h b/drivers/net/fec_mpc52xx/fec.h
+new file mode 100644
+index 0000000..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..1b2f4e1
+--- /dev/null
++++ b/drivers/net/fec_mpc52xx/fec_phy.c
+@@ -0,0 +1,532 @@
++/*
++ * 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>
++
++#ifdef CONFIG_PPC_EFIKA
++#include <platforms/efika/bestcomm.h>
++#else
++#include <syslib/bestcomm/bestcomm.h>
++#include <syslib/bestcomm/fec.h>
++#endif
++
++#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.3.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0008-Add-MPC5200-SDMA-PIO-driver.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0008-Add-MPC5200-SDMA-PIO-driver.diff	Sat Nov 25 17:21:50 2006
@@ -0,0 +1,3973 @@
+From e94e3e06dcf17bc739806a8a4cd8d732f7f45074 Mon Sep 17 00:00:00 2001
+From: Nicolas DET <nd at bplan-gmbh.de>
+Date: Fri, 24 Nov 2006 13:10:46 +0100
+Subject: [PATCH] Add MPC5200 SDMA/PIO driver
+
+Signed-off-by: Nicolas DET <nd at bplan-gmbh.de>
+---
+ drivers/block/Kconfig                    |   25 +
+ drivers/block/Makefile                   |    1 +
+ drivers/block/mpc52xx/Makefile           |    9 +
+ drivers/block/mpc52xx/ata.c              |  216 +++++++
+ drivers/block/mpc52xx/dodrivecmd.c       |  138 ++++
+ drivers/block/mpc52xx/hwmisc.c           |  577 +++++++++++++++++
+ drivers/block/mpc52xx/mpc52xx_blockata.h |  311 +++++++++
+ drivers/block/mpc52xx/mpc52xx_ide.h      |  131 ++++
+ drivers/block/mpc52xx/piofunc_inline.h   |  250 ++++++++
+ drivers/block/mpc52xx/protos.h           |  107 ++++
+ drivers/block/mpc52xx/sdmatask.c         |  142 ++++
+ drivers/block/mpc52xx/skel.c             | 1024 ++++++++++++++++++++++++++++++
+ drivers/block/mpc52xx/transfer.c         |  932 +++++++++++++++++++++++++++
+ 13 files changed, 3863 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
+index 17dc222..0d9d9c1 100644
+--- a/drivers/block/Kconfig
++++ b/drivers/block/Kconfig
+@@ -63,6 +63,31 @@ config AMIGA_Z2RAM
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called z2ram.
+ 
++config BLK_DEV_MPC52XX_ATAPIO
++      tristate "MPC52xx ATA/PIO support"
++      depends on PPC_EFIKA
++      help
++        Selects this one if you are running on Efika 5k2
++
++config BLK_DEV_MPC52XX_ATAPIO_SDMA
++      bool "Use DMA driven PIO transfert"
++      depends on BLK_DEV_MPC52XX_ATAPIO
++      help
++        take advantage of the Bestcom SDMA engine on the MPC52xx to transfer
++        data to and from the PIO Fifo.
++        This offload the CPU core and allow higher transfer rate.
++
++config BLK_DEV_MPC52XX_ATAPIO_MAXPIO
++      bool "Probe and set up the best PIO mode when setting the drive up"
++      depends on BLK_DEV_MPC52XX_ATAPIO
++      help
++        Probe and set up the best PIO mode available for the drive on
++        driver startup
++
++config BLK_DEV_MPC52XX_ATAPIO_VERBOSE
++      bool "Print out loads of verbose information"
++      depends on BLK_DEV_MPC52XX_ATAPIO
++
+ config ATARI_ACSI
+ 	tristate "Atari ACSI support"
+ 	depends on ATARI && BROKEN
+diff --git a/drivers/block/Makefile b/drivers/block/Makefile
+index 410f259..72a5e66 100644
+--- a/drivers/block/Makefile
++++ b/drivers/block/Makefile
+@@ -30,3 +30,4 @@ obj-$(CONFIG_VIODASD)		+= viodasd.o
+ obj-$(CONFIG_BLK_DEV_SX8)	+= sx8.o
+ obj-$(CONFIG_BLK_DEV_UB)	+= ub.o
+ 
++obj-$(CONFIG_BLK_DEV_MPC52XX_ATAPIO)    += mpc52xx/
+diff --git a/drivers/block/mpc52xx/Makefile b/drivers/block/mpc52xx/Makefile
+new file mode 100644
+index 0000000..3f20c67
+--- /dev/null
++++ b/drivers/block/mpc52xx/Makefile
+@@ -0,0 +1,9 @@
++#
++# Makefile for the kernel block device drivers.
++#
++# 12 June 2000, Christoph Hellwig <hch at infradead.org>
++# Rewritten to use lists instead of if-statements.
++# 
++
++obj-$(CONFIG_BLK_DEV_MPC52XX_ATAPIO)	+= skel.o sdmatask.o ata.o transfer.o hwmisc.o dodrivecmd.o
++
+diff --git a/drivers/block/mpc52xx/ata.c b/drivers/block/mpc52xx/ata.c
+new file mode 100644
+index 0000000..dced8b1
+--- /dev/null
++++ b/drivers/block/mpc52xx/ata.c
+@@ -0,0 +1,216 @@
++/*
++ *  mpc52xx_atablock / ata.c
++ *
++ *  Copyright 2006 bplan GmbH
++ *
++ *  This file is subject to the terms and conditions of the GNU General Public
++ *  License.  See the file "COPYING" in the main directory of this archive
++ *  for more details.
++ */
++
++
++/**************/
++/**************/
++/**************/
++
++#include "mpc52xx_blockata.h"
++
++/**************/
++/**************/
++/**************/
++int mpc52xx_ata_dodrivereset(struct mpc52xx_blockata_priv  *priv)
++{
++        int ret;
++
++        write_cmd(priv, ATA_CMD_RESET);
++
++        ret = wait_not_busy(priv);
++        if (ret<0)
++                return ret;
++
++        if ( ATASTS_GOT_ERR(read_altstatus(priv)) )
++                return -1;
++
++        return mpc52xx_ata_doidentify(priv);
++}
++
++
++/**************/
++int mpc52xx_ata_regcheck(struct mpc52xx_blockata_priv  *priv)
++{
++        u8 seccnt;
++        u8 sector;
++
++        write_sectorcnt(priv, 0x55);
++        write_sectornum(priv, 0xaa);
++        write_sectorcnt(priv, 0xaa);
++        write_sectornum(priv, 0x55);
++        write_sectorcnt(priv, 0x55);
++        write_sectornum(priv, 0xaa);
++
++        seccnt = read_sectorcnt(priv);
++        sector = read_sectornum(priv);
++
++        NPRINTK("%s: seccnt=%x, sector=%x\n", __func__, seccnt,  sector );
++
++        if
++        (
++                ( (seccnt == 0x55) || (seccnt == 0x01) )
++                && (sector == 0xaa)
++        )
++                return 0;
++
++        return -1;
++}
++
++/**************/
++/**************/
++static int ata_docpupollread(
++        struct mpc52xx_blockata_priv  *priv,
++        void *buffer,
++        int len)
++{
++        u16 *buffer16 = (u16 *) buffer;
++        int local_len = len;
++
++        while(local_len--)
++                *buffer16++ = read_data(priv);
++
++        return len - local_len;
++}
++
++/**************/
++static int ata_docpupollwrite(
++        struct mpc52xx_blockata_priv  *priv,
++        void *buffer,
++        int len)
++{
++        u16 *buffer16 = (u16 *) buffer;
++        int local_len = len;
++
++        while(local_len--)
++                write_data(priv, *buffer16++);
++
++        return len - local_len;
++
++}
++
++
++/**************/
++int mpc52xx_ata_setupsector(
++        struct mpc52xx_blockata_priv  *priv,
++        sector_t sector,
++        int sector_num,
++        int is_write)
++{
++        u8 seccnt, secnum, cyl_lo, cyl_hi, devhead;
++        u16 cyl16;
++
++        if (priv->drive_canlba) {
++                if ( sector & (0xfffff0000000LL) ) {
++                        if (!priv->drive_canlba48)
++                                return -1;
++
++                        write_sectornum(priv, (sector >> 24) & 0xff);
++
++                        write_cyllo(priv, (sector >> 32) & 0xff);
++
++                        write_cylhi(priv, (sector >> 40) & 0xff);
++
++                        write_sectorcnt(priv, sector_num & 0xff00);
++                        sector_num &= 0xff;
++
++                        sector &= 0xffffff;
++
++                        if ( (priv->multi_available) && (sector_num > 1) )
++                                priv->curio_atacmd = is_write ? ATA_CMD_WRITE_MULTI_EXT : ATA_CMD_READ_MULTI_EXT;
++                        else
++                                priv->curio_atacmd = is_write ? ATA_CMD_PIO_WRITE_EXT : ATA_CMD_PIO_READ_EXT;
++
++                } else {                        
++                        if ( (priv->multi_available) && (sector_num > 1) )
++                                priv->curio_atacmd = is_write ? ATA_CMD_WRITE_MULTI : ATA_CMD_READ_MULTI;
++                        else
++                                priv->curio_atacmd = is_write ? ATA_CMD_PIO_WRITE : ATA_CMD_PIO_READ;
++                }
++
++                secnum = sector & 0xff;
++                cyl16 = (sector >> 8) & 0xffff;
++
++                devhead = (sector >> 24) & 0xf;
++                devhead |= ATA_LBA;
++        } else {
++                unsigned long blkno = (unsigned long) sector;
++                int sectorspertrack = priv->drive_chs_sectorspertrack;
++                int cylinders = priv->drive_chs_cylinders;
++                int heads = priv->drive_chs_heads;
++
++                secnum = (blkno % sectorspertrack) + 1;
++                blkno -= secnum - 1;
++
++                blkno /= sectorspertrack;
++
++                devhead = blkno / cylinders;
++
++                cyl16 = blkno % cylinders;
++
++                if (devhead > (heads-1) ) {
++                        return -1;
++                }
++        }
++
++        seccnt = (u8) sector_num;
++        cyl_hi = (cyl16 >> 8) & 0xff;
++        cyl_lo = cyl16 & 0xff;
++
++        write_devhead(priv, devhead);
++        write_sectornum(priv, secnum);
++        write_cyllo(priv, cyl_lo);
++        write_cylhi(priv, cyl_hi);
++        write_sectorcnt(priv, seccnt);
++
++        NPRINTK("lba=%d, sector=%lld, seccnt=%x sector=0x%x (%d), cyl_lo=%x, cyl_hi=%x, cyl16=0x%x, devhead=%x\n",
++                priv->drive_canlba, sector, seccnt, secnum, secnum, cyl_lo, cyl_hi, cyl16, devhead);
++
++        return 0;
++}
++
++
++
++int mpc52xx_ata_doreset(struct mpc52xx_blockata_priv  *priv)
++{
++        int ret = 0;
++
++        ret = wait_not_busy(priv);
++        if (ret!=0)
++                return -1;
++
++        NPRINTK("%s: set reset %x\n", __func__, read_altstatus(priv) );
++       
++        write_ctl(priv, ATA_SRST | ATA_NIEN);
++        ata_sleep(priv);
++
++        NPRINTK("%s: release reset, %x\n", __func__, read_altstatus(priv));
++
++        write_ctl(priv, ATA_NIEN);
++
++
++        ata_sleep(priv);
++
++        ret = wait_not_busy(priv);
++        if (ret<0)
++                return ret;
++
++        write_devhead(priv, 0x00);
++        ata_sleep(priv);
++
++        return wait_not_busy(priv);
++}
++
++/*
++ * Export stuff
++*/
++
++EXPORT_SYMBOL(mpc52xx_ata_setupsector);
++EXPORT_SYMBOL(mpc52xx_ata_doreset);
++EXPORT_SYMBOL(mpc52xx_ata_regcheck);
+diff --git a/drivers/block/mpc52xx/dodrivecmd.c b/drivers/block/mpc52xx/dodrivecmd.c
+new file mode 100644
+index 0000000..afbfded
+--- /dev/null
++++ b/drivers/block/mpc52xx/dodrivecmd.c
+@@ -0,0 +1,138 @@
++/*
++ *  mpc52xx_atablock / dodrivecmd.c
++ *
++ *  Copyright 2006 bplan GmbH
++ *
++ *  This file is subject to the terms and conditions of the GNU General Public
++ *  License.  See the file "COPYING" in the main directory of this archive
++ *  for more details.
++ */
++
++/*
++ * handle the ioctl HDIO_DRIVE_CMD command
++*/
++
++/**************/
++/**************/
++/**************/
++#include "mpc52xx_blockata.h"
++
++/**************/
++/**************/
++/**************/
++irqreturn_t ata_drivecmd_handler(struct mpc52xx_blockata_priv *priv, u8 ata_status)
++{
++	NPRINTK("%s: status=0x%2.2x\n", __func__, ata_status);
++
++	priv->ata_handler = ata_void_handler;
++	priv->io_inprogress = 0;
++	wake_up_interruptible(&priv->my_waitqueue);
++
++                 return IRQ_HANDLED;
++}
++
++         int mpc52xx_ata_dodrivecmd(
++                 struct mpc52xx_blockata_priv *priv,
++                 unsigned long *irqflags,
++                 u8 *args)
++         {
++                 int ret;
++                 u8 status;
++                 u8 cmd;
++
++                 NPRINTK("arg [0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x],\n", args[0], args[1], args[2], args[3]);
++
++                 cmd = args[0];
++                 if ( (cmd==ATA_CMD_ID_ATAPI) || (cmd==ATA_CMD_ID_ATA) )
++                 {
++                         int i;
++                         u16 *iddest_u16;
++                         u16 *drive_idendify;
++
++                         drive_idendify = priv->drive_identify;
++                         iddest_u16 = (u16*) (&args[4]);
++                         ret = 0;
++
++                         if (!priv->drive_identify_valid) {
++                                 if (priv->io_inprogress) {
++                                         VPRINTK("IO already in-progress, can not do more!\n");
++                                         ret = -EBUSY;
++                                         goto end;
++                                 }
++
++                                 priv->io_inprogress = 1;
++                                 ret = mpc52xx_ata_doidentify(priv);
++                                 priv->io_inprogress = 0;
++
++                                 if (ret!=0)
++                                         goto end;
++                         }
++
++                         for(i=0; i < 256; i++)
++                                 iddest_u16[i] = cpu_to_le16(drive_idendify[i]);
++
++                         goto end;
++                 }
++
++                 if (priv->io_inprogress)
++                 {
++                         VPRINTK("IO already in-progress, can not do more!\n");
++                         ret = -EBUSY;
++                         goto end;
++                 }
++
++                 priv->io_inprogress = 1;
++
++                 // a drive cmd looks very simple
++                 // simply copy the stuff in the  drive reg and wait for some interrupt
++
++                 // Get preprepatre to receive an interrupt
++                 priv->ata_handler = ata_drivecmd_handler;
++
++                 write_devfeature(priv, args[2]);
++                 write_sectorcnt(priv, args[3]);
++                 write_sectornum(priv, args[1]);
++
++                 write_cmd(priv, cmd);
++
++                 /*
++                  * I'm 100% (well not even 10%) happy and confortable with this IRQ/wait stuff
++                  * People should really write an how to "How to wait for an event in atomic section?"
++                 */
++                 spin_unlock_irqrestore(&priv->lock, *irqflags);
++                 ret = wait_event_interruptible_timeout(priv->my_waitqueue, priv->io_inprogress==0, 5*HZ);
++                 spin_lock_irqsave(&priv->lock, *irqflags);
++
++                 if (ret<0)
++                 {
++                         ret = -ERESTARTSYS;
++                         goto end;
++                 }
++
++                 // Whatever happen, we can read back the status to users mess
++                 //args[0] = read_devfeature(priv);
++
++                 status = read_status(priv);
++                 if ( ATASTS_GOT_ERR(status) )
++                         ret = -EIO;
++
++                 // Not sure for arg0
++                 args[0] = status;
++                 args[1] = read_devfeature(priv);
++                 args[2] = read_sectorcnt(priv);
++                 args[3] = read_sectornum(priv);
++
++                 NPRINTK("arg cmd=0x%2.2x, [0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x]\n", cmd, args[0], args[1], args[2], args[3]);
++                 NPRINTK("return %d\n", ret);
++
++                 if(ret>0)
++                         ret = 0;
++
++         end:
++                 priv->io_inprogress = 0;
++                 priv->ata_handler = ata_void_handler;
++                 return ret;
++         }
++
++
++EXPORT_SYMBOL(mpc52xx_ata_dodrivecmd);
+diff --git a/drivers/block/mpc52xx/hwmisc.c b/drivers/block/mpc52xx/hwmisc.c
+new file mode 100644
+index 0000000..862729a
+--- /dev/null
++++ b/drivers/block/mpc52xx/hwmisc.c
+@@ -0,0 +1,577 @@
++/*
++ *  mpc52xx_atablock / hwmisc.c
++ *
++ *  Copyright 2006 bplan GmbH
++ *
++ *  This file is subject to the terms and conditions of the GNU General Public
++ *  License.  See the file "COPYING" in the main directory of this archive
++ *  for more details.
++ */
++
++/*
++ * misc hw func (pio mode ...)
++*/
++
++/**************/
++/**************/
++/**************/
++#include "mpc52xx_blockata.h"
++
++/**************/
++/**************/
++/**************/
++static int ata_doidentify_atapi(struct mpc52xx_blockata_priv *priv)
++{
++        u16 * drive_idendify;
++        int ret;
++        u16 OneShort;
++
++        NPRINTK("\n");
++
++        ret = 0;
++        drive_idendify = priv->drive_identify;
++
++        NPRINTK("id[00]=0x%2.2x\n", drive_idendify[0]);
++        NPRINTK("id[85]=0x%2.2x\n", drive_idendify[85]);
++
++        OneShort = drive_idendify[0];
++        if ( (OneShort & 0xc000) != 0x8000)
++                return -1;
++
++        if (OneShort & (1<<7) )
++                priv->IsRemovable = 1;
++        else
++                priv->IsRemovable = 0;
++
++        priv->drive_canlba = 0;
++        priv->IsATAPI = 1;
++
++        priv->drive_identify_valid = 1;
++
++        return ret;
++}
++
++static int ata_doidentify(struct mpc52xx_blockata_priv *priv)
++{
++        int ret;
++
++        priv->drive_identify_valid = 0;
++
++        ret = wait_ready(priv);
++        if (ret!=0)
++                goto error;
++
++        write_cmd(priv, priv->UsePacket ? ATA_CMD_ID_ATAPI : ATA_CMD_ID_ATA);
++        ret = wait_drq(priv);
++        if (ret!=0)
++                goto error;
++
++        ret = mpc52xx_ata_docpupollread(priv, priv->drive_identify, 256);
++        if (ret<0)
++                goto error;
++
++        priv->drive_identify[49] = priv->drive_identify[49] & ~(1<<8);
++
++        memcpy(priv->drive_model, (char *) & priv->drive_identify[27], 40);
++        priv->drive_model[39] = '\0';
++        memcpy(priv->drive_firmware, (char *) & priv->drive_identify[23], 8);
++        priv->drive_firmware[7] = '\0';
++
++        if (priv->UsePacket)
++                return ata_doidentify_atapi(priv);
++
++        priv->drive_heads = priv->drive_identify[3];
++        priv->drive_cylinders = priv->drive_identify[1];
++        priv->drive_sectorspertrack = priv->drive_identify[6];
++        priv->drive_cap = priv->drive_identify[49];
++
++        priv->drive_canlba = priv->drive_cap & CAPF_LBA;
++        priv->drive_canlba48 = ((priv->drive_identify[83]) & (1 << 10))  == (1 << 10) ;
++
++        if (priv->drive_canlba) {
++                priv->drive_sectors = (sector_t)
++                                      ( (priv->drive_identify[60] & 0xffff)
++                                        | ( (priv->drive_identify[61] << 16) & 0xffff0000) );
++        } else {
++                priv->drive_sectors = (sector_t)
++                                      ( (priv->drive_identify[57] & 0xffff)
++                                        | ( (priv->drive_identify[58] << 16) & 0xffff0000) );
++        }
++
++
++        NPRINTK("%s: id[0]=%x\n", __func__, priv->drive_identify[0]);
++        NPRINTK("%s: id[1]=%x\n", __func__, priv->drive_identify[1]);
++        NPRINTK("%s: id[3]=%x\n", __func__, priv->drive_identify[3]);
++        NPRINTK("%s: id[6]=%x\n", __func__, priv->drive_identify[6]);
++        NPRINTK("%s: id[53]=%x\n", __func__, priv->drive_identify[53]);
++        NPRINTK("%s: id[54]=%x\n", __func__, priv->drive_identify[54]);
++        NPRINTK("%s: id[55]=%x\n", __func__, priv->drive_identify[55]);
++        NPRINTK("%s: id[56]=%x\n", __func__, priv->drive_identify[56]);
++
++        NPRINTK("%s: id[57/58]=%x %x\n", __func__, priv->drive_identify[57], priv->drive_identify[58]);
++        NPRINTK("%s: id[60/61]=%x %x\n", __func__, priv->drive_identify[57], priv->drive_identify[58]);
++        NPRINTK("%s: id[82]=%x\n", __func__, priv->drive_identify[82]);
++        NPRINTK("%s: id[83]=%x\n", __func__, priv->drive_identify[83]);
++
++
++        NPRINTK("%s: model=%s, fw=%s. %d heads, %d cylinders, %lld sectors. LBA=%d\n",
++                __func__,
++                priv->drive_model, priv->drive_firmware,
++                priv->drive_heads, priv->drive_cylinders, priv->drive_sectors, priv->drive_canlba );
++
++        priv->drive_identify_valid = 1;
++        return 0;
++
++error:
++        return -1;
++}
++
++int mpc52xx_ata_doidentify(struct mpc52xx_blockata_priv *priv)
++{
++        return ata_doidentify(priv);
++}
++
++/**************/
++/**************/
++int mpc52xx_ata_setpiomode(struct mpc52xx_blockata_priv *priv, int pio_mode)
++{
++        u8 setfeature_val;
++        int ret;
++
++        NPRINTK("%s: pio_mode=%d\n", __func__, pio_mode);
++
++        switch(pio_mode) {
++        case 0:
++                setfeature_val = XFER_PIO_0;
++                break;
++        case 1:
++                setfeature_val = XFER_PIO_1;
++                break;
++        case 2:
++                setfeature_val = XFER_PIO_2;
++                break;
++        case 3:
++                setfeature_val = XFER_PIO_3;
++                break;
++        case 4:
++                setfeature_val = XFER_PIO_4;
++                break;
++        default:
++                return -1;
++        }
++
++        write_sectorcnt(priv, setfeature_val);
++        write_devfeature(priv, SETFEATURES_XFER);
++
++        ret = wait_ready(priv);
++        if (ret !=0)
++                return ret;
++
++        write_cmd(priv, ATA_CMD_SET_FEATURES);
++
++        return wait_not_busy(priv);
++}
++
++/*
++ * if pio_arg is <0 then, return the best pio mode available
++*/
++int mpc52xx_ata_isthispiovalid(struct mpc52xx_blockata_priv *priv, int pio_arg)
++{
++        int ret;
++        int mode;
++
++        u16 id_fieldval;
++        u16 id_advpio;
++
++        NPRINTK("pio_arg=%d\n",  pio_arg);
++
++        if (!priv->drive_identify_valid) {
++                ret = ata_doidentify(priv);
++                if (ret!=0)
++                        return -1;
++        }
++
++        id_advpio = priv->drive_identify[64];
++        id_fieldval = priv->drive_identify[53];
++
++        NPRINTK("id_advpio=%x, id_fieldval=%x\n",id_advpio,  id_fieldval);
++
++        if (pio_arg<0) {
++                pio_arg = 2;
++
++                if (id_fieldval & 0x0002) {
++                        if (id_advpio&0x2)
++                                pio_arg = 4;
++                        else if (id_advpio&0x1)
++                                pio_arg = 3;
++                }
++        }
++
++        NPRINTK("pio_arg=%d\n", pio_arg);
++
++        switch(pio_arg) {
++        case 0:
++        case 1:
++        case 2:
++                mode = pio_arg;
++                break;
++
++        case 3:
++                mode = ( (id_fieldval&0x0002) && (id_advpio&0x1) )? pio_arg : -1;
++                break;
++
++        case 4:
++                mode = ( (id_fieldval&0x0002) && (id_advpio&0x2) )? pio_arg : -1;
++                break;
++
++        default:
++                mode = -1;
++        }
++
++        return mode;
++}
++
++
++/**************/
++#define IDENTIFY_MULTI_MAXSECMASK   0x00ff
++#define IDENTIFY_MULTI_OKFLAG    0x00100
++
++int mpx52xx_ata_dosetmulti(struct mpc52xx_blockata_priv *priv, u16 val)
++{
++        int ret;
++
++        NPRINTK("set multi to %d\n", val);
++
++        if (priv->UsePacket)
++                return -1;
++
++        write_sectorcnt(priv, val&0xff);
++
++        ret = wait_ready(priv);
++        if (ret !=0)
++                return -1;
++
++        ATA_DUMPREG
++        write_cmd(priv, ATA_CMD_SETMULTI);
++
++        ata_sleep(priv);
++        ret = wait_not_busy(priv);
++        if (ret !=0)
++                return -1;
++
++        return 0;
++}
++
++#define IS_MULTIOK(__identify_multi__)  \
++(  \
++ (__identify_multi__ & IDENTIFY_MULTI_OKFLAG)  \
++  && (__identify_multi__ & IDENTIFY_MULTI_MAXSECMASK) \
++)
++
++static int ata_multi_probeandset(struct mpc52xx_blockata_priv *priv)
++{
++        int ret;
++        u16 identify_multi;
++        u16 identify_multimax;
++
++        priv->multi_available = 0;
++
++        if (priv->UsePacket)
++                return -1;
++
++        NPRINTK("id[59]=0x%x, id[47]=0x%x\n", priv->drive_identify[59], priv->drive_identify[47]);
++
++        identify_multi = priv->drive_identify[59];
++        if ( IS_MULTIOK(identify_multi) ) {
++                priv->multi_available = 1;
++                priv->multi_secpercmd = identify_multi & IDENTIFY_MULTI_MAXSECMASK;
++        } else {
++                identify_multimax = priv->drive_identify[47] & IDENTIFY_MULTI_MAXSECMASK;
++                ret = mpx52xx_ata_dosetmulti(priv, identify_multimax);
++                if (ret<0)
++                        goto error;
++
++                ret = ata_doidentify(priv);
++                if (ret!=0)
++                        goto error;
++
++                NPRINTK("idenditify updated, identify_multimax=%d, s=%x, id[59]=0x%x, id[47]=0x%x\n",
++                        identify_multimax, read_altstatus(priv), priv->drive_identify[59], priv->drive_identify[47]);
++
++                identify_multi = priv->drive_identify[59];
++
++                if ( IS_MULTIOK(identify_multi) ) {
++                        priv->multi_available = 1;
++                        priv->multi_secpercmd = identify_multi & IDENTIFY_MULTI_MAXSECMASK;
++                } else {
++                        priv->multi_secpercmd = MAX_SECPERREQ;
++                }
++
++        }
++
++        return 0;
++
++error:
++        priv->multi_secpercmd = MAX_SECPERREQ;
++        priv->multi_available = 0;
++
++        return ret;
++}
++
++
++/**************/
++static int ata_dodiag(struct mpc52xx_blockata_priv *priv)
++{
++        int ret;
++        u8 diagcode;
++        u8 sectorcount;
++        u8 lbah;
++        u8 lbal;
++        u8 lbam;
++
++        NPRINTK("1\n");
++
++        ret = wait_not_busy(priv);
++        if (ret!=0)
++                goto error;
++
++        NPRINTK("cmd\n");
++        write_cmd(priv, ATA_CMD_EDD);
++
++        wait_not_busy(priv);
++        diagcode = read_devfeature(priv);
++
++        NPRINTK("diagcode=%x\n", diagcode);
++
++        /* Check if this device implement the PACKET feature set
++         * see ATAPI6 spec section 9.12
++         * Non Packet has this signature: 
++         *   Sector Count 01h
++         *   LBA Low     01h
++         *   LBA Mid    00h
++         *   LBA High    00h
++         *   Device    00h
++         *  
++         * Packet has this signature: 
++         *   Sector Count 01h
++         *   LBA Low     01h
++         *   LBA Mid    14h
++         *   LBA High    EBh
++         *
++         *  
++        */
++        sectorcount = read_sectorcnt(priv);
++        lbal = read_sectornum(priv);
++        lbam = read_cyllo(priv);
++        lbah = read_cylhi(priv);
++
++        NPRINTK("sc=%2.2x lbal=%2.2x lbam=%2.2x lbah=%2.2x\n", sectorcount, lbal, lbam, lbah);
++
++        if ( (sectorcount != 0x01) && (lbal != 0x01) )
++                goto error;
++
++        if ( (lbam==0) && (lbah==0) )
++                priv->UsePacket = 0;
++        else if ((lbam==0x14) && (lbah==0xeb) )
++                priv->UsePacket = 1;
++        else
++                goto error;
++
++        return ! (diagcode & 0x01);
++
++error:
++        NPRINTK("error %d\n", ret);
++        ATA_DUMPREG
++
++        return -1;
++}
++/**************/
++void mpc52xx_ata_dumpreg(struct mpc52xx_blockata_priv *priv)
++{
++        u8 seccnt, sector, cyl_lo, cyl_hi, error, status;
++
++        seccnt = read_sectorcnt(priv);
++        sector = read_sectornum(priv);
++        cyl_lo = read_cyllo(priv);
++        cyl_hi = read_cylhi(priv);
++        error  = read_error(priv);
++        status = read_altstatus(priv);
++
++        VPRINTK("seccnt=%x sector=%x, cyl_lo=%x, cyl_hi=%x, error=%x, status =%x \n",
++                seccnt, sector, cyl_lo, cyl_hi, error, status);
++}
++
++static int ata_doreset(struct mpc52xx_blockata_priv *priv)
++{
++        int ret = 0;
++
++        ret = wait_not_busy(priv);
++        if (ret!=0)
++                return -1;
++
++        NPRINTK("set reset %x\n", read_altstatus(priv) );
++        write_ctl(priv, ATA_SRST | ATA_NIEN);
++        ata_sleep(priv);
++
++        NPRINTK("release reset, %x\n", read_altstatus(priv));
++        write_ctl(priv, ATA_NIEN);
++
++        ata_sleep(priv);
++
++        ret = wait_not_busy(priv);
++        if (ret<0)
++                return ret;
++
++        write_devhead(priv, 0x00);
++        ata_sleep(priv);
++
++        wait_not_busy(priv);
++        if (ret<0)
++                return ret;
++
++        return ATASTS_GOT_ERR( read_altstatus(priv) );
++}
++
++/**************/
++static int ata_setupchs(struct mpc52xx_blockata_priv *priv)
++{
++        int ret = 0;
++
++        NPRINTK("s=0x%2.2x, lba=%d, secper=%d, heads=%dn",
++                read_altstatus(priv),
++                priv->drive_canlba,
++                priv->drive_sectorspertrack,
++                priv->drive_heads);
++
++        priv->drive_chs_ok = 0;
++
++        if
++        (
++                (priv->drive_sectorspertrack == 0)
++                || priv->drive_canlba
++        )
++		return -1;
++
++        if (!priv->drive_identify_valid) {
++                ret = ata_doidentify(priv);
++                if (ret!=0)
++                        return -1;
++        }
++
++        NPRINTK("wait1 s=%2.2x\n", read_altstatus(priv) );
++        ret = wait_not_busy(priv);
++        if (ret<0)
++                return ret;
++
++        write_sectorcnt(priv, priv->drive_sectorspertrack );
++        write_devhead(priv, priv->drive_heads - 1);
++
++        NPRINTK("wait2 s=%2.2x\n", read_altstatus(priv) );
++        ret = wait_ready(priv);
++        if (ret<0) {
++                ATA_DUMPREG
++                return ret;
++        }
++
++        write_cmd(priv, ATA_CMD_INIT_DEV_PARAMS);
++
++        NPRINTK("wait3 s=%2.2x\n", read_altstatus(priv) );
++        ret = wait_not_busy(priv);
++        if (ret<0) {
++                ATA_DUMPREG
++                return ret;
++        }
++
++        ret = ata_doidentify(priv);
++        if (ret!=0)
++                return ret;
++
++        if (!(priv->drive_identify[53] & 0x0001))
++                return -1;
++
++        priv->drive_chs_ok = 1;
++
++        priv->drive_chs_heads = priv->drive_identify[54];
++        priv->drive_chs_cylinders = priv->drive_identify[55];
++        priv->drive_chs_sectorspertrack = priv->drive_identify[56];
++
++        NPRINTK("ok. CHS=%d/%d/%ds=0x%2.2x\n",
++                read_altstatus(priv),
++                priv->drive_chs_cylinders,
++                priv->drive_chs_heads,
++                priv->drive_chs_sectorspertrack);
++
++        return 0;
++}
++
++/**************/
++/**************/
++/**************/
++
++/*
++ * Simple and dump drive init func
++ * reset, sanity check, drive presence, get drive info
++*/
++int mpc52xx_ata_init_drive(struct mpc52xx_blockata_priv *priv)
++{
++        int ret;
++
++        ret = wait_not_busy(priv);
++        if (ret!=0)
++                goto error;
++
++        write_ctl(priv, ATA_NIEN);
++
++        NPRINTK("select dev 0\n");
++        write_devhead(priv, 0x00);
++
++        ata_sleep(priv);
++
++        ata_doreset(priv);
++
++        /* Some check ... */
++        NPRINTK("regcheck %x\n", read_altstatus(priv));
++        ret = mpc52xx_ata_regcheck(priv);
++        if (ret!=0)
++                goto error;
++
++        /* diagnostic */
++        NPRINTK("diag %x\n", read_altstatus(priv));
++        ret = ata_dodiag(priv);
++        if (ret!=0)
++                goto error;
++
++        /* Get information from the drive */
++        NPRINTK("do id %x, UsePacket=%d\n", read_altstatus(priv),  priv->UsePacket);
++        if (!priv->drive_identify_valid) {
++                ret = ata_doidentify(priv);
++                if (ret!=0)
++                        goto error;
++        }
++
++        ata_setupchs(priv);
++        ata_multi_probeandset(priv);
++
++        return ret;
++
++error:
++        NPRINTK("%s: error %d, altsts=%x, err=%x\n", __func__, ret, read_altstatus(priv),  read_error(priv));
++        ATA_DUMPREG;
++
++        return -1;
++}
++
++u32 mpc52xx_ata_getregisterbase(struct mpc52xx_blockata_priv *priv)
++{ return 0xf0003a00; }
++
++/*
++ * Export stuff
++*/
++
++EXPORT_SYMBOL(mpc52xx_ata_init_drive);
++EXPORT_SYMBOL(mpc52xx_ata_getregisterbase);
++EXPORT_SYMBOL(mpc52xx_ata_doidentify);
++EXPORT_SYMBOL(mpc52xx_ata_setpiomode);
++
++EXPORT_SYMBOL(mpc52xx_ata_isthispiovalid);
++EXPORT_SYMBOL(mpx52xx_ata_dosetmulti);
+diff --git a/drivers/block/mpc52xx/mpc52xx_blockata.h b/drivers/block/mpc52xx/mpc52xx_blockata.h
+new file mode 100644
+index 0000000..69a6a88
+--- /dev/null
++++ b/drivers/block/mpc52xx/mpc52xx_blockata.h
+@@ -0,0 +1,311 @@
++/*
++ *  mpc52xx_blockata.h
++ *
++ *  Copyright 2006 bplan GmbH
++ *
++ *  This file is subject to the terms and conditions of the GNU General Public
++ *  License.  See the file "COPYING" in the main directory of this archive
++ *  for more details.
++ */
++
++
++#ifndef __MPC52xx_BLOCKATA_H__
++#define __MPC52xx_BLOCKATA_H__
++
++#include <linux/major.h>
++#include <linux/vmalloc.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/blkdev.h>
++#include <linux/bitops.h>
++#include <linux/genhd.h>
++#include <linux/hdreg.h>
++#include <linux/fs.h>
++
++#include <asm/kmap_types.h>
++#include <asm/mpc52xx.h>
++
++/**************/
++/**************/
++/**************/
++//#define __DEBUG__
++
++/**************/
++/**************/
++/**************/
++#include <platforms/efika/bestcomm.h>
++
++#include "protos.h"
++#include "mpc52xx_ide.h"
++
++
++/**************/
++/**************/
++/**************/
++
++#ifdef __DEBUG__
++#define DEBUG
++#define NPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args)
++//#define NPRINTK2(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args)
++#define NPRINTK2(fmt, args...)
++
++#define ATA_DUMPREG mpc52xx_ata_dumpreg(priv);
++
++#else
++#define NPRINTK(fmt, args...)
++#define NPRINTK2(fmt, args...)
++#define ATA_DUMPREG
++#endif
++
++/**************/
++/**************/
++/**************/
++
++#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_VERBOSE
++#define VPRINTK(fmt, args...) if ( printk_ratelimit() ) { printk(KERN_ERR DEVSKEL_DEVICENAME ": " fmt, ## args); }
++#else
++#define VPRINTK(fmt, args...)
++#endif
++
++#define DEVICE_USERLIMIT 1024
++#define KERNEL_SECTOR_SIZE 512
++
++// I notice 8 gives some good result
++#define DRIVER_MAXHWSEG 8
++
++/**************/
++/**************/
++/**************/
++
++
++#ifndef ATA_CMD_RESET
++#define ATA_CMD_RESET   0x08
++#endif
++
++#ifndef ATA_CMD_SETMULTI
++#define ATA_CMD_SETMULTI   0xc6
++#endif
++
++/**************/
++/**************/
++/**************/
++
++#ifndef bio_cur_sectors_idx
++#define bio_cur_sectors_idx(__bio__,__idx__)    (bio_iovec_idx((__bio__), (__idx__))->bv_len >> 9)
++#endif
++
++#ifndef bio_getnext
++#define bio_getnext(__bio__) ( (__bio__)->bi_next )
++#endif
++
++
++#ifndef bio_getsector
++#define bio_getsector(__bio__) ( (__bio__)->bi_sector )
++#endif
++
++#ifndef bio_getcuridx
++#define bio_getcuridx(__bio__) ( (__bio__)->bi_idx )
++#endif
++
++#ifndef bio_islastidx
++#define bio_islastidx(__bio__, __idx__) ( (__idx__) >= (__bio__)->bi_vcnt )
++#endif
++
++
++
++/**************/
++/**************/
++/**************/
++
++/*
++ *
++ * TO DO:
++ * - better error handling
++ * - Transaction timeout/reset
++ * - test and fix LBA48 addressing
++ * - code, test and fix CHS addressing
++ *
++ * History
++ * - 0.1. 27.06.2006
++ *        Initial revision
++ *        PIO func, SDMA/CPU polling...
++ *        Reliable operation (1 or 2 MB/s)
++ *
++ * - 0.2. 28.06.2006
++ *        Interrupt based driver!
++ *        IRQ handlers, handles better bio, bio vec, req...
++ *        Reliable operation (write 1.5MB/s, read 3.5MB/s to 6.5MB/s)
++ *
++ * - 0.3b1. 29.06.2006
++ *        Cleanup and small fixes
++ *        Wait for DRQ interrupt instead of polling for read
++ *        Add user count feature
++ *
++ * - 0.3b2. 30.06.2006
++ *        Fixed the nopen/nrelease -> release was disabling IRQ even if
++ *          there was still some people using it. I don't even speak about open!
++ *        Cleanup and small fixes
++ *
++ * - 0.4  02.07.2006
++ *        Driver totaly cleaned up  and spread other severals sources file
++ *        Implemented LBA48 but untested due to lack of drive (you've been warmed!)
++ *        
++ * - 0.5  07.07.2006
++ *        General cleanup
++ *        Better SDMA task configuration
++ *        Try to adjust the block queue config
++ *
++ * - 0.6b1 30.07.2006
++ *        General cleanup
++ *        Add HIDIO_DRIVE_CMD support
++ *        Fixed (a bit) spinlock_* 
++ *        Primilary ATAPI/Packet support
++ *
++ * - 0.6  31.07.2006
++ *        General cleanup
++ *        Nicely failed when ATAPI/Packet command is needed
++ *        Fixed HDIO_DRIVE_CMD/Identify
++ *
++ * - 0.7  18.10.2006
++ *        General cleanup
++ *        fix text layout for Linux patch
++ *        First try to init the drive and then the Linux block system becase
++ *          the block code BUG() on free
++*/
++
++
++/**************/
++/**************/
++/**************/
++
++#define MAX_DMA_BUFFERS 4
++#define MAX_DMA_BUFFER_SIZE 512*256
++
++#define DEVSKEL_DRIVERVERSION "0.7"
++#define DEVSKEL_DRIVERNAME "MPC52xx ATA/PIO"
++#define DEVSKEL_DEVICENAME "mpc52xx_ata"
++
++#define MAX_SECPERREQ DRIVER_MAXHWSEG
++
++
++/**************/
++/**************/
++/**************/
++
++#ifndef MPC52xx_ATA_OFFSET
++#define MPC52xx_ATA_OFFSET (0x3a00)
++#endif
++
++#define ATAFIFO_BUSADDR ( (u32) 0xf0003a60 )
++
++
++/**************/
++/**************/
++/**************/
++
++/* Helper to compute timing parameters */
++#define CALC_CLK_VALUE_UP(c,v) (((v) + c - 1) / c)
++
++/**************/
++/**************/
++/**************/
++/* Private structures used by the driver */
++struct mpc52xx_ata_timings
++{
++        u32 pio1;
++        u32 pio2;
++        u32 mdma1;
++        u32 mdma2;
++        u32 udma1;
++        u32 udma2;
++        u32 udma3;
++        u32 udma4;
++        u32 udma5;
++        int using_udma;
++};
++
++/**************/
++/**************/
++/**************/
++struct mpc52xx_blockata_priv
++{
++        struct gendisk *device_gendisk;
++        struct request_queue *device_queue;
++        int major;
++
++        spinlock_t lock;
++
++	wait_queue_head_t my_waitqueue;
++
++	int drive_inited;
++	int usercnt;
++
++	int drive_identify_valid;
++	u16 drive_identify[256];
++
++        char drive_model[40];
++        char drive_firmware[8];
++
++        sector_t drive_sectors;
++        int drive_sectorspertrack;
++        int drive_cylinders;
++        int drive_heads;
++
++        int drive_chs_ok;
++        int drive_chs_sectorspertrack;
++        int drive_chs_cylinders;
++        int drive_chs_heads;
++
++#define CAPF_LBA (1<<9)
++        u16 drive_cap;
++        int drive_canlba;
++        int drive_canlba48;
++
++        u8 curio_atacmd;
++
++        int io_inprogress;
++
++        unsigned int ipb_period;	/* in ps */
++
++        struct mpc52xx_ata __iomem *ata_regs;
++        u32 ata_regs_bus;
++        struct mpc52xx_ata_timings  timings[2];
++
++        struct bestcomm_taskhandle taskhandle;
++        struct bestcomm_taskhandle *sdma;
++
++        int ata_irq;
++        int sdma_irq;
++
++        int multi_secpercmd;
++        int multi_available;
++
++        irqreturn_t (*sdma_handler) (struct mpc52xx_blockata_priv  *priv);
++        irqreturn_t (*ata_handler) (struct mpc52xx_blockata_priv  *priv, u8 ata_status);
++
++        int curio_sectodo;
++
++        int curio_secidx;
++        int curio_secpershot;
++        u16 *curio_buffer;
++
++        struct request *curio_req;
++        struct bio *curio_bio;
++        int curio_bioidx;
++        sector_t curio_sector;
++
++        int piomode;
++ 
++        int UsePacket;
++        int IsATAPI;
++        int IsRemovable;
++};
++
++
++/**************/
++/**************/
++/**************/
++
++#include "piofunc_inline.h"
++
++#endif
+diff --git a/drivers/block/mpc52xx/mpc52xx_ide.h b/drivers/block/mpc52xx/mpc52xx_ide.h
+new file mode 100644
+index 0000000..6cd35eb
+--- /dev/null
++++ b/drivers/block/mpc52xx/mpc52xx_ide.h
+@@ -0,0 +1,131 @@
++/*
++ * drivers/ide/ppc/mpc52xx_ide.h
++ *
++ * Definitions 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.
++ */
++
++#ifndef __MPC52xx_IDE_H__
++#define __MPC52xx_IDE_H__
++
++
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/ide.h>
++#include <asm/types.h>
++#include <asm/io.h>
++
++#include <asm/mpc52xx.h>
++
++/* 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];
++};
++
++
++/* Function definition */
++
++
++static inline void
++mpc52xx_ide_wait_tip_bit_clear(struct mpc52xx_ata __iomem *regs)
++{
++        int timeout = 1000;
++
++        while (in_be32(&regs->host_status) & MPC52xx_ATA_HOSTSTAT_TIP)
++                if (timeout-- == 0)
++                {
++                        printk(KERN_ERR
++                               "mpc52xx-ide: Timeout waiting for TIP clear\n");
++                        break;
++                }
++        udelay(10);	/* FIXME: Necessary ??? */
++}
++
++extern void mpc52xx_ide_setup_hwif_iops(ide_hwif_t *hwif);
++
++
++#endif /* __MPC52xx_IDE_H__ */
++
+diff --git a/drivers/block/mpc52xx/piofunc_inline.h b/drivers/block/mpc52xx/piofunc_inline.h
+new file mode 100644
+index 0000000..ca89dec
+--- /dev/null
++++ b/drivers/block/mpc52xx/piofunc_inline.h
+@@ -0,0 +1,250 @@
++/*
++ *  mpc52xx_atablock / piofunc_inline.h
++ *
++ *  Copyright 2006 bplan GmbH
++ *
++ *  This file is subject to the terms and conditions of the GNU General Public
++ *  License.  See the file "COPYING" in the main directory of this archive
++ *  for more details.
++ */
++
++
++#ifndef __MPC52xx_BLOCKATA_PIOFUNC_H__
++#define __MPC52xx_BLOCKATA_PIOFUNC_H__
++
++
++/**************/
++/**************/
++/**************/
++
++#include "mpc52xx_blockata.h"
++
++/**************/
++/**************/
++/**************/
++
++#include <asm/io.h>
++
++/*
++ * Pio helper
++*/
++
++static inline u8 read_altstatus(struct mpc52xx_blockata_priv *priv)
++{
++        struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs;
++        return readb(&ata_regs->tf_control);
++}
++
++static inline u8 read_status(struct mpc52xx_blockata_priv *priv)
++{
++        struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs;
++        return readb(&ata_regs->tf_command);
++}
++
++static inline u8 read_sectorcnt(struct mpc52xx_blockata_priv *priv)
++{
++        struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs;
++        return readb(&ata_regs->tf_sec_count);
++}
++
++static inline u8 read_sectornum(struct mpc52xx_blockata_priv *priv)
++{
++        struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs;
++        return readb(&ata_regs->tf_sec_num);
++}
++
++static inline u8 read_cylhi(struct mpc52xx_blockata_priv *priv)
++{
++        struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs;
++        return readb(&ata_regs->tf_cyl_high);
++}
++
++static inline u8 read_cyllo(struct mpc52xx_blockata_priv *priv)
++{
++        struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs;
++        return readb(&ata_regs->tf_cyl_low);
++}
++
++static inline u8 read_devfeature(struct mpc52xx_blockata_priv *priv)
++{
++        struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs;
++        return readb(&ata_regs->tf_features);
++}
++static inline u8 read_error(struct mpc52xx_blockata_priv *priv)
++{
++        return read_devfeature(priv);
++}
++
++static inline u16 read_data(struct mpc52xx_blockata_priv *priv)
++{
++        struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs;
++        return readw(&ata_regs->tf_data);
++}
++
++/**************/
++static inline void write_data(struct mpc52xx_blockata_priv *priv, u16 val)
++{
++        struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs;
++        writew(val, &ata_regs->tf_data);
++}
++
++static inline void write_devfeature(struct mpc52xx_blockata_priv *priv, u8 val)
++{
++        struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs;
++        writeb(val, &ata_regs->tf_features);
++}
++
++
++static inline void write_cyllo(struct mpc52xx_blockata_priv *priv, u8 val)
++{
++        struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs;
++        writeb(val, &ata_regs->tf_cyl_low);
++}
++
++static inline void write_cylhi(struct mpc52xx_blockata_priv *priv, u8 val)
++{
++        struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs;
++        writeb(val, &ata_regs->tf_cyl_high);
++}
++
++static inline void write_cmd(struct mpc52xx_blockata_priv *priv, u8 val)
++{
++        struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs;
++        writeb(val, &ata_regs->tf_command);
++}
++
++static inline void write_ctl(struct mpc52xx_blockata_priv *priv, u8 val)
++{
++        struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs;
++        writeb(val, &ata_regs->tf_control);
++}
++
++static inline void write_sectornum(struct mpc52xx_blockata_priv *priv, u8 val)
++{
++        struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs;
++        writeb(val, &ata_regs->tf_sec_num);
++}
++
++static inline void write_sectorcnt(struct mpc52xx_blockata_priv *priv, u8 val)
++{
++        struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs;
++        writeb(val, &ata_regs->tf_sec_count);
++}
++
++
++static inline void write_devhead(struct mpc52xx_blockata_priv *priv, u8 val)
++{
++        struct mpc52xx_ata __iomem *ata_regs = priv->ata_regs;
++        writeb(val, &ata_regs->tf_dev_head);
++}
++
++
++/**************/
++static inline void ata_sleep(struct mpc52xx_blockata_priv *priv)
++{
++        read_altstatus(priv);
++        udelay(500);
++}
++
++static inline void ata_sleep2(struct mpc52xx_blockata_priv *priv)
++{
++        read_altstatus(priv);
++        udelay(1);
++}
++
++/**************/
++#define ATASTS_IS_NOTBUSY(__status__)  ( ! ( (__status__) & ATA_BUSY) )
++#define ATASTS_IS_READY(__status__) ( ( (__status__) & (ATA_DRDY|ATA_BUSY) ) == ATA_DRDY )
++#define ATASTS_IS_DRQ(__status__) ( (__status__) & ATA_DRQ)
++#define ATASTS_GOT_ERR(__status__) ( (__status__) & ATA_ERR)
++
++#define WAIT_TIMEOUT  (1000*1000)
++
++
++static inline u8 read_mystatus(struct mpc52xx_blockata_priv *priv)
++{
++        return read_altstatus(priv);
++}
++
++static inline int wait_not_busy(struct mpc52xx_blockata_priv *priv)
++{
++        int timeout;
++        u8 status;
++
++        timeout = WAIT_TIMEOUT;
++
++        status = read_mystatus(priv);
++        if ( ATASTS_IS_NOTBUSY(status) )
++                goto end;
++
++        while(timeout--) {
++                status = read_mystatus(priv);
++                if (  ATASTS_IS_NOTBUSY(status)  )
++                        goto end;
++
++                ata_sleep2(priv);
++        }
++
++        NPRINTK("%s: timeout, %x\n", __func__, status);
++
++        return -1;
++
++end:
++        return 0;
++}
++
++
++static inline int wait_ready(struct mpc52xx_blockata_priv *priv)
++{
++        int timeout;
++        u8 status;
++
++        timeout = WAIT_TIMEOUT;
++
++        status = read_mystatus(priv);
++        if ( ATASTS_IS_READY(status) )
++                goto end;
++
++        while(timeout--) {
++                status = read_mystatus(priv);
++                if (  ATASTS_IS_READY(status)  )
++                        goto end;
++
++                ata_sleep2(priv);
++        }
++
++        NPRINTK("%s: timeout, %x\n", __func__, status);
++
++        return -1;
++
++end:
++        return ATASTS_GOT_ERR(status) ? -1 : 0;
++}
++
++static inline int wait_drq(struct mpc52xx_blockata_priv *priv)
++{
++        int timeout;
++        u8 status;
++
++        timeout = WAIT_TIMEOUT;
++
++        status = read_mystatus(priv);
++        if ( ATASTS_IS_DRQ(status) )
++                goto end;
++
++        while(timeout--) {
++                status = read_mystatus(priv);
++                if ( ATASTS_IS_DRQ(status) )
++                        goto end;
++
++                ata_sleep2(priv);
++        }
++
++        NPRINTK("%s: timeout, %x\n", __func__, status);
++        return -1;
++
++end:
++        return ATASTS_GOT_ERR(status) ? -1 : 0;
++}
++
++#endif
+diff --git a/drivers/block/mpc52xx/protos.h b/drivers/block/mpc52xx/protos.h
+new file mode 100644
+index 0000000..aaee5b6
+--- /dev/null
++++ b/drivers/block/mpc52xx/protos.h
+@@ -0,0 +1,107 @@
++/*
++ *  protos.h
++ *
++ *  Copyright 2006 bplan GmbH
++ *
++ *  This file is subject to the terms and conditions of the GNU General Public
++ *  License.  See the file "COPYING" in the main directory of this archive
++ *  for more details.
++ */
++
++
++/*
++ * Simply summaries every protos we use over the driver
++*/
++
++#ifndef __MPC52xx_BLOCKATA_PROTOS_H__
++#define __MPC52xx_BLOCKATA_PROTOS_H__
++
++#include <linux/irq.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++
++struct mpc52xx_blockata_priv;
++
++/**********/
++/* HWMISC */
++/**********/
++int mpc52xx_ata_setpiomode(struct mpc52xx_blockata_priv *priv, int pio_mode);
++int mpc52xx_ata_init_drive(struct mpc52xx_blockata_priv *priv);
++int mpc52xx_ata_isthispiovalid(struct mpc52xx_blockata_priv *priv, int pio_arg);
++int mpc52xx_ata_doidentify(struct mpc52xx_blockata_priv *priv);
++u32 mpc52xx_ata_getregisterbase(struct mpc52xx_blockata_priv *priv);
++int mpx52xx_ata_dosetmulti(struct mpc52xx_blockata_priv *priv, u16 val);
++
++
++/**********/
++/*  ATA   */
++/**********/
++int mpc52xx_ata_setupsector(struct mpc52xx_blockata_priv  *priv, sector_t sector, int sector_num, int is_write);
++int mpc52xx_ata_isthispiovalid(struct mpc52xx_blockata_priv  *priv, int pio_arg);
++void mpc52xx_ata_dumpreg(struct mpc52xx_blockata_priv  *priv);
++int mpc52xx_ata_doreset(struct mpc52xx_blockata_priv  *priv);
++int mpc52xx_ata_regcheck(struct mpc52xx_blockata_priv  *priv);
++int mpc52xx_ata_dodrivereset(struct mpc52xx_blockata_priv  *priv);
++
++/************/
++/*DODRIVECMD*/
++/************/
++int mpc52xx_ata_dodrivecmd(
++        struct mpc52xx_blockata_priv *priv,
++        unsigned long *irqflags,
++        u8 *arg);
++
++#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA
++
++
++/**********/
++/*  SDMA  */
++/**********/
++int mpc52xx_ata_sdma_setup(struct mpc52xx_blockata_priv  *priv);
++
++void sdma_ata_rx_init(struct bestcomm_taskhandle *mytaskhandle);
++void sdma_ata_tx_init(struct bestcomm_taskhandle *mytaskhandle);
++void sdma_ata_reset(struct bestcomm_taskhandle *mytaskhandle);
++int sdma_ata_getirq(struct bestcomm_taskhandle *mytaskhandle);
++void sdma_ata_clear_irq(struct bestcomm_taskhandle *mytaskhandle);
++void sdma_ata_disable(struct bestcomm_taskhandle *mytaskhandle);
++void sdma_ata_enable(struct bestcomm_taskhandle *mytaskhandle);
++
++void sdma_ata_submit_buffer(
++        struct bestcomm_taskhandle *mytaskhandle,
++        void *cookie,
++        void *data1,
++        void *data2,
++        int length);
++
++#endif /* CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA */
++
++/**********/
++/*TRANSFER*/
++/**********/
++int mpc52xx_ata_docpupollread(
++        struct mpc52xx_blockata_priv *priv,
++        void *buffer,
++        int len);
++
++int mpc52xx_ata_docpupollwrite(
++        struct mpc52xx_blockata_priv*priv,
++        void *buffer,
++        int len);
++
++int mpc52xx_ata_dotransfer(
++        struct mpc52xx_blockata_priv *priv,
++        struct request *req,
++        struct bio *bio,
++        int bio_index,
++        sector_t sector,
++        int sectorcnt,
++        char *buffer,
++        int is_write);
++
++irqreturn_t sdma_void_handler(struct mpc52xx_blockata_priv *priv);
++irqreturn_t ata_void_handler(struct mpc52xx_blockata_priv *priv, u8 ata_status);
++
++void mpc52xx_ata_ack_blkreq(struct mpc52xx_blockata_priv *priv, int retval);
++
++#endif
+diff --git a/drivers/block/mpc52xx/sdmatask.c b/drivers/block/mpc52xx/sdmatask.c
+new file mode 100644
+index 0000000..eb321e8
+--- /dev/null
++++ b/drivers/block/mpc52xx/sdmatask.c
+@@ -0,0 +1,142 @@
++/*
++ *  mpc52xx_atablock / piofunc.c
++ *
++ *  Copyright 2006 bplan GmbH
++ *
++ *  This file is subject to the terms and conditions of the GNU General Public
++ *  License.  See the file "COPYING" in the main directory of this archive
++ *  for more details.
++ */
++
++
++/**************/
++/**************/
++/**************/
++
++#include "mpc52xx_blockata.h"
++
++
++/**************/
++/**************/
++/**************/
++
++
++#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA
++
++#include <asm/prom.h>
++
++/**************/
++/**************/
++/**************/
++
++/**************/
++void sdma_ata_rx_init(struct bestcomm_taskhandle *mytaskhandle)
++{
++        struct sdma_ata_inc *inc;
++        inc = (struct sdma_ata_inc *)bestcomm_taskget_inctable(mytaskhandle);
++
++        NPRINTK("inc = %p\n", inc);
++
++        inc->incr_bytes = -(s16)sizeof(u16);
++        inc->incr_src = 0;
++        inc->incr_dst = sizeof(u16);
++}
++
++/**************/
++/*
++ * Initialize ATA transmit task.
++ */
++void sdma_ata_tx_init(struct bestcomm_taskhandle *mytaskhandle)
++{
++        struct sdma_ata_inc *inc;
++        inc = (struct sdma_ata_inc *)bestcomm_taskget_inctable(mytaskhandle);
++
++        NPRINTK("inc = %p\n", inc);
++
++        inc->incr_bytes = -(s16)sizeof(u16);
++        inc->incr_src = sizeof(u16);
++        inc->incr_dst = 0;
++}
++
++/**************/
++void sdma_ata_reset(struct bestcomm_taskhandle *mytaskhandle)
++{
++        struct sdma_ata_var *var;
++        var = (struct sdma_ata_var *)bestcomm_taskget_vartable(mytaskhandle);
++
++        NPRINTK("var = %p\n", var);
++
++        sdma_reset_buffers2((struct sdma *) mytaskhandle);
++
++        var->bd_start = var->bd_base;
++}
++
++
++/**************/
++int sdma_ata_getirq(struct bestcomm_taskhandle *mytaskhandle)
++{
++        return bestcomm_taskget_irq(mytaskhandle);
++}
++
++/**************/
++void sdma_ata_clear_irq(struct bestcomm_taskhandle *mytaskhandle)
++{
++        bestcomm_taskclear_irq(mytaskhandle);
++}
++
++/**************/
++void sdma_ata_disable(struct bestcomm_taskhandle *mytaskhandle)
++{
++        bestcomm_taskdisable(mytaskhandle);
++}
++
++/**************/
++void sdma_ata_enable(struct bestcomm_taskhandle *mytaskhandle)
++{
++        bestcomm_taskenable(mytaskhandle);
++}
++
++int mpc52xx_ata_sdma_setup(struct mpc52xx_blockata_priv  *priv)
++{
++        struct sdma *s;
++
++        s = sdma_ata_preinit(MAX_DMA_BUFFERS);
++        if (!s)
++                return -1;
++
++        priv->sdma = (struct bestcomm_taskhandle *)s;
++        return sdma_ata_init((struct bestcomm_taskhandle *)s, MAX_DMA_BUFFER_SIZE);
++}
++
++/**************/
++void sdma_ata_submit_buffer(
++        struct bestcomm_taskhandle *mytaskhandle,
++        void *cookie,
++        void *data1,
++        void *data2,
++        int length)
++{
++        NPRINTK(" d1=%p, d2=%p, len=%d\n",  data1, data2, length);
++
++        sdma_submit_buffer2(
++                (struct sdma *)mytaskhandle,
++                cookie, data1, data2, length);
++}
++
++/*
++ * Export stuff
++*/
++
++EXPORT_SYMBOL(sdma_ata_rx_init);
++EXPORT_SYMBOL(sdma_ata_tx_init);
++EXPORT_SYMBOL(sdma_ata_disable);
++EXPORT_SYMBOL(sdma_ata_enable);
++EXPORT_SYMBOL(sdma_ata_submit_buffer);
++EXPORT_SYMBOL(sdma_ata_reset);
++EXPORT_SYMBOL(sdma_ata_getirq);
++EXPORT_SYMBOL(sdma_ata_clear_irq);
++EXPORT_SYMBOL(mpc52xx_ata_sdma_setup);
++
++
++#endif // CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA
++
+diff --git a/drivers/block/mpc52xx/skel.c b/drivers/block/mpc52xx/skel.c
+new file mode 100644
+index 0000000..85b20ad
+--- /dev/null
++++ b/drivers/block/mpc52xx/skel.c
+@@ -0,0 +1,1024 @@
++/*
++ *  mpc52xx.c
++ *
++ *  Copyright 2006 bplan GmbH
++ *
++ *  This file is subject to the terms and conditions of the GNU General Public
++ *  License.  See the file "COPYING" in the main directory of this archive
++ *  for more details.
++ */
++
++/*
++ * Here we "translate" Linux API mess to our funcs
++*/
++
++#include <linux/major.h>
++#include <linux/vmalloc.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/blkdev.h>
++#include <linux/bitops.h>
++#include <linux/genhd.h>
++#include <linux/hdreg.h>
++#include <linux/fs.h>
++
++/**************/
++/**************/
++/**************/
++#include "mpc52xx_blockata.h"
++
++/**************/
++/**************/
++/**************/
++static int local_setpiomode(struct mpc52xx_blockata_priv *priv, int piomode_arg);
++
++/**************/
++/**************/
++/**************/
++
++static void dump_config(struct mpc52xx_blockata_priv *priv)
++{
++        VPRINTK(" configuration:\n");
++
++        if (priv->multi_available)
++                VPRINTK("\t * Multi-PIO commands: available (%d sectors per shot)\n", priv->multi_secpercmd );
++        VPRINTK("\t * PIO Mode: %d\n", priv->piomode < 0 ? 0 : priv->piomode);
++
++        if (priv->UsePacket)
++                VPRINTK("\t * Packet feature set supported\n");
++
++        if (priv->IsATAPI)
++                VPRINTK("\t * %s ATAPI device detected\n", priv->IsRemovable ? "Removable" : "");
++
++        VPRINTK("\t * LBA48 supported: %s\n", priv->drive_canlba48 ? "Yes" : "No");
++        VPRINTK("\t * CHS: %s (%d/%d/%d)\n", priv->drive_chs_ok ? "Ok" : "Ko", priv->drive_chs_cylinders, priv->drive_chs_heads , priv->drive_chs_sectorspertrack);
++        VPRINTK("\t * SDMA Engine: %s\n",
++#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA
++                "Enable");
++#else
++                "Disable"
++               );
++#endif
++}
++
++/**************/
++/**************/
++/**************/
++
++
++
++/* ATAPI-4 PIO specs (arranged for the 5200, cfr User Manual) */
++/* numbers in ns, extrapolation done by code */
++static int ataspec_t0[5]    = {600, 383, 240, 180, 120};
++static int ataspec_t1[5]    = { 70,  50,  30,  30,  25};
++static int ataspec_t2_8[5]  = {290, 290, 290,  80,  70};
++static int ataspec_t2_16[5] = {165, 125, 100,  80,  70};
++static int ataspec_t2i[5]   = {  0,   0,   0,  70,  25};
++static int ataspec_t4[5]    = { 30,  20,  15,  10,  10};
++static int ataspec_ta[5]    = { 35,  35,  35,  35,  35};
++
++
++
++/**************/
++/**************/
++/**************/
++static int device_handlebio(
++        struct mpc52xx_blockata_priv *priv,
++        struct request *req,
++        struct bio *bio,
++        int *sectorcnt_ptr)
++{
++        int i;
++        struct bio_vec *bvec;
++        sector_t sector;
++        int sectorcnt_biovec;
++        int sectorcnt;
++        int is_write;
++        int ret;
++
++        ret = -1;
++        is_write = bio_data_dir(bio);
++        sector = bio_getsector(bio);
++
++        sectorcnt = 0;
++
++        NPRINTK("bio=%p\n", bio);
++
++        bio_for_each_segment(bvec, bio, i)
++        {
++                char *buffer;
++
++                sectorcnt_biovec = bio_cur_sectors_idx(bio, i);
++                buffer = __bio_kmap_atomic(bio, i, KM_USER0);
++                ret = mpc52xx_ata_dotransfer(
++                              priv,
++                              req, bio, i,
++                              sector, sectorcnt_biovec,
++                              buffer, is_write);
++
++                if (ret==0)
++                        goto end;
++
++                // Success or error, we kunmap the buffer -> it's done!
++                __bio_kunmap_atomic(buffer, KM_USER0);
++
++                if (ret<0)
++                        goto end;
++
++                /* Ret > 0 -> done, do the next one */
++                sector += ret;
++                sectorcnt += ret;
++        }
++
++        ret = sector;
++
++end:
++        *sectorcnt_ptr = sectorcnt;
++        return ret;
++}
++
++/**************/
++/**************/
++/**************/
++/*
++ * The main challenge!
++*/
++
++static int device_handlereq(
++        struct mpc52xx_blockata_priv *priv,
++        struct request *req,
++        int *sectorcnt_ptr)
++{
++        struct bio *bio;
++        int ret;
++        int nsect;
++        int nsect_thisbio;
++
++        ret = 0;
++        nsect = 0;
++
++        if (priv->UsePacket)
++                return -ENOTSUPP;
++
++        if (priv->io_inprogress)
++        {
++                VPRINTK("IO already in-progress, can not do more!\n");
++                ret = -EBUSY;
++                goto end;
++        }
++
++
++        rq_for_each_bio(bio, req)
++        {
++                ret = device_handlebio(priv, req, bio, &nsect_thisbio);
++
++                if (ret<=0)
++                        goto end;
++
++                nsect += nsect_thisbio;
++        }
++
++        ret = nsect;
++
++end:
++        *sectorcnt_ptr = nsect;
++        return ret;
++}
++
++/**************/
++static void device_request(request_queue_t *q)
++{
++        struct mpc52xx_blockata_priv *priv = (struct mpc52xx_blockata_priv *) q->queuedata;
++        struct request *req;
++        int ret=0;
++        int sectorcnt;
++
++        while ((req = elv_next_request(q)) != NULL) {
++
++                if (! blk_fs_request(req)) {
++                        printk (KERN_NOTICE "Skip non-fs request\n");
++                        end_request(req, 0);
++                        continue;
++                }
++
++                ret = device_handlereq(priv, req, &sectorcnt);
++                if (ret==0) {
++                        NPRINTK("stop the queue\n");
++                        blk_stop_queue(q);
++                        break;
++                } else if (ret>0)
++                        end_request(req, 1);
++                else
++                        end_request(req, 0);
++        }
++
++        NPRINTK("end, ret=%d\n", ret);
++}
++
++
++/**************/
++/**************/
++/**************/
++
++static int device_doreset(
++        struct mpc52xx_blockata_priv *priv,
++        int do_drivereset)
++{
++        int ret = 0;
++
++        NPRINTK("priv->io_inprogress = %d, do_drivereset=%d\n",
++                priv->io_inprogress, do_drivereset );
++
++        if (priv->io_inprogress != 0)
++                mpc52xx_ata_ack_blkreq(priv, 0);
++
++        ret = mpc52xx_ata_doreset(priv);
++        if(ret<0)
++                ret = -EIO;
++
++        return ret;
++}
++
++/*
++ * The device open/close func
++*/
++
++/**************/
++static int device_open(struct inode *inode, struct file *filp)
++{
++        unsigned long flags;
++        struct mpc52xx_blockata_priv *priv = inode->i_bdev->bd_disk->private_data;
++        int ret = 0;
++        int force_enableirq;
++
++        NPRINTK("enter. sectors=%lld, usercnt=%d\n", priv->drive_sectors, priv->usercnt);
++
++        spin_lock_irqsave(&priv->lock, flags);
++        force_enableirq = 0;
++
++        if (priv->usercnt >= DEVICE_USERLIMIT)
++        {
++                VPRINTK("Error! Too much openers (%d)!\n", priv->usercnt);
++                ret = -1;
++                goto end;
++        }
++
++        // device not inited ? -> try to init it a gain
++        if (!priv->drive_inited)
++        {
++                priv->drive_sectors = 0;
++                priv->drive_inited = 0;
++
++                ret = mpc52xx_ata_init_drive(priv);
++                if (ret>=0)
++                        priv->drive_inited = 1;
++
++                ret = 0;
++        }
++
++        NPRINTK("drive inited ok. s=%x, ret=%d\n", read_altstatus(priv), ret);
++        NPRINTK("drive looks ok. s=%x\n", read_altstatus(priv));
++
++        if ( (priv->usercnt==0) || force_enableirq )
++        {
++                priv->ata_handler = ata_void_handler;
++                priv->sdma_handler = sdma_void_handler;
++
++                write_ctl(priv, 0);
++
++                priv->curio_bio = NULL;
++                priv->curio_req = NULL;
++                priv->io_inprogress = 0;
++        }
++
++        priv->usercnt++;
++
++end:
++        spin_unlock_irqrestore(&priv->lock, flags);
++
++        NPRINTK("end. ret=%d\n", ret);
++        return ret;
++}
++
++/**************/
++static int device_release(struct inode *inode, struct file *filp)
++{
++        unsigned long flags;
++        int ret;
++        struct mpc52xx_blockata_priv *priv = inode->i_bdev->bd_disk->private_data;
++
++        ret = 0;
++
++        NPRINTK("enter usercnt=%d\n", priv->usercnt);
++
++        spin_lock_irqsave(&priv->lock, flags);
++        priv->usercnt--;
++
++        if (priv->usercnt==0)
++        {
++                write_ctl(priv, ATA_NIEN);
++
++#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA
++                sdma_ata_disable(priv->sdma);
++                sdma_ata_clear_irq(priv->sdma);
++                sdma_ata_reset(priv->sdma);
++#endif
++        }
++
++        if (priv->usercnt<0)
++                VPRINTK("Warning! _release and _open count doesn't match!\n");
++
++        NPRINTK("end, ret=%d\n", ret);
++
++        spin_unlock_irqrestore(&priv->lock, flags);
++
++        return ret;
++}
++
++/**************/
++/**************/
++/**************/
++/*
++ * The device ioctl
++*/
++
++#ifndef HDIO_GETGEO_BIG
++
++/*
++ * Let's define GETGEO big because it's used!
++ * they removed it from recent linux kernel
++ * but already compiled software use it (eg: hdparm)
++ *
++ * this define and struct has been picked from linux 2.4.32
++*/
++
++#define HDIO_GETGEO_BIG 0x330
++struct hd_big_geometry
++{
++        unsigned char heads;
++        unsigned char sectors;
++        unsigned int cylinders;
++        unsigned long start;
++};
++#endif
++
++static int device_ioctl(
++        struct inode *inode,
++        struct file *filp,
++        unsigned int cmd,
++        unsigned long arg)
++{
++        int ret;
++        unsigned long flags;
++        struct mpc52xx_blockata_priv *priv = inode->i_bdev->bd_disk->private_data;
++
++        NPRINTK("%s: cmd=0x%x\n", __func__, cmd);
++
++        spin_lock_irqsave(&priv->lock, flags);
++
++        switch(cmd)
++        {
++        case HDIO_SET_MULTCOUNT: {
++                u16 multicount;
++
++                NPRINTK("HDIO_SET_PIO_MODE. Try to set the multicount value to %ld\n", arg);
++
++                if (priv->UsePacket) {
++                        ret = -EIO;
++                        break;
++                }
++
++                multicount = (u16) arg;
++
++                ret = mpx52xx_ata_dosetmulti(priv, multicount);
++                if (ret<0)
++                        ret = -EFAULT;
++        }
++        break;
++
++        case HDIO_GET_MULTCOUNT:
++                if (priv->UsePacket) {
++                        ret = -EIO;
++                        break;
++                }
++
++                ret = put_user(priv->multi_secpercmd , (long __user *) arg);
++                break;
++
++        case HDIO_DRIVE_CMD: {
++                u8 drivecmd_args[4+512];
++                u8 drivecmd;
++                int lentocopy;
++
++                if (NULL == (void *)arg) {
++                        ret = -EINVAL;
++                        break;
++                }
++
++                if (copy_from_user(drivecmd_args, (void __user *) arg, sizeof(drivecmd_args) )) {
++                        ret = -EFAULT;
++                        break;
++                }
++
++                drivecmd = drivecmd_args[0];
++                ret = mpc52xx_ata_dodrivecmd(priv, &flags, drivecmd_args);
++
++                lentocopy =
++                        ( (drivecmd==ATA_CMD_ID_ATAPI) || (drivecmd==ATA_CMD_ID_ATA) )
++                        ? (512 + 4): 4;
++
++                if (copy_to_user((void __user *)arg, drivecmd_args, lentocopy))
++                        ret = -EFAULT;
++        }
++        break;
++
++        case HDIO_SET_PIO_MODE: {
++                int piomode;
++                NPRINTK("HDIO_SET_PIO_MODE. Try to set PIO %ld\n", arg);
++
++                if (priv->io_inprogress) {
++                        VPRINTK("IO already in-progress, can not do more!\n");
++                        ret = -EBUSY;
++                        break;
++                }
++
++                priv->io_inprogress = 1;
++                piomode = local_setpiomode(priv, (int) arg);
++                priv->io_inprogress = 0;
++
++                if (piomode>0)
++                        VPRINTK("PIO mode %d sat\n", piomode);
++
++                ret = 0;
++        }
++        break;
++
++        case HDIO_GET_IDENTITY: {
++                NPRINTK("HDIO_GET_IDENTITY:\n" );
++
++                if (priv->drive_identify_valid) {
++                        if (copy_to_user((void __user *) arg, priv->drive_identify, sizeof(priv->drive_identify) ))
++                                ret = -EFAULT;
++                        else
++                                ret = 0;
++                } else
++                        ret = -1;
++        }
++        break;
++
++        case HDIO_GETGEO: {
++                struct hd_geometry geo;
++
++                NPRINTK("HDIO_GETGEO\n");
++
++                geo.cylinders = priv->drive_cylinders;
++                geo.heads = priv->drive_heads;
++                geo.sectors = priv->drive_sectorspertrack;
++                geo.start = 0;
++                if (copy_to_user((void __user *) arg, &geo, sizeof(geo)))
++                        ret = -EFAULT;
++                else
++                        ret = 0;
++
++                NPRINTK("HDIO_GETGEO, ret=%d\n", ret);
++        }
++        break;
++
++        case HDIO_GETGEO_BIG: {
++                struct hd_big_geometry biggeo;
++
++                NPRINTK("HDIO_GETGEO_BIG\n");
++
++                biggeo.cylinders = priv->drive_cylinders;
++                biggeo.heads = priv->drive_heads;
++                biggeo.sectors = priv->drive_sectorspertrack;
++                biggeo.start = 0;
++
++                if (copy_to_user((void __user *) arg, &biggeo, sizeof(biggeo)))
++                        ret = -EFAULT;
++                else
++                        ret = 0;
++
++                NPRINTK("HDIO_GETGEO_BIG, ret=%d\n", ret);
++        }
++        break;
++
++        case HDIO_DRIVE_RESET: {
++                VPRINTK("Issue a controller and drive reset\n");
++                ret = device_doreset(priv, 1);
++                if(ret<0)
++                        ret = -EIO;
++
++                break;
++        }
++
++        default:
++                ret = -EINVAL;
++        }
++
++        NPRINTK("%s: end, ret=%d\n", __func__, ret);
++
++        spin_unlock_irqrestore(&priv->lock, flags);
++
++        return ret;
++}
++
++/**************/
++/**************/
++/**************/
++/*
++ * The device media changes/revalidate
++*/
++static int device_media_changed(struct gendisk *gd)
++{
++        /* Our media won't move! */
++        NPRINTK("\n");
++        return 0;
++}
++
++static int device_revalidate_disk(struct gendisk *gd)
++{
++        NPRINTK("\n");
++        return 0;
++}
++
++/**************/
++/**************/
++/**************/
++/*
++ * Modules prove/init
++*/
++
++static struct block_device_operations device_fops =
++        {
++                .owner   = THIS_MODULE,
++                           .open	   = device_open,
++                                      .release = device_release,
++                                                 .ioctl   = device_ioctl,
++                                                            .media_changed = device_media_changed,
++                                                                             .revalidate_disk = device_revalidate_disk,
++                                                                                        };
++
++/**************/
++static void module_free(struct mpc52xx_blockata_priv *priv)
++{
++        NPRINTK("Enter. priv=%p\n", priv);
++        if (priv)
++        {
++                NPRINTK("free private private\n");
++
++		if (priv->ata_irq>=0)
++			free_irq(priv->ata_irq, priv);
++
++#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA
++		if (priv->sdma_irq>=0)
++			free_irq(priv->sdma_irq, priv);
++#endif
++
++                NPRINTK("priv->device_queue=%p\n", priv->device_queue);
++                if (priv->device_queue)
++                        blk_cleanup_queue(priv->device_queue);
++
++                NPRINTK("priv->device_gendisk=%p\n", priv->device_gendisk);
++                if (priv->device_gendisk)
++                        del_gendisk(priv->device_gendisk);
++
++                NPRINTK("priv->major=%d\n", priv->major);
++                if (priv->major>0)
++                        unregister_blkdev(priv->major, DEVSKEL_DEVICENAME);
++
++                NPRINTK("free priv. p=%p\n", priv);
++                kfree(priv);
++        }
++
++        NPRINTK("End\n");
++}
++
++static void module_remove(struct mpc52xx_blockata_priv *priv)
++{
++        printk(KERN_INFO DEVSKEL_DRIVERNAME ": Tchuss!\n");
++        module_free(priv);
++}
++
++
++
++/**************/
++/**************/
++/**************/
++
++#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA
++
++irqreturn_t generalsdma_handler(int irq, void *host)
++         {
++                 struct mpc52xx_blockata_priv *priv = (struct mpc52xx_blockata_priv *) host;
++                 irqreturn_t ret = IRQ_NONE;
++
++                 NPRINTK2("%s: irq=%d, sdma_handler %p\n", __func__, irq, priv->sdma_handler);
++
++                 if (irq == priv->sdma_irq)
++                 {
++                         ret =
++                                 (priv->sdma_handler)
++                                 ? priv->sdma_handler(priv)
++                                 : IRQ_HANDLED;
++                 } else
++                 {
++                         ret = IRQ_NONE;
++                 }
++
++                 return ret;
++         }
++
++
++#endif
++
++         irqreturn_t generalata_handler(int irq, void *host)
++                  {
++                          struct mpc52xx_blockata_priv *priv = (struct mpc52xx_blockata_priv  *) host;
++                          irqreturn_t ret;
++
++                          if (irq == priv->ata_irq)
++                          {
++                                  u8 status;
++                                  status = read_status(priv);
++
++                                  ret =
++                                          (priv->ata_handler)
++                                          ? priv->ata_handler(priv, status)
++                                          : IRQ_HANDLED;
++                          } else
++                          {
++                                  ret = IRQ_NONE;
++                          }
++
++                          return ret;
++                  }
++
++
++                  static void
++                  mpc52xx_ide_apply_timing(struct mpc52xx_ata __iomem *regs, struct mpc52xx_ata_timings *timing)
++                  {
++                          out_be32(&regs->pio1,  timing->pio1);
++                          out_be32(&regs->pio2,  timing->pio2);
++                          out_be32(&regs->mdma1, timing->mdma1);
++                          out_be32(&regs->mdma2, timing->mdma2);
++                          out_be32(&regs->udma1, timing->udma1);
++                          out_be32(&regs->udma2, timing->udma2);
++                          out_be32(&regs->udma3, timing->udma3);
++                          out_be32(&regs->udma4, timing->udma4);
++                          out_be32(&regs->udma5, timing->udma5);
++                  }
++
++                  static void
++                  mpc52xx_ide_compute_pio_timing( struct mpc52xx_ata_timings *timing, unsigned int ipb_period, u8 pio)
++                  {
++                          u32 t0, t2_8, t2_16, t2i, t4, t1, ta;
++
++                          /* We add 1 as a 'margin' */
++                          t0    = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t0[pio]);
++                          t2_8  = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t2_8[pio]);
++                          t2_16 = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t2_16[pio]);
++                          t2i   = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t2i[pio]);
++                          t4    = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t4[pio]);
++                          t1    = 1 + CALC_CLK_VALUE_UP(ipb_period, 1000*ataspec_t1[pio]);
++                          ta    = 1 + CALC_CLK_VALUE_UP(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);
++                  }
++
++                  static int local_setpiomode(struct mpc52xx_blockata_priv *priv, int piomode_arg)
++                  {
++                          int piomode;
++                          int ret;
++
++                          NPRINTK(KERN_DEBUG DEVSKEL_DEVICENAME "pio mode arg=%d\n", piomode_arg);
++
++                          piomode = mpc52xx_ata_isthispiovalid(priv, piomode_arg);
++                          if (piomode<0)
++                                  return -1;
++
++                          NPRINTK(KERN_DEBUG DEVSKEL_DEVICENAME "pio mode=%d\n", piomode);
++
++                          ret = mpc52xx_ata_setpiomode(priv, piomode);
++                          if (ret<0)
++                                  return -1;
++
++                          mpc52xx_ide_compute_pio_timing(&priv->timings[0], priv->ipb_period, piomode);
++                          mpc52xx_ide_apply_timing(priv->ata_regs, &priv->timings[0]);
++
++                          return piomode;
++                  }
++
++                  static int
++                  mpc52xx_ide_setup(
++                          struct mpc52xx_ata __iomem *regs,
++                          struct mpc52xx_blockata_priv *priv)
++                  {
++
++#define MPC52xx_IPBFREQ (132*1000*1000)
++
++                          /* Vars */
++
++                          int tslot;
++
++                          NPRINTK("%s: enter\n", __func__);
++
++                          out_8(&regs->dma_mode, MPC52xx_ATA_DMAMODE_FR);
++                          udelay(10);
++
++                          /* All sample code do this */
++                          out_be32(&regs->share_cnt, 0);
++
++                          /* Configure & 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);
++
++                          /* Get IPB bus period */
++                          priv->ipb_period = 1000000000 / (MPC52xx_IPBFREQ/1000);
++
++                          /* Try to set the time slot to around 1us = 1000000 ps */
++                          tslot = CALC_CLK_VALUE_UP(priv->ipb_period, 1000000);
++                          out_be32(&regs->share_cnt, tslot << 16);
++
++
++                          /* Init imings to PIO0 (safest) */
++                          memset(priv->timings, 0x00, 2*sizeof(struct mpc52xx_ata_timings));
++
++                          mpc52xx_ide_compute_pio_timing(&priv->timings[0], priv->ipb_period, 0);
++                          mpc52xx_ide_compute_pio_timing(&priv->timings[1], priv->ipb_period, 0);
++
++                          mpc52xx_ide_apply_timing(regs, &priv->timings[0]);
++
++                          return 0;
++                  }
++
++
++
++
++                  static int some_hwinit(struct mpc52xx_blockata_priv *priv)
++                  {
++                          struct mpc52xx_gpio __iomem *gpio_regs;
++                          struct mpc52xx_ata __iomem *ata_regs;
++			struct device_node *of_dev;	
++                          int ata_irq;
++                          u32 res_mem;
++                          int sdma_irqnum;
++                          int ret;
++
++                          ata_irq = -1;
++                          sdma_irqnum = -1;
++
++                          ata_regs = NULL;
++                          gpio_regs = NULL;
++                          res_mem = 0;
++
++
++
++                          priv->ata_irq = -1;
++                          priv->sdma_irq = -1;
++
++			of_dev = of_find_compatible_node(NULL, "ata", "mpc5200-ata");
++			if (of_dev == NULL)
++				return -ENODEV;
++
++		       
++                          /* Get the resources of this device */
++                          ata_irq = irq_of_parse_and_map(of_dev, 0);
++                          if (ata_irq<0)
++                          {
++                                  printk(KERN_ERR DEVSKEL_DRIVERNAME ": Invalid resource set!\n");
++                                  return -EINVAL;
++                          }
++
++                          ret = request_irq(ata_irq, generalata_handler, SA_INTERRUPT, DEVSKEL_DRIVERNAME " ATA interrupt", priv);
++                          if (ret)
++                          {
++                                  printk(KERN_ERR DEVSKEL_DRIVERNAME ": Can not allocate interrupt for the ATA controller\n");
++                                  ata_irq=-1;
++                                  goto error;
++                          }
++                          priv->ata_irq = ata_irq;
++
++                          res_mem = mpc52xx_ata_getregisterbase(priv);
++                          if (!res_mem)
++                          {
++                                  printk(KERN_ERR DEVSKEL_DRIVERNAME ": Unable to locate ATA registers\n");
++                                  ret = -ENOMEM;
++                                  goto error;
++                          }
++
++                          ata_regs = ioremap(res_mem, sizeof(struct mpc52xx_ata));
++                          if (!ata_regs)
++                          {
++                                  printk(KERN_ERR DEVSKEL_DRIVERNAME ": Unable to ioremap ATA registers\n");
++                                  ret = -ENOMEM;
++                                  goto error;
++                          }
++
++                          priv->ata_regs = ata_regs;
++                          priv->ata_regs_bus = res_mem;
++
++                          /* Setup the ATA controller */
++                          ret = mpc52xx_ide_setup(ata_regs, priv);
++                          if (ret)
++                          {
++                                  printk(KERN_ERR DEVSKEL_DRIVERNAME ": Controller setup failed !\n");
++                                  goto error;
++                          }
++
++#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA
++                          ret = mpc52xx_ata_sdma_setup(priv);
++                          if (ret)
++                          {
++                                  printk(KERN_ERR DEVSKEL_DRIVERNAME ": SDMA setup failed !\n");
++                                  goto error;
++                          }
++
++                          sdma_irqnum = sdma_ata_getirq(priv->sdma);
++                          ret = request_irq(sdma_irqnum, generalsdma_handler, SA_INTERRUPT, DEVSKEL_DRIVERNAME " SDMA interrupt", priv);
++                          if (ret)
++                          {
++                                  printk(KERN_ERR DEVSKEL_DRIVERNAME ": Can not allocate interrupt for the SDMA Task\n");
++                                  goto error;
++                          }
++
++                          priv->sdma_irq = sdma_irqnum;
++
++                          NPRINTK("%s: ATA irq=%d, SDMA IRQ=%d\n", __func__, ata_irq, priv->sdma_irq);
++
++#endif
++
++                          return 0;
++
++                  error:
++                          return ret;
++                  }
++
++                  /**************/
++                  static struct mpc52xx_blockata_priv *module_probe(int *retcode)
++                  {
++                          int ret;
++                          struct mpc52xx_blockata_priv *priv;
++                          struct gendisk *device_gendisk;
++                          struct request_queue *device_queue;
++
++                          ret = 0;
++                          priv = NULL;
++                          device_gendisk = NULL;
++                          device_queue = NULL;
++
++                          NPRINTK("enter\n");
++
++								
++                          /* Setup private structure */
++                          priv = kmalloc(sizeof(*priv), GFP_ATOMIC);
++                          if (!priv)
++                          {
++                                  printk(KERN_ERR DEVSKEL_DRIVERNAME ": Can't allocate private structure !\n");
++                                  ret = -ENOMEM;
++                                  goto error;
++                          }
++                          memset(priv, 0, sizeof (*priv) );
++
++
++                          spin_lock_init(&priv->lock);
++                          priv->major = -1;
++
++                          NPRINTK("device privata data ok. p=%p\n", priv);
++
++                          ret = some_hwinit(priv);
++                          if(ret<0)
++                          {
++                                  printk(KERN_ERR DEVSKEL_DRIVERNAME ": Can't allcoate some private stuff !\n");
++                                  goto error;
++                          }
++
++                          priv->drive_sectors = 0;
++                          priv->drive_inited = 0;
++
++			  /*
++			   * I prefer to the drive init here. Indeed, in case of failure
++			   * (for example no drive present), the linux block code generally exploses
++			   * 
++			  */
++                          ret = mpc52xx_ata_init_drive(priv);
++                          if (ret<0)
++                          {
++                                  printk(KERN_ERR DEVSKEL_DRIVERNAME ": Can not init the ATA drive\n");
++                                  goto error;
++                          }
++
++                          ret = register_blkdev(0, DEVSKEL_DEVICENAME);
++                          if (ret<0)
++                          {
++                                  printk(KERN_ERR DEVSKEL_DRIVERNAME ": Can not register the block device\n");
++                                  goto error;
++                          }
++                          priv->major = ret;
++
++                          NPRINTK("block device registered with major %d\n", ret);
++
++                          // minors must be >1 for partition mess (?)
++                          device_gendisk = alloc_disk(32);
++                          if (!device_gendisk)
++                          {
++                                  printk(KERN_ERR DEVSKEL_DRIVERNAME ": Can not allocate a block disk\n");
++                                  goto error;
++                          }
++                          priv->device_gendisk = device_gendisk;
++
++                          device_gendisk->major = priv->major;
++                          device_gendisk->first_minor = 0;
++                          device_gendisk->fops = &device_fops;
++                          sprintf(device_gendisk->disk_name, DEVSKEL_DEVICENAME);
++
++                          NPRINTK("device disk allocated. p=%p\n", device_gendisk);
++
++                          device_queue = blk_init_queue(device_request, &priv->lock);
++                          if (!device_queue)
++                          {
++                                  printk(KERN_ERR DEVSKEL_DRIVERNAME ": Can not init the block queue\n");
++                                  ret = -1;
++                                  goto error;
++                          }
++
++                          priv->device_queue = device_queue;
++                          device_gendisk->queue = device_queue;
++
++                          NPRINTK("block queue ok. p=%p\n", device_queue);
++
++                          device_queue->queuedata = priv;
++                          device_gendisk->private_data = priv;
++
++
++#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_MAXPIO
++                          NPRINTK("Set pio mode to max\n");
++                          priv->piomode = local_setpiomode( priv, -1);
++#endif
++
++                          priv->drive_inited = 1;
++
++                          /* Only add the disk as very last step */
++                          blk_queue_max_phys_segments(device_queue, DRIVER_MAXHWSEG);
++                          blk_queue_max_sectors(priv->device_queue, DRIVER_MAXHWSEG);
++
++                          // This should be the multi pio value
++                          blk_queue_max_hw_segments(device_queue, priv->multi_secpercmd);
++
++                          set_capacity(priv->device_gendisk, priv->drive_sectors);
++                          add_disk(device_gendisk);
++
++                          init_waitqueue_head(&priv->my_waitqueue);
++
++                          printk(KERN_INFO DEVSKEL_DRIVERNAME ": %s (Version %s - Compiled date %s at %s)\n", DEVSKEL_DRIVERNAME, DEVSKEL_DRIVERVERSION, __DATE__, __TIME__);
++                          dump_config(priv);
++
++                          *retcode = 0;
++                          return priv;
++
++                  error:
++
++                          module_free(priv);
++
++                          *retcode = (ret == 0) ? -1 : ret;
++                          return NULL;
++                  }
++
++                  /**************/
++                  /**************/
++                  /**************/
++                  /*
++                   * Kernel call for module load/remove
++                  */
++                  struct mpc52xx_blockata_priv *global_priv = NULL;
++
++static int __init kernelcall_init(void)
++{
++        int retcode;
++
++        global_priv = module_probe(&retcode);
++        return retcode;
++}
++
++static void __exit kernelcall_exit(void)
++{
++        module_remove(global_priv);
++        global_priv = NULL;
++}
++
++
++module_init(kernelcall_init);
++module_exit(kernelcall_exit);
++
++MODULE_AUTHOR("bplan GmbH");
++MODULE_DESCRIPTION(DEVSKEL_DRIVERNAME);
++MODULE_LICENSE("GPL");
++
+diff --git a/drivers/block/mpc52xx/transfer.c b/drivers/block/mpc52xx/transfer.c
+new file mode 100644
+index 0000000..50f5f3a
+--- /dev/null
++++ b/drivers/block/mpc52xx/transfer.c
+@@ -0,0 +1,932 @@
++/*
++ *  mpc52xx_atablock / transfer.c
++ *
++ *  Copyright 2006 bplan GmbH
++ *
++ *  This file is subject to the terms and conditions of the GNU General Public
++ *  License.  See the file "COPYING" in the main directory of this archive
++ *  for more details.
++ */
++
++/*
++ * real brain!
++*/
++
++
++#include "mpc52xx_blockata.h"
++
++
++/**************/
++/**************/
++/**************/
++static int ata_dopollwrite(
++        struct mpc52xx_blockata_priv *priv,
++        void *buffer,
++        int len);
++static int ata_dopollread(
++        struct mpc52xx_blockata_priv *priv,
++        void *buffer,
++        int len);
++
++/**************/
++/**************/
++/**************/
++/*
++ * We could check for unexpected interrupt or status here
++*/
++
++irqreturn_t sdma_void_handler(struct mpc52xx_blockata_priv *priv)
++         {
++                 NPRINTK("%s: \n", __func__);
++                 return IRQ_HANDLED;
++         }
++
++         irqreturn_t ata_void_handler(struct mpc52xx_blockata_priv *priv, u8 ata_status)
++                  {
++                          NPRINTK("%s: status=0x%2.2x\n", __func__, ata_status);
++                          return IRQ_HANDLED;
++                  }
++
++
++
++#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA
++
++                  /**************/
++                  static int start_writerequest(
++                          struct mpc52xx_blockata_priv *priv,
++                          struct request *req,
++                          struct bio *bio,
++                          int bio_index,
++                          sector_t sector,
++                          int sectorcnt,
++                          u16 * buffer);
++static void submit_writebuffer(
++        struct mpc52xx_blockata_priv *priv,
++        u16 *buffer,
++        int curio_secidx);
++
++static void submit_readbuffer(
++        struct mpc52xx_blockata_priv *priv,
++        u16 *buffer,
++        int curio_secidx);
++static int submitandenable_readbuffer(
++        struct mpc52xx_blockata_priv *priv,
++        u16 *buffer);
++static int start_readrequest(
++        struct mpc52xx_blockata_priv *priv,
++        struct request *req,
++        struct bio *bio,
++        int bio_index,
++        sector_t sector,
++        int sectorcnt,
++        u16 * buffer);
++
++/**************/
++void mpc52xx_ata_ack_blkreq(struct mpc52xx_blockata_priv *priv, int retval)
++{
++        struct request *req;
++
++        req = priv->curio_req;
++
++        priv->curio_bio = NULL;
++        priv->curio_req = NULL;
++        priv->sdma_handler = sdma_void_handler;
++        priv->ata_handler = ata_void_handler;
++
++        priv->io_inprogress = 0;
++
++        // Ack the req if any
++        if (req)
++                end_request(req, retval);
++
++        // Make sure to restart the queue
++        blk_start_queue(priv->device_queue);
++}
++
++/**************/
++static int inhandlercheck_atastatus(
++        struct mpc52xx_blockata_priv *priv,
++        u8 ata_status)
++{
++        if ( ATASTS_GOT_ERR(ata_status) )
++        {
++                VPRINTK("ATA Error, transfer aborted");
++                ATA_DUMPREG
++
++                mpc52xx_ata_ack_blkreq(priv, 0);
++
++                // taut!
++                return -1;
++        }
++
++        return 0;
++}
++
++
++/**************/
++/*
++ * This func will do the necessary operation when a bio iovec is done
++ * -> end the transfer if there are no more job
++ * -> start a new io vec if any
++ * -> start a new bio if any
++ *
++ * This is the same for RX and TX buffer that's why I wrote this static
++ * (and hopefully inlined !) func
++ * 
++*/
++static inline u16 *handle_nextbio(
++        struct mpc52xx_blockata_priv *priv,
++        struct request *req,
++        struct bio **ptr_bio,
++        int *ptr_bio_idx,
++        sector_t *ptr_sector,
++        int *ptr_sectorcnt)
++{
++        struct bio *bio;
++        int bio_idx;
++        int lastvec_sectorcnt;
++        sector_t sector;
++
++        bio = priv->curio_bio;
++
++        // need to do!
++        NPRINTK2(KERN_DEBUG "One iovec done. bio idx=%d. cnt=%d\n", bio->bi_idx, bio->bi_vcnt);
++
++        /* Unmap the previous one
++           * kmap stuff is a bit strange
++           * the LDD manual pass the bio, but the 
++           * macro seen to accept the buffer...
++           * maybe API change between the LDD (3rd release)
++           * and this Linux kernel (2.6.16.15 but also in 2.6.17.1).
++           * anyway, kmap* seens void.
++        */
++        __bio_kunmap_atomic( bio_data(bio), KM_USER0);
++
++        bio_idx = priv->curio_bioidx;
++        lastvec_sectorcnt = bio_cur_sectors_idx(bio, bio_idx);
++
++        bio_idx++;
++        if (bio_islastidx(bio, bio_idx) )
++        {
++                // Finish with this bio
++
++                // Let's see if there is another bio in this req
++                bio = bio_getnext(bio);
++                if (!bio) {
++                        // we have done!
++                        NPRINTK(KERN_DEBUG "req (%p, bio=%p) over, ack it and start the queue\n",
++                                req, bio);
++
++                        mpc52xx_ata_ack_blkreq(priv, 1);
++
++                        // vertig
++                        return NULL;
++                }
++
++                NPRINTK(KERN_DEBUG "bio over,but new one %p\n", bio);
++
++                // Set up stuff for the new bio
++                bio_idx = bio_getcuridx(bio);
++                sector = bio_getsector(bio);
++        } else
++        {
++                // Set up stuff for the next bio iovec
++                NPRINTK(KERN_DEBUG "bio iovec over,but new one %d\n", bio_idx);
++
++                sector = priv->curio_sector + lastvec_sectorcnt;
++        }
++
++        *ptr_bio = bio;
++        *ptr_sector = sector;
++        *ptr_bio_idx = bio_idx;
++        *ptr_sectorcnt = bio_cur_sectors_idx(bio, bio_idx);
++
++        // Small notes, I'm really not sure kmap atomix is smart here
++        // We should prolly use kmap_irq as we will prolly be called from an interrupt
++        return __bio_kmap_atomic(bio, bio_idx, KM_USER0);
++}
++
++/**************/
++
++irqreturn_t ata_complete_txtransfer_handler(struct mpc52xx_blockata_priv *priv, u8 ata_status)
++         {
++                 int secidx;
++                 int sectodo;
++                 int secpershot;
++                 u16 *buffer;
++
++                 NPRINTK2("curio_secidx=%d, curio_sectodo=%d. bio=%p, req=%p. s=0x%x\n",
++                          priv->curio_secidx, priv->curio_sectodo, priv->curio_bio,  priv->curio_req, ata_status );
++
++                 // Make sure to kill the task first
++                 sdma_ata_disable(priv->sdma);
++
++                 // Sanity check!
++                 if ( ! priv->io_inprogress )
++                         goto end;
++
++                 if ( inhandlercheck_atastatus(priv, ata_status ) )
++                         goto end;
++
++                 // grab some data
++                 secidx = priv->curio_secidx;
++                 sectodo = priv->curio_sectodo;
++                 secpershot = priv->curio_secpershot;
++
++                 secidx += secpershot;
++                 if (secidx < sectodo)
++                 {
++                         if ( ATASTS_IS_READY(ata_status)  ) {
++                                 // Update the buffer to the position of the new sector to write
++                                 // buffer is a u16*
++                                 buffer = ( (u16 *) priv->curio_buffer) + (priv->curio_secpershot * 256);
++
++                                 submit_writebuffer(priv, buffer, secidx);
++
++                                 sdma_ata_enable(priv->sdma);
++                         } else {
++                                 // Error here, DRQ should be set
++                                 goto end;
++                         }
++                 } else
++                 {
++                         struct bio *bio;
++                         struct request *req;
++                         int ret;
++                         int bio_idx;
++                         int sectorcnt;
++                         u16 *buffer;
++                         sector_t sector;
++
++                         req =  priv->curio_req;
++                         buffer = handle_nextbio(priv, req, &bio, &bio_idx, &sector, &sectorcnt);
++
++                         ret =
++                                 buffer
++                                 ? start_writerequest(priv, req, bio, bio_idx, sector, sectorcnt, buffer)
++                                 : -1;
++                 }
++
++         end:
++                 return IRQ_HANDLED;
++         }
++
++
++
++         /**************/
++         irqreturn_t sdma_complete_rxtransfer_handler(struct mpc52xx_blockata_priv *priv);
++
++irqreturn_t ata_wait_rxready_handler(struct mpc52xx_blockata_priv *priv, u8 ata_status)
++         {
++                 NPRINTK2("%s: \n", __func__);
++
++                 // Sanity check!
++                 if (!priv->io_inprogress)
++                 {
++                         // Should report some erro rhere!
++                         goto end;
++                 }
++
++                 if ( inhandlercheck_atastatus(priv, ata_status ) )
++                         goto end;
++
++                 if ( ATASTS_IS_DRQ(ata_status) )
++                 {
++                         // Set up the new handlers
++                         priv->sdma_handler = sdma_complete_rxtransfer_handler;
++                         priv->ata_handler = ata_void_handler;
++
++                         // Now start the transfer
++                         submitandenable_readbuffer(priv, priv->curio_buffer);
++                 }
++
++         end:
++                 return IRQ_HANDLED;
++         }
++
++         irqreturn_t sdma_complete_rxtransfer_handler(struct mpc52xx_blockata_priv *priv)
++                  {
++                          int secidx;
++                          int sectodo;
++                          int secpershot;
++                          u16 *buffer;
++
++                          NPRINTK("curio_secidx=%d, curio_sectodo=%d. bio=%p, req=%p.\n",
++                                  priv->curio_secidx, priv->curio_sectodo, priv->curio_bio,  priv->curio_req  );
++
++                          // Make sure to kill the task first
++                          sdma_ata_disable(priv->sdma);
++
++                          // Sanity check!
++                          if ( ! priv->io_inprogress )
++                                  goto end;
++
++                          // grab
++                          secidx = priv->curio_secidx;
++                          sectodo = priv->curio_sectodo;
++                          secpershot = priv->curio_secpershot;
++
++                          if ( inhandlercheck_atastatus(priv, read_altstatus(priv) ) )
++                                  goto end;
++
++                          secidx += secpershot;
++                          if (secidx < sectodo)
++                          {
++#if 0
++                                  u8 ata_status;
++
++                                  // Rx transfer for this sector over, wait for intr for the new one
++                                  priv->sdma_handler = sdma_void_handler;
++                                  priv->ata_handler = ata_wait_rxready_handler;
++
++                                  // reading the status reg should acknowledge this transfer
++                                  // and start the next  one
++                                  ata_status = read_status(priv);
++#else
++                                  // Stuff data to transfer for this iovec
++                                  //if ( IS_READY( read_altstatus(priv) )  )
++                                  {
++                                          buffer = ( (u16 *) priv->curio_buffer) + (secpershot * 256);
++
++                                          NPRINTK("%s: ATA ready -> read task started. Sector=%lld\n", __func__, priv->curio_sector);
++
++                                          submit_readbuffer(priv, buffer, secidx);
++
++                                          // I don't like to wait here
++                                          wait_drq(priv);
++                                          sdma_ata_enable(priv->sdma);
++                                  }
++#endif
++                          } else
++                          {
++                                  struct bio *bio;
++                                  struct request *req;
++                                  int ret;
++                                  int bio_idx;
++                                  int sectorcnt;
++                                  u16 *buffer;
++                                  sector_t sector;
++
++                                  req = priv->curio_req;
++                                  buffer = handle_nextbio(priv, req, &bio, &bio_idx, &sector, &sectorcnt);
++
++                                  ret =
++                                          buffer
++                                          ? start_readrequest(priv, req, bio, bio_idx, sector, sectorcnt, buffer)
++                                          : -1;
++                          }
++
++                  end:
++                          return IRQ_HANDLED;
++                  }
++
++
++                  /*
++                   * This func will setup the ATA and the SDMA buffers
++                   * and install the ATA handler
++                  */
++                  /**************/
++                  static void submit_writebuffer(
++                          struct mpc52xx_blockata_priv *priv,
++                          u16 *buffer,
++                          int curio_secidx)
++                  {
++                          u32 port_BusAddr;
++                          u32 addr_BusAddr;
++
++                          port_BusAddr = ATAFIFO_BUSADDR;
++                          addr_BusAddr = virt_to_phys( (void*) buffer);
++
++                          NPRINTK("priv=%p, , port bus=0x%8.8x, addr bus =0x%8.8x, buf=%p, idx=%d\n",
++                                  priv, port_BusAddr, addr_BusAddr, buffer, curio_secidx);
++
++                          // reset the buf
++                          sdma_ata_reset(priv->sdma);
++
++                          sdma_ata_submit_buffer(
++                                  priv->sdma,
++                                  (void *) buffer,
++                                  (void *) addr_BusAddr,
++                                  (void *) port_BusAddr,
++                                  512*priv->curio_secpershot);
++
++                          priv->curio_secidx = curio_secidx;
++                          priv->curio_buffer = buffer;
++                  }
++
++
++                  static int start_writerequest(
++                          struct mpc52xx_blockata_priv *priv,
++                          struct request *req,
++                          struct bio *bio,
++                          int bio_index,
++                          sector_t sector,
++                          int sectorcnt,
++                          u16 *buffer)
++                  {
++
++                          int ret;
++                          int secperreq;
++                          int sectodo;
++                          int secpershot;
++
++                          NPRINTK("%s: sector=%ld, sectorcnt=%d, buffer=%p\n", __func__, (long) sector, sectorcnt,  buffer);
++
++                          secperreq = priv->multi_secpercmd;
++                          sectodo = sectorcnt > secperreq ? secperreq : sectorcnt;
++                          secpershot = sectodo ;
++
++                          ret = wait_not_busy(priv);
++                          if (ret!=0)
++                                  return ret;
++                          mpc52xx_ata_setupsector(priv, sector, sectodo, 1);
++
++                          // I don't like to call wait here
++                          ret = wait_ready(priv);
++                          if (ret!=0)
++                          {
++                                  NPRINTK("can't wait rdy=%d. 0x%x\n", ret, read_altstatus(priv));
++                                  ATA_DUMPREG
++                                  return ret;
++                          }
++
++                          priv->curio_sector = sector;
++                          priv->curio_secpershot = secpershot;
++                          priv->curio_sectodo = sectodo;
++                          priv->curio_req = req;
++                          priv->curio_bio = bio;
++                          priv->curio_bioidx = bio_index;
++
++                          priv->sdma_handler = sdma_void_handler;
++                          priv->ata_handler =  ata_complete_txtransfer_handler;
++
++                          priv->io_inprogress = 1;
++
++                          write_cmd(priv, priv->curio_atacmd);
++                          ret = wait_drq(priv);
++                          if (ret!=0)
++                          {
++                                  ATA_DUMPREG
++                                  return ret;
++                          }
++
++                          submit_writebuffer(priv, (u16 *) buffer, 0);
++                          sdma_ata_enable(priv->sdma);
++
++                          return 0;
++                  }
++
++
++                  /**************/
++
++                  /**************/
++                  static void submit_readbuffer(
++                          struct mpc52xx_blockata_priv *priv,
++                          u16 *buffer,
++                          int curio_secidx)
++                  {
++                          u32 port_BusAddr;
++                          u32 addr_BusAddr;
++
++                          port_BusAddr = ATAFIFO_BUSADDR;
++                          addr_BusAddr = virt_to_phys( (void*) buffer);
++
++                          NPRINTK2("priv=%p, , port bus=0x%8.8x, addr bus =0x%8.8x, buf=%p, idx=%d\n",
++                                   priv, port_BusAddr, addr_BusAddr, buffer, curio_secidx);
++
++                          // reset the buf
++                          sdma_ata_reset(priv->sdma);
++
++                          sdma_ata_submit_buffer(
++                                  priv->sdma,
++                                  (void *) buffer,
++                                  (void *) port_BusAddr,
++                                  (void *) addr_BusAddr,
++                                  512*priv->curio_secpershot);
++
++                          priv->curio_secidx = curio_secidx;
++                          priv->curio_buffer = buffer;
++                  }
++
++                  static int submitandenable_readbuffer(
++                          struct mpc52xx_blockata_priv *priv,
++                          u16 *buffer)
++                  {
++
++                          submit_readbuffer(priv, (u16 *) buffer, 0);
++                          sdma_ata_enable(priv->sdma);
++
++                          return 0;
++                  }
++
++                  static int start_readrequest(
++                          struct mpc52xx_blockata_priv *priv,
++                          struct request *req,
++                          struct bio *bio,
++                          int bio_index,
++                          sector_t sector,
++                          int sectorcnt,
++                          u16 *buffer)
++                  {
++                          int ret;
++                          int secperreq;
++                          int sectodo;
++                          int secpershot;
++
++                          NPRINTK2("%s: sector=%ld, sectorcnt=%d, buffer=%p, cmd=0%2.2x\n", __func__, (long) sector, sectorcnt,  buffer, priv->curio_atacmd);
++
++                          secperreq = priv->multi_secpercmd;
++                          sectodo = sectorcnt > secperreq ? secperreq : sectorcnt;
++                          secpershot = sectodo;
++
++                          ret = wait_not_busy(priv);
++                          if (ret!=0)
++                                  return ret;
++
++                          mpc52xx_ata_setupsector(priv, sector, sectodo, 0);
++
++                          ret = wait_ready(priv);
++                          if (ret!=0)
++                          {
++                                  NPRINTK("can't wait rdy=%d. 0x%x\n", ret, read_altstatus(priv));
++                                  ATA_DUMPREG
++                                  return ret;
++                          }
++
++                          priv->curio_sector = sector;
++                          priv->curio_secpershot = secpershot;
++                          priv->curio_sectodo = sectodo;
++                          priv->curio_req = req;
++                          priv->curio_bio = bio;
++                          priv->curio_bioidx = bio_index;
++
++                          priv->sdma_handler = sdma_void_handler;
++                          priv->ata_handler = ata_wait_rxready_handler;
++
++                          priv->io_inprogress = 1;
++
++                          /*
++                           * We only start the task when we got the drive int
++                          */
++                          priv->curio_secidx = 0;
++                          priv->curio_buffer = buffer;
++                          write_cmd(priv, priv->curio_atacmd);
++
++                          return 0;
++                  }
++#endif
++
++
++
++#ifndef CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA
++                  /**************/
++                  /**************/
++                  /**************/
++                  /*
++                   * This do_read func use polling -> not interrupt!
++                  */
++
++                  static int do_readrequest(
++                          struct mpc52xx_blockata_priv *priv,
++                          struct request *req,
++                          struct bio *bio,
++                          int bio_index,
++                          sector_t sector,
++                          int sectorcnt,
++                          u16 * buffer)
++                  {
++                          int ret;
++                          int secperreq;
++                          int sectodo;
++                          int sectorcnt_original = sectorcnt;
++
++                          NPRINTK("%s: sector=%ld, sectorcnt=%d, buffer=%p\n", __func__, (long) sector, sectorcnt, buffer);
++
++                          secperreq = priv->multi_secpercmd;
++
++                          while(sectorcnt>0)
++                          {
++                                  int i;
++                                  sectodo = sectorcnt > secperreq ? secperreq : sectorcnt;
++
++                                  ret = wait_not_busy(priv);
++                                  if (ret!=0)
++                                          return -1;
++                                  mpc52xx_ata_setupsector(priv, sector, sectodo, 0);
++
++                                  ret = wait_ready(priv);
++                                  if (ret!=0) {
++                                          ATA_DUMPREG
++                                          return ret;
++                                  }
++
++                                  if (priv->multi_available) {
++                                          write_cmd(priv, ATA_CMD_READ_MULTI);
++                                          ret = wait_drq(priv);
++                                          if (ret!=0) {
++                                                  ATA_DUMPREG
++                                                  return ret;
++                                          }
++                                          ret = ata_dopollread(priv, buffer, 256*sectodo );
++                                          buffer = ( ((u16*) buffer) + 256*sectodo );
++                                  } else {
++                                          write_cmd(priv, ATA_CMD_PIO_READ);
++
++                                          for(i=0; i < sectodo; i++) {
++                                                  ret = wait_drq(priv);
++                                                  if (ret!=0) {
++                                                          ATA_DUMPREG
++                                                          return ret;
++                                                  }
++
++                                                  ret = ata_dopollread(priv, buffer, 256);
++
++                                                  // Check!
++
++                                                  buffer =( ((u16*) buffer) + 256 );
++                                          }
++                                  }
++
++                                  sector += sectodo;
++                                  sectorcnt -= sectodo;
++                          }
++
++                          return sectorcnt_original ;
++                  }
++
++                  /**************/
++                  static int do_writerequest(
++                          struct mpc52xx_blockata_priv *priv,
++                          struct request *req,
++                          struct bio *bio,
++                          int bio_index,
++                          sector_t sector,
++                          int sectorcnt,
++                          u16 *buffer)
++                  {
++                          int ret;
++                          int secperreq;
++                          int sectodo;
++                          int sectorcnt_original = sectorcnt;
++
++                          NPRINTK("%s: sector=%ld, sectorcnt=%d, buffer=%p\n", __func__, (long) sector, sectorcnt,  buffer);
++
++                          secperreq = priv->multi_secpercmd;
++
++                          while(sectorcnt)
++                          {
++                                  int i;
++                                  sectodo = sectorcnt > secperreq ? secperreq : sectorcnt;
++
++                                  ret = wait_not_busy(priv);
++                                  if (ret!=0)
++                                          return ret;
++                                  mpc52xx_ata_setupsector(priv, sector, sectodo, 1);
++
++                                  ret = wait_ready(priv);
++                                  if (ret!=0) {
++                                          NPRINTK("can't wait rdy=%d. 0x%x\n", ret, read_altstatus(priv));
++                                          ATA_DUMPREG
++                                          return ret;
++                                  }
++
++                                  if (priv->multi_available) {
++                                          /* If the drive support the multi write, let's go!
++                                           * should be really faster as we don't have to wait for DRQ
++                                           * However, either I make something wrong, either I did not find 
++                                           * any disk supporting this!
++                                          */
++                                          write_cmd(priv, ATA_CMD_WRITE_MULTI);
++                                          ret = wait_drq(priv);
++                                          if (ret!=0) {
++                                                  NPRINTK("can't wait drq %d\n", ret);
++                                                  ATA_DUMPREG
++                                                  return ret;
++                                          }
++
++                                          ret = ata_dopollwrite(priv, buffer, 256*sectodo);
++                                          buffer = ( (u16*) buffer + 256*sectodo );
++                                  } else {
++                                          write_cmd(priv, ATA_CMD_PIO_WRITE);
++                                          for(i=0; i < sectodo; i++) {
++                                                  ret = wait_drq(priv);
++                                                  if (ret!=0) {
++                                                          ATA_DUMPREG
++                                                          return ret;
++                                                  }
++
++                                                  ret = ata_dopollwrite(priv, buffer, 256 );
++
++                                                  // Check!
++
++                                                  buffer = ( ((u16*) buffer) + 256 );
++                                          }
++                                  }
++
++                                  sector += sectodo;
++                                  sectorcnt-= sectodo;
++                          }
++
++                          //NPRINTK("return %d\n", sectorcnt_original);
++                          return sectorcnt_original;
++                  }
++#endif /* CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA */
++
++                  /**************/
++                  /**************/
++                  /**************/
++                  /*
++                   * This is call by nicoskel
++                  */
++
++                  int mpc52xx_ata_dotransfer(
++                          struct mpc52xx_blockata_priv *priv,
++                          struct request *req,
++                          struct bio *bio,
++                          int bio_index,
++                          sector_t sector,
++                          int sectorcnt,
++                          char *buffer,
++                          int is_write)
++                  {
++#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA
++#warning Using interrupt based SDMA
++                          int ret;
++
++                          if (is_write)
++                          {
++                                  /*
++                                   * for TX beter wait the drive interrupt
++                                   * because we first write into drive buffer and the drive do the real stuff
++                                  */
++                                  sdma_ata_tx_init(priv->sdma);
++
++                                  ret = start_writerequest(priv, req, bio, bio_index, sector, sectorcnt, (u16 *) buffer);
++                          } else
++                          {
++                                  /*
++                                   * for RX better write for sdma int
++                                   * because the drive will first to the read and then the SDMA task fetch
++                                   * the data from the FIFO
++                                  */
++                                  sdma_ata_rx_init(priv->sdma);
++
++                                  // Wait for int before starting the task
++                                  ret = start_readrequest(priv, req, bio, bio_index, sector, sectorcnt, (u16 *) buffer);
++                          }
++
++                          return ret;
++
++#else /* CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA */
++#warning Using poll based SDMA -> Slow and obsolet!
++                          return
++                                  is_write
++                                  ? do_writerequest(priv, req, bio, bio_index, sector, sectorcnt, (u16 *) buffer)
++                                  : do_readrequest(priv, req, bio, bio_index, sector, sectorcnt, (u16 *) buffer);
++#endif /* CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA */
++                  }
++
++
++
++                  /**************/
++                  /**************/
++                  int mpc52xx_ata_docpupollread(
++                          struct mpc52xx_blockata_priv *priv,
++                          void *buffer,
++                          int len)
++                  {
++                          u16 *buffer16 = (u16 *) buffer;
++                          int local_len = len;
++
++                          while(local_len--)
++                                  *buffer16++ = read_data(priv);
++
++                          return len - local_len;
++                  }
++
++#ifdef CONFIG_BLK_DEV_MPC52XX_ATAPIO_SDMA
++#if 0
++                  static int ata_dosdmapollwrite(
++                          struct mpc52xx_blockata_priv *priv,
++                          void *buffer,
++                          int len)
++                  {
++                          int ret = 0;
++                          u32 port_BusAddr;
++                          u32 addr_BusAddr;
++                          int taskirq;
++                          int timeout = 10*1000;
++
++                  //NPRINTK("%s: have to read %d , from port 0x%8.8lx to mem %p\n", __func__, count, port, addr);
++
++                          taskirq = priv->sdma_irq;
++                          port_BusAddr = ATAFIFO_BUSADDR;
++
++                          addr_BusAddr = virt_to_phys( (void*) buffer);
++
++                          //NPRINTK("%s:priv=%p, irq=%d, port bus=0x%8.8x, addr bus =0x%8.8x\n",
++                          //  __func__, priv, taskirq, port_BusAddr, addr_BusAddr)
++
++                          // Turn the SDMA into RX
++                          sdma_ata_tx_init(priv->sdma);
++
++                          sdma_ata_submit_buffer(priv->sdma, (void *)buffer, (void *) addr_BusAddr, (void *)port_BusAddr, len*2);
++
++                          sdma_ata_clear_irq(priv->sdma);
++                          sdma_ata_enable(priv->sdma);
++
++                          for(;;)
++                          {
++
++                                  u32 val;
++                                  val = in_be32(&sdma.io->IntPend);
++                                  if ( (val & (1 << priv->sdma->tasknum) ) )
++                                          break;
++
++                                  if (timeout--<=0) {
++                                          ret = -1;
++                                          printk("timeout 0x%x\n", read_altstatus(priv) );
++                                          break;
++                                  }
++
++                                  udelay(1);
++                          }
++
++                          sdma_ata_disable(priv->sdma);
++                          sdma_ata_reset(priv->sdma);
++
++                          return 0;
++                  }
++
++                  static int ata_dosdmapollread(
++                          struct mpc52xx_blockata_priv *priv,
++                          void *buffer,
++                          int len)
++                  {
++                          int ret = 0;
++                          u32 port_BusAddr;
++                          u32 addr_BusAddr;
++                          int taskirq;
++                          int timeout = 10*1000;
++
++                          taskirq = priv->sdma_irq;
++                          port_BusAddr = ATAFIFO_BUSADDR;
++                          addr_BusAddr = virt_to_phys( (void*) buffer);
++
++                          // Turn the SDMA into RX
++                          sdma_ata_rx_init(priv->sdma);
++
++                          sdma_ata_submit_buffer(priv->sdma, (void *)buffer, (void *)port_BusAddr, (void *) addr_BusAddr, len*2);
++
++                          sdma_ata_clear_irq(priv->sdma);
++                          sdma_ata_enable(priv->sdma);
++
++                          for(;;)
++                          {
++                                  u32 val;
++                                  val = in_be32(&sdma.io->IntPend);
++                                  if ( (val & (1 << priv->sdma->tasknum) ) )
++                                          break;
++
++                                  if (timeout--<=0) {
++                                          printk("timeout 0x%x\n", read_altstatus(priv) );
++                                          ret = -1;
++                                          break;
++                                  }
++
++                                  udelay(1);
++                          }
++
++                          sdma_ata_disable(priv->sdma);
++                          sdma_ata_reset(priv->sdma);
++
++                          return ret;
++                  }
++#endif
++#endif
++
++                  /**************/
++                  int mpc52xx_ata_docpupollwrite(
++                          struct mpc52xx_blockata_priv *priv,
++                          void *buffer,
++                          int len)
++                  {
++                          u16 *buffer16 = (u16 *) buffer;
++                          int local_len = len;
++
++                          while(local_len--)
++                                  write_data(priv, *buffer16++);
++
++                          return len - local_len;
++                  }
++
++/*
++ *
++*/
++
++EXPORT_SYMBOL(mpc52xx_ata_docpupollread);
++EXPORT_SYMBOL(mpc52xx_ata_docpupollwrite);
++EXPORT_SYMBOL(mpc52xx_ata_dotransfer);
++EXPORT_SYMBOL(sdma_void_handler);
++EXPORT_SYMBOL(ata_void_handler);
++EXPORT_SYMBOL(mpc52xx_ata_ack_blkreq);
+-- 
+1.4.3.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0009-Added-RTAS-support-for-32bit-PowerPC.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0009-Added-RTAS-support-for-32bit-PowerPC.diff	Sat Nov 25 17:21:50 2006
@@ -0,0 +1,108 @@
+From 6d3cbf9a4549928be8ed15cf6a3576c217723895 Mon Sep 17 00:00:00 2001
+From: Nicolas DET <nd at bplan-gmbh.de>
+Date: Fri, 24 Nov 2006 13:22:22 +0100
+Subject: [PATCH] Added RTAS support for 32bit PowerPC
+
+Signed-off-by: Nicolas DET <nd at bplan-gmbh.de>
+---
+ arch/powerpc/kernel/proc_ppc64.c |    9 ---------
+ arch/powerpc/kernel/rtas-proc.c  |   36 ++++++++++++++++++++++++++----------
+ 2 files changed, 26 insertions(+), 19 deletions(-)
+
+diff --git a/arch/powerpc/kernel/proc_ppc64.c b/arch/powerpc/kernel/proc_ppc64.c
+index f598cb5..9b9c32d 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
+ 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;
+ 
+-- 
+1.4.3.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0010-Add-Efika-platform.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0010-Add-Efika-platform.diff	Sat Nov 25 17:21:50 2006
@@ -0,0 +1,1898 @@
+From 6a9d4efc825b36726e94ecfe9e642cc923cb6d78 Mon Sep 17 00:00:00 2001
+From: Nicolas DET <nd at bplan-gmbh.de>
+Date: Fri, 24 Nov 2006 13:33:48 +0100
+Subject: [PATCH] Add Efika platform
+
+Signed-off-by: Nicolas DET <nd at bplan-gmbh.de>
+---
+ arch/powerpc/Kconfig                               |    8 +
+ arch/powerpc/boot/Makefile                         |    1 +
+ arch/powerpc/platforms/Makefile                    |    1 +
+ arch/powerpc/platforms/efika/Makefile              |    1 +
+ arch/powerpc/platforms/efika/bestcomm.h            |  488 +++++++++++++
+ arch/powerpc/platforms/efika/efika.h               |   19 +
+ arch/powerpc/platforms/efika/mpc52xx_bestcomm.c    |  715 ++++++++++++++++++++
+ .../platforms/efika/mpc52xx_bestcomm_helper.c      |  299 ++++++++
+ arch/powerpc/platforms/efika/pci.c                 |  119 ++++
+ arch/powerpc/platforms/efika/setup.c               |  150 ++++
+ 10 files changed, 1801 insertions(+), 0 deletions(-)
+
+diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
+index 0673dbe..32a128d 100644
+--- a/arch/powerpc/Kconfig
++++ b/arch/powerpc/Kconfig
+@@ -386,6 +386,14 @@ config PPC_CHRP
+ 	select PPC_UDBG_16550
+ 	default y
+ 
++config PPC_EFIKA
++	bool "bPlan Efika 5k2. MPC5200B based computer"
++	depends on PPC_MULTIPLATFORM && PPC32
++	select PPC_RTAS
++	select RTAS_PROC
++	select PPC_MPC52xx
++	default y
++
+ config PPC_PMAC
+ 	bool "Apple PowerMac based machines"
+ 	depends on PPC_MULTIPLATFORM
+diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
+index 4b2be61..7b8ce5e 100644
+--- a/arch/powerpc/boot/Makefile
++++ b/arch/powerpc/boot/Makefile
+@@ -155,6 +155,7 @@ image-$(CONFIG_PPC_PSERIES)		+= zImage.p
+ image-$(CONFIG_PPC_MAPLE)		+= zImage.pseries
+ image-$(CONFIG_PPC_IBM_CELL_BLADE)	+= zImage.pseries
+ image-$(CONFIG_PPC_CHRP)		+= zImage.chrp
++image-$(CONFIG_PPC_EFIKA)		+= zImage.chrp
+ image-$(CONFIG_PPC_PMAC)		+= zImage.pmac
+ image-$(CONFIG_DEFAULT_UIMAGE)		+= uImage
+ 
+diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile
+index e58fa95..8294fe4 100644
+--- a/arch/powerpc/platforms/Makefile
++++ b/arch/powerpc/platforms/Makefile
+@@ -6,6 +6,7 @@ obj-$(CONFIG_PPC_PMAC)		+= powermac/
+ endif
+ endif
+ obj-$(CONFIG_PPC_CHRP)		+= chrp/
++obj-$(CONFIG_PPC_EFIKA)		+= efika/
+ obj-$(CONFIG_4xx)		+= 4xx/
+ obj-$(CONFIG_PPC_83xx)		+= 83xx/
+ obj-$(CONFIG_PPC_85xx)		+= 85xx/
+diff --git a/arch/powerpc/platforms/efika/Makefile b/arch/powerpc/platforms/efika/Makefile
+new file mode 100644
+index 0000000..5aefd3d
+--- /dev/null
++++ b/arch/powerpc/platforms/efika/Makefile
+@@ -0,0 +1 @@
++obj-y += setup.o pci.o mpc52xx_bestcomm.o mpc52xx_bestcomm_helper.o
+diff --git a/arch/powerpc/platforms/efika/bestcomm.h b/arch/powerpc/platforms/efika/bestcomm.h
+new file mode 100644
+index 0000000..9555c1b
+--- /dev/null
++++ b/arch/powerpc/platforms/efika/bestcomm.h
+@@ -0,0 +1,488 @@
++/*
++ * include/asm-powerpc/Bestcomm.h
++ *
++ * Driver for MPC52xx processor BestComm peripheral controller
++ * Using bplan GmbH OpenFirmware
++ *
++ * 2006 (c) 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 __BESTCOMM_BESTCOMM_H__
++#define __BESTCOMM_BESTCOMM_H__
++
++
++/**************/
++/**************/
++/**************/
++
++#include <asm/io.h>
++#include <asm/mpc52xx.h>
++
++#include <linux/types.h>
++
++/**************/
++/**************/
++/**************/
++
++#define BESTCOMM_MAX_VAR    24
++#define BESTCOMM_MAX_INC    8
++#define BESTCOMM_MAX_TASKS  16
++
++/**************/
++/**************/
++/**************/
++
++/* Task Descriptor Table Entry */
++/* copied from bestcomm.h, can be found in the public freescale doc */
++
++/* pragma pack required ? */
++struct bestcomm_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;
++};
++
++struct bestcomm_taskhandle
++{
++	int taskid;
++	int irq;
++
++	struct bestcomm_tdt __iomem * bestcomm_tdt;
++
++	u32 __iomem *bestcomm_taskcode;
++	u32 __iomem *bestcomm_vartable;
++
++	union {
++		struct sdma_bd *bd;
++		struct sdma_bd2 *bd2;
++	};
++
++	void **cookie;
++	u16 index;
++	u16 outdex;
++	u16 num_bd;
++	u32 flags;
++};
++
++
++/**************/
++struct bestcomm_mainhandle
++{
++	struct device_node *buildin_ofwnode;
++	struct device_node *sram_ofwnode;
++	struct device_node *bestcomm_ofwnode;
++
++	int bestcomm_irq;
++
++	unsigned long sdma_io_basebus;
++	struct mpc52xx_sdma __iomem* sdma_io_basevirt;
++	size_t sdma_io_size;
++
++	struct bestcomm_tdt __iomem *sdma_tdtentry;
++
++	unsigned long sram_basebus;
++	void __iomem* sram_basevirt;
++	size_t sram_size;
++	size_t sram_available;
++
++	struct bestcomm_taskhandle taskhandle_table[BESTCOMM_MAX_TASKS];
++};
++
++
++
++/**************/
++/**************/
++/**************/
++int
++bestcomm_init_once(void);
++
++struct device_node *
++bestcomm_find_hw(char *name);
++
++int 
++bestcomm_hwiscapable(void);
++
++u32
++bestcomm_getreg(char *name, int *size);
++
++int
++bestcomm_getintrvector(char *name);
++
++/**************/
++struct bestcomm_taskhandle *
++bestcomm_taskallocate(int bestcomm_tasknum, int queue_size);
++
++void
++bestcomm_taskfree(struct bestcomm_taskhandle *mytaskhandle);
++
++int
++bestcomm_taskclear_irq(struct bestcomm_taskhandle *mytaskhandle);
++
++int
++bestcomm_taskenable(struct bestcomm_taskhandle *mytaskhandle);
++
++int
++bestcomm_taskdisable(struct bestcomm_taskhandle *mytaskhandle);
++
++int
++bestcomm_taskget_irq(struct bestcomm_taskhandle *mytaskhandle);
++
++u32 __iomem*
++bestcomm_taskget_code(struct bestcomm_taskhandle *mytaskhandle);
++
++u32 __iomem*
++bestcomm_taskget_vartable(struct bestcomm_taskhandle *mytaskhandle);
++
++u32 __iomem*
++bestcomm_taskget_inctable(struct bestcomm_taskhandle *mytaskhandle);
++
++u16 __iomem*
++bestcomm_taskget_tcr(struct bestcomm_taskhandle *mytaskhandle);
++
++void __iomem *
++bestcomm_phys_to_virt(struct bestcomm_mainhandle *mymainhandle, unsigned long busaddr);
++
++unsigned long
++bestcomm_virt_to_phys(struct bestcomm_mainhandle *mymainhandle, void *virtaddr);
++
++void __iomem*
++bestcomm_sram_alloc(struct bestcomm_taskhandle *mytaskhandle, int len, unsigned long *busaddr);
++
++void
++bestcomm_sram_free(struct bestcomm_taskhandle *mytaskhandle, void *ptr, int len);
++
++/**************/
++/*
++ * The original Linux API has been here partially copied or wrapped
++ * this way, it's quiet easy to reuse exising code
++*/
++/* Buffer Descriptor definitions */
++struct sdma_bd {
++	u32 status;
++	void *data;
++};
++
++struct sdma_bd2 {
++	u32 status;
++	void *data1;
++	void *data2;
++};
++
++#define FIELD_OFFSET(s,f) ((unsigned long)(&(((struct s*)0)->f)))
++
++#define SDMA_FLAGS_NONE		0x0000
++#define SDMA_FLAGS_ENABLE_TASK	0x0001
++#define SDMA_FLAGS_BD2		0x0002
++#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)
++
++#define SDMA_LEN_BITS		26
++#define SDMA_LEN_MASK		((1 << SDMA_LEN_BITS) - 1)
++
++#define SDMA_BD_ALIGN		0x10
++
++/**************/
++/**************/
++/**************/
++struct sdma { struct bestcomm_taskhandle taskhandle; };
++
++/**************/
++/**************/
++/**************/
++unsigned long
++sdma_sram_pa(void __iomem *virt);
++
++void __iomem *
++sdma_sram_va(unsigned long pa);
++
++unsigned long sdma_io_pa
++(void __iomem *virt);
++
++void __iomem *
++sdma_io_va(unsigned long pa);
++
++/**************/
++struct sdma *
++sdma_fex_tx_preinit(int bdnum);
++
++struct sdma *
++sdma_fex_rx_preinit(int bdnum);
++
++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);
++
++struct sdma *
++sdma_ata_preinit(int maxbuffers);
++
++int
++sdma_ata_init(struct bestcomm_taskhandle *mytaskhandle, int maxbufsize);
++
++struct sdma_ata_var {
++	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;	/* size of receive buffer */
++};
++
++/**************/
++/* ata task incs that need to be set before enabling the task */
++struct sdma_ata_inc {
++	u16 pad0;
++	s16 incr_bytes;
++	u16 pad1;
++	s16 incr_dst;
++	u16 pad2;
++	s16 incr_src;
++};
++
++/* 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;
++};
++/**************/
++void *
++sdma_sram_alloc(int size, int alignment, u32 *dma_handle);
++
++static inline struct sdma *
++sdma_alloc(int request_queue_size)
++{ return NULL; };
++
++static inline void
++sdma_free(struct sdma *s)
++{  bestcomm_taskfree( (struct bestcomm_taskhandle *)s); }
++
++static inline int
++sdma_irq(struct sdma *s)
++{ return bestcomm_taskget_irq(&s->taskhandle); }
++
++static inline void
++sdma_enable(struct sdma *s)
++{ bestcomm_taskenable(&s->taskhandle); }
++
++static inline void
++sdma_disable(struct sdma *s)
++{ bestcomm_taskdisable(&s->taskhandle); }
++
++static inline int
++sdma_queue_empty(struct sdma *s_)
++{
++	struct bestcomm_taskhandle *s = &s_->taskhandle;
++	return s->index == s->outdex;
++}
++
++static inline void
++sdma_clear_irq(struct sdma *s)
++{ bestcomm_taskclear_irq( &s->taskhandle); }
++
++static inline int
++sdma_next_index(struct sdma *s_)
++{
++	struct bestcomm_taskhandle *s = &s_->taskhandle;
++	return ((s->index + 1) == s->num_bd) ? 0 : s->index + 1;
++}
++
++static inline int
++sdma_next_outdex(struct sdma *s_)
++{
++	struct bestcomm_taskhandle *s = &s_->taskhandle;
++	return ((s->outdex + 1) == s->num_bd) ? 0 : s->outdex + 1;
++}
++
++static inline int
++sdma_queue_full(struct sdma *s_)
++{
++	struct bestcomm_taskhandle *s = &s_->taskhandle;
++	return s->outdex == sdma_next_index(s_);
++}
++
++static inline int
++sdma_buffer_done(struct sdma *s_)
++{
++	struct bestcomm_taskhandle *s = &s_->taskhandle;
++
++	if (sdma_queue_empty(s_))
++		return 0;
++
++	rmb();
++	return (s->bd[s->outdex].status & SDMA_BD_READY) == 0;
++}
++
++static inline int
++sdma_buffer_done_fixed(struct sdma *s_)
++{
++	struct bestcomm_taskhandle *s = &s_->taskhandle;
++	rmb();
++	return (s->bd[s->outdex].status & SDMA_BD_READY) == 0;
++}
++
++static inline int
++sdma_buffer2_done(struct sdma *s_)
++{
++	struct bestcomm_taskhandle *s = &s_->taskhandle;
++
++	if (sdma_queue_empty(s_))
++		return 0;
++
++	rmb();
++	return (s->bd2[s->outdex].status & SDMA_BD_READY) == 0;
++}
++
++static inline void
++sdma_submit_buffer(struct sdma *s_, void *cookie, void *data, int length)
++{
++	struct bestcomm_taskhandle *s = &s_->taskhandle;
++
++	s->cookie[s->index] = cookie;
++	s->bd[s->index].data = data;
++	wmb();
++	s->bd[s->index].status = SDMA_BD_READY | length;
++	s->index = sdma_next_index(s_);
++	if (s->flags & SDMA_FLAGS_ENABLE_TASK)
++		bestcomm_taskenable(s);
++}
++
++/*
++ * 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)
++{
++	struct bestcomm_taskhandle *s = &s_->taskhandle;
++
++	s->cookie[s->index] = cookie;
++	s->bd[s->index].data = data;
++	wmb();
++	s->bd[s->index].status = SDMA_FEC_TX_BD_TFD_INIT | length;
++	s->index = sdma_next_index(s_);
++	bestcomm_taskenable(s);
++}
++
++static inline void *
++sdma_retrieve_buffer(struct sdma *s_, int *length)
++{
++	struct bestcomm_taskhandle *s = &s_->taskhandle;
++	void *cookie = s->cookie[s->outdex];
++
++	if (length) {
++		rmb();
++		*length = s->bd[s->outdex].status & SDMA_LEN_MASK;
++	}
++	s->outdex = sdma_next_outdex(s_);
++	return cookie;
++}
++
++static inline void
++sdma_reset_buffers(struct sdma *s_)
++{
++	struct bestcomm_taskhandle *s = &s_->taskhandle;
++
++	while (!sdma_queue_empty(s_)) {
++		s->bd[s->outdex].status = 0;
++		wmb();
++		s->bd[s->outdex].data = 0;
++		sdma_retrieve_buffer(s_, NULL);
++	}
++	s->index = s->outdex = 0;
++}
++
++static inline void
++sdma_submit_buffer2(struct sdma *s_, void *cookie,
++					void *data1, void *data2, int length)
++{
++	struct bestcomm_taskhandle *s = &s_->taskhandle;
++
++	s->cookie[s->index] = cookie;
++	s->bd2[s->index].data1 = data1;
++	s->bd2[s->index].data2 = data2;
++	wmb();
++	s->bd2[s->index].status = SDMA_BD_READY | length;
++	s->index = sdma_next_index(s_);
++	if (s->flags & SDMA_FLAGS_ENABLE_TASK)
++		bestcomm_taskenable(s);
++}
++
++static inline void *
++sdma_retrieve_buffer2(struct sdma *s_, int *length)
++{
++	struct bestcomm_taskhandle *s = &s_->taskhandle;
++	void *cookie = s->cookie[s->outdex];
++
++	if (length) {
++		rmb();
++		*length = s->bd2[s->outdex].status & SDMA_LEN_MASK;
++	}
++
++	s->outdex = sdma_next_outdex(s_);
++	return cookie;
++}
++
++static inline void
++sdma_reset_buffers2(struct sdma *s_)
++{
++	struct bestcomm_taskhandle *s = &s_->taskhandle;
++	while (!sdma_queue_empty(s_)) {
++		s->bd2[s->outdex].status = 0;
++		s->bd2[s->outdex].data1 = 0;
++		s->bd2[s->outdex].data2 = 0;
++		wmb();
++		sdma_retrieve_buffer2(s_, NULL);
++	}
++
++	s->index = s->outdex = 0;
++}
++
++#endif 
++
+diff --git a/arch/powerpc/platforms/efika/efika.h b/arch/powerpc/platforms/efika/efika.h
+new file mode 100644
+index 0000000..2f060fd
+--- /dev/null
++++ b/arch/powerpc/platforms/efika/efika.h
+@@ -0,0 +1,19 @@
++/*
++ * 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
+diff --git a/arch/powerpc/platforms/efika/mpc52xx_bestcomm.c b/arch/powerpc/platforms/efika/mpc52xx_bestcomm.c
+new file mode 100644
+index 0000000..c573aed
+--- /dev/null
++++ b/arch/powerpc/platforms/efika/mpc52xx_bestcomm.c
+@@ -0,0 +1,715 @@
++/*
++ * arch/powerpc/platforms/mpc52xx_bestcomm.c
++ *
++ * Driver for MPC52xx processor BestComm peripheral controller
++ * Using bplan GmbH OpenFirmware
++ *
++ * 2006 (c) 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.
++ *
++ */
++
++#undef DEBUG
++
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/module.h>
++
++#include <asm/mpc52xx.h>
++#include <asm/prom.h>
++
++#include "bestcomm.h"
++
++/**************/
++/**************/
++/**************/
++
++struct bestcomm_mainhandle bestcomm_mainhandle;
++
++static int opencnt = 0;
++static struct bestcomm_taskhandle *mysdma_alloc(struct bestcomm_taskhandle *mytaskhandle, int queue_size);
++
++/**************/
++/**************/
++/**************/
++
++typedef u32 Cell;
++
++/*
++ * Virtutal <-> Bus address translator
++ * everything is static inlien here
++*/
++
++/**************/
++static void __iomem *
++sram_bustovirt(struct bestcomm_mainhandle *mymainhandle, unsigned long busaddr)
++{
++        void __iomem *virtaddr;
++        long offset;
++
++        offset = busaddr - mymainhandle->sram_basebus;
++
++        if (offset < 0)
++                return NULL;
++
++        if (offset > mymainhandle->sram_size)
++                return NULL;
++
++        virtaddr = (void __iomem   *) ( (u8 *)mymainhandle->sram_basevirt + offset);
++
++        return virtaddr;
++}
++
++static unsigned long
++sram_virttobus(struct bestcomm_mainhandle *mymainhandle, void *virtaddr)
++{
++        unsigned long busaddr;
++        long offset;
++
++        offset = (u8 *) virtaddr - (u8 *) mymainhandle->sram_basevirt;
++
++        if (offset < 0)
++                return 0;
++
++        if (offset > mymainhandle->sram_size)
++                return 0;
++
++        busaddr = mymainhandle->sram_basebus + offset;
++
++        return busaddr;
++}
++
++static void __iomem *
++io_bustovirt(struct bestcomm_mainhandle *mymainhandle, unsigned long busaddr)
++{
++        void __iomem *virtaddr;
++        long offset;
++
++        offset = busaddr - mymainhandle->sdma_io_basebus;
++
++        if (offset < 0)
++                return NULL;
++
++        if (offset > mymainhandle->sdma_io_size)
++                return NULL;
++
++        virtaddr = (void __iomem   *) ( (u8 *)mymainhandle->sdma_io_basevirt + offset);
++
++        return virtaddr;
++}
++
++static unsigned long
++io_virttobus(struct bestcomm_mainhandle *mymainhandle, void *virtaddr)
++{
++        unsigned long busaddr;
++        long offset;
++
++        offset = (u8 *) virtaddr - (u8 *) mymainhandle->sdma_io_basevirt;
++
++        if (offset < 0)
++                return 0;
++
++        if (offset > mymainhandle->sdma_io_size)
++                return 0;
++
++        busaddr = mymainhandle->sdma_io_basebus + offset;
++
++        return busaddr;
++}
++
++/**************/
++static u8 *area1_end;
++static u8 *area2_begin;
++static spinlock_t sdma_lock = SPIN_LOCK_UNLOCKED;
++
++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;
++}
++
++void __iomem*
++bestcomm_sram_alloc(struct bestcomm_taskhandle *mytaskhandle, int len, unsigned long *busaddr)
++{
++        void *virtaddr;
++        u32 lbusaddr=0;
++
++        virtaddr =  sdma_sram_alloc(len, 32, &lbusaddr);
++        *busaddr = (unsigned long) lbusaddr;
++
++        return virtaddr;
++}
++
++/**************/
++void
++bestcomm_sram_free(struct bestcomm_taskhandle *mytaskhandle, void *ptr, int len)
++{
++}
++
++/**************/
++static int probemisc(struct bestcomm_mainhandle *mymainhandle)
++{
++        int interrupt;
++        interrupt = 0xc0;
++        mymainhandle->bestcomm_irq = interrupt;
++        return 0;
++}
++
++/**************/
++static int
++probeavailable_sram(struct bestcomm_mainhandle *mymainhandle)
++{
++        struct device_node *sram_ofwnode;
++        Cell *oneptr;
++        int proplen;
++        int nac;
++        int nsc;
++        int onepair_size;
++        int paircount;
++        int i;
++
++        int pair_size;
++        unsigned long pair_addr;
++
++        int biggestpair_size=0;
++        unsigned long biggestpair_addr=0;
++
++        pr_debug("\n");
++
++        sram_ofwnode = mymainhandle->sram_ofwnode;
++        nac = prom_n_addr_cells(sram_ofwnode);
++        nsc = prom_n_size_cells(sram_ofwnode);
++        onepair_size = nac + nsc;
++
++        oneptr = (Cell *) get_property(sram_ofwnode, "available", &proplen);
++        if (!oneptr)
++                return -1;
++
++        paircount = proplen / (sizeof(Cell) * onepair_size);
++
++        for(i=0; i < paircount; i++)
++        {
++                pair_addr = (unsigned long) oneptr[i * onepair_size];
++                pair_size = (int) oneptr[i * onepair_size + nac];
++
++                mymainhandle->sram_available += pair_size;
++
++                pr_debug("SRAM free at 0x%8.8lx, size=%d\n", pair_addr, pair_size);
++
++                if (pair_size>biggestpair_size) {
++                        biggestpair_size = pair_size;
++                        biggestpair_addr = pair_addr;
++                }
++        }
++
++        area1_end = sram_bustovirt(mymainhandle, biggestpair_addr);
++        area2_begin = sram_bustovirt(mymainhandle, biggestpair_addr + biggestpair_size);
++
++        pr_debug("SRAM area %p -> %p\n", area1_end, area2_begin);
++
++        return 0;
++}
++
++/**************/
++static int
++mapsram(struct bestcomm_mainhandle *mymainhandle)
++{
++        unsigned long sram_offset;
++        int sram_size;
++        void *__iomem sram_virtmem;
++
++        sram_size = mymainhandle->sram_size;
++        sram_offset = mymainhandle->sram_basebus;
++
++        sram_virtmem = ioremap_nocache(sram_offset, sram_size);
++        if (!sram_virtmem)
++                return -1;
++
++        mymainhandle->sram_basevirt = sram_virtmem;
++
++        pr_debug("SRAM mapped at %p\n", sram_virtmem);
++
++        return 0;
++}
++
++/**************/
++static int
++probesram(struct bestcomm_mainhandle *mymainhandle)
++{
++        struct device_node *onenode;
++        Cell *oneptr;
++        int proplen;
++        int nac;
++        int nsc;
++
++        unsigned long sram_offset;
++        int sram_size;
++
++        pr_debug("\n");
++
++	onenode = of_find_compatible_node(NULL, "memory", "mpc5200-sram");
++        if (!onenode)
++                return -1;
++
++        nac = prom_n_addr_cells(onenode);
++        nsc = prom_n_size_cells(onenode);
++
++        pr_debug("nac=%d, nsc=%d\n", nac, nsc);
++
++        oneptr = (Cell *) get_property(onenode, "reg", &proplen);
++        if (!oneptr)
++                return -1;
++
++        if (proplen < 2)
++                return -1;
++
++        sram_offset = (unsigned long) oneptr[0];
++        sram_size = (int) oneptr[nac];
++
++        pr_debug("oneptr=%p. %lx %d\n", oneptr, sram_offset , sram_size);
++
++        mymainhandle->sram_size = sram_size;
++        mymainhandle->sram_basebus = sram_offset;
++        mymainhandle->sram_ofwnode = onenode;
++
++        return 0;
++}
++
++/**************/
++static int
++probetasktable(struct bestcomm_mainhandle *mymainhandle)
++{
++        struct device_node *onenode;
++        Cell *oneptr;
++        int proplen;
++        int nac;
++        unsigned long tdt_busaddr;
++        long tdt_offset;
++        int tdt_size;
++
++        pr_debug("\n");
++
++        onenode = mymainhandle->bestcomm_ofwnode;
++        oneptr = (Cell *) get_property(onenode, "bestcomm_tasktable", &proplen);
++        if (!oneptr)
++                return -1;
++
++        if (proplen < 2)
++                return -1;
++
++        nac = prom_n_addr_cells(onenode);
++
++        tdt_busaddr = (unsigned long) oneptr[0];
++        tdt_size = (int) oneptr[nac];
++
++        tdt_offset = tdt_busaddr - mymainhandle->sram_basebus;
++
++        pr_debug("tdt_busaddr=%8.8lx, tdt_size=%d, tdt_offset=%ld \n", tdt_busaddr, tdt_size, tdt_offset);
++
++        if (tdt_offset < 0)
++                return -1;
++
++        if (tdt_offset > mymainhandle->sram_size)
++                return -1;
++
++        mymainhandle->sdma_tdtentry = (struct bestcomm_tdt __iomem *) ( (u8 *)mymainhandle->sram_basevirt + tdt_offset);
++
++        pr_debug("SDMA_TDTEntry =%p\n", mymainhandle->sdma_tdtentry);
++
++        return 0;
++}
++
++/**************/
++static int
++probeio(struct bestcomm_mainhandle *mymainhandle)
++{
++        struct device_node *onenode;
++        Cell *oneptr;
++        int proplen;
++        int nac;
++        int nsc;
++
++        unsigned long io_busaddr;
++        int io_size;
++
++        pr_debug("\n");
++
++        onenode = of_find_compatible_node(NULL, "dma-controller", "mpc5200-bestcomm");
++        if (!onenode)
++                return -1;
++
++        nac = prom_n_addr_cells(onenode);
++        nsc = prom_n_size_cells(onenode);
++
++        pr_debug("nac=%d, nsc=%d\n", nac, nsc);
++
++        oneptr = (Cell *) get_property(onenode, "reg", &proplen);
++        if (!oneptr)
++                return -1;
++
++        if (proplen < 2)
++                return -1;
++
++        io_busaddr = (unsigned long) oneptr[0];
++        io_size = (int) oneptr[nac];
++
++        pr_debug("oneptr=%p. %lx %d\n", oneptr, io_busaddr , io_size);
++        mymainhandle->sdma_io_size = io_size;
++        mymainhandle->sdma_io_basebus = io_busaddr;
++        mymainhandle->bestcomm_ofwnode = onenode;
++
++        return 0;
++}
++
++/**************/
++static int
++mapio(struct bestcomm_mainhandle *mymainhandle)
++{
++        unsigned long io_busaddr;
++        void __iomem *io_virtaddr;
++        int io_size;
++
++        io_busaddr = mymainhandle->sdma_io_basebus;
++        io_size = mymainhandle->sdma_io_size;
++
++        io_virtaddr = ioremap_nocache(io_busaddr, io_size);
++        if (!io_virtaddr)
++                goto fail;
++
++        mymainhandle->sdma_io_basevirt = io_virtaddr;
++
++        pr_debug("Bestcomm mapped at %p\n", io_virtaddr );
++
++        return 0;
++
++fail:
++        return -1;
++}
++
++
++/**************/
++static int
++do_bestcomminit(struct bestcomm_mainhandle *mymainhandle)
++{
++        int ret;
++
++        ret = probeio(mymainhandle);
++        if (ret<0)
++                goto fail;
++
++        ret = mapio(mymainhandle);
++        if (ret<0)
++                goto fail;
++
++        ret = probesram(mymainhandle);
++        if (ret<0)
++                goto fail;
++
++        ret = mapsram(mymainhandle);
++        if (ret<0)
++                goto fail;
++
++        ret = probeavailable_sram(mymainhandle);
++        if (ret<0)
++                goto fail;
++
++        ret = probetasktable(mymainhandle);
++        if (ret<0)
++                goto fail;
++
++        ret = probemisc(mymainhandle);
++        if (ret<0)
++                goto fail;
++
++        return 0;
++
++fail:
++        return -1;
++}
++
++/**************/
++int
++bestcomm_hwiscapable(void)
++{
++        return bestcomm_mainhandle.buildin_ofwnode != NULL;
++}
++
++/**************/
++/*
++ * Entry, should be called when the CPU is running
++ * on an OFW machine.
++ * We will silently and properly failed if no compatible
++ * hardware (MPC5200, MPC5200b yet)
++*/
++int
++bestcomm_init_once(void)
++{
++        int ret;
++
++        pr_debug("opencnt %d\n", opencnt);
++
++        /* Already inited ? */
++        if (opencnt>0)
++                return 0;
++
++        memset(&bestcomm_mainhandle, 0x00, sizeof(bestcomm_mainhandle) );
++
++        ret = do_bestcomminit(&bestcomm_mainhandle);
++        if (ret<0)
++                return -1;
++
++        opencnt++;
++
++        printk(KERN_INFO "MPC52xx/OpenFirmware: %d kB of free SRAM\n", bestcomm_mainhandle.sram_available );
++
++        return 0;
++}
++
++/**************/
++/**************/
++/**************/
++void
++bestcomm_taskfree(struct bestcomm_taskhandle *mytaskhandle)
++{
++        if (mytaskhandle)
++        {
++                kfree(mytaskhandle->cookie);
++                mytaskhandle->cookie = NULL;
++        }
++}
++
++struct bestcomm_taskhandle *
++bestcomm_taskallocate(int bestcomm_tasknum, int queue_size)
++{
++        struct bestcomm_taskhandle *mytaskhandle;
++        struct bestcomm_tdt __iomem   *bestcomm_tdt;
++
++        if (bestcomm_tasknum<0)
++                return NULL;
++
++        if (bestcomm_tasknum>=BESTCOMM_MAX_TASKS)
++                return NULL;
++
++        mytaskhandle = &bestcomm_mainhandle.taskhandle_table[bestcomm_tasknum];
++
++        pr_debug("bestcomm_tasknum %d\n", bestcomm_tasknum);
++
++        bestcomm_tdt = &bestcomm_mainhandle.sdma_tdtentry[bestcomm_tasknum];
++
++        mytaskhandle->taskid = bestcomm_tasknum;
++        mytaskhandle->bestcomm_taskcode = sram_bustovirt(&bestcomm_mainhandle, bestcomm_tdt->start);
++        mytaskhandle->bestcomm_vartable = sram_bustovirt(&bestcomm_mainhandle, bestcomm_tdt->var);
++        mytaskhandle->irq = bestcomm_mainhandle.bestcomm_irq + bestcomm_tasknum;
++
++	pr_debug("irq=%d\n", mytaskhandle->irq );
++
++        mytaskhandle = mysdma_alloc(mytaskhandle, queue_size);
++
++        return mytaskhandle;
++}
++
++/**************/
++int
++bestcomm_taskenable(struct bestcomm_taskhandle *mytaskhandle)
++{
++        int task;
++        u16 reg;
++
++        task = mytaskhandle->taskid;
++
++        reg = in_be16(&bestcomm_mainhandle.sdma_io_basevirt->tcr[task]);
++        out_be16(&bestcomm_mainhandle.sdma_io_basevirt->tcr[task], reg | 0x8000);
++
++        return task;
++}
++
++/**************/
++int
++bestcomm_taskdisable(struct bestcomm_taskhandle *mytaskhandle)
++{
++        int task;
++        u16 reg;
++
++        task = mytaskhandle->taskid;
++
++        reg = in_be16(&bestcomm_mainhandle.sdma_io_basevirt->tcr[task]);
++        out_be16(&bestcomm_mainhandle.sdma_io_basevirt->tcr[task], reg & ~0x8000);
++
++        return task;
++}
++
++/**************/
++int
++bestcomm_taskclear_irq(struct bestcomm_taskhandle *mytaskhandle)
++{
++        int tasknum =  mytaskhandle->taskid;
++        out_be32(&bestcomm_mainhandle.sdma_io_basevirt->IntPend, 1 << tasknum);
++        return tasknum;
++}
++
++/**************/
++/**************/
++/**************/
++
++
++/**************/
++void __iomem *
++bestcomm_phys_to_virt(struct bestcomm_mainhandle *mymainhandle, unsigned long busaddr)
++{
++        return sram_bustovirt(mymainhandle, busaddr);
++}
++
++unsigned long
++bestcomm_virt_to_phys(struct bestcomm_mainhandle *mymainhandle, void __iomem* virtaddr)
++{
++        return sram_virttobus(mymainhandle, virtaddr);
++}
++
++/**************/
++/**************/
++/**************/
++
++/*
++ * friendly helper func
++*/
++
++int
++bestcomm_taskget_irq(struct bestcomm_taskhandle *mytaskhandle)
++{
++        return mytaskhandle->irq;
++}
++
++u32 __iomem*
++bestcomm_taskget_code(struct bestcomm_taskhandle *mytaskhandle)
++{
++        return mytaskhandle->bestcomm_taskcode;
++}
++
++u32 __iomem*
++bestcomm_taskget_vartable(struct bestcomm_taskhandle *mytaskhandle)
++{
++        return mytaskhandle->bestcomm_vartable;
++}
++
++u32 __iomem*
++bestcomm_taskget_inctable(struct bestcomm_taskhandle *mytaskhandle)
++{
++        return mytaskhandle->bestcomm_vartable + BESTCOMM_MAX_VAR;
++}
++
++u16 __iomem*
++bestcomm_taskget_tcr(struct bestcomm_taskhandle *mytaskhandle)
++{
++        return &bestcomm_mainhandle.sdma_io_basevirt->tcr[mytaskhandle->taskid];
++}
++
++
++/**************/
++/**************/
++/**************/
++/*
++ * Stuff copied and a little bit modified from the original Linux code
++ * indeed, I think it makes sense to reuse code which works. Moreover,
++ * it's then easier to reuse existing driver with SDMA task which are
++ * not in the OFW
++*/
++
++/**************/
++unsigned long
++sdma_sram_pa(void __iomem *virt)
++{
++        return sram_virttobus(&bestcomm_mainhandle, virt);
++}
++
++void __iomem *
++sdma_sram_va(unsigned long pa)
++{
++        return sram_bustovirt(&bestcomm_mainhandle, pa);
++}
++
++unsigned long
++sdma_io_pa(void __iomem *virt)
++{
++        return io_virttobus(&bestcomm_mainhandle, virt);
++}
++
++void __iomem *
++sdma_io_va(unsigned long pa)
++{
++        return io_bustovirt(&bestcomm_mainhandle, pa);
++}
++
++/**************/
++/*
++ * Here, I just alloc and setup the buffer management stuff
++ * for this task
++*/
++static struct bestcomm_taskhandle *
++mysdma_alloc(struct bestcomm_taskhandle *mytaskhandle, int queue_size)
++{
++        void **cookie;
++
++        if (!mytaskhandle)
++                return NULL;
++
++        if (queue_size)
++        {
++                cookie = kmalloc(sizeof(*cookie) * queue_size, GFP_KERNEL);
++                if (!cookie) {
++                        return NULL;
++                }
++
++                mytaskhandle->cookie = cookie;
++        }
++
++        mytaskhandle->num_bd = queue_size;
++        return mytaskhandle;
++}
++
++/**************/
++/*
++ * Export symbol for modules
++*/
++
++EXPORT_SYMBOL(bestcomm_init_once);
++EXPORT_SYMBOL(bestcomm_hwiscapable);
++EXPORT_SYMBOL(bestcomm_taskallocate);
++EXPORT_SYMBOL(bestcomm_taskfree);
++EXPORT_SYMBOL(bestcomm_taskclear_irq);
++EXPORT_SYMBOL(bestcomm_taskenable);
++EXPORT_SYMBOL(bestcomm_taskdisable);
++EXPORT_SYMBOL(bestcomm_taskget_irq);
++EXPORT_SYMBOL(bestcomm_taskget_code);
++EXPORT_SYMBOL(bestcomm_taskget_vartable);
++EXPORT_SYMBOL(bestcomm_taskget_inctable);
++EXPORT_SYMBOL(bestcomm_taskget_tcr);
++EXPORT_SYMBOL(bestcomm_phys_to_virt);
++EXPORT_SYMBOL(bestcomm_virt_to_phys);
++EXPORT_SYMBOL(bestcomm_sram_alloc);
++EXPORT_SYMBOL(bestcomm_sram_free);
+diff --git a/arch/powerpc/platforms/efika/mpc52xx_bestcomm_helper.c b/arch/powerpc/platforms/efika/mpc52xx_bestcomm_helper.c
+new file mode 100644
+index 0000000..0eef3be
+--- /dev/null
++++ b/arch/powerpc/platforms/efika/mpc52xx_bestcomm_helper.c
+@@ -0,0 +1,299 @@
++/*
++ * arch/powerpc/platforms/mpc52xx_bestcomm_helper.c
++ *
++ * This piece of code help the driver using the Bestcomm DMA
++ * for example, it find and setup the bestcomm dma tasks.
++ * Notice that the prototypes are all gather in Bestcomm.h
++ *
++ * 2006 (c) 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.
++ *
++ */
++
++#undef DEBUG
++
++#include <linux/stddef.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++
++#include <asm/mpc52xx.h>
++#include <asm/prom.h>
++#include <asm/irq.h>
++
++#include "bestcomm.h"
++
++
++/**************/
++/**************/
++/**************/
++extern struct bestcomm_mainhandle bestcomm_mainhandle;
++
++static int irqhack(int irq)
++{
++        struct irq_host *mpc52xx_irqhost;
++        struct device_node *pic_dev;
++
++        pic_dev = of_find_compatible_node(NULL, "interrupt-controller", "mpc5200-pic");
++
++        if (pic_dev == NULL)
++                return -1;
++
++        mpc52xx_irqhost = irq_find_host(pic_dev);
++        if (mpc52xx_irqhost == NULL)
++                return -1;
++
++        pr_debug("%s: irq=0x%x\n", __func__, irq);
++        return irq_create_mapping(mpc52xx_irqhost, irq);
++}
++
++
++/**************/
++/**************/
++/**************/
++static struct sdma *
++sdma_task_preinit(char * devicetype, char * devicecomp, char* taskname, int bdnum)
++{
++        struct sdma *sdma;
++        struct device_node *onenode;
++	struct device_node *parentnode;
++        uint32_t *oneptr;
++        int tasknum;
++	int irq;
++
++        pr_debug("%s:\n", __FUNCTION__);
++
++        if (!devicecomp)
++                return NULL;
++
++        if (!taskname)
++                return NULL;
++
++        if ( bestcomm_init_once() != 0)
++                return NULL;
++
++        pr_debug("devicecomp=%s, taskname=%s, type=%s\n", devicecomp, taskname, devicetype);
++
++	onenode = of_find_compatible_node(NULL, devicetype, devicecomp);
++        if (!onenode)
++                return NULL;
++
++        pr_debug("node=%p\n", onenode);
++
++	parentnode = onenode;
++	onenode = NULL;
++	while( (onenode = of_get_next_child(parentnode, onenode) ) )
++	{
++	        pr_debug("node=%p, name=%s\n", onenode, onenode->name);
++		if ( strcmp(onenode->name, taskname) == 0)
++			break;
++	}
++
++        pr_debug("node=%p\n", onenode);
++
++	if (!onenode)
++                return NULL;
++
++        oneptr = (uint32_t*) get_property(onenode, "taskid", NULL);
++        if (!oneptr)
++                return NULL;
++
++        tasknum = (int) * oneptr;
++
++        pr_debug("tasknum=%d, bdnum=%d\n", tasknum, bdnum);
++
++        sdma = (struct sdma *) bestcomm_taskallocate(tasknum, bdnum);
++        if (!sdma)
++                return NULL;
++
++	irq = irq_of_parse_and_map(onenode, 0);
++	irqhack(irq);
++
++        return sdma;
++}
++
++
++/**************/
++/**************/
++/**************/
++/*
++ * FEC driver helper
++*/
++
++struct sdma *
++sdma_fex_tx_preinit(int bdnum)
++{
++        pr_debug("\n");
++        return sdma_task_preinit("network", "mpc5200-ethernet", "bestcomm-txtask", bdnum);
++}
++
++int
++sdma_fec_tx_init(struct sdma *s, phys_addr_t fifo)
++{
++        struct bestcomm_taskhandle *mytaskhandle = (struct bestcomm_taskhandle *) s;
++        struct sdma_fec_tx_var *var;
++        struct sdma_fec_tx_inc *inc;
++
++        int tasknum = -1;
++        struct sdma_bd *bd = 0;
++        u32 bd_pa;
++
++        if (!bd)
++                bd = (struct sdma_bd *)sdma_sram_alloc(sizeof(*bd) * mytaskhandle->num_bd, SDMA_BD_ALIGN, &bd_pa);
++        if (!bd)
++                return -ENOMEM;
++
++        bestcomm_taskdisable(mytaskhandle);
++
++        tasknum = mytaskhandle->taskid;
++
++        mytaskhandle->bd = bd;
++        mytaskhandle->flags = SDMA_FLAGS_ENABLE_TASK;
++        mytaskhandle->index = 0;
++        mytaskhandle->outdex = 0;
++        memset(bd, 0, sizeof(*bd) * mytaskhandle->num_bd);
++
++        var = (struct sdma_fec_tx_var *) bestcomm_taskget_vartable(mytaskhandle);
++        var->DRD	= sdma_sram_pa( bestcomm_taskget_code(mytaskhandle) + 31);
++        var->fifo	= fifo;
++        var->enable	= sdma_io_pa(&bestcomm_mainhandle.sdma_io_basevirt->tcr[tasknum]);
++        var->bd_base	= bd_pa;
++        var->bd_last	= bd_pa + (mytaskhandle->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 *)bestcomm_taskget_inctable(mytaskhandle);
++        inc->incr_bytes	= -(s16)sizeof(u32);
++        inc->incr_src		= sizeof(u32);
++        inc->incr_src_ma	= sizeof(u8);
++
++        pr_debug("tasknum=%d, bdnum=%d\n", tasknum, mytaskhandle->num_bd);
++
++        mb();
++
++        return tasknum;
++}
++
++struct sdma *sdma_fex_rx_preinit(int bdnum)
++{
++        pr_debug("%s:\n", __FUNCTION__);
++        return sdma_task_preinit("network", "mpc5200-ethernet", "bestcomm-rxtask", bdnum);
++}
++
++
++int sdma_fec_rx_init(struct sdma *s, phys_addr_t fifo, int maxbufsize)
++{
++        int tasknum;
++        struct sdma_fec_rx_var *var;
++        struct sdma_fec_rx_inc *inc;
++        struct bestcomm_taskhandle *mytaskhandle = (struct bestcomm_taskhandle *) s;
++
++        struct sdma_bd *bd = 0;
++        u32 bd_pa;
++
++        if (!bd)
++                bd = (struct sdma_bd *)sdma_sram_alloc(sizeof(*bd) * mytaskhandle->num_bd, SDMA_BD_ALIGN, &bd_pa);
++
++        if (!bd)
++                return -ENOMEM;
++
++        bestcomm_taskdisable(mytaskhandle);
++
++        tasknum = mytaskhandle->taskid;
++
++        mytaskhandle->bd = bd;
++        mytaskhandle->flags = SDMA_FLAGS_NONE;
++        mytaskhandle->index = 0;
++        mytaskhandle->outdex = 0;
++        memset(bd, 0, sizeof(*bd) * mytaskhandle->num_bd);
++
++        var = (struct sdma_fec_rx_var *) bestcomm_taskget_vartable(mytaskhandle);
++
++        var->enable		= sdma_io_pa(&bestcomm_mainhandle.sdma_io_basevirt->tcr[tasknum]);
++        var->fifo		= fifo;
++        var->bd_base		= bd_pa;
++        var->bd_last		= bd_pa + (mytaskhandle->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 *) bestcomm_taskget_inctable(mytaskhandle);
++        inc->incr_bytes	= -(s16)sizeof(u32);
++        inc->incr_dst		= sizeof(u32);
++        inc->incr_dst_ma	= sizeof(u8);
++
++        pr_debug("tasknum=%d, bdnum=%d\n", tasknum, mytaskhandle->num_bd);
++
++        mb();
++
++        return tasknum;
++}
++
++/**************/
++/**************/
++/**************/
++int sdma_ata_init(struct bestcomm_taskhandle *mytaskhandle, int maxbufsize)
++{
++        struct sdma_ata_var *var;
++        struct sdma_bd2 *bd2 = 0;
++        u32 bd_pa;
++        int tasknum = -1;
++
++        pr_debug("MyTaskHandle=%pn max buf=%d\n", mytaskhandle, maxbufsize);
++
++        if (!bd2)
++                bd2 = (struct sdma_bd2 *)sdma_sram_alloc(sizeof(*bd2) * mytaskhandle->num_bd, SDMA_BD_ALIGN, &bd_pa);
++
++        if (!bd2)
++                return -ENOMEM;
++
++        bestcomm_taskdisable(mytaskhandle);
++
++        tasknum = mytaskhandle->taskid;
++
++        mytaskhandle->flags = SDMA_FLAGS_BD2;
++        mytaskhandle->bd2 = bd2;
++        mytaskhandle->index = 0;
++        mytaskhandle->outdex = 0;
++        memset(bd2, 0, sizeof(*bd2) * mytaskhandle->num_bd);
++
++        var = (struct sdma_ata_var *)bestcomm_taskget_vartable(mytaskhandle);
++        var->enable		= sdma_io_pa(&bestcomm_mainhandle.sdma_io_basevirt->tcr[tasknum]);
++        var->bd_base		= bd_pa;
++        var->bd_last		= bd_pa + (mytaskhandle->num_bd - 1)*sizeof(struct sdma_bd2);
++        var->bd_start		= bd_pa;
++        var->buffer_size	= maxbufsize;
++
++        mb();
++
++        return 0;
++}
++
++/**************/
++
++struct sdma *sdma_ata_preinit(int maxbuffers)
++{
++        pr_debug("%s:\n", __FUNCTION__);
++        return sdma_task_preinit("ata", "mpc5200-ata", "bestcomm-task", maxbuffers);
++}
++
++
++/**************/
++/*
++ * Export symbol for modules
++*/
++
++EXPORT_SYMBOL(sdma_sram_pa);
++EXPORT_SYMBOL(sdma_sram_va);
++EXPORT_SYMBOL(sdma_io_pa);
++EXPORT_SYMBOL(sdma_io_va);
++
++EXPORT_SYMBOL(sdma_fex_tx_preinit);
++EXPORT_SYMBOL(sdma_fex_rx_preinit);
++EXPORT_SYMBOL(sdma_fec_rx_init);
++EXPORT_SYMBOL(sdma_fec_tx_init);
++
++EXPORT_SYMBOL(sdma_ata_preinit);
++EXPORT_SYMBOL(sdma_ata_init);
+diff --git a/arch/powerpc/platforms/efika/pci.c b/arch/powerpc/platforms/efika/pci.c
+new file mode 100644
+index 0000000..62e05b2
+--- /dev/null
++++ b/arch/powerpc/platforms/efika/pci.c
+@@ -0,0 +1,119 @@
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/string.h>
++#include <linux/init.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/prom.h>
++#include <asm/machdep.h>
++#include <asm/sections.h>
++#include <asm/pci-bridge.h>
++#include <asm/rtas.h>
++
++#include "efika.h"
++
++#ifdef CONFIG_PCI
++/*
++ * Access functions for PCI config space using RTAS calls.
++ */
++static int rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
++			    int len, u32 * val)
++{
++	struct pci_controller *hose = bus->sysdata;
++	unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8)
++	    | (((bus->number - hose->first_busno) & 0xff) << 16)
++	    | (hose->index << 24);
++	int ret = -1;
++	int rval;
++
++	rval = rtas_call(rtas_token("read-pci-config"), 2, 2, &ret, addr, len);
++	*val = ret;
++	return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
++}
++
++static int rtas_write_config(struct pci_bus *bus, unsigned int devfn,
++			     int offset, int len, u32 val)
++{
++	struct pci_controller *hose = bus->sysdata;
++	unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8)
++	    | (((bus->number - hose->first_busno) & 0xff) << 16)
++	    | (hose->index << 24);
++	int rval;
++
++	rval = rtas_call(rtas_token("write-pci-config"), 3, 1, NULL,
++			 addr, len, val);
++	return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
++}
++
++static struct pci_ops rtas_pci_ops = {
++	rtas_read_config,
++	rtas_write_config
++};
++
++void __init efika_pcisetup(void)
++{
++	const int *bus_range;
++	int len;
++	struct pci_controller *hose;
++	struct device_node *root;
++	struct device_node *pcictrl;
++
++	root = of_find_node_by_path("/");
++	if (root == NULL) {
++		printk(KERN_WARNING EFIKA_PLATFORM_NAME
++		       ": Unable to find the root node\n");
++		return;
++	}
++
++	for (pcictrl = NULL;;) {
++		pcictrl = of_get_next_child(root, pcictrl);
++		if ((pcictrl == NULL) || (strcmp(pcictrl->name, "pci") == 0))
++			break;
++	}
++
++	of_node_put(root);
++
++	if (pcictrl == NULL) {
++		printk(KERN_WARNING EFIKA_PLATFORM_NAME
++		       ": 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
++		       ": 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",
++		       bus_range[0]);
++	else
++		printk(KERN_INFO EFIKA_PLATFORM_NAME ": 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
++		       ": Can't allocate PCI controller structure for %s\n",
++		       pcictrl->full_name);
++		return;
++	}
++
++	hose->arch_data = of_node_get(pcictrl);
++	hose->first_busno = bus_range[0];
++	hose->last_busno = bus_range[1];
++	hose->ops = &rtas_pci_ops;
++
++	pci_process_bridge_OF_ranges(hose, pcictrl, 0);
++}
++
++#else
++void __init efika_pcisetup(void)
++{}
++#endif
+diff --git a/arch/powerpc/platforms/efika/setup.c b/arch/powerpc/platforms/efika/setup.c
+new file mode 100644
+index 0000000..110c980
+--- /dev/null
++++ b/arch/powerpc/platforms/efika/setup.c
+@@ -0,0 +1,150 @@
++/*
++ *
++ * 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
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ *
++ */
++
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/reboot.h>
++#include <linux/init.h>
++#include <linux/utsrelease.h>
++#include <linux/seq_file.h>
++#include <linux/root_dev.h>
++#include <linux/initrd.h>
++#include <linux/timer.h>
++#include <linux/pci.h>
++
++#include <asm/pgtable.h>
++#include <asm/prom.h>
++#include <asm/time.h>
++#include <asm/machdep.h>
++#include <asm/rtas.h>
++#include <asm/of_device.h>
++#include <asm/of_platform.h>
++#include <asm/mpc52xx.h>
++
++#include "efika.h"
++
++static void efika_show_cpuinfo(struct seq_file *m)
++{
++	struct device_node *root;
++	const char *revision = NULL;
++	const char *codegendescription = NULL;
++	const char *codegenvendor = NULL;
++
++	root = of_find_node_by_path("/");
++	if (root) {
++		revision = get_property(root, "revision", NULL);
++		codegendescription =
++		    get_property(root, "CODEGEN,description", NULL);
++		codegenvendor = get_property(root, "CODEGEN,vendor", NULL);
++
++		of_node_put(root);
++	}
++
++	if (codegendescription)
++		seq_printf(m, "machine\t\t: %s\n", codegendescription);
++	else
++		seq_printf(m, "machine\t\t: Efika\n");
++
++	if (revision)
++		seq_printf(m, "revision\t: %s\n", revision);
++
++	if (codegenvendor)
++		seq_printf(m, "vendor\t\t: %s\n", codegenvendor);
++
++	of_node_put(root);
++}
++
++static void __init efika_setup_arch(void)
++{
++	rtas_initialize();
++
++#ifdef CONFIG_BLK_DEV_INITRD
++	initrd_below_start_ok = 1;
++
++	if (initrd_start)
++		ROOT_DEV = Root_RAM0;
++	else
++#endif
++		ROOT_DEV = Root_SDA2;	/* sda2 (sda1 is for the kernel) */
++
++	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);
++}
++
++static int __init efika_probe(void)
++{
++	char *model = of_get_flat_dt_prop(of_get_flat_dt_root(),
++					  "model", NULL);
++
++	if (model == NULL)
++		return 0;
++	if (strcmp(model, "EFIKA5K2"))
++		return 0;
++
++	ISA_DMA_THRESHOLD = ~0L;
++	DMA_MODE_READ = 0x44;
++	DMA_MODE_WRITE = 0x48;
++
++	return 1;
++}
++
++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,
++};
+-- 
+1.4.3.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0011-Filter-out-efika.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0011-Filter-out-efika.diff	Sat Nov 25 17:21:50 2006
@@ -0,0 +1,38 @@
+From 473274f1f615316cf5828caa47704f4d2f9ad1be Mon Sep 17 00:00:00 2001
+From: Nicolas DET <nd at bplan-gmbh.de>
+Date: Fri, 24 Nov 2006 13:34:18 +0100
+Subject: [PATCH] Filter out efika
+
+Signed-off-by: Nicolas DET <nd at bplan-gmbh.de>
+---
+ arch/powerpc/platforms/chrp/setup.c |    9 +++++++++
+ 1 files changed, 9 insertions(+), 0 deletions(-)
+
+diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
+index 49b8dab..1337da8 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.3.2
+

Added: dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0012-Backport-of_platform.diff
==============================================================================
--- (empty file)
+++ dists/trunk/linux-2.6/debian/patches/features/powerpc/efika/0012-Backport-of_platform.diff	Sat Nov 25 17:21:50 2006
@@ -0,0 +1,900 @@
+From 2842fd40de284f328016997ba40d7b83823510c5 Mon Sep 17 00:00:00 2001
+From: Nicolas DET <nd at bplan-gmbh.de>
+Date: Fri, 24 Nov 2006 13:49:57 +0100
+Subject: [PATCH] Backport of_platform
+
+Signed-off-by: Nicolas DET <nd at bplan-gmbh.de>
+---
+ arch/powerpc/kernel/Makefile            |    2 +-
+ arch/powerpc/kernel/of_device.c         |  172 +++------------
+ arch/powerpc/kernel/of_platform.c       |  374 +++++++++++++++++++++++++++++++
+ arch/powerpc/platforms/powermac/setup.c |    1 +
+ drivers/macintosh/smu.c                 |    3 +-
+ drivers/macintosh/therm_adt746x.c       |    2 +-
+ drivers/macintosh/therm_pm72.c          |    5 +-
+ drivers/macintosh/therm_windtunnel.c    |    7 +-
+ drivers/video/platinumfb.c              |    5 +-
+ include/asm-powerpc/of_device.h         |   34 +---
+ include/asm-powerpc/of_platform.h       |   60 +++++
+ 11 files changed, 478 insertions(+), 187 deletions(-)
+
+diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
+index 7af23c4..6d9476f 100644
+--- a/arch/powerpc/kernel/Makefile
++++ b/arch/powerpc/kernel/Makefile
+@@ -21,7 +21,7 @@ obj-$(CONFIG_PPC64)		+= setup_64.o binfm
+ obj-$(CONFIG_PPC64)		+= vdso64/
+ obj-$(CONFIG_ALTIVEC)		+= vecemu.o vector.o
+ obj-$(CONFIG_PPC_970_NAP)	+= idle_power4.o
+-obj-$(CONFIG_PPC_OF)		+= of_device.o prom_parse.o
++obj-$(CONFIG_PPC_OF)		+= of_device.o of_platform.o prom_parse.o
+ procfs-$(CONFIG_PPC64)		:= proc_ppc64.o
+ obj-$(CONFIG_PROC_FS)		+= $(procfs-y)
+ rtaspci-$(CONFIG_PPC64)		:= rtas_pci.o
+diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c
+index 397c83e..5c65398 100644
+--- a/arch/powerpc/kernel/of_device.c
++++ b/arch/powerpc/kernel/of_device.c
+@@ -9,30 +9,26 @@ #include <asm/errno.h>
+ #include <asm/of_device.h>
+ 
+ /**
+- * of_match_device - Tell if an of_device structure has a matching
+- * of_match structure
++ * of_match_node - Tell if an device_node has a matching of_match structure
+  * @ids: array of of device match structures to search in
+- * @dev: the of device structure to match against
++ * @node: the of device structure to match against
+  *
+- * Used by a driver to check whether an of_device present in the
+- * system is in its list of supported devices.
++ * Low level utility function used by device matching.
+  */
+-const struct of_device_id *of_match_device(const struct of_device_id *matches,
+-					const struct of_device *dev)
++const struct of_device_id *of_match_node(const struct of_device_id *matches,
++					 const struct device_node *node)
+ {
+-	if (!dev->node)
+-		return NULL;
+ 	while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
+ 		int match = 1;
+ 		if (matches->name[0])
+-			match &= dev->node->name
+-				&& !strcmp(matches->name, dev->node->name);
++			match &= node->name
++				&& !strcmp(matches->name, node->name);
+ 		if (matches->type[0])
+-			match &= dev->node->type
+-				&& !strcmp(matches->type, dev->node->type);
++			match &= node->type
++				&& !strcmp(matches->type, node->type);
+ 		if (matches->compatible[0])
+-			match &= device_is_compatible(dev->node,
+-				matches->compatible);
++			match &= device_is_compatible(node,
++						      matches->compatible);
+ 		if (match)
+ 			return matches;
+ 		matches++;
+@@ -40,16 +36,21 @@ const struct of_device_id *of_match_devi
+ 	return NULL;
+ }
+ 
+-static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
++/**
++ * of_match_device - Tell if an of_device structure has a matching
++ * of_match structure
++ * @ids: array of of device match structures to search in
++ * @dev: the of device structure to match against
++ *
++ * Used by a driver to check whether an of_device present in the
++ * system is in its list of supported devices.
++ */
++const struct of_device_id *of_match_device(const struct of_device_id *matches,
++					const struct of_device *dev)
+ {
+-	struct of_device * of_dev = to_of_device(dev);
+-	struct of_platform_driver * of_drv = to_of_platform_driver(drv);
+-	const struct of_device_id * matches = of_drv->match_table;
+-
+-	if (!matches)
+-		return 0;
+-
+-	return of_match_device(matches, of_dev) != NULL;
++	if (!dev->node)
++		return NULL;
++	return of_match_node(matches, dev->node);
+ }
+ 
+ struct of_device *of_dev_get(struct of_device *dev)
+@@ -71,96 +72,8 @@ void of_dev_put(struct of_device *dev)
+ 		put_device(&dev->dev);
+ }
+ 
+-
+-static int of_device_probe(struct device *dev)
+-{
+-	int error = -ENODEV;
+-	struct of_platform_driver *drv;
+-	struct of_device *of_dev;
+-	const struct of_device_id *match;
+-
+-	drv = to_of_platform_driver(dev->driver);
+-	of_dev = to_of_device(dev);
+-
+-	if (!drv->probe)
+-		return error;
+-
+-	of_dev_get(of_dev);
+-
+-	match = of_match_device(drv->match_table, of_dev);
+-	if (match)
+-		error = drv->probe(of_dev, match);
+-	if (error)
+-		of_dev_put(of_dev);
+-
+-	return error;
+-}
+-
+-static int of_device_remove(struct device *dev)
+-{
+-	struct of_device * of_dev = to_of_device(dev);
+-	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
+-
+-	if (dev->driver && drv->remove)
+-		drv->remove(of_dev);
+-	return 0;
+-}
+-
+-static int of_device_suspend(struct device *dev, pm_message_t state)
+-{
+-	struct of_device * of_dev = to_of_device(dev);
+-	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
+-	int error = 0;
+-
+-	if (dev->driver && drv->suspend)
+-		error = drv->suspend(of_dev, state);
+-	return error;
+-}
+-
+-static int of_device_resume(struct device * dev)
+-{
+-	struct of_device * of_dev = to_of_device(dev);
+-	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
+-	int error = 0;
+-
+-	if (dev->driver && drv->resume)
+-		error = drv->resume(of_dev);
+-	return error;
+-}
+-
+-struct bus_type of_platform_bus_type = {
+-       .name	= "of_platform",
+-       .match	= of_platform_bus_match,
+-       .probe	= of_device_probe,
+-       .remove	= of_device_remove,
+-       .suspend	= of_device_suspend,
+-       .resume	= of_device_resume,
+-};
+-
+-static int __init of_bus_driver_init(void)
+-{
+-	return bus_register(&of_platform_bus_type);
+-}
+-
+-postcore_initcall(of_bus_driver_init);
+-
+-int of_register_driver(struct of_platform_driver *drv)
+-{
+-	/* initialize common driver fields */
+-	drv->driver.name = drv->name;
+-	drv->driver.bus = &of_platform_bus_type;
+-
+-	/* register with core */
+-	return driver_register(&drv->driver);
+-}
+-
+-void of_unregister_driver(struct of_platform_driver *drv)
+-{
+-	driver_unregister(&drv->driver);
+-}
+-
+-
+-static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
++static ssize_t dev_show_devspec(struct device *dev,
++				struct device_attribute *attr, char *buf)
+ {
+ 	struct of_device *ofdev;
+ 
+@@ -208,41 +121,10 @@ void of_device_unregister(struct of_devi
+ 	device_unregister(&ofdev->dev);
+ }
+ 
+-struct of_device* of_platform_device_create(struct device_node *np,
+-					    const char *bus_id,
+-					    struct device *parent)
+-{
+-	struct of_device *dev;
+-
+-	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+-	if (!dev)
+-		return NULL;
+-	memset(dev, 0, sizeof(*dev));
+-
+-	dev->node = of_node_get(np);
+-	dev->dma_mask = 0xffffffffUL;
+-	dev->dev.dma_mask = &dev->dma_mask;
+-	dev->dev.parent = parent;
+-	dev->dev.bus = &of_platform_bus_type;
+-	dev->dev.release = of_release_dev;
+-
+-	strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
+-
+-	if (of_device_register(dev) != 0) {
+-		kfree(dev);
+-		return NULL;
+-	}
+-
+-	return dev;
+-}
+ 
+ EXPORT_SYMBOL(of_match_device);
+-EXPORT_SYMBOL(of_platform_bus_type);
+-EXPORT_SYMBOL(of_register_driver);
+-EXPORT_SYMBOL(of_unregister_driver);
+ EXPORT_SYMBOL(of_device_register);
+ EXPORT_SYMBOL(of_device_unregister);
+ EXPORT_SYMBOL(of_dev_get);
+ EXPORT_SYMBOL(of_dev_put);
+-EXPORT_SYMBOL(of_platform_device_create);
+ EXPORT_SYMBOL(of_release_dev);
+diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c
+new file mode 100644
+index 0000000..41c71bc
+--- /dev/null
++++ b/arch/powerpc/kernel/of_platform.c
+@@ -0,0 +1,374 @@
++/*
++ *    Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
++ *			 <benh at kernel.crashing.org>
++ *
++ *  This program is free software; you can redistribute it and/or
++ *  modify it under the terms of the GNU General Public License
++ *  as published by the Free Software Foundation; either version
++ *  2 of the License, or (at your option) any later version.
++ *
++ */
++
++#undef DEBUG
++
++#include <linux/string.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/mod_devicetable.h>
++#include <linux/slab.h>
++
++#include <asm/errno.h>
++#ifdef CONFIG_PPC_DCR
++#include <asm/dcr.h>
++#endif
++#include <asm/of_device.h>
++#include <asm/of_platform.h>
++
++
++/*
++ * The list of OF IDs below is used for matching bus types in the
++ * system whose devices are to be exposed as of_platform_devices.
++ *
++ * This is the default list valid for most platforms. This file provides
++ * functions who can take an explicit list if necessary though
++ *
++ * The search is always performed recursively looking for children of
++ * the provided device_node and recursively if such a children matches
++ * a bus type in the list
++ */
++
++static struct of_device_id of_default_bus_ids[] = {
++	{ .type = "soc", },
++	{ .compatible = "soc", },
++	{ .type = "spider", },
++	{ .type = "axon", },
++	{ .type = "plb5", },
++	{ .type = "plb4", },
++	{ .type = "opb", },
++	{},
++};
++
++/*
++ *
++ * OF platform device type definition & base infrastructure
++ *
++ */
++
++static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
++{
++	struct of_device * of_dev = to_of_device(dev);
++	struct of_platform_driver * of_drv = to_of_platform_driver(drv);
++	const struct of_device_id * matches = of_drv->match_table;
++
++	if (!matches)
++		return 0;
++
++	return of_match_device(matches, of_dev) != NULL;
++}
++
++static int of_platform_device_probe(struct device *dev)
++{
++	int error = -ENODEV;
++	struct of_platform_driver *drv;
++	struct of_device *of_dev;
++	const struct of_device_id *match;
++
++	drv = to_of_platform_driver(dev->driver);
++	of_dev = to_of_device(dev);
++
++	if (!drv->probe)
++		return error;
++
++	of_dev_get(of_dev);
++
++	match = of_match_device(drv->match_table, of_dev);
++	if (match)
++		error = drv->probe(of_dev, match);
++	if (error)
++		of_dev_put(of_dev);
++
++	return error;
++}
++
++static int of_platform_device_remove(struct device *dev)
++{
++	struct of_device * of_dev = to_of_device(dev);
++	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
++
++	if (dev->driver && drv->remove)
++		drv->remove(of_dev);
++	return 0;
++}
++
++static int of_platform_device_suspend(struct device *dev, pm_message_t state)
++{
++	struct of_device * of_dev = to_of_device(dev);
++	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
++	int error = 0;
++
++	if (dev->driver && drv->suspend)
++		error = drv->suspend(of_dev, state);
++	return error;
++}
++
++static int of_platform_device_resume(struct device * dev)
++{
++	struct of_device * of_dev = to_of_device(dev);
++	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
++	int error = 0;
++
++	if (dev->driver && drv->resume)
++		error = drv->resume(of_dev);
++	return error;
++}
++
++struct bus_type of_platform_bus_type = {
++       .name	= "of_platform",
++       .match	= of_platform_bus_match,
++       .probe	= of_platform_device_probe,
++       .remove	= of_platform_device_remove,
++       .suspend	= of_platform_device_suspend,
++       .resume	= of_platform_device_resume,
++};
++EXPORT_SYMBOL(of_platform_bus_type);
++
++static int __init of_bus_driver_init(void)
++{
++	return bus_register(&of_platform_bus_type);
++}
++
++postcore_initcall(of_bus_driver_init);
++
++int of_register_platform_driver(struct of_platform_driver *drv)
++{
++	/* initialize common driver fields */
++	drv->driver.name = drv->name;
++	drv->driver.bus = &of_platform_bus_type;
++
++	/* register with core */
++	return driver_register(&drv->driver);
++}
++EXPORT_SYMBOL(of_register_platform_driver);
++
++void of_unregister_platform_driver(struct of_platform_driver *drv)
++{
++	driver_unregister(&drv->driver);
++}
++EXPORT_SYMBOL(of_unregister_platform_driver);
++
++static void of_platform_make_bus_id(struct of_device *dev)
++{
++	struct device_node *node = dev->node;
++	char *name = dev->dev.bus_id;
++	const u32 *reg;
++	u64 addr;
++
++	/*
++	 * If it's a DCR based device, use 'd' for native DCRs
++	 * and 'D' for MMIO DCRs.
++	 */
++#ifdef CONFIG_PPC_DCR
++	reg = get_property(node, "dcr-reg", NULL);
++	if (reg) {
++#ifdef CONFIG_PPC_DCR_NATIVE
++		snprintf(name, BUS_ID_SIZE, "d%x.%s",
++			 *reg, node->name);
++#else /* CONFIG_PPC_DCR_NATIVE */
++		addr = of_translate_dcr_address(node, *reg, NULL);
++		if (addr != OF_BAD_ADDR) {
++			snprintf(name, BUS_ID_SIZE,
++				 "D%llx.%s", (unsigned long long)addr,
++				 node->name);
++			return;
++		}
++#endif /* !CONFIG_PPC_DCR_NATIVE */
++	}
++#endif /* CONFIG_PPC_DCR */
++
++	/*
++	 * For MMIO, get the physical address
++	 */
++	reg = get_property(node, "reg", NULL);
++	if (reg) {
++		addr = of_translate_address(node, reg);
++		if (addr != OF_BAD_ADDR) {
++			snprintf(name, BUS_ID_SIZE,
++				 "%llx.%s", (unsigned long long)addr,
++				 node->name);
++			return;
++		}
++	}
++
++	/*
++	 * No BusID, use the node name and pray
++	 */
++	snprintf(name, BUS_ID_SIZE, "%s", node->name);
++}
++
++struct of_device* of_platform_device_create(struct device_node *np,
++					    const char *bus_id,
++					    struct device *parent)
++{
++	struct of_device *dev;
++
++	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
++	if (!dev)
++		return NULL;
++	memset(dev, 0, sizeof(*dev));
++
++	dev->node = of_node_get(np);
++	dev->dma_mask = 0xffffffffUL;
++	dev->dev.dma_mask = &dev->dma_mask;
++	dev->dev.parent = parent;
++	dev->dev.bus = &of_platform_bus_type;
++	dev->dev.release = of_release_dev;
++
++	if (bus_id)
++		strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
++	else
++		of_platform_make_bus_id(dev);
++
++	if (of_device_register(dev) != 0) {
++		kfree(dev);
++		return NULL;
++	}
++
++	return dev;
++}
++EXPORT_SYMBOL(of_platform_device_create);
++
++
++
++/**
++ * of_platform_bus_create - Create an OF device for a bus node and all its
++ * children. Optionally recursively instanciate matching busses.
++ * @bus: device node of the bus to instanciate
++ * @matches: match table, NULL to use the default, OF_NO_DEEP_PROBE to
++ * disallow recursive creation of child busses
++ */
++static int of_platform_bus_create(struct device_node *bus,
++				  struct of_device_id *matches,
++				  struct device *parent)
++{
++	struct device_node *child;
++	struct of_device *dev;
++	int rc = 0;
++
++	for (child = NULL; (child = of_get_next_child(bus, child)); ) {
++		pr_debug("   create child: %s\n", child->full_name);
++		dev = of_platform_device_create(child, NULL, parent);
++		if (dev == NULL)
++			rc = -ENOMEM;
++		else if (!of_match_node(matches, child))
++			continue;
++		if (rc == 0) {
++			pr_debug("   and sub busses\n");
++			rc = of_platform_bus_create(child, matches, &dev->dev);
++		} if (rc) {
++			of_node_put(child);
++			break;
++		}
++	}
++	return rc;
++}
++
++/**
++ * of_platform_bus_probe - Probe the device-tree for platform busses
++ * @root: parent of the first level to probe or NULL for the root of the tree
++ * @matches: match table, NULL to use the default
++ * @parent: parent to hook devices from, NULL for toplevel
++ *
++ * Note that children of the provided root are not instanciated as devices
++ * unless the specified root itself matches the bus list and is not NULL.
++ */
++
++int of_platform_bus_probe(struct device_node *root,
++			  struct of_device_id *matches,
++			  struct device *parent)
++{
++	struct device_node *child;
++	struct of_device *dev;
++	int rc = 0;
++
++	if (matches == NULL)
++		matches = of_default_bus_ids;
++	if (matches == OF_NO_DEEP_PROBE)
++		return -EINVAL;
++	if (root == NULL)
++		root = of_find_node_by_path("/");
++	else
++		of_node_get(root);
++
++	pr_debug("of_platform_bus_probe()\n");
++	pr_debug(" starting at: %s\n", root->full_name);
++
++	/* Do a self check of bus type, if there's a match, create
++	 * children
++	 */
++	if (of_match_node(matches, root)) {
++		pr_debug(" root match, create all sub devices\n");
++		dev = of_platform_device_create(root, NULL, parent);
++		if (dev == NULL) {
++			rc = -ENOMEM;
++			goto bail;
++		}
++		pr_debug(" create all sub busses\n");
++		rc = of_platform_bus_create(root, matches, &dev->dev);
++		goto bail;
++	}
++	for (child = NULL; (child = of_get_next_child(root, child)); ) {
++		if (!of_match_node(matches, child))
++			continue;
++
++		pr_debug("  match: %s\n", child->full_name);
++		dev = of_platform_device_create(child, NULL, parent);
++		if (dev == NULL)
++			rc = -ENOMEM;
++		else
++			rc = of_platform_bus_create(child, matches, &dev->dev);
++		if (rc) {
++			of_node_put(child);
++			break;
++		}
++	}
++ bail:
++	of_node_put(root);
++	return rc;
++}
++EXPORT_SYMBOL(of_platform_bus_probe);
++
++static int of_dev_node_match(struct device *dev, void *data)
++{
++	return to_of_device(dev)->node == data;
++}
++
++struct of_device *of_find_device_by_node(struct device_node *np)
++{
++	struct device *dev;
++
++	dev = bus_find_device(&of_platform_bus_type,
++			      NULL, np, of_dev_node_match);
++	if (dev)
++		return to_of_device(dev);
++	return NULL;
++}
++EXPORT_SYMBOL(of_find_device_by_node);
++
++static int of_dev_phandle_match(struct device *dev, void *data)
++{
++	phandle *ph = data;
++	return to_of_device(dev)->node->linux_phandle == *ph;
++}
++
++struct of_device *of_find_device_by_phandle(phandle ph)
++{
++	struct device *dev;
++
++	dev = bus_find_device(&of_platform_bus_type,
++			      NULL, &ph, of_dev_phandle_match);
++	if (dev)
++		return to_of_device(dev);
++	return NULL;
++}
++EXPORT_SYMBOL(of_find_device_by_phandle);
+diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
+index 824a618..e25a0bd 100644
+--- a/arch/powerpc/platforms/powermac/setup.c
++++ b/arch/powerpc/platforms/powermac/setup.c
+@@ -70,6 +70,7 @@ #include <asm/btext.h>
+ #include <asm/pmac_feature.h>
+ #include <asm/time.h>
+ #include <asm/of_device.h>
++#include <asm/of_platform.h>
+ #include <asm/mmu_context.h>
+ #include <asm/iommu.h>
+ #include <asm/smu.h>
+diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
+index ade25b3..4f724cd 100644
+--- a/drivers/macintosh/smu.c
++++ b/drivers/macintosh/smu.c
+@@ -46,6 +46,7 @@ #include <asm/sections.h>
+ #include <asm/abs_addr.h>
+ #include <asm/uaccess.h>
+ #include <asm/of_device.h>
++#include <asm/of_platform.h>
+ 
+ #define VERSION "0.7"
+ #define AUTHOR  "(c) 2005 Benjamin Herrenschmidt, IBM Corp."
+@@ -653,7 +654,7 @@ static int __init smu_init_sysfs(void)
+ 	 * I'm a bit too far from figuring out how that works with those
+ 	 * new chipsets, but that will come back and bite us
+ 	 */
+-	of_register_driver(&smu_of_platform_driver);
++	of_register_platform_driver(&smu_of_platform_driver);
+ 	return 0;
+ }
+ 
+diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
+index a0f30d0..13b953a 100644
+--- a/drivers/macintosh/therm_adt746x.c
++++ b/drivers/macintosh/therm_adt746x.c
+@@ -30,7 +30,7 @@ #include <asm/machdep.h>
+ #include <asm/io.h>
+ #include <asm/system.h>
+ #include <asm/sections.h>
+-#include <asm/of_device.h>
++#include <asm/of_platform.h>
+ 
+ #undef DEBUG
+ 
+diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
+index d00c0c3..2e4ad44 100644
+--- a/drivers/macintosh/therm_pm72.c
++++ b/drivers/macintosh/therm_pm72.c
+@@ -129,6 +129,7 @@ #include <asm/system.h>
+ #include <asm/sections.h>
+ #include <asm/of_device.h>
+ #include <asm/macio.h>
++#include <asm/of_platform.h>
+ 
+ #include "therm_pm72.h"
+ 
+@@ -2236,14 +2237,14 @@ static int __init therm_pm72_init(void)
+ 		return -ENODEV;
+ 	}
+ 
+-	of_register_driver(&fcu_of_platform_driver);
++	of_register_platform_driver(&fcu_of_platform_driver);
+ 	
+ 	return 0;
+ }
+ 
+ static void __exit therm_pm72_exit(void)
+ {
+-	of_unregister_driver(&fcu_of_platform_driver);
++	of_unregister_platform_driver(&fcu_of_platform_driver);
+ 
+ 	if (of_dev)
+ 		of_device_unregister(of_dev);
+diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c
+index 738faab..a1d3a98 100644
+--- a/drivers/macintosh/therm_windtunnel.c
++++ b/drivers/macintosh/therm_windtunnel.c
+@@ -36,12 +36,13 @@ #include <linux/sched.h>
+ #include <linux/i2c.h>
+ #include <linux/slab.h>
+ #include <linux/init.h>
++
+ #include <asm/prom.h>
+ #include <asm/machdep.h>
+ #include <asm/io.h>
+ #include <asm/system.h>
+ #include <asm/sections.h>
+-#include <asm/of_device.h>
++#include <asm/of_platform.h>
+ #include <asm/macio.h>
+ 
+ #define LOG_TEMP		0			/* continously log temperature */
+@@ -511,14 +512,14 @@ g4fan_init( void )
+ 		return -ENODEV;
+ 	}
+ 
+-	of_register_driver( &therm_of_driver );
++	of_register_platform_driver( &therm_of_driver );
+ 	return 0;
+ }
+ 
+ static void __exit
+ g4fan_exit( void )
+ {
+-	of_unregister_driver( &therm_of_driver );
++	of_unregister_platform_driver( &therm_of_driver );
+ 
+ 	if( x.of_dev )
+ 		of_device_unregister( x.of_dev );
+diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
+index fdb33cd..cb26c6d 100644
+--- a/drivers/video/platinumfb.c
++++ b/drivers/video/platinumfb.c
+@@ -34,6 +34,7 @@ #include <asm/io.h>
+ #include <asm/prom.h>
+ #include <asm/pgtable.h>
+ #include <asm/of_device.h>
++#include <asm/of_platform.h>
+ 
+ #include "macmodes.h"
+ #include "platinumfb.h"
+@@ -682,14 +683,14 @@ #ifndef MODULE
+ 		return -ENODEV;
+ 	platinumfb_setup(option);
+ #endif
+-	of_register_driver(&platinum_driver);
++	of_register_platform_driver(&platinum_driver);
+ 
+ 	return 0;
+ }
+ 
+ static void __exit platinumfb_exit(void)
+ {
+-	of_unregister_driver(&platinum_driver);	
++	of_unregister_platform_driver(&platinum_driver);
+ }
+ 
+ MODULE_LICENSE("GPL");
+diff --git a/include/asm-powerpc/of_device.h b/include/asm-powerpc/of_device.h
+index c5c0b0b..1ef7e9e 100644
+--- a/include/asm-powerpc/of_device.h
++++ b/include/asm-powerpc/of_device.h
+@@ -6,12 +6,6 @@ #include <linux/device.h>
+ #include <linux/mod_devicetable.h>
+ #include <asm/prom.h>
+ 
+-/*
+- * The of_platform_bus_type is a bus type used by drivers that do not
+- * attach to a macio or similar bus but still use OF probing
+- * mechanism
+- */
+-extern struct bus_type of_platform_bus_type;
+ 
+ /*
+  * The of_device is a kind of "base class" that is a superset of
+@@ -26,40 +20,16 @@ struct of_device
+ };
+ #define	to_of_device(d) container_of(d, struct of_device, dev)
+ 
++extern const struct of_device_id *of_match_node(
++	const struct of_device_id *matches, const struct device_node *node);
+ extern const struct of_device_id *of_match_device(
+ 	const struct of_device_id *matches, const struct of_device *dev);
+ 
+ extern struct of_device *of_dev_get(struct of_device *dev);
+ extern void of_dev_put(struct of_device *dev);
+ 
+-/*
+- * An of_platform_driver driver is attached to a basic of_device on
+- * the "platform bus" (of_platform_bus_type)
+- */
+-struct of_platform_driver
+-{
+-	char			*name;
+-	struct of_device_id	*match_table;
+-	struct module		*owner;
+-
+-	int	(*probe)(struct of_device* dev, const struct of_device_id *match);
+-	int	(*remove)(struct of_device* dev);
+-
+-	int	(*suspend)(struct of_device* dev, pm_message_t state);
+-	int	(*resume)(struct of_device* dev);
+-	int	(*shutdown)(struct of_device* dev);
+-
+-	struct device_driver	driver;
+-};
+-#define	to_of_platform_driver(drv) container_of(drv,struct of_platform_driver, driver)
+-
+-extern int of_register_driver(struct of_platform_driver *drv);
+-extern void of_unregister_driver(struct of_platform_driver *drv);
+ extern int of_device_register(struct of_device *ofdev);
+ extern void of_device_unregister(struct of_device *ofdev);
+-extern struct of_device *of_platform_device_create(struct device_node *np,
+-						   const char *bus_id,
+-						   struct device *parent);
+ extern void of_release_dev(struct device *dev);
+ 
+ #endif /* __KERNEL__ */
+diff --git a/include/asm-powerpc/of_platform.h b/include/asm-powerpc/of_platform.h
+new file mode 100644
+index 0000000..217eafb
+--- /dev/null
++++ b/include/asm-powerpc/of_platform.h
+@@ -0,0 +1,60 @@
++/*
++ *    Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
++ *			 <benh at kernel.crashing.org>
++ *
++ *  This program is free software; you can redistribute it and/or
++ *  modify it under the terms of the GNU General Public License
++ *  as published by the Free Software Foundation; either version
++ *  2 of the License, or (at your option) any later version.
++ *
++ */
++
++#include <asm/of_device.h>
++
++/*
++ * The of_platform_bus_type is a bus type used by drivers that do not
++ * attach to a macio or similar bus but still use OF probing
++ * mechanism
++ */
++extern struct bus_type of_platform_bus_type;
++
++/*
++ * An of_platform_driver driver is attached to a basic of_device on
++ * the "platform bus" (of_platform_bus_type)
++ */
++struct of_platform_driver
++{
++	char			*name;
++	struct of_device_id	*match_table;
++	struct module		*owner;
++
++	int	(*probe)(struct of_device* dev,
++			 const struct of_device_id *match);
++	int	(*remove)(struct of_device* dev);
++
++	int	(*suspend)(struct of_device* dev, pm_message_t state);
++	int	(*resume)(struct of_device* dev);
++	int	(*shutdown)(struct of_device* dev);
++
++	struct device_driver	driver;
++};
++#define	to_of_platform_driver(drv) \
++	container_of(drv,struct of_platform_driver, driver)
++
++/* Platform drivers register/unregister */
++extern int of_register_platform_driver(struct of_platform_driver *drv);
++extern void of_unregister_platform_driver(struct of_platform_driver *drv);
++
++/* Platform devices and busses creation */
++extern struct of_device *of_platform_device_create(struct device_node *np,
++						   const char *bus_id,
++						   struct device *parent);
++/* pseudo "matches" value to not do deep probe */
++#define OF_NO_DEEP_PROBE ((struct of_device_id *)-1)
++
++extern int of_platform_bus_probe(struct device_node *root,
++				 struct of_device_id *matches,
++				 struct device *parent);
++
++extern struct of_device *of_find_device_by_node(struct device_node *np);
++extern struct of_device *of_find_device_by_phandle(phandle ph);
+-- 
+1.4.3.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	Sat Nov 25 17:21:50 2006
@@ -3,9 +3,26 @@
 + 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-powerpc.patch
++ bugfix/powerpc/build-links.patch
++ bugfix/powerpc/mv643xx-hotplug-support.patch
++ bugfix/powerpc/oldworld-boot-fix.patch
++ bugfix/powerpc/prep-utah-ide-interrupt.patch
++ bugfix/powerpc/serial.patch
++ features/powerpc/efika/0001-Fix-compilation-issue-when-PPC_MPC52xx-and-PPC_MERGE-are-selected.diff
++ features/powerpc/efika/0002-Add-USB-OHCI-glue-for-OpenFirmware-devices.diff
++ features/powerpc/efika/0003-Add-MPC5200-serial-driver.diff
++ features/powerpc/efika/0004-Add-MPC5200-CPU-PIO-driver-using-libata.diff
++ features/powerpc/efika/0005-Add-MPC5200-specific-header.diff
++ features/powerpc/efika/0006-Add-MPC5200-interrupt-controller-driver.diff
++ features/powerpc/efika/0007-Add-MPC5200-ethernet-driver.diff
++ features/powerpc/efika/0008-Add-MPC5200-SDMA-PIO-driver.diff
++ features/powerpc/efika/0009-Added-RTAS-support-for-32bit-PowerPC.diff
++ features/powerpc/efika/0010-Add-Efika-platform.diff
++ features/powerpc/efika/0011-Filter-out-efika.diff
++ features/powerpc/efika/0012-Backport-of_platform.diff
++ features/all/fs-asfs.patch
 
-#+ features/all/fs-asfs.patch
 + bugfix/arm/nslu2-disk-leds.patch
 + features/arm/nslu2-setup-mac.patch
 + features/arm/nslu2-eth-mac.patch



More information about the Kernel-svn-changes mailing list