From 3047145cb4af0407bb02530579b371c19057e6e1 Mon Sep 17 00:00:00 2001 From: Sven Luther Date: Sat, 25 Nov 2006 16:21:50 +0000 Subject: [PATCH] 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. svn path=/dists/trunk/linux-2.6/; revision=7873 --- debian/changelog | 3 + .../powerpc-mkvmlinuz-support-powerpc.patch | 22 +- debian/patches/features/all/fs-asfs.patch | 499 +-- ...PC_MPC52xx-and-PPC_MERGE-are-selected.diff | 26 + ...SB-OHCI-glue-for-OpenFirmware-devices.diff | 360 ++ .../efika/0003-Add-MPC5200-serial-driver.diff | 719 +++ ...d-MPC5200-CPU-PIO-driver-using-libata.diff | 677 +++ .../0005-Add-MPC5200-specific-header.diff | 306 ++ ...d-MPC5200-interrupt-controller-driver.diff | 570 +++ .../0007-Add-MPC5200-ethernet-driver.diff | 1834 ++++++++ .../0008-Add-MPC5200-SDMA-PIO-driver.diff | 3973 +++++++++++++++++ ...-Added-RTAS-support-for-32bit-PowerPC.diff | 108 + .../efika/0010-Add-Efika-platform.diff | 1898 ++++++++ .../powerpc/efika/0011-Filter-out-efika.diff | 38 + .../efika/0012-Backport-of_platform.diff | 900 ++++ debian/patches/series/1~experimental.1 | 21 +- 16 files changed, 11689 insertions(+), 265 deletions(-) create mode 100644 debian/patches/features/powerpc/efika/0001-Fix-compilation-issue-when-PPC_MPC52xx-and-PPC_MERGE-are-selected.diff create mode 100644 debian/patches/features/powerpc/efika/0002-Add-USB-OHCI-glue-for-OpenFirmware-devices.diff create mode 100644 debian/patches/features/powerpc/efika/0003-Add-MPC5200-serial-driver.diff create mode 100644 debian/patches/features/powerpc/efika/0004-Add-MPC5200-CPU-PIO-driver-using-libata.diff create mode 100644 debian/patches/features/powerpc/efika/0005-Add-MPC5200-specific-header.diff create mode 100644 debian/patches/features/powerpc/efika/0006-Add-MPC5200-interrupt-controller-driver.diff create mode 100644 debian/patches/features/powerpc/efika/0007-Add-MPC5200-ethernet-driver.diff create mode 100644 debian/patches/features/powerpc/efika/0008-Add-MPC5200-SDMA-PIO-driver.diff create mode 100644 debian/patches/features/powerpc/efika/0009-Added-RTAS-support-for-32bit-PowerPC.diff create mode 100644 debian/patches/features/powerpc/efika/0010-Add-Efika-platform.diff create mode 100644 debian/patches/features/powerpc/efika/0011-Filter-out-efika.diff create mode 100644 debian/patches/features/powerpc/efika/0012-Backport-of_platform.diff diff --git a/debian/changelog b/debian/changelog index 626105c21..5f8ce6f48 100644 --- a/debian/changelog +++ b/debian/changelog @@ -8,6 +8,9 @@ linux-2.6 (2.6.19~rc6-1~experimental.1) UNRELEASED; urgency=low * arm/footbridge: Unset SATA. * arm/s3c2410: Likewise. + [ Sven Luther ] + * [powerpc] Added Genesi Efika support patch + -- Bastian Blank Sun, 19 Nov 2006 12:05:33 +0100 linux-2.6 (2.6.18-6) UNRELEASED; urgency=low diff --git a/debian/patches/debian/powerpc-mkvmlinuz-support-powerpc.patch b/debian/patches/debian/powerpc-mkvmlinuz-support-powerpc.patch index d6bb7545e..ac6de570f 100644 --- a/debian/patches/debian/powerpc-mkvmlinuz-support-powerpc.patch +++ b/debian/patches/debian/powerpc-mkvmlinuz-support-powerpc.patch @@ -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))) diff --git a/debian/patches/features/all/fs-asfs.patch b/debian/patches/features/all/fs-asfs.patch index 94a897358..557ceb23d 100644 --- a/debian/patches/features/all/fs-asfs.patch +++ b/debian/patches/features/all/fs-asfs.patch @@ -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 @@ diff -urN linux-2.6.18/Documentation/filesystems/00-INDEX linux-2.6.18-asfs-1.0b 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 @@ diff -urN linux-2.6.18/Documentation/filesystems/asfs.txt linux-2.6.18-asfs-1.0b +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 ++ ++ 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 ++ ++ 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@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 @@ diff -urN linux-2.6.18/fs/asfs/adminspace.c linux-2.6.18-asfs-1.0b11/fs/asfs/adm +} + +#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 @@ diff -urN linux-2.6.18/fs/asfs/asfs_fs.h linux-2.6.18-asfs-1.0b11/fs/asfs/asfs_f +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 @@ diff -urN linux-2.6.18/fs/asfs/bitfuncs.c linux-2.6.18-asfs-1.0b11/fs/asfs/bitfu + } + 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 @@ diff -urN linux-2.6.18/fs/asfs/bitfuncs.h linux-2.6.18-asfs-1.0b11/fs/asfs/bitfu +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@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 @@ diff -urN linux-2.6.18/fs/asfs/dir.c linux-2.6.18-asfs-1.0b11/fs/asfs/dir.c + 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 @@ diff -urN linux-2.6.18/fs/asfs/extents.c linux-2.6.18-asfs-1.0b11/fs/asfs/extent + 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 @@ diff -urN linux-2.6.18/fs/asfs/file.c linux-2.6.18-asfs-1.0b11/fs/asfs/file.c +} + +#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 @@ diff -urN linux-2.6.18/fs/asfs/inode.c linux-2.6.18-asfs-1.0b11/fs/asfs/inode.c +} +*/ +#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 @@ diff -urN linux-2.6.18/fs/asfs/namei.c linux-2.6.18-asfs-1.0b11/fs/asfs/namei.c + 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 @@ diff -urN linux-2.6.18/fs/asfs/nodes.c linux-2.6.18-asfs-1.0b11/fs/asfs/nodes.c +} + +#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 @@ diff -urN linux-2.6.18/fs/asfs/objects.c linux-2.6.18-asfs-1.0b11/fs/asfs/object + 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 @@ diff -urN linux-2.6.18/fs/asfs/super.c linux-2.6.18-asfs-1.0b11/fs/asfs/super.c + +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 @@ diff -urN linux-2.6.18/fs/asfs/symlink.c linux-2.6.18-asfs-1.0b11/fs/asfs/symlin +} + +#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 -+ -+ 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 -+ -+ 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 @@ diff -urN linux-2.6.18/include/linux/amigasfs.h linux-2.6.18-asfs-1.0b11/include +}; + +#endif - - - diff --git a/debian/patches/features/powerpc/efika/0001-Fix-compilation-issue-when-PPC_MPC52xx-and-PPC_MERGE-are-selected.diff b/debian/patches/features/powerpc/efika/0001-Fix-compilation-issue-when-PPC_MPC52xx-and-PPC_MERGE-are-selected.diff new file mode 100644 index 000000000..e8eef7dbc --- /dev/null +++ b/debian/patches/features/powerpc/efika/0001-Fix-compilation-issue-when-PPC_MPC52xx-and-PPC_MERGE-are-selected.diff @@ -0,0 +1,26 @@ +From 9f3ff0ffed7c1fc1dbf3c0628f1a22a20d0846ce Mon Sep 17 00:00:00 2001 +From: Nicolas DET +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 +--- + 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 +-#elif defined(CONFIG_PPC_MPC52xx) ++#elif defined(CONFIG_PPC_MPC52xx) && !defined(CONFIG_PPC_MERGE) + #include + #elif defined(CONFIG_8xx) + #include +-- +1.4.3.2 + diff --git a/debian/patches/features/powerpc/efika/0002-Add-USB-OHCI-glue-for-OpenFirmware-devices.diff b/debian/patches/features/powerpc/efika/0002-Add-USB-OHCI-glue-for-OpenFirmware-devices.diff new file mode 100644 index 000000000..86dd8f3e3 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0002-Add-USB-OHCI-glue-for-OpenFirmware-devices.diff @@ -0,0 +1,360 @@ +From bc515daf6d0845b0ddb739f3ba822b66f84344a7 Mon Sep 17 00:00:00 2001 +From: Nicolas DET +Date: Fri, 24 Nov 2006 12:55:37 +0100 +Subject: [PATCH] Add USB/OHCI glue for OpenFirmware devices + +Signed-off-by: Nicolas DET +--- + 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 ++ * (C) Copyright 2000-2002 David Brownell ++ * (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 from ohci-sa1111.c ++ * ++ * This file is licenced under the GPL. ++ */ ++ ++#include ++ ++#include ++#include ++#include ++ ++/* 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 + diff --git a/debian/patches/features/powerpc/efika/0003-Add-MPC5200-serial-driver.diff b/debian/patches/features/powerpc/efika/0003-Add-MPC5200-serial-driver.diff new file mode 100644 index 000000000..6779065bb --- /dev/null +++ b/debian/patches/features/powerpc/efika/0003-Add-MPC5200-serial-driver.diff @@ -0,0 +1,719 @@ +From 0ac70faf67a7e5e3f24a841ace4658336f8f98df Mon Sep 17 00:00:00 2001 +From: Nicolas DET +Date: Fri, 24 Nov 2006 13:00:06 +0100 +Subject: [PATCH] Add MPC5200 serial driver + +Signed-off-by: Nicolas DET +--- + 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 +- * ++ * + * Some of the code has been inspired/copied from the 2.4 code written + * by Dale Farnsworth . +- * ++ * + * Copyright (C) 2004-2005 Sylvain Munaut + * 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 ++#define DEBUG ++ + #include + #include + #include +@@ -53,6 +52,8 @@ #include + + #include + #include ++#include ++#include + + #include + #include +@@ -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 ; inum_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 + diff --git a/debian/patches/features/powerpc/efika/0004-Add-MPC5200-CPU-PIO-driver-using-libata.diff b/debian/patches/features/powerpc/efika/0004-Add-MPC5200-CPU-PIO-driver-using-libata.diff new file mode 100644 index 000000000..8e8ef4ef1 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0004-Add-MPC5200-CPU-PIO-driver-using-libata.diff @@ -0,0 +1,677 @@ +From bb6dea9b9a251e42efcec030af2d5272d5d5714a Mon Sep 17 00:00:00 2001 +From: Nicolas DET +Date: Fri, 24 Nov 2006 13:01:30 +0100 +Subject: [PATCH] Add MPC5200 CPU/PIO driver using libata + +Signed-off-by: Nicolas DET +--- + 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 ++ * 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 ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#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 "); ++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 ++ * 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 ++#include ++#include ++#include ++#include ++ ++ ++ ++/* 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 + diff --git a/debian/patches/features/powerpc/efika/0005-Add-MPC5200-specific-header.diff b/debian/patches/features/powerpc/efika/0005-Add-MPC5200-specific-header.diff new file mode 100644 index 000000000..692260837 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0005-Add-MPC5200-specific-header.diff @@ -0,0 +1,306 @@ +From e63b95820892f44ac7eec431900378763a83ae9d Mon Sep 17 00:00:00 2001 +From: Nicolas DET +Date: Fri, 24 Nov 2006 13:05:34 +0100 +Subject: [PATCH] Add MPC5200 specific header + +Signed-off-by: Nicolas DET +--- + 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 ++ * 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 ++#include ++#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 + diff --git a/debian/patches/features/powerpc/efika/0006-Add-MPC5200-interrupt-controller-driver.diff b/debian/patches/features/powerpc/efika/0006-Add-MPC5200-interrupt-controller-driver.diff new file mode 100644 index 000000000..113605c66 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0006-Add-MPC5200-interrupt-controller-driver.diff @@ -0,0 +1,570 @@ +From b20c97e6f809bff52b864db1352a866c66a2bbd1 Mon Sep 17 00:00:00 2001 +From: Nicolas DET +Date: Fri, 24 Nov 2006 13:06:28 +0100 +Subject: [PATCH] Add MPC5200 interrupt controller driver + +Signed-off-by: Nicolas DET +--- + 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 and Kent Borg. ++ * ++ * Copyright (C) 2004 Sylvain Munaut ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * ++*/ ++ ++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 + diff --git a/debian/patches/features/powerpc/efika/0007-Add-MPC5200-ethernet-driver.diff b/debian/patches/features/powerpc/efika/0007-Add-MPC5200-ethernet-driver.diff new file mode 100644 index 000000000..0d2818893 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0007-Add-MPC5200-ethernet-driver.diff @@ -0,0 +1,1834 @@ +From 0eae8b0fed7d8342c027e15d2a6d52eae10366e1 Mon Sep 17 00:00:00 2001 +From: Nicolas DET +Date: Fri, 24 Nov 2006 13:09:04 +0100 +Subject: [PATCH] Add MPC5200 ethernet driver + +Signed-off-by: Nicolas DET +--- + 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 ++ * ++ * 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 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_PPC_EFIKA ++#include ++#else ++#include ++#include ++#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; imc_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 ++ * ++ * 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 ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_PPC_EFIKA ++#include ++#else ++#include ++#include ++#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; iphy_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 ++ * ++ * 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 + diff --git a/debian/patches/features/powerpc/efika/0008-Add-MPC5200-SDMA-PIO-driver.diff b/debian/patches/features/powerpc/efika/0008-Add-MPC5200-SDMA-PIO-driver.diff new file mode 100644 index 000000000..e398cba38 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0008-Add-MPC5200-SDMA-PIO-driver.diff @@ -0,0 +1,3973 @@ +From e94e3e06dcf17bc739806a8a4cd8d732f7f45074 Mon Sep 17 00:00:00 2001 +From: Nicolas DET +Date: Fri, 24 Nov 2006 13:10:46 +0100 +Subject: [PATCH] Add MPC5200 SDMA/PIO driver + +Signed-off-by: Nicolas DET +--- + 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 ++# 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/**************/ ++/**************/ ++/**************/ ++//#define __DEBUG__ ++ ++/**************/ ++/**************/ ++/**************/ ++#include ++ ++#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 ++ * 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 ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* 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 ++ ++/* ++ * 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 ++#include ++#include ++ ++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 ++ ++/**************/ ++/**************/ ++/**************/ ++ ++/**************/ ++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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/**************/ ++/**************/ ++/**************/ ++#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 + diff --git a/debian/patches/features/powerpc/efika/0009-Added-RTAS-support-for-32bit-PowerPC.diff b/debian/patches/features/powerpc/efika/0009-Added-RTAS-support-for-32bit-PowerPC.diff new file mode 100644 index 000000000..137ed5f03 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0009-Added-RTAS-support-for-32bit-PowerPC.diff @@ -0,0 +1,108 @@ +From 6d3cbf9a4549928be8ed15cf6a3576c217723895 Mon Sep 17 00:00:00 2001 +From: Nicolas DET +Date: Fri, 24 Nov 2006 13:22:22 +0100 +Subject: [PATCH] Added RTAS support for 32bit PowerPC + +Signed-off-by: Nicolas DET +--- + 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 + diff --git a/debian/patches/features/powerpc/efika/0010-Add-Efika-platform.diff b/debian/patches/features/powerpc/efika/0010-Add-Efika-platform.diff new file mode 100644 index 000000000..8a51cca01 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0010-Add-Efika-platform.diff @@ -0,0 +1,1898 @@ +From 6a9d4efc825b36726e94ecfe9e642cc923cb6d78 Mon Sep 17 00:00:00 2001 +From: Nicolas DET +Date: Fri, 24 Nov 2006 13:33:48 +0100 +Subject: [PATCH] Add Efika platform + +Signed-off-by: Nicolas DET +--- + 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 ++#include ++ ++#include ++ ++/**************/ ++/**************/ ++/**************/ ++ ++#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 ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#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 ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 + diff --git a/debian/patches/features/powerpc/efika/0011-Filter-out-efika.diff b/debian/patches/features/powerpc/efika/0011-Filter-out-efika.diff new file mode 100644 index 000000000..29c1532b8 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0011-Filter-out-efika.diff @@ -0,0 +1,38 @@ +From 473274f1f615316cf5828caa47704f4d2f9ad1be Mon Sep 17 00:00:00 2001 +From: Nicolas DET +Date: Fri, 24 Nov 2006 13:34:18 +0100 +Subject: [PATCH] Filter out efika + +Signed-off-by: Nicolas DET +--- + 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 + diff --git a/debian/patches/features/powerpc/efika/0012-Backport-of_platform.diff b/debian/patches/features/powerpc/efika/0012-Backport-of_platform.diff new file mode 100644 index 000000000..4ec17e761 --- /dev/null +++ b/debian/patches/features/powerpc/efika/0012-Backport-of_platform.diff @@ -0,0 +1,900 @@ +From 2842fd40de284f328016997ba40d7b83823510c5 Mon Sep 17 00:00:00 2001 +From: Nicolas DET +Date: Fri, 24 Nov 2006 13:49:57 +0100 +Subject: [PATCH] Backport of_platform + +Signed-off-by: Nicolas DET +--- + 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 + #include + + /** +- * 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. ++ * ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#ifdef CONFIG_PPC_DCR ++#include ++#endif ++#include ++#include ++ ++ ++/* ++ * 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 + #include + #include + #include ++#include + #include + #include + #include +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 + #include + #include + #include ++#include + + #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 + #include + #include + #include +-#include ++#include + + #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 + #include + #include + #include ++#include + + #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 + #include + #include + #include ++ + #include + #include + #include + #include + #include +-#include ++#include + #include + + #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 + #include + #include + #include ++#include + + #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 + #include + #include + +-/* +- * 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. ++ * ++ * ++ * 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 ++ ++/* ++ * 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 + diff --git a/debian/patches/series/1~experimental.1 b/debian/patches/series/1~experimental.1 index 65c521003..8ce7c5457 100644 --- a/debian/patches/series/1~experimental.1 +++ b/debian/patches/series/1~experimental.1 @@ -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