[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(®s->pio1, timing->pio1);
++ out_be32(®s->pio2, timing->pio2);
++ out_be32(®s->mdma1, 0);
++ out_be32(®s->mdma2, 0);
++ out_be32(®s->udma1, 0);
++ out_be32(®s->udma2, 0);
++ out_be32(®s->udma3, 0);
++ out_be32(®s->udma4, 0);
++ out_be32(®s->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(®s->share_cnt, 0);
++
++ /* Configure and reset host */
++ out_be32(®s->config,
++ MPC52xx_ATA_HOSTCONF_IE |
++ MPC52xx_ATA_HOSTCONF_IORDY |
++ MPC52xx_ATA_HOSTCONF_SMR |
++ MPC52xx_ATA_HOSTCONF_FR);
++
++ udelay(10);
++
++ out_be32(®s->config,
++ MPC52xx_ATA_HOSTCONF_IE |
++ MPC52xx_ATA_HOSTCONF_IORDY);
++
++ /* Set the time slot to 1us */
++ tslot = CALC_CLKCYC(priv->ipb_period, 1000000);
++ out_be32(®s->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(ðcmd, useraddr, sizeof ethcmd))
++ return -EFAULT;
++
++ switch (ethcmd) {
++
++ /* Get driver info */
++ case ETHTOOL_GDRVINFO:{
++ struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
++ strncpy(info.driver, "MPC5200 FEC",
++ sizeof info.driver - 1);
++ if (copy_to_user(useraddr, &info, sizeof info))
++ return -EFAULT;
++ return 0;
++ }
++ /* get message-level */
++ case ETHTOOL_GMSGLVL:{
++ struct ethtool_value edata = { ETHTOOL_GMSGLVL };
++ edata.data = 0; /* XXX */
++ if (copy_to_user(useraddr, &edata, sizeof edata))
++ return -EFAULT;
++ return 0;
++ }
++ /* set message-level */
++ case ETHTOOL_SMSGLVL:{
++ struct ethtool_value edata;
++ if (copy_from_user(&edata, useraddr, sizeof edata))
++ return -EFAULT;
++ return 0;
++ }
++ }
++ return -EOPNOTSUPP;
++}
++
++int fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
++{
++ int retval;
++
++ switch (cmd) {
++ case SIOCETHTOOL:
++ retval = mpc52xx_netdev_ethtool_ioctl(
++ dev, (void *) rq->ifr_data);
++ break;
++
++ default:
++ retval = -EOPNOTSUPP;
++ break;
++ }
++ return retval;
++}
++
++void fec_mii_init(struct net_device *dev)
++{
++ struct fec_priv *priv = (struct fec_priv *)dev->priv;
++ int i;
++
++ for (i=0; i<NMII-1; i++)
++ mii_cmds[i].mii_next = &mii_cmds[i+1];
++ mii_free = mii_cmds;
++
++ /* Queue up command to detect the PHY and initialize the
++ * remainder of the interface.
++ */
++ priv->phy_id_done = 0;
++ priv->phy_addr = 0;
++ mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy, 0);
++
++ priv->old_status = 0;
++}
++
++int fec_mii_wait(struct net_device *dev)
++{
++ struct fec_priv *priv = (struct fec_priv *)dev->priv;
++
++ if (!priv->sequence_done) {
++ if (!priv->phy) {
++ printk("KERN_ERR fec_open: PHY not configured\n");
++ return -ENODEV; /* No PHY we understand */
++ }
++
++ mii_do_cmd(dev, priv->phy->config);
++ mii_do_cmd(dev, phy_cmd_config); /* display configuration */
++ while(!priv->sequence_done)
++ schedule();
++
++ mii_do_cmd(dev, priv->phy->startup);
++ }
++ return 0;
++}
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Dale Farnsworth");
++MODULE_DESCRIPTION("PHY driver for Motorola MPC52xx FEC");
+diff --git a/drivers/net/fec_mpc52xx/fec_phy.h b/drivers/net/fec_mpc52xx/fec_phy.h
+new file mode 100644
+index 0000000..5c23bff
+--- /dev/null
++++ b/drivers/net/fec_mpc52xx/fec_phy.h
+@@ -0,0 +1,73 @@
++/*
++ * arch/ppc/52xx_io/fec_phy.h
++ *
++ * Driver for the MPC5200 Fast Ethernet Controller
++ * Based heavily on the MII support for the MPC8xx by Dan Malek
++ *
++ * Author: Dale Farnsworth <dfarnsworth at mvista.com>
++ *
++ * 2003-2004 (c) MontaVista, Software, Inc. This file is licensed under
++ * the terms of the GNU General Public License version 2. This program
++ * is licensed "as is" without any warranty of any kind, whether express
++ * or implied.
++ */
++
++#ifdef CONFIG_USE_MDIO
++#define MII_ADVERTISE_HALF (ADVERTISE_100HALF | ADVERTISE_10HALF | \
++ ADVERTISE_CSMA)
++
++#define MII_ADVERTISE_ALL (ADVERTISE_100FULL | ADVERTISE_10FULL | \
++ MII_ADVERTISE_HALF)
++#ifdef PHY_INTERRUPT
++#define MII_ADVERTISE_DEFAULT MII_ADVERTISE_ALL
++#else
++#define MII_ADVERTISE_DEFAULT MII_ADVERTISE_HALF
++#endif
++
++#define MII_RCNTL_MODE FEC_RCNTRL_MII_MODE
++#define set_phy_speed(fec, s) out_be32(&fec->mii_speed, s)
++#define FEC_IMASK_ENABLE 0xf0fe0000
++
++typedef struct {
++ uint mii_data;
++ void (*funct)(uint mii_reg, struct net_device *dev, uint data);
++} phy_cmd_t;
++
++typedef struct {
++ uint id;
++ char *name;
++
++ const phy_cmd_t *config;
++ const phy_cmd_t *startup;
++ const phy_cmd_t *ack_int;
++ const phy_cmd_t *shutdown;
++} phy_info_t;
++
++#else
++#define MII_RCNTL_MODE 0
++#define set_phy_speed(fec, s)
++#define FEC_IMASK_ENABLE 0xf07e0000
++#define fec_mii_wait(dev) 0
++#define fec_mii(dev) printk(KERN_WARNING "unexpected FEC_IEVENT_MII\n")
++#define fec_mii_init(dev)
++#endif /* CONFIG_USE_MDIO */
++
++/* MII-related definitions */
++#define FEC_MII_DATA_ST 0x40000000 /* Start frame */
++#define FEC_MII_DATA_OP_RD 0x20000000 /* Perform read */
++#define FEC_MII_DATA_OP_WR 0x10000000 /* Perform write */
++#define FEC_MII_DATA_PA_MSK 0x0f800000 /* PHY Address mask */
++#define FEC_MII_DATA_RA_MSK 0x007c0000 /* PHY Register mask */
++#define FEC_MII_DATA_TA 0x00020000 /* Turnaround */
++#define FEC_MII_DATA_DATAMSK 0x00000fff /* PHY data mask */
++
++#define FEC_MII_DATA_RA_SHIFT 0x12 /* MII reg addr bits */
++#define FEC_MII_DATA_PA_SHIFT 0x17 /* MII PHY addr bits */
++
++#define FEC_MII_SPEED (5 * 2)
++
++extern void fec_mii_init(struct net_device *dev);
++extern int fec_mii_wait(struct net_device *dev);
++extern void fec_mii(struct net_device *dev);
++
++extern int fec_ioctl(struct net_device *, struct ifreq *rq, int cmd);
+--
+1.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(®s->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, §orcnt);
++ 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(®s->pio1, timing->pio1);
++ out_be32(®s->pio2, timing->pio2);
++ out_be32(®s->mdma1, timing->mdma1);
++ out_be32(®s->mdma2, timing->mdma2);
++ out_be32(®s->udma1, timing->udma1);
++ out_be32(®s->udma2, timing->udma2);
++ out_be32(®s->udma3, timing->udma3);
++ out_be32(®s->udma4, timing->udma4);
++ out_be32(®s->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(®s->dma_mode, MPC52xx_ATA_DMAMODE_FR);
++ udelay(10);
++
++ /* All sample code do this */
++ out_be32(®s->share_cnt, 0);
++
++ /* Configure & Reset host */
++ out_be32(®s->config,
++ MPC52xx_ATA_HOSTCONF_IE |
++ MPC52xx_ATA_HOSTCONF_IORDY |
++ MPC52xx_ATA_HOSTCONF_SMR |
++ MPC52xx_ATA_HOSTCONF_FR);
++ udelay(10);
++ out_be32(®s->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(®s->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, §or, §orcnt);
++
++ 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, §or, §orcnt);
++
++ 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