diff options
author | Denys Dmytriyenko <denis@denix.org> | 2009-03-17 14:32:59 -0400 |
---|---|---|
committer | Denys Dmytriyenko <denis@denix.org> | 2009-03-17 14:32:59 -0400 |
commit | 709c4d66e0b107ca606941b988bad717c0b45d9b (patch) | |
tree | 37ee08b1eb308f3b2b6426d5793545c38396b838 /recipes/linux/opensimpad-2.4.27-vrs1-pxa1-jpm1/2.4.27-vrs1-pxa1.patch | |
parent | fa6cd5a3b993f16c27de4ff82b42684516d433ba (diff) |
rename packages/ to recipes/ per earlier agreement
See links below for more details:
http://thread.gmane.org/gmane.comp.handhelds.openembedded/21326
http://thread.gmane.org/gmane.comp.handhelds.openembedded/21816
Signed-off-by: Denys Dmytriyenko <denis@denix.org>
Acked-by: Mike Westerhof <mwester@dls.net>
Acked-by: Philip Balister <philip@balister.org>
Acked-by: Khem Raj <raj.khem@gmail.com>
Acked-by: Marcin Juszkiewicz <hrw@openembedded.org>
Acked-by: Koen Kooi <koen@openembedded.org>
Acked-by: Frans Meulenbroeks <fransmeulenbroeks@gmail.com>
Diffstat (limited to 'recipes/linux/opensimpad-2.4.27-vrs1-pxa1-jpm1/2.4.27-vrs1-pxa1.patch')
-rw-r--r-- | recipes/linux/opensimpad-2.4.27-vrs1-pxa1-jpm1/2.4.27-vrs1-pxa1.patch | 40457 |
1 files changed, 40457 insertions, 0 deletions
diff --git a/recipes/linux/opensimpad-2.4.27-vrs1-pxa1-jpm1/2.4.27-vrs1-pxa1.patch b/recipes/linux/opensimpad-2.4.27-vrs1-pxa1-jpm1/2.4.27-vrs1-pxa1.patch new file mode 100644 index 0000000000..7c1252e93c --- /dev/null +++ b/recipes/linux/opensimpad-2.4.27-vrs1-pxa1-jpm1/2.4.27-vrs1-pxa1.patch @@ -0,0 +1,40457 @@ + +# +# Patch managed by http://www.holgerschurig.de/patcher.html +# + +--- linux-2.4.27/Documentation/Configure.help~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/Documentation/Configure.help +@@ -4630,6 +4630,24 @@ + building a kernel for install/rescue disks or your system is very + limited in memory. + ++Kernel Execute-In-Place from ROM ++CONFIG_XIP_KERNEL ++ Execute-In-Place allows the kernel to run directly from ++ non-volatile storage, such as flash. This saves RAM space since ++ the text section of the kernel is not loaded from flash to ++ RAM. Read-write sections, such as the data section and stack, ++ are still copied to RAM. The XIP kernel is not compressed since it ++ has to run directly from flash, so it will take more space to store ++ it. The flash address where the kernel is linked to run from and ++ is stored is board dependent. Therefore, if you say Y, you must ++ know the proper physical address where to store the kernel image. ++ ++ Also note that the make target becomes "make xipImage" rather than ++ "make zImage" or "make Image". The final kernel binary to put in ++ ROM memory will be arch/arm/boot/xipImage. ++ ++ If unsure, say N. ++ + # Choice: kcore + Kernel core (/proc/kcore) format + CONFIG_KCORE_ELF +@@ -13609,6 +13627,30 @@ + + If you don't know what this all is, saying Y is a safe choice. + ++Workaround for XScale cache errata ++CONFIG_XSCALE_CACHE_ERRATA ++ There are couple errata that say that the cache may get confused ++ whether some cache lines are dirty or not, resulting in some memory ++ corruptions. The workaround (using the cache only in write through ++ mode) is performance impairing, and the bug _might_ just not be ++ that visible or critical to you depending on many esoteric ++ hardware factors. ++ ++ Not using the workaround makes Linux unreliable. If you're used ++ to some other OSes which requires to be rebooted once in a while ++ then this won't look so bad to you. On the other hand you may ++ stress test the system for hours without seeing any effect of this ++ bug. ++ ++ So this is configurable. Let's hope a future core revision will tell ++ this was just a bad dream. But in the mean time the risk and ++ trade-off is yours to decide. ++ ++ This should apply to all PXA250 up to rev B2 (erratum #120) and ++ possibly other current XScale cores as well. ++ ++ If you don't know what to answer, say Y. ++ + Support CD-ROM drives that are not SCSI or IDE/ATAPI + CONFIG_CD_NO_IDESCSI + If you have a CD-ROM drive that is neither SCSI nor IDE/ATAPI, say Y +@@ -16812,6 +16854,40 @@ + + If unsure, say N. + ++Use linear addressing for cramfs ++CONFIG_CRAMFS_LINEAR ++ This option tells the cramfs driver to load data directly from a linear ++ adressed memory range (usually non volatile memory like flash) instead ++ of going through the block device layer. This saves some memory since ++ no intermediate buffering is necessary. ++ ++ This is also a prerequisite for XIP of binaries stored on the filesystem. ++ ++ The location of the cramfs image in memory is board dependent. Therefore, ++ if you say Y, you must know the proper physical address where to store ++ the cramfs image and specify it using the physaddr=0x******** mount ++ option (for example: "mount -t cramfs -o physaddr=0x100000 none /mnt"). ++ ++ If unsure, say N. ++ ++Support XIP on linear cramfs ++CONFIG_CRAMFS_LINEAR_XIP ++ You must say Y to this option if you want to be able to run applications ++ directly from non-volatile memory. XIP applications are marked by ++ setting the sticky bit (ie, "chmod +t <app name>"). A cramfs file system ++ then needs to be created using mkcramfs (with XIP cramfs support ++ in it). Applications marked for XIP execution will not be compressed ++ since they have to run directly from flash. ++ ++Root file system on linear cramfs ++CONFIG_ROOT_CRAMFS_LINEAR ++ Say Y if you have enabled linear cramfs, and you want to be able to use ++ the linear cramfs image as a root file system. To actually have the ++ kernel mount this cramfs image as a root file system, you must also pass ++ the command line parameter "root=/dev/null rootflags=physaddr=0x********" ++ to the kernel (replace 0x******** with the physical address location ++ of the linear cramfs image to boot with). ++ + CMS file system support + CONFIG_CMS_FS + Read only support for CMS minidisk file systems found on IBM +--- /dev/null ++++ linux-2.4.27/Documentation/arm/XScale/PXA/USB-client +@@ -0,0 +1,38 @@ ++Date: Wed, 05 Jun 2002 13:38:53 -0700 ++From: Frank Becker <fbecker@intrinsyc.com> ++To: Nicolas Pitre <nico@cam.org> ++Subject: [PATCH] PXA-USB ++ ++Hi Nicolas, ++ ++one more patch... ++ ++This patch adds minimal USB client (UDC) support. ++ ++Some notes: ++It adds just enough to get usb-eth working. I.e. ++endpoints 0-2, no dma. Performance isn't stellar ++partially due to UDC bug workarounds... ++(~350K @ 100Mhz, ~550K @ 200Mhz). ++ ++Endpoint 1&2 have changed direction compared to ++the SA, so the host side requires a change to ++usbnet.c to flip endpoints (in:2/out:1 -> in:1/out:2). ++ ++usb-eth and usb-char for PXA are almost identical ++to the SA versions, so they could probably be merged at ++one point. I made some minor changes to the eth driver ++to grab the usb resources at open, rather than at init ++and allow eth&char to be loaded at the same time. ++ ++Stuart Lynne was working on his own USB client driver ++(and he was getting higher throughput than my driver). ++Assuming you guys have something in the oven for USB ++as well, there should be good selection for best of ++breed :) ++ ++Cheers, ++Frank. ++-- ++Frank Becker - Intrinsyc Software, Inc. - http://www.intrinsyc.com/ ++Need a break? http://criticalmass.sf.net/ +--- linux-2.4.27/Makefile~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/Makefile +@@ -1,7 +1,7 @@ + VERSION = 2 + PATCHLEVEL = 4 + SUBLEVEL = 27 +-EXTRAVERSION = -vrs1 ++EXTRAVERSION =-vrs1-pxa1 + + KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) + +@@ -167,6 +167,7 @@ + DRIVERS-$(CONFIG_SOUND) += drivers/sound/sounddrivers.o + DRIVERS-$(CONFIG_PCI) += drivers/pci/driver.o + DRIVERS-$(CONFIG_MTD) += drivers/mtd/mtdlink.o ++DRIVERS-$(CONFIG_MMC) += drivers/mmc/mmcdrivers.o + DRIVERS-$(CONFIG_PCMCIA) += drivers/pcmcia/pcmcia.o + DRIVERS-$(CONFIG_NET_PCMCIA) += drivers/net/pcmcia/pcmcia_net.o + DRIVERS-$(CONFIG_NET_WIRELESS) += drivers/net/wireless/wireless_net.o +--- linux-2.4.27/arch/arm/Makefile~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/arch/arm/Makefile +@@ -13,10 +13,11 @@ + CFLAGS +=-Uarm -fno-common -pipe + + ifeq ($(CONFIG_FRAME_POINTER),y) +-CFLAGS :=$(CFLAGS:-fomit-frame-pointer=-mapcs -mno-sched-prolog) ++CFLAGS :=$(CFLAGS:-fomit-frame-pointer=) ++CFLAGS +=-fno-omit-frame-pointer -mapcs -mno-sched-prolog + endif + +-CFLAGS :=$(CFLAGS:-O2=-Os) ++#CFLAGS :=$(CFLAGS:-O2=-Os) + + ifeq ($(CONFIG_DEBUG_INFO),y) + CFLAGS +=-g +@@ -38,6 +39,8 @@ + arch-$(CONFIG_CPU_32v3) :=-D__LINUX_ARM_ARCH__=3 -march=armv3 + arch-$(CONFIG_CPU_32v4) :=-D__LINUX_ARM_ARCH__=4 -march=armv4 + arch-$(CONFIG_CPU_32v5) :=-D__LINUX_ARM_ARCH__=5 -march=armv5 ++#arch-$(CONFIG_CPU_XSCALE) :=-D__LINUX_ARM_ARCH__=5 -mcpu=xscale ++arch-$(CONFIG_CPU_XSCALE) :=-D__LINUX_ARM_ARCH__=5 -march=armv4 -Wa,-mxscale + + # This selects how we optimise for the processor. + tune-y := +@@ -49,6 +52,8 @@ + tune-$(CONFIG_CPU_ARM926T) :=-mtune=arm9tdmi + tune-$(CONFIG_CPU_SA110) :=-mtune=strongarm110 + tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100 ++#tune-$(CONFIG_CPU_XSCALE) :=-mtune=xscale ++tune-$(CONFIG_CPU_XSCALE) :=-mtune=strongarm + + CFLAGS_BOOT :=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Uarm + CFLAGS +=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Uarm +@@ -127,6 +132,10 @@ + MACHINE = sa1100 + endif + ++ifeq ($(CONFIG_ARCH_PXA),y) ++MACHINE = pxa ++endif ++ + ifeq ($(CONFIG_ARCH_L7200),y) + MACHINE = l7200 + endif +@@ -164,6 +173,17 @@ + MACHINE = omaha + endif + ++ifeq ($(CONFIG_XIP_KERNEL),y) ++ DATAADDR := $(TEXTADDR) ++ # Replace phys addr with virt addr while keeping offset from base. ++ # Virt base addr also defined in include/asm-arm/arch-*/hardware.h ++ TEXTADDR = $(shell echo 0x`echo $(CONFIG_XIP_PHYS_ADDR)|sed -e's/^0x//'` |\ ++ awk --non-decimal-data '/[:xdigit:]/ \ ++ {printf("0x%x\n",and($$0,0x001fffff)+0xe8000000)}' ) ++ LDSCRIPT = arch/arm/vmlinux-armv-xip.lds.in ++ export DATAADDR ++endif ++ + export MACHINE PROCESSOR TEXTADDR GZFLAGS CFLAGS_BOOT OBJCOPYFLAGS + + # Only set INCDIR if its not already defined above +@@ -269,7 +289,7 @@ + arch/arm/kernel arch/arm/mm arch/arm/lib: dummy + $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@) + +-bzImage zImage zinstall Image bootpImage install: vmlinux ++bzImage zImage zinstall Image xipImage bootpImage install: vmlinux + @$(MAKEBOOT) $@ + + CLEAN_FILES += \ +--- linux-2.4.27/arch/arm/boot/Makefile~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/arch/arm/boot/Makefile +@@ -113,6 +113,10 @@ + endif + endif + ++ifeq ($(CONFIG_ARCH_PXA),y) ++ZRELADDR = 0xa0008000 ++endif ++ + ifeq ($(CONFIG_ARCH_ANAKIN),y) + ZRELADDR = 0x20008000 + endif +@@ -140,6 +144,14 @@ + zImage: compressed/vmlinux + $(OBJCOPY) $(OBJCOPYFLAGS) $< $@ + ++ifeq ($(CONFIG_XIP_KERNEL),y) ++xipImage: $(CONFIGURE) $(SYSTEM) ++ $(OBJCOPY) -S -O binary -R .data $(SYSTEM) vmlinux-text.bin ++ $(OBJCOPY) -S -O binary -R .init -R .text -R __ex_table -R __ksymtab $(SYSTEM) vmlinux-data.bin ++ cat vmlinux-text.bin vmlinux-data.bin > $@ ++ $(RM) -f vmlinux-text.bin vmlinux-data.bin ++endif ++ + bootpImage: bootp/bootp + $(OBJCOPY) $(OBJCOPYFLAGS) $< $@ + +@@ -160,7 +172,7 @@ + sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)" + + clean: +- $(RM) Image zImage bootpImage ++ $(RM) Image xipImage zImage bootpImage + @$(MAKE) -C compressed clean + @$(MAKE) -C bootp clean + +--- linux-2.4.27/arch/arm/boot/compressed/Makefile~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/arch/arm/boot/compressed/Makefile +@@ -71,6 +71,10 @@ + OBJS += head-sa1100.o + endif + ++ifeq ($(CONFIG_CPU_XSCALE),y) ++OBJS += head-xscale.o ++endif ++ + SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/LOAD_ADDR/$(ZRELADDR)/;s/BSS_START/$(ZBSSADDR)/ + + LIBGCC := $(shell $(CC) $(CFLAGS) --print-libgcc-file-name) +--- /dev/null ++++ linux-2.4.27/arch/arm/boot/compressed/head-xscale.S +@@ -0,0 +1,50 @@ ++/* ++ * linux/arch/arm/boot/compressed/head-xscale.S ++ * ++ * XScale specific tweaks. This is merged into head.S by the linker. ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/linkage.h> ++#include <asm/mach-types.h> ++ ++ .section ".start", #alloc, #execinstr ++ ++__XScale_start: ++ ++ @ Preserve r8/r7 i.e. kernel entry values ++ ++ @ Data cache might be active. ++ @ Be sure to flush kernel binary out of the cache, ++ @ whatever state it is, before it is turned off. ++ @ This is done by fetching through currently executed ++ @ memory to be sure we hit the same cache. ++ bic r2, pc, #0x1f ++ add r3, r2, #0x10000 @ 64 kb is quite enough... ++1: ldr r0, [r2], #32 ++ teq r2, r3 ++ bne 1b ++ mcr p15, 0, r0, c7, c10, 4 @ drain WB ++ mcr p15, 0, r0, c7, c7, 0 @ flush I & D caches ++ ++ @ disabling MMU and caches ++ mrc p15, 0, r0, c1, c0, 0 @ read control reg ++ bic r0, r0, #0x05 @ clear DC, MMU ++ bic r0, r0, #0x1000 @ clear Icache ++ mcr p15, 0, r0, c1, c0, 0 ++ ++#ifdef CONFIG_ARCH_LUBBOCK ++ mov r7, #MACH_TYPE_LUBBOCK ++#endif ++ ++#ifdef CONFIG_ARCH_PXA_IDP ++ mov r7, #MACH_TYPE_PXA_IDP ++#endif ++ ++#ifdef CONFIG_ARCH_TRIZEPS2 ++ mov r7, #(MACH_TYPE_TRIZEPS2 & 0xFF00) ++ add r7, r7, #(MACH_TYPE_TRIZEPS2 & 0xFF) ++#endif ++ ++ +--- linux-2.4.27/arch/arm/boot/compressed/head.S~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/arch/arm/boot/compressed/head.S +@@ -351,7 +351,11 @@ + orr r1, r1, #3 << 10 + add r2, r3, #16384 + 1: cmp r1, r8 @ if virt > start of RAM ++#ifdef CONFIG_XSCALE_CACHE_ERRATA ++ orrhs r1, r1, #0x08 @ set cacheable, not bufferable ++#else + orrhs r1, r1, #0x0c @ set cacheable, bufferable ++#endif + cmp r1, r9 @ if virt > end of RAM + bichs r1, r1, #0x0c @ clear cacheable, bufferable + str r1, [r0], #4 @ 1:1 mapping +@@ -364,7 +368,11 @@ + * so there is no map overlap problem for up to 1 MB compressed kernel. + * If the execution is in RAM then we would only be duplicating the above. + */ ++#ifdef CONFIG_XSCALE_CACHE_ERRATA ++ mov r1, #0x1a ++#else + mov r1, #0x1e ++#endif + orr r1, r1, #3 << 10 + mov r2, pc, lsr #20 + orr r1, r1, r2, lsl #20 +--- linux-2.4.27/arch/arm/config.in~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/arch/arm/config.in +@@ -38,6 +38,7 @@ + Cirrus-CL-PS7500FE CONFIG_ARCH_CLPS7500 \ + CLPS711x/EP721x-based CONFIG_ARCH_CLPS711X \ + Co-EBSA285 CONFIG_ARCH_CO285 \ ++ PXA250/210-based CONFIG_ARCH_PXA \ + EBSA-110 CONFIG_ARCH_EBSA110 \ + Excalibur-ARM CONFIG_ARCH_CAMELOT \ + FootBridge CONFIG_ARCH_FOOTBRIDGE \ +@@ -148,6 +149,47 @@ + endmenu + + mainmenu_option next_comment ++comment 'Intel PXA250/210 Implementations' ++dep_bool ' Intel DBPXA250 Development Platform' CONFIG_ARCH_LUBBOCK $CONFIG_ARCH_PXA ++dep_bool ' Accelent Xscale IDP' CONFIG_ARCH_PXA_IDP $CONFIG_ARCH_PXA ++dep_bool ' Intrinsyc CerfBoard' CONFIG_ARCH_PXA_CERF $CONFIG_ARCH_PXA ++dep_bool ' Trizeps-II MT6N' CONFIG_ARCH_TRIZEPS2 $CONFIG_ARCH_PXA ++ ++if [ "$CONFIG_ARCH_PXA_CERF" = "y" ]; then ++ define_bool CONFIG_PXA_CERF y ++ ++ choice 'CerfBoard Style' \ ++ "PDA CONFIG_PXA_CERF_PDA \ ++ BOARD CONFIG_PXA_CERF_BOARD" PDA ++ ++ choice 'CerfBoard RAM Available' \ ++ "128MB CONFIG_PXA_CERF_RAM_128MB \ ++ 64MB CONFIG_PXA_CERF_RAM_64MB \ ++ 32MB CONFIG_PXA_CERF_RAM_32MB \ ++ 16MB CONFIG_PXA_CERF_RAM_16MB" 64MB ++ ++ choice 'CerfBoard Flash Available' \ ++ "64MB CONFIG_PXA_CERF_FLASH_64MB \ ++ 32MB CONFIG_PXA_CERF_FLASH_32MB \ ++ 16MB CONFIG_PXA_CERF_FLASH_16MB \ ++ 8MB CONFIG_PXA_CERF_FLASH_8MB" 32MB ++fi ++ ++if [ "$CONFIG_ARCH_LUBBOCK" = "y" ]; then ++ define_bool CONFIG_SA1111 y ++fi ++ ++if [ "$CONFIG_ARCH_TRIZEPS2" = "y" ]; then ++ define_bool CONFIG_TRIZEPS2 y ++fi ++ ++dep_tristate 'PXA USB function support' CONFIG_PXA_USB $CONFIG_ARCH_PXA ++dep_tristate ' Support for PXA USB network link function' CONFIG_PXA_USB_NETLINK $CONFIG_PXA_USB ++dep_tristate ' Support for PXA USB character device emulation' CONFIG_PXA_USB_CHAR $CONFIG_PXA_USB ++ ++endmenu ++ ++mainmenu_option next_comment + comment 'CLPS711X/EP721X Implementations' + dep_bool ' AUTCPU12' CONFIG_ARCH_AUTCPU12 $CONFIG_ARCH_CLPS711X + dep_bool ' CDB89712' CONFIG_ARCH_CDB89712 $CONFIG_ARCH_CLPS711X +@@ -385,6 +427,12 @@ + define_bool CONFIG_CPU_SA1100 n + fi + ++if [ "$CONFIG_ARCH_PXA" = "y" ]; then ++ define_bool CONFIG_CPU_32v5 y ++ define_bool CONFIG_CPU_XSCALE y ++ bool 'Workaround for XScale cache errata (see help)' CONFIG_XSCALE_CACHE_ERRATA ++fi ++ + # Figure out what processor architecture version we should be using. + # This defines the compiler instruction set which depends on the machine type. + +@@ -493,6 +541,7 @@ + hex 'Compressed ROM boot loader BSS address' CONFIG_ZBOOT_ROM_BSS 0 + + if [ "$CONFIG_ARCH_SA1100" = "y" -o \ ++ "$CONFIG_ARCH_PXA" = "y" -o \ + "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then + dep_bool 'Support CPU clock change (EXPERIMENTAL)' CONFIG_CPU_FREQ $CONFIG_EXPERIMENTAL + fi +@@ -501,8 +550,10 @@ + bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG + if [ "$CONFIG_HOTPLUG" = "y" ]; then + source drivers/pcmcia/Config.in ++ source drivers/mmc/Config.in + else + define_bool CONFIG_PCMCIA n ++ define_bool CONFIG_MMC n + fi + if [ "$CONFIG_SA1100_ACCELENT" = "y" ]; then + if [ "$CONFIG_PCMCIA" != "n" ]; then +@@ -513,6 +564,14 @@ + bool 'System V IPC' CONFIG_SYSVIPC + bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT + bool 'Sysctl support' CONFIG_SYSCTL ++ ++if [ "$CONFIG_ARCH_PXA" = "y" ]; then ++ dep_bool 'Kernel Execute-In-Place from ROM (EXPERIMENTAL)' CONFIG_XIP_KERNEL $CONFIG_EXPERIMENTAL ++ if [ "$CONFIG_XIP_KERNEL" = "y" ]; then ++ hex ' Kernel .text physical address' CONFIG_XIP_PHYS_ADDR 0 ++ fi ++fi ++ + comment 'At least one math emulation must be selected' + tristate 'NWFPE math emulation' CONFIG_FPE_NWFPE + if [ "$CONFIG_FPE_NWFPE" != "n" ]; then +@@ -538,6 +597,9 @@ + "$CONFIG_ARCH_SHARK" = "y" -o \ + "$CONFIG_ARCH_CO285" = "y" -o \ + "$CONFIG_ARCH_SA1100" = "y" -o \ ++ "$CONFIG_ARCH_LUBBOCK" = "y" -o \ ++ "$CONFIG_ARCH_PXA_IDP" = "y" -o \ ++ "$CONFIG_ARCH_PXA_CERF" = "y" -o \ + "$CONFIG_ARCH_INTEGRATOR" = "y" -o \ + "$CONFIG_ARCH_CDB89712" = "y" -o \ + "$CONFIG_ARCH_P720T" = "y" -o \ +@@ -550,9 +612,12 @@ + "$CONFIG_ARCH_SHARK" = "y" -o \ + "$CONFIG_ARCH_CO285" = "y" -o \ + "$CONFIG_ARCH_SA1100" = "y" -o \ ++ "$CONFIG_ARCH_LUBBOCK" = "y" -o \ + "$CONFIG_ARCH_INTEGRATOR" = "y" -o \ + "$CONFIG_ARCH_P720T" = "y" -o \ + "$CONFIG_ARCH_OMAHA" = "y" -o \ ++ "$CONFIG_ARCH_PXA_CERF" = "y" -o \ ++ "$CONFIG_ARCH_PXA_IDP" = "y" -o \ + "$CONFIG_ARCH_AT91RM9200" = "y" ]; then + bool ' Timer LED' CONFIG_LEDS_TIMER + bool ' CPU usage LED' CONFIG_LEDS_CPU +@@ -686,6 +751,7 @@ + if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \ + "$CONFIG_ARCH_SHARK" = "y" -o \ + "$CONFIG_ARCH_SA1100" = "y" -o \ ++ "$CONFIG_ARCH_PXA" = "y" -o \ + "$CONFIG_ARCH_INTEGRATOR" = "y" -o \ + "$CONFIG_ARCH_TBOX" = "y" -o \ + "$CONFIG_ARCH_CLPS7500" = "y" -o \ +@@ -707,6 +773,7 @@ + "$CONFIG_ARCH_TBOX" = "y" -o \ + "$CONFIG_ARCH_SHARK" = "y" -o \ + "$CONFIG_ARCH_SA1100" = "y" -o \ ++ "$CONFIG_ARCH_PXA" = "y" -o \ + "$CONFIG_PCI" = "y" ]; then + mainmenu_option next_comment + comment 'Sound' +--- /dev/null ++++ linux-2.4.27/arch/arm/def-configs/cerfboard_pxa +@@ -0,0 +1,857 @@ ++# ++# Automatically generated by make menuconfig: don't edit ++# ++CONFIG_ARM=y ++# CONFIG_EISA is not set ++# CONFIG_SBUS is not set ++# CONFIG_MCA is not set ++CONFIG_UID16=y ++CONFIG_RWSEM_GENERIC_SPINLOCK=y ++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set ++# CONFIG_GENERIC_BUST_SPINLOCK is not set ++# CONFIG_GENERIC_ISA_DMA is not set ++ ++# ++# Code maturity level options ++# ++CONFIG_EXPERIMENTAL=y ++# CONFIG_OBSOLETE is not set ++ ++# ++# Loadable module support ++# ++CONFIG_MODULES=y ++# CONFIG_MODVERSIONS is not set ++CONFIG_KMOD=y ++ ++# ++# System Type ++# ++# CONFIG_ARCH_ANAKIN is not set ++# CONFIG_ARCH_ARCA5K is not set ++# CONFIG_ARCH_CLPS7500 is not set ++# CONFIG_ARCH_CLPS711X is not set ++# CONFIG_ARCH_CO285 is not set ++CONFIG_ARCH_PXA=y ++# CONFIG_ARCH_EBSA110 is not set ++# CONFIG_ARCH_CAMELOT is not set ++# CONFIG_ARCH_FOOTBRIDGE is not set ++# CONFIG_ARCH_INTEGRATOR is not set ++# CONFIG_ARCH_OMAHA is not set ++# CONFIG_ARCH_L7200 is not set ++# CONFIG_ARCH_MX1ADS is not set ++# CONFIG_ARCH_RPC is not set ++# CONFIG_ARCH_RISCSTATION is not set ++# CONFIG_ARCH_SA1100 is not set ++# CONFIG_ARCH_SHARK is not set ++ ++# ++# Archimedes/A5000 Implementations ++# ++# CONFIG_ARCH_ARC is not set ++# CONFIG_ARCH_A5K is not set ++ ++# ++# Footbridge Implementations ++# ++# CONFIG_ARCH_CATS is not set ++# CONFIG_ARCH_PERSONAL_SERVER is not set ++# CONFIG_ARCH_EBSA285_ADDIN is not set ++# CONFIG_ARCH_EBSA285_HOST is not set ++# CONFIG_ARCH_NETWINDER is not set ++ ++# ++# SA11x0 Implementations ++# ++# CONFIG_SA1100_ACCELENT is not set ++# CONFIG_SA1100_ASSABET is not set ++# CONFIG_ASSABET_NEPONSET is not set ++# CONFIG_SA1100_ADSBITSY is not set ++# CONFIG_SA1100_BRUTUS is not set ++# CONFIG_SA1100_CEP is not set ++# CONFIG_SA1100_CERF is not set ++# CONFIG_SA1100_H3100 is not set ++# CONFIG_SA1100_H3600 is not set ++# CONFIG_SA1100_H3800 is not set ++# CONFIG_SA1100_H3XXX is not set ++# CONFIG_SA1100_EXTENEX1 is not set ++# CONFIG_SA1100_FLEXANET is not set ++# CONFIG_SA1100_FREEBIRD is not set ++# CONFIG_SA1100_FRODO is not set ++# CONFIG_SA1100_GRAPHICSCLIENT is not set ++# CONFIG_SA1100_GRAPHICSMASTER is not set ++# CONFIG_SA1100_BADGE4 is not set ++# CONFIG_SA1100_JORNADA720 is not set ++# CONFIG_SA1100_HUW_WEBPANEL is not set ++# CONFIG_SA1100_ITSY is not set ++# CONFIG_SA1100_LART is not set ++# CONFIG_SA1100_NANOENGINE is not set ++# CONFIG_SA1100_OMNIMETER is not set ++# CONFIG_SA1100_PANGOLIN is not set ++# CONFIG_SA1100_PLEB is not set ++# CONFIG_SA1100_PT_SYSTEM3 is not set ++# CONFIG_SA1100_SHANNON is not set ++# CONFIG_SA1100_SHERMAN is not set ++# CONFIG_SA1100_SIMPAD is not set ++# CONFIG_SA1100_SIMPUTER is not set ++# CONFIG_SA1100_PFS168 is not set ++# CONFIG_SA1100_VICTOR is not set ++# CONFIG_SA1100_XP860 is not set ++# CONFIG_SA1100_YOPY is not set ++# CONFIG_SA1100_USB is not set ++# CONFIG_SA1100_USB_NETLINK is not set ++# CONFIG_SA1100_USB_CHAR is not set ++# CONFIG_H3600_SLEEVE is not set ++ ++# ++# Intel PXA250/210 Implementations ++# ++# CONFIG_ARCH_LUBBOCK is not set ++# CONFIG_ARCH_PXA_IDP is not set ++CONFIG_ARCH_PXA_CERF=y ++CONFIG_PXA_CERF=y ++# CONFIG_PXA_CERF_PDA is not set ++CONFIG_PXA_CERF_BOARD=y ++# CONFIG_PXA_CERF_RAM_128MB is not set ++CONFIG_PXA_CERF_RAM_64MB=y ++# CONFIG_PXA_CERF_RAM_32MB is not set ++# CONFIG_PXA_CERF_RAM_16MB is not set ++# CONFIG_PXA_CERF_FLASH_64MB is not set ++CONFIG_PXA_CERF_FLASH_32MB=y ++# CONFIG_PXA_CERF_FLASH_16MB is not set ++# CONFIG_PXA_CERF_FLASH_8MB is not set ++CONFIG_PXA_USB=y ++CONFIG_PXA_USB_NETLINK=y ++CONFIG_PXA_USB_CHAR=m ++ ++# ++# CLPS711X/EP721X Implementations ++# ++# CONFIG_ARCH_AUTCPU12 is not set ++# CONFIG_ARCH_CDB89712 is not set ++# CONFIG_ARCH_CLEP7312 is not set ++# CONFIG_ARCH_EDB7211 is not set ++# CONFIG_ARCH_P720T is not set ++# CONFIG_ARCH_FORTUNET is not set ++# CONFIG_ARCH_EP7211 is not set ++# CONFIG_ARCH_EP7212 is not set ++# CONFIG_ARCH_ACORN is not set ++# CONFIG_FOOTBRIDGE is not set ++# CONFIG_FOOTBRIDGE_HOST is not set ++# CONFIG_FOOTBRIDGE_ADDIN is not set ++CONFIG_CPU_32=y ++# CONFIG_CPU_26 is not set ++# CONFIG_CPU_ARM610 is not set ++# CONFIG_CPU_ARM710 is not set ++# CONFIG_CPU_ARM720T is not set ++# CONFIG_CPU_ARM920T is not set ++# CONFIG_CPU_ARM922T is not set ++# CONFIG_PLD is not set ++# CONFIG_CPU_ARM926T is not set ++# CONFIG_CPU_ARM1020 is not set ++# CONFIG_CPU_ARM1026 is not set ++# CONFIG_CPU_SA110 is not set ++# CONFIG_CPU_SA1100 is not set ++CONFIG_CPU_32v5=y ++CONFIG_CPU_XSCALE=y ++CONFIG_XSCALE_CACHE_ERRATA=y ++# CONFIG_CPU_32v3 is not set ++# CONFIG_CPU_32v4 is not set ++# CONFIG_DISCONTIGMEM is not set ++ ++# ++# General setup ++# ++# CONFIG_PCI is not set ++# CONFIG_ISA is not set ++# CONFIG_ISA_DMA is not set ++# CONFIG_ZBOOT_ROM is not set ++CONFIG_ZBOOT_ROM_TEXT=0 ++CONFIG_ZBOOT_ROM_BSS=0 ++CONFIG_CPU_FREQ=y ++CONFIG_HOTPLUG=y ++ ++# ++# PCMCIA/CardBus support ++# ++CONFIG_PCMCIA=y ++# CONFIG_I82092 is not set ++# CONFIG_I82365 is not set ++# CONFIG_TCIC is not set ++# CONFIG_PCMCIA_CLPS6700 is not set ++# CONFIG_PCMCIA_SA1100 is not set ++CONFIG_PCMCIA_PXA=y ++CONFIG_NET=y ++CONFIG_SYSVIPC=y ++CONFIG_BSD_PROCESS_ACCT=y ++CONFIG_SYSCTL=y ++CONFIG_FPE_NWFPE=y ++# CONFIG_FPE_FASTFPE is not set ++CONFIG_KCORE_ELF=y ++# CONFIG_KCORE_AOUT is not set ++# CONFIG_BINFMT_AOUT is not set ++CONFIG_BINFMT_ELF=y ++# CONFIG_BINFMT_MISC is not set ++# CONFIG_PM is not set ++# CONFIG_ARTHUR is not set ++CONFIG_CMDLINE="root=1f03 rw console=tty0 console=ttyS0,38400 init=/linuxrc" ++CONFIG_LEDS=y ++# CONFIG_LEDS_TIMER is not set ++CONFIG_LEDS_CPU=y ++CONFIG_ALIGNMENT_TRAP=y ++ ++# ++# Parallel port support ++# ++# CONFIG_PARPORT is not set ++ ++# ++# Memory Technology Devices (MTD) ++# ++CONFIG_MTD=y ++# CONFIG_MTD_DEBUG is not set ++CONFIG_MTD_PARTITIONS=y ++# CONFIG_MTD_CONCAT is not set ++CONFIG_MTD_REDBOOT_PARTS=y ++# CONFIG_MTD_CMDLINE_PARTS is not set ++# CONFIG_MTD_AFS_PARTS is not set ++CONFIG_MTD_CHAR=y ++CONFIG_MTD_BLOCK=y ++# CONFIG_FTL is not set ++# CONFIG_NFTL is not set ++ ++# ++# RAM/ROM/Flash chip drivers ++# ++CONFIG_MTD_CFI=y ++# CONFIG_MTD_JEDECPROBE is not set ++CONFIG_MTD_GEN_PROBE=y ++CONFIG_MTD_CFI_ADV_OPTIONS=y ++CONFIG_MTD_CFI_NOSWAP=y ++# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set ++# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set ++CONFIG_MTD_CFI_GEOMETRY=y ++# CONFIG_MTD_CFI_B1 is not set ++# CONFIG_MTD_CFI_B2 is not set ++CONFIG_MTD_CFI_B4=y ++# CONFIG_MTD_CFI_B8 is not set ++# CONFIG_MTD_CFI_I1 is not set ++CONFIG_MTD_CFI_I2=y ++# CONFIG_MTD_CFI_I4 is not set ++# CONFIG_MTD_CFI_I8 is not set ++CONFIG_MTD_CFI_INTELEXT=y ++# CONFIG_MTD_CFI_AMDSTD is not set ++# CONFIG_MTD_RAM is not set ++# CONFIG_MTD_ROM is not set ++# CONFIG_MTD_ABSENT is not set ++# CONFIG_MTD_OBSOLETE_CHIPS is not set ++# CONFIG_MTD_AMDSTD is not set ++# CONFIG_MTD_SHARP is not set ++# CONFIG_MTD_JEDEC is not set ++ ++# ++# Mapping drivers for chip access ++# ++# CONFIG_MTD_PHYSMAP is not set ++# CONFIG_MTD_LUBBOCK is not set ++# CONFIG_MTD_NORA is not set ++# CONFIG_MTD_ARM_INTEGRATOR is not set ++# CONFIG_MTD_CDB89712 is not set ++# CONFIG_MTD_SA1100 is not set ++# CONFIG_MTD_DC21285 is not set ++# CONFIG_MTD_IQ80310 is not set ++# CONFIG_MTD_FORTUNET is not set ++CONFIG_MTD_PXA_CERF=y ++# CONFIG_MTD_EPXA10DB is not set ++# CONFIG_MTD_AUTCPU12 is not set ++# CONFIG_MTD_EDB7312 is not set ++# CONFIG_MTD_IMPA7 is not set ++# CONFIG_MTD_PCI is not set ++ ++# ++# Self-contained MTD device drivers ++# ++# CONFIG_MTD_PMC551 is not set ++# CONFIG_MTD_SLRAM is not set ++# CONFIG_MTD_MTDRAM is not set ++# CONFIG_MTD_BLKMTD is not set ++# CONFIG_MTD_DOC1000 is not set ++# CONFIG_MTD_DOC2000 is not set ++# CONFIG_MTD_DOC2001 is not set ++# CONFIG_MTD_DOCPROBE is not set ++ ++# ++# NAND Flash Device Drivers ++# ++# CONFIG_MTD_NAND is not set ++ ++# ++# Plug and Play configuration ++# ++# CONFIG_PNP is not set ++# CONFIG_ISAPNP is not set ++ ++# ++# Block devices ++# ++# CONFIG_BLK_DEV_FD is not set ++# CONFIG_BLK_DEV_XD is not set ++# CONFIG_PARIDE is not set ++# CONFIG_BLK_CPQ_DA is not set ++# CONFIG_BLK_CPQ_CISS_DA is not set ++# CONFIG_CISS_SCSI_TAPE is not set ++# CONFIG_BLK_DEV_DAC960 is not set ++# CONFIG_BLK_DEV_UMEM is not set ++CONFIG_BLK_DEV_LOOP=m ++# CONFIG_BLK_DEV_NBD is not set ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_SIZE=4096 ++CONFIG_BLK_DEV_INITRD=y ++ ++# ++# Multi-device support (RAID and LVM) ++# ++# CONFIG_MD is not set ++# CONFIG_BLK_DEV_MD is not set ++# CONFIG_MD_LINEAR is not set ++# CONFIG_MD_RAID0 is not set ++# CONFIG_MD_RAID1 is not set ++# CONFIG_MD_RAID5 is not set ++# CONFIG_MD_MULTIPATH is not set ++# CONFIG_BLK_DEV_LVM is not set ++ ++# ++# Networking options ++# ++CONFIG_PACKET=y ++# CONFIG_PACKET_MMAP is not set ++# CONFIG_NETLINK_DEV is not set ++# CONFIG_NETFILTER is not set ++CONFIG_FILTER=y ++CONFIG_UNIX=y ++CONFIG_INET=y ++# CONFIG_IP_MULTICAST is not set ++# CONFIG_IP_ADVANCED_ROUTER is not set ++CONFIG_IP_PNP=y ++CONFIG_IP_PNP_DHCP=y ++CONFIG_IP_PNP_BOOTP=y ++CONFIG_IP_PNP_RARP=y ++# CONFIG_NET_IPIP is not set ++# CONFIG_NET_IPGRE is not set ++# CONFIG_ARPD is not set ++# CONFIG_INET_ECN is not set ++# CONFIG_SYN_COOKIES is not set ++# CONFIG_IPV6 is not set ++# CONFIG_KHTTPD is not set ++# CONFIG_ATM is not set ++# CONFIG_VLAN_8021Q is not set ++# CONFIG_IPX is not set ++# CONFIG_ATALK is not set ++ ++# ++# Appletalk devices ++# ++# CONFIG_DEV_APPLETALK is not set ++# CONFIG_DECNET is not set ++# CONFIG_BRIDGE is not set ++# CONFIG_X25 is not set ++# CONFIG_LAPB is not set ++# CONFIG_LLC is not set ++# CONFIG_NET_DIVERT is not set ++# CONFIG_ECONET is not set ++# CONFIG_WAN_ROUTER is not set ++# CONFIG_NET_FASTROUTE is not set ++# CONFIG_NET_HW_FLOWCONTROL is not set ++ ++# ++# QoS and/or fair queueing ++# ++# CONFIG_NET_SCHED is not set ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++ ++# ++# Network device support ++# ++CONFIG_NETDEVICES=y ++ ++# ++# ARCnet devices ++# ++# CONFIG_ARCNET is not set ++# CONFIG_DUMMY is not set ++# CONFIG_BONDING is not set ++# CONFIG_EQUALIZER is not set ++# CONFIG_TUN is not set ++# CONFIG_ETHERTAP is not set ++ ++# ++# Ethernet (10 or 100Mbit) ++# ++CONFIG_NET_ETHERNET=y ++# CONFIG_ARM_AM79C961A is not set ++# CONFIG_ARM_CIRRUS is not set ++# CONFIG_SUNLANCE is not set ++# CONFIG_SUNBMAC is not set ++# CONFIG_SUNQE is not set ++# CONFIG_SUNGEM is not set ++# CONFIG_NET_VENDOR_3COM is not set ++# CONFIG_LANCE is not set ++CONFIG_NET_VENDOR_SMC=y ++# CONFIG_WD80x3 is not set ++# CONFIG_ULTRAMCA is not set ++# CONFIG_ULTRA is not set ++# CONFIG_ULTRA32 is not set ++# CONFIG_SMC9194 is not set ++# CONFIG_NET_VENDOR_RACAL is not set ++# CONFIG_NET_ISA is not set ++# CONFIG_NET_PCI is not set ++# CONFIG_NET_POCKET is not set ++ ++# ++# Ethernet (1000 Mbit) ++# ++# CONFIG_ACENIC is not set ++# CONFIG_DL2K is not set ++# CONFIG_MYRI_SBUS is not set ++# CONFIG_NS83820 is not set ++# CONFIG_HAMACHI is not set ++# CONFIG_YELLOWFIN is not set ++# CONFIG_SK98LIN is not set ++# CONFIG_TIGON3 is not set ++# CONFIG_FDDI is not set ++# CONFIG_HIPPI is not set ++# CONFIG_PLIP is not set ++CONFIG_PPP=m ++# CONFIG_PPP_MULTILINK is not set ++# CONFIG_PPP_FILTER is not set ++CONFIG_PPP_ASYNC=m ++# CONFIG_PPP_SYNC_TTY is not set ++CONFIG_PPP_DEFLATE=m ++CONFIG_PPP_BSDCOMP=m ++# CONFIG_PPPOE is not set ++# CONFIG_SLIP is not set ++ ++# ++# Wireless LAN (non-hamradio) ++# ++# CONFIG_NET_RADIO is not set ++ ++# ++# Token Ring devices ++# ++# CONFIG_TR is not set ++# CONFIG_NET_FC is not set ++# CONFIG_RCPCI is not set ++# CONFIG_SHAPER is not set ++ ++# ++# Wan interfaces ++# ++# CONFIG_WAN is not set ++ ++# ++# PCMCIA network device support ++# ++CONFIG_NET_PCMCIA=y ++CONFIG_PCMCIA_3C589=m ++CONFIG_PCMCIA_3C574=m ++CONFIG_PCMCIA_FMVJ18X=m ++CONFIG_PCMCIA_PCNET=m ++CONFIG_PCMCIA_AXNET=m ++CONFIG_PCMCIA_NMCLAN=m ++CONFIG_PCMCIA_SMC91C92=m ++CONFIG_PCMCIA_XIRC2PS=m ++# CONFIG_ARCNET_COM20020_CS is not set ++# CONFIG_PCMCIA_IBMTR is not set ++CONFIG_NET_PCMCIA_RADIO=y ++CONFIG_PCMCIA_RAYCS=m ++CONFIG_PCMCIA_NETWAVE=m ++CONFIG_PCMCIA_WAVELAN=m ++CONFIG_AIRONET4500_CS=m ++ ++# ++# Amateur Radio support ++# ++# CONFIG_HAMRADIO is not set ++ ++# ++# IrDA (infrared) support ++# ++# CONFIG_IRDA is not set ++ ++# ++# ATA/ATAPI/MFM/RLL support ++# ++CONFIG_IDE=y ++ ++# ++# IDE, ATA and ATAPI Block devices ++# ++CONFIG_BLK_DEV_IDE=y ++# CONFIG_BLK_DEV_HD_IDE is not set ++# CONFIG_BLK_DEV_HD is not set ++CONFIG_BLK_DEV_IDEDISK=y ++# CONFIG_IDEDISK_MULTI_MODE is not set ++# CONFIG_IDEDISK_STROKE is not set ++# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set ++# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set ++# CONFIG_BLK_DEV_IDEDISK_IBM is not set ++# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set ++# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set ++# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set ++# CONFIG_BLK_DEV_IDEDISK_WD is not set ++# CONFIG_BLK_DEV_COMMERIAL is not set ++# CONFIG_BLK_DEV_TIVO is not set ++CONFIG_BLK_DEV_IDECS=m ++# CONFIG_BLK_DEV_IDECD is not set ++# CONFIG_BLK_DEV_IDETAPE is not set ++# CONFIG_BLK_DEV_IDEFLOPPY is not set ++# CONFIG_BLK_DEV_IDESCSI is not set ++# CONFIG_IDE_TASK_IOCTL is not set ++# CONFIG_BLK_DEV_CMD640 is not set ++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set ++# CONFIG_BLK_DEV_ISAPNP is not set ++# CONFIG_IDE_CHIPSETS is not set ++# CONFIG_IDEDMA_AUTO is not set ++# CONFIG_DMA_NONPCI is not set ++# CONFIG_BLK_DEV_IDE_MODES is not set ++# CONFIG_BLK_DEV_ATARAID is not set ++# CONFIG_BLK_DEV_ATARAID_PDC is not set ++# CONFIG_BLK_DEV_ATARAID_HPT is not set ++ ++# ++# SCSI support ++# ++# CONFIG_SCSI is not set ++ ++# ++# I2O device support ++# ++# CONFIG_I2O is not set ++# CONFIG_I2O_BLOCK is not set ++# CONFIG_I2O_LAN is not set ++# CONFIG_I2O_SCSI is not set ++# CONFIG_I2O_PROC is not set ++ ++# ++# ISDN subsystem ++# ++# CONFIG_ISDN is not set ++ ++# ++# Input core support ++# ++# CONFIG_INPUT is not set ++# CONFIG_INPUT_KEYBDEV is not set ++# CONFIG_INPUT_MOUSEDEV is not set ++# CONFIG_INPUT_JOYDEV is not set ++# CONFIG_INPUT_EVDEV is not set ++ ++# ++# Character devices ++# ++CONFIG_VT=y ++CONFIG_VT_CONSOLE=y ++CONFIG_SERIAL=y ++CONFIG_SERIAL_CONSOLE=y ++# CONFIG_SERIAL_EXTENDED is not set ++# CONFIG_SERIAL_NONSTANDARD is not set ++ ++# ++# Serial drivers ++# ++# CONFIG_SERIAL_ANAKIN is not set ++# CONFIG_SERIAL_ANAKIN_CONSOLE is not set ++# CONFIG_SERIAL_AMBA is not set ++# CONFIG_SERIAL_AMBA_CONSOLE is not set ++# CONFIG_SERIAL_CLPS711X is not set ++# CONFIG_SERIAL_CLPS711X_CONSOLE is not set ++# CONFIG_SERIAL_21285 is not set ++# CONFIG_SERIAL_21285_OLD is not set ++# CONFIG_SERIAL_21285_CONSOLE is not set ++# CONFIG_SERIAL_UART00 is not set ++# CONFIG_SERIAL_UART00_CONSOLE is not set ++# CONFIG_SERIAL_SA1100 is not set ++# CONFIG_SERIAL_SA1100_CONSOLE is not set ++# CONFIG_SERIAL_OMAHA is not set ++# CONFIG_SERIAL_OMAHA_CONSOLE is not set ++# CONFIG_SERIAL_8250 is not set ++# CONFIG_SERIAL_8250_CONSOLE is not set ++# CONFIG_SERIAL_8250_EXTENDED is not set ++# CONFIG_SERIAL_8250_MANY_PORTS is not set ++# CONFIG_SERIAL_8250_SHARE_IRQ is not set ++# CONFIG_SERIAL_8250_DETECT_IRQ is not set ++# CONFIG_SERIAL_8250_MULTIPORT is not set ++# CONFIG_SERIAL_8250_HUB6 is not set ++CONFIG_UNIX98_PTYS=y ++CONFIG_UNIX98_PTY_COUNT=256 ++ ++# ++# I2C support ++# ++CONFIG_I2C=y ++# CONFIG_I2C_ALGOBIT is not set ++# CONFIG_I2C_ALGOPCF is not set ++CONFIG_I2C_PXA_ALGO=y ++CONFIG_I2C_PXA_ADAP=y ++# CONFIG_I2C_CHARDEV is not set ++# CONFIG_I2C_PROC is not set ++# CONFIG_I2C_DS1307 is not set ++ ++# ++# L3 serial bus support ++# ++# CONFIG_L3 is not set ++# CONFIG_L3_ALGOBIT is not set ++# CONFIG_L3_BIT_SA1100_GPIO is not set ++# CONFIG_L3_SA1111 is not set ++# CONFIG_BIT_SA1100_GPIO is not set ++ ++# ++# Mice ++# ++# CONFIG_BUSMOUSE is not set ++# CONFIG_MOUSE is not set ++ ++# ++# Joysticks ++# ++# CONFIG_INPUT_GAMEPORT is not set ++# CONFIG_QIC02_TAPE is not set ++ ++# ++# Watchdog Cards ++# ++CONFIG_WATCHDOG=y ++# CONFIG_WATCHDOG_NOWAYOUT is not set ++# CONFIG_ACQUIRE_WDT is not set ++# CONFIG_ADVANTECH_WDT is not set ++# CONFIG_ALIM7101_WDT is not set ++# CONFIG_SC520_WDT is not set ++# CONFIG_PCWATCHDOG is not set ++# CONFIG_21285_WATCHDOG is not set ++# CONFIG_977_WATCHDOG is not set ++# CONFIG_SA1100_WATCHDOG is not set ++CONFIG_PXA_WATCHDOG=m ++# CONFIG_OMAHA_WATCHDOG is not set ++# CONFIG_EUROTECH_WDT is not set ++# CONFIG_IB700_WDT is not set ++# CONFIG_WAFER_WDT is not set ++# CONFIG_I810_TCO is not set ++# CONFIG_MIXCOMWD is not set ++# CONFIG_60XX_WDT is not set ++# CONFIG_SC1200_WDT is not set ++# CONFIG_SOFT_WATCHDOG is not set ++# CONFIG_W83877F_WDT is not set ++# CONFIG_WDT is not set ++# CONFIG_WDTPCI is not set ++# CONFIG_MACHZ_WDT is not set ++# CONFIG_NVRAM is not set ++# CONFIG_RTC is not set ++# CONFIG_PXA_RTC is not set ++# CONFIG_DTLK is not set ++# CONFIG_R3964 is not set ++# CONFIG_APPLICOM is not set ++ ++# ++# Ftape, the floppy tape device driver ++# ++# CONFIG_FTAPE is not set ++# CONFIG_AGP is not set ++# CONFIG_DRM is not set ++ ++# ++# PCMCIA character devices ++# ++CONFIG_PCMCIA_SERIAL_CS=y ++CONFIG_PCMCIA_CHRDEV=y ++ ++# ++# Multimedia devices ++# ++# CONFIG_VIDEO_DEV is not set ++ ++# ++# File systems ++# ++# CONFIG_QUOTA is not set ++CONFIG_AUTOFS_FS=y ++CONFIG_AUTOFS4_FS=y ++# CONFIG_REISERFS_FS is not set ++# CONFIG_REISERFS_CHECK is not set ++# CONFIG_REISERFS_PROC_INFO is not set ++# CONFIG_ADFS_FS is not set ++# CONFIG_ADFS_FS_RW is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_BFS_FS is not set ++# CONFIG_EXT3_FS is not set ++# CONFIG_JBD is not set ++# CONFIG_JBD_DEBUG is not set ++CONFIG_FAT_FS=m ++CONFIG_MSDOS_FS=m ++CONFIG_UMSDOS_FS=m ++CONFIG_VFAT_FS=m ++# CONFIG_EFS_FS is not set ++# CONFIG_JFFS_FS is not set ++CONFIG_JFFS2_FS=y ++CONFIG_JFFS2_FS_DEBUG=0 ++# CONFIG_CRAMFS is not set ++CONFIG_TMPFS=y ++CONFIG_RAMFS=y ++# CONFIG_ISO9660_FS is not set ++# CONFIG_JOLIET is not set ++# CONFIG_ZISOFS is not set ++# CONFIG_MINIX_FS is not set ++# CONFIG_VXFS_FS is not set ++# CONFIG_NTFS_FS is not set ++# CONFIG_NTFS_RW is not set ++# CONFIG_HPFS_FS is not set ++CONFIG_PROC_FS=y ++# CONFIG_DEVFS_FS is not set ++# CONFIG_DEVFS_MOUNT is not set ++# CONFIG_DEVFS_DEBUG is not set ++CONFIG_DEVPTS_FS=y ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_QNX4FS_RW is not set ++CONFIG_ROMFS_FS=y ++CONFIG_EXT2_FS=y ++# CONFIG_SYSV_FS is not set ++# CONFIG_UDF_FS is not set ++# CONFIG_UDF_RW is not set ++# CONFIG_UFS_FS is not set ++# CONFIG_UFS_FS_WRITE is not set ++ ++# ++# Network File Systems ++# ++# CONFIG_CODA_FS is not set ++# CONFIG_INTERMEZZO_FS is not set ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_ROOT_NFS=y ++# CONFIG_NFSD is not set ++# CONFIG_NFSD_V3 is not set ++CONFIG_SUNRPC=y ++CONFIG_LOCKD=y ++CONFIG_LOCKD_V4=y ++# CONFIG_SMB_FS is not set ++# CONFIG_NCP_FS is not set ++# CONFIG_NCPFS_PACKET_SIGNING is not set ++# CONFIG_NCPFS_IOCTL_LOCKING is not set ++# CONFIG_NCPFS_STRONG is not set ++# CONFIG_NCPFS_NFS_NS is not set ++# CONFIG_NCPFS_OS2_NS is not set ++# CONFIG_NCPFS_SMALLDOS is not set ++# CONFIG_NCPFS_NLS is not set ++# CONFIG_NCPFS_EXTRAS is not set ++# CONFIG_ZISOFS_FS is not set ++# CONFIG_ZLIB_FS_INFLATE is not set ++ ++# ++# Partition Types ++# ++# CONFIG_PARTITION_ADVANCED is not set ++CONFIG_MSDOS_PARTITION=y ++# CONFIG_SMB_NLS is not set ++CONFIG_NLS=y ++ ++# ++# Native Language Support ++# ++CONFIG_NLS_DEFAULT="iso8859-1" ++CONFIG_NLS_CODEPAGE_437=m ++# CONFIG_NLS_CODEPAGE_737 is not set ++# CONFIG_NLS_CODEPAGE_775 is not set ++CONFIG_NLS_CODEPAGE_850=m ++CONFIG_NLS_CODEPAGE_852=m ++# CONFIG_NLS_CODEPAGE_855 is not set ++# CONFIG_NLS_CODEPAGE_857 is not set ++# CONFIG_NLS_CODEPAGE_860 is not set ++# CONFIG_NLS_CODEPAGE_861 is not set ++# CONFIG_NLS_CODEPAGE_862 is not set ++CONFIG_NLS_CODEPAGE_863=m ++# CONFIG_NLS_CODEPAGE_864 is not set ++# CONFIG_NLS_CODEPAGE_865 is not set ++# CONFIG_NLS_CODEPAGE_866 is not set ++# CONFIG_NLS_CODEPAGE_869 is not set ++# CONFIG_NLS_CODEPAGE_936 is not set ++# CONFIG_NLS_CODEPAGE_950 is not set ++# CONFIG_NLS_CODEPAGE_932 is not set ++# CONFIG_NLS_CODEPAGE_949 is not set ++# CONFIG_NLS_CODEPAGE_874 is not set ++# CONFIG_NLS_ISO8859_8 is not set ++# CONFIG_NLS_CODEPAGE_1250 is not set ++# CONFIG_NLS_CODEPAGE_1251 is not set ++CONFIG_NLS_ISO8859_1=m ++CONFIG_NLS_ISO8859_2=m ++CONFIG_NLS_ISO8859_3=m ++CONFIG_NLS_ISO8859_4=m ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++# CONFIG_NLS_UTF8 is not set ++ ++# ++# Console drivers ++# ++CONFIG_PC_KEYMAP=y ++# CONFIG_VGA_CONSOLE is not set ++ ++# ++# Frame-buffer support ++# ++# CONFIG_FB is not set ++ ++# ++# Sound ++# ++# CONFIG_SOUND is not set ++ ++# ++# Multimedia Capabilities Port drivers ++# ++# CONFIG_MCP is not set ++# CONFIG_MCP_SA1100 is not set ++# CONFIG_MCP_UCB1200 is not set ++# CONFIG_MCP_UCB1200_AUDIO is not set ++# CONFIG_MCP_UCB1200_TS is not set ++# CONFIG_MCP_UCB1400_TS is not set ++ ++# ++# USB support ++# ++# CONFIG_USB is not set ++ ++# ++# Bluetooth support ++# ++# CONFIG_BLUEZ is not set ++ ++# ++# Kernel hacking ++# ++CONFIG_FRAME_POINTER=y ++CONFIG_DEBUG_USER=y ++# CONFIG_DEBUG_INFO is not set ++# CONFIG_NO_PGT_CACHE is not set ++CONFIG_DEBUG_KERNEL=y ++# CONFIG_DEBUG_SLAB is not set ++CONFIG_MAGIC_SYSRQ=y ++# CONFIG_DEBUG_SPINLOCK is not set ++# CONFIG_DEBUG_WAITQ is not set ++CONFIG_DEBUG_BUGVERBOSE=y ++CONFIG_DEBUG_ERRORS=y ++CONFIG_DEBUG_LL=y ++# CONFIG_DEBUG_DC21285_PORT is not set ++# CONFIG_DEBUG_CLPS711X_UART2 is not set +--- /dev/null ++++ linux-2.4.27/arch/arm/def-configs/cerfpda_pxa +@@ -0,0 +1,962 @@ ++# ++# Automatically generated by make menuconfig: don't edit ++# ++CONFIG_ARM=y ++# CONFIG_EISA is not set ++# CONFIG_SBUS is not set ++# CONFIG_MCA is not set ++CONFIG_UID16=y ++CONFIG_RWSEM_GENERIC_SPINLOCK=y ++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set ++# CONFIG_GENERIC_BUST_SPINLOCK is not set ++# CONFIG_GENERIC_ISA_DMA is not set ++ ++# ++# Code maturity level options ++# ++CONFIG_EXPERIMENTAL=y ++# CONFIG_OBSOLETE is not set ++ ++# ++# Loadable module support ++# ++CONFIG_MODULES=y ++# CONFIG_MODVERSIONS is not set ++CONFIG_KMOD=y ++ ++# ++# System Type ++# ++# CONFIG_ARCH_ANAKIN is not set ++# CONFIG_ARCH_ARCA5K is not set ++# CONFIG_ARCH_CLPS7500 is not set ++# CONFIG_ARCH_CLPS711X is not set ++# CONFIG_ARCH_CO285 is not set ++CONFIG_ARCH_PXA=y ++# CONFIG_ARCH_EBSA110 is not set ++# CONFIG_ARCH_CAMELOT is not set ++# CONFIG_ARCH_FOOTBRIDGE is not set ++# CONFIG_ARCH_INTEGRATOR is not set ++# CONFIG_ARCH_L7200 is not set ++# CONFIG_ARCH_MX1ADS is not set ++# CONFIG_ARCH_RPC is not set ++# CONFIG_ARCH_SA1100 is not set ++# CONFIG_ARCH_SHARK is not set ++ ++# ++# Archimedes/A5000 Implementations ++# ++# CONFIG_ARCH_ARC is not set ++# CONFIG_ARCH_A5K is not set ++ ++# ++# Footbridge Implementations ++# ++# CONFIG_ARCH_CATS is not set ++# CONFIG_ARCH_PERSONAL_SERVER is not set ++# CONFIG_ARCH_EBSA285_ADDIN is not set ++# CONFIG_ARCH_EBSA285_HOST is not set ++# CONFIG_ARCH_NETWINDER is not set ++ ++# ++# SA11x0 Implementations ++# ++# CONFIG_SA1100_ASSABET is not set ++# CONFIG_ASSABET_NEPONSET is not set ++# CONFIG_SA1100_ADSBITSY is not set ++# CONFIG_SA1100_BRUTUS is not set ++# CONFIG_SA1100_CEP is not set ++# CONFIG_SA1100_CERF is not set ++# CONFIG_SA1100_H3100 is not set ++# CONFIG_SA1100_H3600 is not set ++# CONFIG_SA1100_H3800 is not set ++# CONFIG_SA1100_H3XXX is not set ++# CONFIG_SA1100_EXTENEX1 is not set ++# CONFIG_SA1100_FLEXANET is not set ++# CONFIG_SA1100_FREEBIRD is not set ++# CONFIG_SA1100_FRODO is not set ++# CONFIG_SA1100_GRAPHICSCLIENT is not set ++# CONFIG_SA1100_GRAPHICSMASTER is not set ++# CONFIG_SA1100_BADGE4 is not set ++# CONFIG_SA1100_JORNADA720 is not set ++# CONFIG_SA1100_HUW_WEBPANEL is not set ++# CONFIG_SA1100_ITSY is not set ++# CONFIG_SA1100_LART is not set ++# CONFIG_SA1100_NANOENGINE is not set ++# CONFIG_SA1100_OMNIMETER is not set ++# CONFIG_SA1100_PANGOLIN is not set ++# CONFIG_SA1100_PLEB is not set ++# CONFIG_SA1100_PT_SYSTEM3 is not set ++# CONFIG_SA1100_SHANNON is not set ++# CONFIG_SA1100_SHERMAN is not set ++# CONFIG_SA1100_SIMPAD is not set ++# CONFIG_SA1100_PFS168 is not set ++# CONFIG_SA1100_VICTOR is not set ++# CONFIG_SA1100_XP860 is not set ++# CONFIG_SA1100_YOPY is not set ++# CONFIG_SA1100_USB is not set ++# CONFIG_SA1100_USB_NETLINK is not set ++# CONFIG_SA1100_USB_CHAR is not set ++# CONFIG_H3600_SLEEVE is not set ++ ++# ++# Intel PXA250/210 Implementations ++# ++# CONFIG_ARCH_LUBBOCK is not set ++# CONFIG_ARCH_PXA_IDP is not set ++CONFIG_ARCH_PXA_CERF=y ++CONFIG_PXA_CERF=y ++CONFIG_PXA_CERF_PDA=y ++# CONFIG_PXA_CERF_BOARD is not set ++# CONFIG_PXA_CERF_RAM_128MB is not set ++CONFIG_PXA_CERF_RAM_64MB=y ++# CONFIG_PXA_CERF_RAM_32MB is not set ++# CONFIG_PXA_CERF_RAM_16MB is not set ++# CONFIG_PXA_CERF_FLASH_64MB is not set ++CONFIG_PXA_CERF_FLASH_32MB=y ++# CONFIG_PXA_CERF_FLASH_16MB is not set ++# CONFIG_PXA_CERF_FLASH_8MB is not set ++CONFIG_PXA_USB=y ++CONFIG_PXA_USB_NETLINK=y ++CONFIG_PXA_USB_CHAR=y ++ ++# ++# CLPS711X/EP721X Implementations ++# ++# CONFIG_ARCH_AUTCPU12 is not set ++# CONFIG_ARCH_CDB89712 is not set ++# CONFIG_ARCH_CLEP7312 is not set ++# CONFIG_ARCH_EDB7211 is not set ++# CONFIG_ARCH_P720T is not set ++# CONFIG_ARCH_FORTUNET is not set ++# CONFIG_ARCH_EP7211 is not set ++# CONFIG_ARCH_EP7212 is not set ++# CONFIG_ARCH_ACORN is not set ++# CONFIG_FOOTBRIDGE is not set ++# CONFIG_FOOTBRIDGE_HOST is not set ++# CONFIG_FOOTBRIDGE_ADDIN is not set ++CONFIG_CPU_32=y ++# CONFIG_CPU_26 is not set ++# CONFIG_CPU_32v3 is not set ++# CONFIG_CPU_32v4 is not set ++# CONFIG_CPU_ARM610 is not set ++# CONFIG_CPU_ARM710 is not set ++# CONFIG_CPU_ARM720T is not set ++# CONFIG_CPU_ARM920T is not set ++# CONFIG_CPU_ARM922T is not set ++# CONFIG_PLD is not set ++# CONFIG_CPU_ARM926T is not set ++# CONFIG_CPU_ARM1020 is not set ++# CONFIG_CPU_SA110 is not set ++# CONFIG_CPU_SA1100 is not set ++CONFIG_CPU_32v5=y ++CONFIG_CPU_XSCALE=y ++# CONFIG_XSCALE_CACHE_ERRATA is not set ++# CONFIG_ARM_THUMB is not set ++# CONFIG_DISCONTIGMEM is not set ++ ++# ++# General setup ++# ++# CONFIG_PCI is not set ++# CONFIG_ISA is not set ++# CONFIG_ISA_DMA is not set ++# CONFIG_ZBOOT_ROM is not set ++CONFIG_ZBOOT_ROM_TEXT=0 ++CONFIG_ZBOOT_ROM_BSS=0 ++CONFIG_HOTPLUG=y ++ ++# ++# PCMCIA/CardBus support ++# ++CONFIG_PCMCIA=y ++# CONFIG_I82092 is not set ++# CONFIG_I82365 is not set ++# CONFIG_TCIC is not set ++# CONFIG_PCMCIA_CLPS6700 is not set ++# CONFIG_PCMCIA_SA1100 is not set ++CONFIG_PCMCIA_PXA=y ++CONFIG_NET=y ++CONFIG_SYSVIPC=y ++CONFIG_BSD_PROCESS_ACCT=y ++CONFIG_SYSCTL=y ++CONFIG_FPE_NWFPE=y ++# CONFIG_FPE_FASTFPE is not set ++CONFIG_KCORE_ELF=y ++# CONFIG_KCORE_AOUT is not set ++# CONFIG_BINFMT_AOUT is not set ++CONFIG_BINFMT_ELF=y ++# CONFIG_BINFMT_MISC is not set ++# CONFIG_PM is not set ++# CONFIG_ARTHUR is not set ++CONFIG_CMDLINE="root=1f03 rw console=tty0 console=ttyS0,38400 init=/linuxrc" ++CONFIG_LEDS=y ++# CONFIG_LEDS_TIMER is not set ++CONFIG_LEDS_CPU=y ++CONFIG_ALIGNMENT_TRAP=y ++ ++# ++# Parallel port support ++# ++# CONFIG_PARPORT is not set ++ ++# ++# Memory Technology Devices (MTD) ++# ++CONFIG_MTD=y ++# CONFIG_MTD_DEBUG is not set ++CONFIG_MTD_PARTITIONS=y ++# CONFIG_MTD_CONCAT is not set ++CONFIG_MTD_REDBOOT_PARTS=y ++# CONFIG_MTD_CMDLINE_PARTS is not set ++# CONFIG_MTD_AFS_PARTS is not set ++CONFIG_MTD_CHAR=y ++CONFIG_MTD_BLOCK=y ++# CONFIG_FTL is not set ++# CONFIG_NFTL is not set ++ ++# ++# RAM/ROM/Flash chip drivers ++# ++CONFIG_MTD_CFI=y ++# CONFIG_MTD_JEDECPROBE is not set ++CONFIG_MTD_GEN_PROBE=y ++CONFIG_MTD_CFI_ADV_OPTIONS=y ++CONFIG_MTD_CFI_NOSWAP=y ++# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set ++# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set ++CONFIG_MTD_CFI_GEOMETRY=y ++# CONFIG_MTD_CFI_B1 is not set ++# CONFIG_MTD_CFI_B2 is not set ++CONFIG_MTD_CFI_B4=y ++# CONFIG_MTD_CFI_B8 is not set ++# CONFIG_MTD_CFI_I1 is not set ++CONFIG_MTD_CFI_I2=y ++# CONFIG_MTD_CFI_I4 is not set ++# CONFIG_MTD_CFI_I8 is not set ++CONFIG_MTD_CFI_INTELEXT=y ++# CONFIG_MTD_CFI_AMDSTD is not set ++# CONFIG_MTD_RAM is not set ++# CONFIG_MTD_ROM is not set ++# CONFIG_MTD_ABSENT is not set ++# CONFIG_MTD_OBSOLETE_CHIPS is not set ++# CONFIG_MTD_AMDSTD is not set ++# CONFIG_MTD_SHARP is not set ++# CONFIG_MTD_JEDEC is not set ++ ++# ++# Mapping drivers for chip access ++# ++# CONFIG_MTD_PHYSMAP is not set ++# CONFIG_MTD_LUBBOCK is not set ++# CONFIG_MTD_NORA is not set ++# CONFIG_MTD_ARM_INTEGRATOR is not set ++# CONFIG_MTD_CDB89712 is not set ++# CONFIG_MTD_SA1100 is not set ++# CONFIG_MTD_DC21285 is not set ++# CONFIG_MTD_IQ80310 is not set ++# CONFIG_MTD_FORTUNET is not set ++CONFIG_MTD_PXA_CERF=y ++# CONFIG_MTD_EPXA10DB is not set ++# CONFIG_MTD_AUTCPU12 is not set ++# CONFIG_MTD_EDB7312 is not set ++# CONFIG_MTD_IMPA7 is not set ++# CONFIG_MTD_PCI is not set ++ ++# ++# Self-contained MTD device drivers ++# ++# CONFIG_MTD_PMC551 is not set ++# CONFIG_MTD_SLRAM is not set ++# CONFIG_MTD_MTDRAM is not set ++# CONFIG_MTD_BLKMTD is not set ++# CONFIG_MTD_DOC1000 is not set ++# CONFIG_MTD_DOC2000 is not set ++# CONFIG_MTD_DOC2001 is not set ++# CONFIG_MTD_DOCPROBE is not set ++ ++# ++# NAND Flash Device Drivers ++# ++# CONFIG_MTD_NAND is not set ++ ++# ++# Plug and Play configuration ++# ++# CONFIG_PNP is not set ++# CONFIG_ISAPNP is not set ++ ++# ++# Block devices ++# ++# CONFIG_BLK_DEV_FD is not set ++# CONFIG_BLK_DEV_XD is not set ++# CONFIG_PARIDE is not set ++# CONFIG_BLK_CPQ_DA is not set ++# CONFIG_BLK_CPQ_CISS_DA is not set ++# CONFIG_BLK_DEV_DAC960 is not set ++CONFIG_BLK_DEV_LOOP=m ++# CONFIG_BLK_DEV_NBD is not set ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_SIZE=4096 ++CONFIG_BLK_DEV_INITRD=y ++ ++# ++# Multi-device support (RAID and LVM) ++# ++# CONFIG_MD is not set ++# CONFIG_BLK_DEV_MD is not set ++# CONFIG_MD_LINEAR is not set ++# CONFIG_MD_RAID0 is not set ++# CONFIG_MD_RAID1 is not set ++# CONFIG_MD_RAID5 is not set ++# CONFIG_MD_MULTIPATH is not set ++# CONFIG_BLK_DEV_LVM is not set ++ ++# ++# Networking options ++# ++CONFIG_PACKET=y ++# CONFIG_PACKET_MMAP is not set ++# CONFIG_NETLINK_DEV is not set ++# CONFIG_NETFILTER is not set ++CONFIG_FILTER=y ++CONFIG_UNIX=y ++CONFIG_INET=y ++# CONFIG_IP_MULTICAST is not set ++# CONFIG_IP_ADVANCED_ROUTER is not set ++CONFIG_IP_PNP=y ++CONFIG_IP_PNP_DHCP=y ++CONFIG_IP_PNP_BOOTP=y ++CONFIG_IP_PNP_RARP=y ++# CONFIG_NET_IPIP is not set ++# CONFIG_NET_IPGRE is not set ++# CONFIG_ARPD is not set ++# CONFIG_INET_ECN is not set ++# CONFIG_SYN_COOKIES is not set ++# CONFIG_IPV6 is not set ++# CONFIG_KHTTPD is not set ++# CONFIG_ATM is not set ++# CONFIG_VLAN_8021Q is not set ++# CONFIG_IPX is not set ++# CONFIG_ATALK is not set ++# CONFIG_DECNET is not set ++# CONFIG_BRIDGE is not set ++# CONFIG_X25 is not set ++# CONFIG_LAPB is not set ++# CONFIG_LLC is not set ++# CONFIG_NET_DIVERT is not set ++# CONFIG_ECONET is not set ++# CONFIG_WAN_ROUTER is not set ++# CONFIG_NET_FASTROUTE is not set ++# CONFIG_NET_HW_FLOWCONTROL is not set ++ ++# ++# QoS and/or fair queueing ++# ++# CONFIG_NET_SCHED is not set ++ ++# ++# Network device support ++# ++CONFIG_NETDEVICES=y ++ ++# ++# ARCnet devices ++# ++# CONFIG_ARCNET is not set ++# CONFIG_DUMMY is not set ++# CONFIG_BONDING is not set ++# CONFIG_EQUALIZER is not set ++# CONFIG_TUN is not set ++# CONFIG_ETHERTAP is not set ++ ++# ++# Ethernet (10 or 100Mbit) ++# ++CONFIG_NET_ETHERNET=y ++# CONFIG_ARM_AM79C961A is not set ++# CONFIG_SUNLANCE is not set ++# CONFIG_SUNBMAC is not set ++# CONFIG_SUNQE is not set ++# CONFIG_SUNGEM is not set ++# CONFIG_NET_VENDOR_3COM is not set ++# CONFIG_LANCE is not set ++# CONFIG_NET_VENDOR_SMC is not set ++# CONFIG_NET_VENDOR_RACAL is not set ++# CONFIG_NET_ISA is not set ++# CONFIG_NET_PCI is not set ++# CONFIG_NET_POCKET is not set ++ ++# ++# Ethernet (1000 Mbit) ++# ++# CONFIG_ACENIC is not set ++# CONFIG_DL2K is not set ++# CONFIG_MYRI_SBUS is not set ++# CONFIG_NS83820 is not set ++# CONFIG_HAMACHI is not set ++# CONFIG_YELLOWFIN is not set ++# CONFIG_SK98LIN is not set ++# CONFIG_FDDI is not set ++# CONFIG_HIPPI is not set ++# CONFIG_PLIP is not set ++CONFIG_PPP=m ++# CONFIG_PPP_MULTILINK is not set ++# CONFIG_PPP_FILTER is not set ++CONFIG_PPP_ASYNC=m ++# CONFIG_PPP_SYNC_TTY is not set ++CONFIG_PPP_DEFLATE=m ++CONFIG_PPP_BSDCOMP=m ++# CONFIG_PPPOE is not set ++# CONFIG_SLIP is not set ++ ++# ++# Wireless LAN (non-hamradio) ++# ++# CONFIG_NET_RADIO is not set ++ ++# ++# Token Ring devices ++# ++# CONFIG_TR is not set ++# CONFIG_NET_FC is not set ++# CONFIG_RCPCI is not set ++# CONFIG_SHAPER is not set ++ ++# ++# Wan interfaces ++# ++# CONFIG_WAN is not set ++ ++# ++# PCMCIA network device support ++# ++CONFIG_NET_PCMCIA=y ++CONFIG_PCMCIA_3C589=m ++CONFIG_PCMCIA_3C574=m ++CONFIG_PCMCIA_FMVJ18X=m ++CONFIG_PCMCIA_PCNET=m ++CONFIG_PCMCIA_AXNET=m ++CONFIG_PCMCIA_NMCLAN=m ++CONFIG_PCMCIA_SMC91C92=m ++CONFIG_PCMCIA_XIRC2PS=m ++# CONFIG_ARCNET_COM20020_CS is not set ++# CONFIG_PCMCIA_IBMTR is not set ++# CONFIG_NET_PCMCIA_RADIO is not set ++ ++# ++# Amateur Radio support ++# ++# CONFIG_HAMRADIO is not set ++ ++# ++# IrDA (infrared) support ++# ++CONFIG_IRDA=y ++CONFIG_IRLAN=y ++# CONFIG_IRNET is not set ++CONFIG_IRCOMM=y ++CONFIG_IRDA_ULTRA=y ++# CONFIG_IRDA_CACHE_LAST_LSAP is not set ++# CONFIG_IRDA_FAST_RR is not set ++CONFIG_IRDA_DEBUG=y ++ ++# ++# Infrared-port device drivers ++# ++CONFIG_IRTTY_SIR=y ++# CONFIG_IRPORT_SIR is not set ++# CONFIG_DONGLE is not set ++# CONFIG_USB_IRDA is not set ++# CONFIG_NSC_FIR is not set ++# CONFIG_WINBOND_FIR is not set ++# CONFIG_TOSHIBA_FIR is not set ++# CONFIG_SMC_IRCC_FIR is not set ++# CONFIG_ALI_FIR is not set ++# CONFIG_VLSI_FIR is not set ++ ++# ++# ATA/IDE/MFM/RLL support ++# ++CONFIG_IDE=y ++ ++# ++# IDE, ATA and ATAPI Block devices ++# ++CONFIG_BLK_DEV_IDE=y ++# CONFIG_BLK_DEV_HD_IDE is not set ++# CONFIG_BLK_DEV_HD is not set ++CONFIG_BLK_DEV_IDEDISK=y ++# CONFIG_IDEDISK_MULTI_MODE is not set ++# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set ++# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set ++# CONFIG_BLK_DEV_IDEDISK_IBM is not set ++# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set ++# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set ++# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set ++# CONFIG_BLK_DEV_IDEDISK_WD is not set ++# CONFIG_BLK_DEV_COMMERIAL is not set ++# CONFIG_BLK_DEV_TIVO is not set ++CONFIG_BLK_DEV_IDECS=m ++# CONFIG_BLK_DEV_IDECD is not set ++# CONFIG_BLK_DEV_IDETAPE is not set ++# CONFIG_BLK_DEV_IDEFLOPPY is not set ++# CONFIG_BLK_DEV_IDESCSI is not set ++# CONFIG_BLK_DEV_CMD640 is not set ++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set ++# CONFIG_BLK_DEV_ISAPNP is not set ++# CONFIG_IDE_CHIPSETS is not set ++# CONFIG_IDEDMA_AUTO is not set ++# CONFIG_DMA_NONPCI is not set ++# CONFIG_BLK_DEV_IDE_MODES is not set ++# CONFIG_BLK_DEV_ATARAID is not set ++# CONFIG_BLK_DEV_ATARAID_PDC is not set ++# CONFIG_BLK_DEV_ATARAID_HPT is not set ++ ++# ++# SCSI support ++# ++# CONFIG_SCSI is not set ++ ++# ++# I2O device support ++# ++# CONFIG_I2O is not set ++# CONFIG_I2O_BLOCK is not set ++# CONFIG_I2O_LAN is not set ++# CONFIG_I2O_SCSI is not set ++# CONFIG_I2O_PROC is not set ++ ++# ++# ISDN subsystem ++# ++# CONFIG_ISDN is not set ++ ++# ++# Input core support ++# ++CONFIG_INPUT=y ++# CONFIG_INPUT_KEYBDEV is not set ++# CONFIG_INPUT_MOUSEDEV is not set ++# CONFIG_INPUT_JOYDEV is not set ++CONFIG_INPUT_EVDEV=y ++ ++# ++# Character devices ++# ++CONFIG_VT=y ++CONFIG_VT_CONSOLE=y ++CONFIG_SERIAL=y ++CONFIG_SERIAL_CONSOLE=y ++# CONFIG_SERIAL_EXTENDED is not set ++# CONFIG_SERIAL_NONSTANDARD is not set ++ ++# ++# Serial drivers ++# ++# CONFIG_SERIAL_ANAKIN is not set ++# CONFIG_SERIAL_ANAKIN_CONSOLE is not set ++# CONFIG_SERIAL_AMBA is not set ++# CONFIG_SERIAL_AMBA_CONSOLE is not set ++# CONFIG_SERIAL_CLPS711X is not set ++# CONFIG_SERIAL_CLPS711X_CONSOLE is not set ++# CONFIG_SERIAL_21285 is not set ++# CONFIG_SERIAL_21285_OLD is not set ++# CONFIG_SERIAL_21285_CONSOLE is not set ++# CONFIG_SERIAL_UART00 is not set ++# CONFIG_SERIAL_UART00_CONSOLE is not set ++# CONFIG_SERIAL_SA1100 is not set ++# CONFIG_SERIAL_SA1100_CONSOLE is not set ++# CONFIG_SERIAL_8250 is not set ++# CONFIG_SERIAL_8250_CONSOLE is not set ++# CONFIG_SERIAL_8250_EXTENDED is not set ++# CONFIG_SERIAL_8250_MANY_PORTS is not set ++# CONFIG_SERIAL_8250_SHARE_IRQ is not set ++# CONFIG_SERIAL_8250_DETECT_IRQ is not set ++# CONFIG_SERIAL_8250_MULTIPORT is not set ++# CONFIG_SERIAL_8250_HUB6 is not set ++CONFIG_UNIX98_PTYS=y ++CONFIG_UNIX98_PTY_COUNT=256 ++ ++# ++# I2C support ++# ++# CONFIG_I2C is not set ++ ++# ++# L3 serial bus support ++# ++# CONFIG_L3 is not set ++# CONFIG_L3_ALGOBIT is not set ++# CONFIG_L3_BIT_SA1100_GPIO is not set ++# CONFIG_L3_SA1111 is not set ++# CONFIG_BIT_SA1100_GPIO is not set ++ ++# ++# Mice ++# ++# CONFIG_BUSMOUSE is not set ++# CONFIG_MOUSE is not set ++ ++# ++# Joysticks ++# ++# CONFIG_INPUT_GAMEPORT is not set ++# CONFIG_INPUT_NS558 is not set ++# CONFIG_INPUT_LIGHTNING is not set ++# CONFIG_INPUT_PCIGAME is not set ++# CONFIG_INPUT_CS461X is not set ++# CONFIG_INPUT_EMU10K1 is not set ++# CONFIG_INPUT_SERIO is not set ++# CONFIG_INPUT_SERPORT is not set ++# CONFIG_INPUT_ANALOG is not set ++# CONFIG_INPUT_A3D is not set ++# CONFIG_INPUT_ADI is not set ++# CONFIG_INPUT_COBRA is not set ++# CONFIG_INPUT_GF2K is not set ++# CONFIG_INPUT_GRIP is not set ++# CONFIG_INPUT_INTERACT is not set ++# CONFIG_INPUT_TMDC is not set ++# CONFIG_INPUT_SIDEWINDER is not set ++# CONFIG_INPUT_IFORCE_USB is not set ++# CONFIG_INPUT_IFORCE_232 is not set ++# CONFIG_INPUT_WARRIOR is not set ++# CONFIG_INPUT_MAGELLAN is not set ++# CONFIG_INPUT_SPACEORB is not set ++# CONFIG_INPUT_SPACEBALL is not set ++# CONFIG_INPUT_STINGER is not set ++# CONFIG_INPUT_DB9 is not set ++# CONFIG_INPUT_GAMECON is not set ++# CONFIG_INPUT_TURBOGRAFX is not set ++# CONFIG_QIC02_TAPE is not set ++ ++# ++# Watchdog Cards ++# ++# CONFIG_WATCHDOG is not set ++# CONFIG_INTEL_RNG is not set ++# CONFIG_NVRAM is not set ++# CONFIG_RTC is not set ++# CONFIG_DTLK is not set ++# CONFIG_R3964 is not set ++# CONFIG_APPLICOM is not set ++ ++# ++# Ftape, the floppy tape device driver ++# ++# CONFIG_FTAPE is not set ++# CONFIG_AGP is not set ++# CONFIG_DRM is not set ++ ++# ++# PCMCIA character devices ++# ++CONFIG_PCMCIA_SERIAL_CS=y ++CONFIG_PCMCIA_CHRDEV=y ++ ++# ++# Multimedia devices ++# ++# CONFIG_VIDEO_DEV is not set ++ ++# ++# File systems ++# ++# CONFIG_QUOTA is not set ++CONFIG_AUTOFS_FS=y ++CONFIG_AUTOFS4_FS=y ++# CONFIG_REISERFS_FS is not set ++# CONFIG_REISERFS_CHECK is not set ++# CONFIG_REISERFS_PROC_INFO is not set ++# CONFIG_ADFS_FS is not set ++# CONFIG_ADFS_FS_RW is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_BFS_FS is not set ++# CONFIG_EXT3_FS is not set ++# CONFIG_JBD is not set ++# CONFIG_JBD_DEBUG is not set ++CONFIG_FAT_FS=m ++CONFIG_MSDOS_FS=m ++CONFIG_UMSDOS_FS=m ++CONFIG_VFAT_FS=m ++# CONFIG_EFS_FS is not set ++# CONFIG_JFFS_FS is not set ++CONFIG_JFFS2_FS=y ++CONFIG_JFFS2_FS_DEBUG=0 ++# CONFIG_CRAMFS is not set ++CONFIG_TMPFS=y ++CONFIG_RAMFS=m ++# CONFIG_ISO9660_FS is not set ++# CONFIG_JOLIET is not set ++# CONFIG_ZISOFS is not set ++# CONFIG_MINIX_FS is not set ++# CONFIG_VXFS_FS is not set ++# CONFIG_NTFS_FS is not set ++# CONFIG_NTFS_RW is not set ++# CONFIG_HPFS_FS is not set ++CONFIG_PROC_FS=y ++# CONFIG_DEVFS_FS is not set ++# CONFIG_DEVFS_MOUNT is not set ++# CONFIG_DEVFS_DEBUG is not set ++CONFIG_DEVPTS_FS=y ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_QNX4FS_RW is not set ++CONFIG_ROMFS_FS=y ++CONFIG_EXT2_FS=y ++# CONFIG_SYSV_FS is not set ++# CONFIG_UDF_FS is not set ++# CONFIG_UDF_RW is not set ++# CONFIG_UFS_FS is not set ++# CONFIG_UFS_FS_WRITE is not set ++ ++# ++# Network File Systems ++# ++# CONFIG_CODA_FS is not set ++# CONFIG_INTERMEZZO_FS is not set ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_ROOT_NFS=y ++# CONFIG_NFSD is not set ++# CONFIG_NFSD_V3 is not set ++CONFIG_SUNRPC=y ++CONFIG_LOCKD=y ++CONFIG_LOCKD_V4=y ++# CONFIG_SMB_FS is not set ++# CONFIG_NCP_FS is not set ++# CONFIG_NCPFS_PACKET_SIGNING is not set ++# CONFIG_NCPFS_IOCTL_LOCKING is not set ++# CONFIG_NCPFS_STRONG is not set ++# CONFIG_NCPFS_NFS_NS is not set ++# CONFIG_NCPFS_OS2_NS is not set ++# CONFIG_NCPFS_SMALLDOS is not set ++# CONFIG_NCPFS_NLS is not set ++# CONFIG_NCPFS_EXTRAS is not set ++# CONFIG_ZISOFS_FS is not set ++# CONFIG_ZLIB_FS_INFLATE is not set ++ ++# ++# Partition Types ++# ++# CONFIG_PARTITION_ADVANCED is not set ++CONFIG_MSDOS_PARTITION=y ++# CONFIG_SMB_NLS is not set ++CONFIG_NLS=y ++ ++# ++# Native Language Support ++# ++CONFIG_NLS_DEFAULT="iso8859-1" ++CONFIG_NLS_CODEPAGE_437=m ++# CONFIG_NLS_CODEPAGE_737 is not set ++# CONFIG_NLS_CODEPAGE_775 is not set ++CONFIG_NLS_CODEPAGE_850=m ++CONFIG_NLS_CODEPAGE_852=m ++# CONFIG_NLS_CODEPAGE_855 is not set ++# CONFIG_NLS_CODEPAGE_857 is not set ++# CONFIG_NLS_CODEPAGE_860 is not set ++# CONFIG_NLS_CODEPAGE_861 is not set ++# CONFIG_NLS_CODEPAGE_862 is not set ++CONFIG_NLS_CODEPAGE_863=m ++# CONFIG_NLS_CODEPAGE_864 is not set ++# CONFIG_NLS_CODEPAGE_865 is not set ++# CONFIG_NLS_CODEPAGE_866 is not set ++# CONFIG_NLS_CODEPAGE_869 is not set ++# CONFIG_NLS_CODEPAGE_936 is not set ++# CONFIG_NLS_CODEPAGE_950 is not set ++# CONFIG_NLS_CODEPAGE_932 is not set ++# CONFIG_NLS_CODEPAGE_949 is not set ++# CONFIG_NLS_CODEPAGE_874 is not set ++# CONFIG_NLS_ISO8859_8 is not set ++# CONFIG_NLS_CODEPAGE_1250 is not set ++# CONFIG_NLS_CODEPAGE_1251 is not set ++CONFIG_NLS_ISO8859_1=m ++CONFIG_NLS_ISO8859_2=m ++CONFIG_NLS_ISO8859_3=m ++CONFIG_NLS_ISO8859_4=m ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++# CONFIG_NLS_UTF8 is not set ++ ++# ++# Console drivers ++# ++CONFIG_PC_KEYMAP=y ++# CONFIG_VGA_CONSOLE is not set ++ ++# ++# Frame-buffer support ++# ++CONFIG_FB=y ++CONFIG_DUMMY_CONSOLE=y ++# CONFIG_FB_ACORN is not set ++# CONFIG_FB_ANAKIN is not set ++# CONFIG_FB_CLPS711X is not set ++# CONFIG_FB_SA1100 is not set ++CONFIG_FB_PXA=y ++# CONFIG_FB_PXA_8BPP is not set ++CONFIG_FB_PXA_16BPP=y ++# CONFIG_FB_CYBER2000 is not set ++# CONFIG_FB_VIRTUAL is not set ++# CONFIG_FBCON_ADVANCED is not set ++CONFIG_FBCON_CFB2=y ++CONFIG_FBCON_CFB4=y ++CONFIG_FBCON_CFB8=y ++CONFIG_FBCON_CFB16=y ++# CONFIG_FBCON_FONTWIDTH8_ONLY is not set ++CONFIG_FBCON_FONTS=y ++# CONFIG_FONT_8x8 is not set ++# CONFIG_FONT_8x16 is not set ++# CONFIG_FONT_SUN8x16 is not set ++# CONFIG_FONT_SUN12x22 is not set ++# CONFIG_FONT_6x11 is not set ++# CONFIG_FONT_PEARL_8x8 is not set ++CONFIG_FONT_ACORN_8x8=y ++ ++# ++# Sound ++# ++CONFIG_SOUND=y ++# CONFIG_SOUND_BT878 is not set ++# CONFIG_SOUND_CMPCI is not set ++# CONFIG_SOUND_EMU10K1 is not set ++# CONFIG_MIDI_EMU10K1 is not set ++# CONFIG_SOUND_FUSION is not set ++# CONFIG_SOUND_CS4281 is not set ++# CONFIG_SOUND_ES1370 is not set ++# CONFIG_SOUND_ES1371 is not set ++# CONFIG_SOUND_ESSSOLO1 is not set ++# CONFIG_SOUND_MAESTRO is not set ++# CONFIG_SOUND_MAESTRO3 is not set ++# CONFIG_SOUND_ICH is not set ++# CONFIG_SOUND_RME96XX is not set ++# CONFIG_SOUND_SONICVIBES is not set ++# CONFIG_SOUND_TRIDENT is not set ++# CONFIG_SOUND_MSNDCLAS is not set ++# CONFIG_SOUND_MSNDPIN is not set ++# CONFIG_SOUND_VIA82CXXX is not set ++# CONFIG_MIDI_VIA82CXXX is not set ++# CONFIG_SOUND_OSS is not set ++# CONFIG_SOUND_WAVEARTIST is not set ++CONFIG_SOUND_PXA_AC97=y ++# CONFIG_SOUND_TVMIXER is not set ++ ++# ++# Multimedia Capabilities Port drivers ++# ++# CONFIG_MCP is not set ++# CONFIG_MCP_SA1100 is not set ++# CONFIG_MCP_UCB1200 is not set ++# CONFIG_MCP_UCB1200_AUDIO is not set ++# CONFIG_MCP_UCB1200_TS is not set ++CONFIG_MCP_UCB1400_TS=y ++ ++# ++# USB support ++# ++# CONFIG_USB is not set ++# CONFIG_USB_UHCI is not set ++# CONFIG_USB_UHCI_ALT is not set ++# CONFIG_USB_OHCI is not set ++# CONFIG_USB_OHCI_SA1111 is not set ++# CONFIG_USB_AUDIO is not set ++# CONFIG_USB_BLUETOOTH is not set ++# CONFIG_USB_STORAGE is not set ++# CONFIG_USB_STORAGE_DEBUG is not set ++# CONFIG_USB_STORAGE_DATAFAB is not set ++# CONFIG_USB_STORAGE_FREECOM is not set ++# CONFIG_USB_STORAGE_ISD200 is not set ++# CONFIG_USB_STORAGE_DPCM is not set ++# CONFIG_USB_STORAGE_HP8200e is not set ++# CONFIG_USB_STORAGE_SDDR09 is not set ++# CONFIG_USB_STORAGE_JUMPSHOT is not set ++# CONFIG_USB_ACM is not set ++# CONFIG_USB_PRINTER is not set ++# CONFIG_USB_HID is not set ++# CONFIG_USB_HIDDEV is not set ++# CONFIG_USB_KBD is not set ++# CONFIG_USB_MOUSE is not set ++# CONFIG_USB_WACOM is not set ++# CONFIG_USB_DC2XX is not set ++# CONFIG_USB_MDC800 is not set ++# CONFIG_USB_SCANNER is not set ++# CONFIG_USB_MICROTEK is not set ++# CONFIG_USB_HPUSBSCSI is not set ++# CONFIG_USB_PEGASUS is not set ++# CONFIG_USB_KAWETH is not set ++# CONFIG_USB_CATC is not set ++# CONFIG_USB_CDCETHER is not set ++# CONFIG_USB_USBNET is not set ++# CONFIG_USB_USS720 is not set ++ ++# ++# USB Serial Converter support ++# ++# CONFIG_USB_SERIAL is not set ++# CONFIG_USB_SERIAL_GENERIC is not set ++# CONFIG_USB_SERIAL_BELKIN is not set ++# CONFIG_USB_SERIAL_WHITEHEAT is not set ++# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set ++# CONFIG_USB_SERIAL_EMPEG is not set ++# CONFIG_USB_SERIAL_FTDI_SIO is not set ++# CONFIG_USB_SERIAL_VISOR is not set ++# CONFIG_USB_SERIAL_IPAQ is not set ++# CONFIG_USB_SERIAL_IR is not set ++# CONFIG_USB_SERIAL_EDGEPORT is not set ++# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set ++# CONFIG_USB_SERIAL_KEYSPAN is not set ++# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set ++# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set ++# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set ++# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set ++# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set ++# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set ++# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set ++# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set ++# CONFIG_USB_SERIAL_MCT_U232 is not set ++# CONFIG_USB_SERIAL_KLSI is not set ++# CONFIG_USB_SERIAL_PL2303 is not set ++# CONFIG_USB_SERIAL_CYBERJACK is not set ++# CONFIG_USB_SERIAL_XIRCOM is not set ++# CONFIG_USB_SERIAL_OMNINET is not set ++# CONFIG_USB_RIO500 is not set ++ ++# ++# Bluetooth support ++# ++CONFIG_BLUEZ=y ++CONFIG_BLUEZ_L2CAP=y ++ ++# ++# Bluetooth device drivers ++# ++# CONFIG_BLUEZ_HCIUSB is not set ++CONFIG_BLUEZ_HCIUART=y ++CONFIG_BLUEZ_HCIVHCI=y ++ ++# ++# Kernel hacking ++# ++CONFIG_FRAME_POINTER=y ++CONFIG_DEBUG_USER=y ++CONFIG_DEBUG_INFO=y ++# CONFIG_NO_PGT_CACHE is not set ++CONFIG_DEBUG_KERNEL=y ++# CONFIG_DEBUG_SLAB is not set ++CONFIG_MAGIC_SYSRQ=y ++# CONFIG_DEBUG_SPINLOCK is not set ++# CONFIG_DEBUG_WAITQ is not set ++CONFIG_DEBUG_BUGVERBOSE=y ++CONFIG_DEBUG_ERRORS=y ++CONFIG_DEBUG_LL=y ++# CONFIG_DEBUG_DC21285_PORT is not set ++# CONFIG_DEBUG_CLPS711X_UART2 is not set +--- /dev/null ++++ linux-2.4.27/arch/arm/def-configs/csb226 +@@ -0,0 +1,615 @@ ++# ++# Automatically generated by make menuconfig: don't edit ++# ++CONFIG_ARM=y ++# CONFIG_EISA is not set ++# CONFIG_SBUS is not set ++# CONFIG_MCA is not set ++CONFIG_UID16=y ++CONFIG_RWSEM_GENERIC_SPINLOCK=y ++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set ++# CONFIG_GENERIC_BUST_SPINLOCK is not set ++# CONFIG_GENERIC_ISA_DMA is not set ++ ++# ++# Code maturity level options ++# ++CONFIG_EXPERIMENTAL=y ++# CONFIG_OBSOLETE is not set ++ ++# ++# Loadable module support ++# ++CONFIG_MODULES=y ++# CONFIG_MODVERSIONS is not set ++CONFIG_KMOD=y ++ ++# ++# System Type ++# ++# CONFIG_ARCH_ANAKIN is not set ++# CONFIG_ARCH_ARCA5K is not set ++# CONFIG_ARCH_CLPS7500 is not set ++# CONFIG_ARCH_CLPS711X is not set ++# CONFIG_ARCH_CO285 is not set ++CONFIG_ARCH_PXA=y ++# CONFIG_ARCH_EBSA110 is not set ++# CONFIG_ARCH_CAMELOT is not set ++# CONFIG_ARCH_FOOTBRIDGE is not set ++# CONFIG_ARCH_INTEGRATOR is not set ++# CONFIG_ARCH_OMAHA is not set ++# CONFIG_ARCH_L7200 is not set ++# CONFIG_ARCH_MX1ADS is not set ++# CONFIG_ARCH_RPC is not set ++# CONFIG_ARCH_RISCSTATION is not set ++# CONFIG_ARCH_SA1100 is not set ++# CONFIG_ARCH_SHARK is not set ++# CONFIG_ARCH_AT91RM9200DK is not set ++ ++# ++# Archimedes/A5000 Implementations ++# ++# CONFIG_ARCH_ARC is not set ++# CONFIG_ARCH_A5K is not set ++ ++# ++# Footbridge Implementations ++# ++# CONFIG_ARCH_CATS is not set ++# CONFIG_ARCH_PERSONAL_SERVER is not set ++# CONFIG_ARCH_EBSA285_ADDIN is not set ++# CONFIG_ARCH_EBSA285_HOST is not set ++# CONFIG_ARCH_NETWINDER is not set ++ ++# ++# SA11x0 Implementations ++# ++# CONFIG_SA1100_ACCELENT is not set ++# CONFIG_SA1100_ASSABET is not set ++# CONFIG_ASSABET_NEPONSET is not set ++# CONFIG_SA1100_ADSBITSY is not set ++# CONFIG_SA1100_BRUTUS is not set ++# CONFIG_SA1100_CEP is not set ++# CONFIG_SA1100_CERF is not set ++# CONFIG_SA1100_H3100 is not set ++# CONFIG_SA1100_H3600 is not set ++# CONFIG_SA1100_H3800 is not set ++# CONFIG_SA1100_H3XXX is not set ++# CONFIG_SA1100_EXTENEX1 is not set ++# CONFIG_SA1100_FLEXANET is not set ++# CONFIG_SA1100_FREEBIRD is not set ++# CONFIG_SA1100_FRODO is not set ++# CONFIG_SA1100_GRAPHICSCLIENT is not set ++# CONFIG_SA1100_GRAPHICSMASTER is not set ++# CONFIG_SA1100_HACKKIT is not set ++# CONFIG_SA1100_BADGE4 is not set ++# CONFIG_SA1100_JORNADA720 is not set ++# CONFIG_SA1100_HUW_WEBPANEL is not set ++# CONFIG_SA1100_ITSY is not set ++# CONFIG_SA1100_LART is not set ++# CONFIG_SA1100_NANOENGINE is not set ++# CONFIG_SA1100_OMNIMETER is not set ++# CONFIG_SA1100_PANGOLIN is not set ++# CONFIG_SA1100_PLEB is not set ++# CONFIG_SA1100_PT_SYSTEM3 is not set ++# CONFIG_SA1100_SHANNON is not set ++# CONFIG_SA1100_SHERMAN is not set ++# CONFIG_SA1100_SIMPAD is not set ++# CONFIG_SA1100_SIMPUTER is not set ++# CONFIG_SA1100_PFS168 is not set ++# CONFIG_SA1100_VICTOR is not set ++# CONFIG_SA1100_XP860 is not set ++# CONFIG_SA1100_YOPY is not set ++# CONFIG_SA1100_USB is not set ++# CONFIG_SA1100_USB_NETLINK is not set ++# CONFIG_SA1100_USB_CHAR is not set ++# CONFIG_H3600_SLEEVE is not set ++ ++# ++# Intel PXA250/210 Board ++# ++# CONFIG_ARCH_PXA_IDP is not set ++# CONFIG_ARCH_INNOKOM is not set ++CONFIG_ARCH_CSB226=y ++# CONFIG_ARCH_LUBBOCK is not set ++# CONFIG_ARCH_PXA_CERF is not set ++# CONFIG_PXA_USB is not set ++# CONFIG_PXA_USB_NETLINK is not set ++# CONFIG_PXA_USB_CHAR is not set ++ ++# ++# CLPS711X/EP721X Implementations ++# ++# CONFIG_ARCH_AUTCPU12 is not set ++# CONFIG_ARCH_CDB89712 is not set ++# CONFIG_ARCH_CLEP7312 is not set ++# CONFIG_ARCH_EDB7211 is not set ++# CONFIG_ARCH_P720T is not set ++# CONFIG_ARCH_FORTUNET is not set ++# CONFIG_ARCH_EP7211 is not set ++# CONFIG_ARCH_EP7212 is not set ++# CONFIG_ARCH_ACORN is not set ++# CONFIG_FOOTBRIDGE is not set ++# CONFIG_FOOTBRIDGE_HOST is not set ++# CONFIG_FOOTBRIDGE_ADDIN is not set ++CONFIG_CPU_32=y ++# CONFIG_CPU_26 is not set ++# CONFIG_CPU_ARM610 is not set ++# CONFIG_CPU_ARM710 is not set ++# CONFIG_CPU_ARM720T is not set ++# CONFIG_CPU_ARM920T is not set ++# CONFIG_CPU_ARM922T is not set ++# CONFIG_PLD is not set ++# CONFIG_CPU_ARM926T is not set ++# CONFIG_CPU_ARM1020 is not set ++# CONFIG_CPU_ARM1026 is not set ++# CONFIG_CPU_SA110 is not set ++# CONFIG_CPU_SA1100 is not set ++CONFIG_CPU_32v5=y ++CONFIG_CPU_XSCALE=y ++CONFIG_XSCALE_CACHE_ERRATA=y ++# CONFIG_CPU_32v3 is not set ++# CONFIG_CPU_32v4 is not set ++# CONFIG_DISCONTIGMEM is not set ++ ++# ++# General setup ++# ++# CONFIG_PCI is not set ++# CONFIG_ISA is not set ++# CONFIG_ISA_DMA is not set ++# CONFIG_ZBOOT_ROM is not set ++CONFIG_ZBOOT_ROM_TEXT=0 ++CONFIG_ZBOOT_ROM_BSS=0 ++# CONFIG_CPU_FREQ is not set ++# CONFIG_HOTPLUG is not set ++# CONFIG_PCMCIA is not set ++# CONFIG_MMC is not set ++CONFIG_NET=y ++CONFIG_SYSVIPC=y ++# CONFIG_BSD_PROCESS_ACCT is not set ++CONFIG_SYSCTL=y ++# CONFIG_XIP_KERNEL is not set ++CONFIG_FPE_NWFPE=y ++# CONFIG_FPE_FASTFPE is not set ++CONFIG_KCORE_ELF=y ++# CONFIG_KCORE_AOUT is not set ++# CONFIG_BINFMT_AOUT is not set ++CONFIG_BINFMT_ELF=y ++# CONFIG_BINFMT_MISC is not set ++# CONFIG_PM is not set ++# CONFIG_ARTHUR is not set ++CONFIG_CMDLINE="console=ttyS0,19200" ++CONFIG_ALIGNMENT_TRAP=y ++CONFIG_ARM_HWTIMER=y ++ ++# ++# Parallel port support ++# ++# CONFIG_PARPORT is not set ++ ++# ++# Memory Technology Devices (MTD) ++# ++# CONFIG_MTD is not set ++ ++# ++# Plug and Play configuration ++# ++# CONFIG_PNP is not set ++# CONFIG_ISAPNP is not set ++ ++# ++# Block devices ++# ++# CONFIG_BLK_DEV_FD is not set ++# CONFIG_BLK_DEV_XD is not set ++# CONFIG_PARIDE is not set ++# CONFIG_BLK_CPQ_DA is not set ++# CONFIG_BLK_CPQ_CISS_DA is not set ++# CONFIG_CISS_SCSI_TAPE is not set ++# CONFIG_BLK_DEV_DAC960 is not set ++# CONFIG_BLK_DEV_UMEM is not set ++# CONFIG_BLK_DEV_LOOP is not set ++# CONFIG_BLK_DEV_NBD is not set ++# CONFIG_BLK_DEV_RAM is not set ++# CONFIG_BLK_DEV_INITRD is not set ++ ++# ++# Multi-device support (RAID and LVM) ++# ++# CONFIG_MD is not set ++# CONFIG_BLK_DEV_MD is not set ++# CONFIG_MD_LINEAR is not set ++# CONFIG_MD_RAID0 is not set ++# CONFIG_MD_RAID1 is not set ++# CONFIG_MD_RAID5 is not set ++# CONFIG_MD_MULTIPATH is not set ++# CONFIG_BLK_DEV_LVM is not set ++ ++# ++# Networking options ++# ++# CONFIG_PACKET is not set ++# CONFIG_NETLINK_DEV is not set ++# CONFIG_NETFILTER is not set ++# CONFIG_FILTER is not set ++CONFIG_UNIX=y ++CONFIG_INET=y ++# CONFIG_IP_MULTICAST is not set ++# CONFIG_IP_ADVANCED_ROUTER is not set ++CONFIG_IP_PNP=y ++# CONFIG_IP_PNP_DHCP is not set ++CONFIG_IP_PNP_BOOTP=y ++# CONFIG_IP_PNP_RARP is not set ++# CONFIG_NET_IPIP is not set ++# CONFIG_NET_IPGRE is not set ++# CONFIG_ARPD is not set ++# CONFIG_INET_ECN is not set ++# CONFIG_SYN_COOKIES is not set ++# CONFIG_IPV6 is not set ++# CONFIG_KHTTPD is not set ++# CONFIG_ATM is not set ++# CONFIG_VLAN_8021Q is not set ++# CONFIG_IPX is not set ++# CONFIG_ATALK is not set ++ ++# ++# Appletalk devices ++# ++# CONFIG_DEV_APPLETALK is not set ++# CONFIG_DECNET is not set ++# CONFIG_BRIDGE is not set ++# CONFIG_X25 is not set ++# CONFIG_LAPB is not set ++# CONFIG_LLC is not set ++# CONFIG_NET_DIVERT is not set ++# CONFIG_ECONET is not set ++# CONFIG_WAN_ROUTER is not set ++# CONFIG_NET_FASTROUTE is not set ++# CONFIG_NET_HW_FLOWCONTROL is not set ++ ++# ++# QoS and/or fair queueing ++# ++# CONFIG_NET_SCHED is not set ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++ ++# ++# Network device support ++# ++CONFIG_NETDEVICES=y ++ ++# ++# ARCnet devices ++# ++# CONFIG_ARCNET is not set ++# CONFIG_DUMMY is not set ++# CONFIG_BONDING is not set ++# CONFIG_EQUALIZER is not set ++# CONFIG_TUN is not set ++# CONFIG_ETHERTAP is not set ++ ++# ++# Ethernet (10 or 100Mbit) ++# ++CONFIG_NET_ETHERNET=y ++# CONFIG_ARM_AM79C961A is not set ++CONFIG_ARM_CIRRUS=y ++# CONFIG_SUNLANCE is not set ++# CONFIG_SUNBMAC is not set ++# CONFIG_SUNQE is not set ++# CONFIG_SUNGEM is not set ++# CONFIG_NET_VENDOR_3COM is not set ++# CONFIG_LANCE is not set ++# CONFIG_NET_VENDOR_SMC is not set ++# CONFIG_NET_VENDOR_RACAL is not set ++# CONFIG_NET_ISA is not set ++# CONFIG_NET_PCI is not set ++# CONFIG_NET_POCKET is not set ++ ++# ++# Ethernet (1000 Mbit) ++# ++# CONFIG_ACENIC is not set ++# CONFIG_DL2K is not set ++# CONFIG_MYRI_SBUS is not set ++# CONFIG_NS83820 is not set ++# CONFIG_HAMACHI is not set ++# CONFIG_YELLOWFIN is not set ++# CONFIG_SK98LIN is not set ++# CONFIG_TIGON3 is not set ++# CONFIG_FDDI is not set ++# CONFIG_HIPPI is not set ++# CONFIG_PLIP is not set ++# CONFIG_PPP is not set ++# CONFIG_SLIP is not set ++ ++# ++# Wireless LAN (non-hamradio) ++# ++# CONFIG_NET_RADIO is not set ++ ++# ++# Token Ring devices ++# ++# CONFIG_TR is not set ++# CONFIG_NET_FC is not set ++# CONFIG_RCPCI is not set ++# CONFIG_SHAPER is not set ++ ++# ++# Wan interfaces ++# ++# CONFIG_WAN is not set ++ ++# ++# Amateur Radio support ++# ++# CONFIG_HAMRADIO is not set ++ ++# ++# IrDA (infrared) support ++# ++# CONFIG_IRDA is not set ++ ++# ++# ATA/ATAPI/MFM/RLL support ++# ++# CONFIG_IDE is not set ++# CONFIG_BLK_DEV_IDE_MODES is not set ++# CONFIG_BLK_DEV_HD is not set ++ ++# ++# SCSI support ++# ++# CONFIG_SCSI is not set ++ ++# ++# I2O device support ++# ++# CONFIG_I2O is not set ++# CONFIG_I2O_BLOCK is not set ++# CONFIG_I2O_LAN is not set ++# CONFIG_I2O_SCSI is not set ++# CONFIG_I2O_PROC is not set ++ ++# ++# ISDN subsystem ++# ++# CONFIG_ISDN is not set ++ ++# ++# Input core support ++# ++# CONFIG_INPUT is not set ++# CONFIG_INPUT_KEYBDEV is not set ++# CONFIG_INPUT_MOUSEDEV is not set ++# CONFIG_INPUT_JOYDEV is not set ++# CONFIG_INPUT_EVDEV is not set ++ ++# ++# Character devices ++# ++# CONFIG_VT is not set ++CONFIG_SERIAL=y ++CONFIG_SERIAL_CONSOLE=y ++# CONFIG_SERIAL_EXTENDED is not set ++# CONFIG_SERIAL_NONSTANDARD is not set ++ ++# ++# Serial drivers ++# ++# CONFIG_SERIAL_ANAKIN is not set ++# CONFIG_SERIAL_ANAKIN_CONSOLE is not set ++# CONFIG_SERIAL_AMBA is not set ++# CONFIG_SERIAL_AMBA_CONSOLE is not set ++# CONFIG_SERIAL_CLPS711X is not set ++# CONFIG_SERIAL_CLPS711X_CONSOLE is not set ++# CONFIG_SERIAL_21285 is not set ++# CONFIG_SERIAL_21285_OLD is not set ++# CONFIG_SERIAL_21285_CONSOLE is not set ++# CONFIG_SERIAL_UART00 is not set ++# CONFIG_SERIAL_UART00_CONSOLE is not set ++# CONFIG_SERIAL_SA1100 is not set ++# CONFIG_SERIAL_SA1100_CONSOLE is not set ++# CONFIG_SERIAL_OMAHA is not set ++# CONFIG_SERIAL_OMAHA_CONSOLE is not set ++# CONFIG_SERIAL_8250 is not set ++# CONFIG_SERIAL_8250_CONSOLE is not set ++# CONFIG_SERIAL_8250_EXTENDED is not set ++# CONFIG_SERIAL_8250_MANY_PORTS is not set ++# CONFIG_SERIAL_8250_SHARE_IRQ is not set ++# CONFIG_SERIAL_8250_DETECT_IRQ is not set ++# CONFIG_SERIAL_8250_MULTIPORT is not set ++# CONFIG_SERIAL_8250_HUB6 is not set ++CONFIG_UNIX98_PTYS=y ++CONFIG_UNIX98_PTY_COUNT=256 ++ ++# ++# I2C support ++# ++# CONFIG_I2C is not set ++ ++# ++# L3 serial bus support ++# ++# CONFIG_L3 is not set ++# CONFIG_L3_ALGOBIT is not set ++# CONFIG_L3_BIT_SA1100_GPIO is not set ++# CONFIG_L3_SA1111 is not set ++# CONFIG_BIT_SA1100_GPIO is not set ++ ++# ++# Mice ++# ++# CONFIG_BUSMOUSE is not set ++# CONFIG_MOUSE is not set ++ ++# ++# Joysticks ++# ++# CONFIG_INPUT_GAMEPORT is not set ++# CONFIG_QIC02_TAPE is not set ++ ++# ++# Watchdog Cards ++# ++# CONFIG_WATCHDOG is not set ++# CONFIG_NVRAM is not set ++# CONFIG_RTC is not set ++# CONFIG_PXA_RTC is not set ++# CONFIG_DTLK is not set ++# CONFIG_R3964 is not set ++# CONFIG_APPLICOM is not set ++ ++# ++# Ftape, the floppy tape device driver ++# ++# CONFIG_FTAPE is not set ++# CONFIG_AGP is not set ++# CONFIG_DRM is not set ++ ++# ++# Multimedia devices ++# ++# CONFIG_VIDEO_DEV is not set ++ ++# ++# File systems ++# ++# CONFIG_QUOTA is not set ++# CONFIG_AUTOFS_FS is not set ++# CONFIG_AUTOFS4_FS is not set ++# CONFIG_REISERFS_FS is not set ++# CONFIG_REISERFS_CHECK is not set ++# CONFIG_REISERFS_PROC_INFO is not set ++# CONFIG_ADFS_FS is not set ++# CONFIG_ADFS_FS_RW is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_BFS_FS is not set ++# CONFIG_EXT3_FS is not set ++# CONFIG_JBD is not set ++# CONFIG_JBD_DEBUG is not set ++# CONFIG_FAT_FS is not set ++# CONFIG_MSDOS_FS is not set ++# CONFIG_UMSDOS_FS is not set ++# CONFIG_VFAT_FS is not set ++# CONFIG_EFS_FS is not set ++# CONFIG_JFFS_FS is not set ++# CONFIG_JFFS2_FS is not set ++# CONFIG_CRAMFS is not set ++# CONFIG_TMPFS is not set ++CONFIG_RAMFS=y ++# CONFIG_ISO9660_FS is not set ++# CONFIG_JOLIET is not set ++# CONFIG_ZISOFS is not set ++# CONFIG_MINIX_FS is not set ++# CONFIG_VXFS_FS is not set ++# CONFIG_NTFS_FS is not set ++# CONFIG_NTFS_RW is not set ++# CONFIG_HPFS_FS is not set ++CONFIG_PROC_FS=y ++# CONFIG_DEVFS_FS is not set ++# CONFIG_DEVFS_MOUNT is not set ++# CONFIG_DEVFS_DEBUG is not set ++CONFIG_DEVPTS_FS=y ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_QNX4FS_RW is not set ++# CONFIG_ROMFS_FS is not set ++# CONFIG_EXT2_FS is not set ++# CONFIG_SYSV_FS is not set ++# CONFIG_UDF_FS is not set ++# CONFIG_UDF_RW is not set ++# CONFIG_UFS_FS is not set ++# CONFIG_UFS_FS_WRITE is not set ++ ++# ++# Network File Systems ++# ++# CONFIG_CODA_FS is not set ++# CONFIG_INTERMEZZO_FS is not set ++CONFIG_NFS_FS=y ++# CONFIG_NFS_V3 is not set ++CONFIG_ROOT_NFS=y ++# CONFIG_NFSD is not set ++# CONFIG_NFSD_V3 is not set ++CONFIG_SUNRPC=y ++CONFIG_LOCKD=y ++# CONFIG_SMB_FS is not set ++# CONFIG_NCP_FS is not set ++# CONFIG_NCPFS_PACKET_SIGNING is not set ++# CONFIG_NCPFS_IOCTL_LOCKING is not set ++# CONFIG_NCPFS_STRONG is not set ++# CONFIG_NCPFS_NFS_NS is not set ++# CONFIG_NCPFS_OS2_NS is not set ++# CONFIG_NCPFS_SMALLDOS is not set ++# CONFIG_NCPFS_NLS is not set ++# CONFIG_NCPFS_EXTRAS is not set ++# CONFIG_ZISOFS_FS is not set ++# CONFIG_ZLIB_FS_INFLATE is not set ++ ++# ++# Partition Types ++# ++CONFIG_PARTITION_ADVANCED=y ++# CONFIG_ACORN_PARTITION is not set ++# CONFIG_OSF_PARTITION is not set ++# CONFIG_AMIGA_PARTITION is not set ++# CONFIG_ATARI_PARTITION is not set ++# CONFIG_MAC_PARTITION is not set ++# CONFIG_MSDOS_PARTITION is not set ++# CONFIG_LDM_PARTITION is not set ++# CONFIG_SGI_PARTITION is not set ++# CONFIG_ULTRIX_PARTITION is not set ++# CONFIG_SUN_PARTITION is not set ++# CONFIG_SMB_NLS is not set ++# CONFIG_NLS is not set ++ ++# ++# Sound ++# ++# CONFIG_SOUND is not set ++ ++# ++# Multimedia Capabilities Port drivers ++# ++# CONFIG_MCP is not set ++# CONFIG_MCP_SA1100 is not set ++# CONFIG_MCP_UCB1200 is not set ++# CONFIG_MCP_UCB1200_AUDIO is not set ++# CONFIG_MCP_UCB1200_TS is not set ++# CONFIG_MCP_UCB1400_TS is not set ++ ++# ++# USB support ++# ++# CONFIG_USB is not set ++ ++# ++# Bluetooth support ++# ++# CONFIG_BLUEZ is not set ++ ++# ++# Kernel hacking ++# ++CONFIG_FRAME_POINTER=y ++CONFIG_DEBUG_USER=y ++CONFIG_DEBUG_INFO=y ++# CONFIG_NO_PGT_CACHE is not set ++CONFIG_DEBUG_KERNEL=y ++CONFIG_DEBUG_SLAB=y ++CONFIG_MAGIC_SYSRQ=y ++CONFIG_DEBUG_SPINLOCK=y ++CONFIG_DEBUG_WAITQ=y ++CONFIG_DEBUG_BUGVERBOSE=y ++CONFIG_DEBUG_ERRORS=y ++CONFIG_DEBUG_LL=y ++# CONFIG_DEBUG_DC21285_PORT is not set ++# CONFIG_DEBUG_CLPS711X_UART2 is not set +--- /dev/null ++++ linux-2.4.27/arch/arm/def-configs/innokom +@@ -0,0 +1,699 @@ ++# ++# Automatically generated by make menuconfig: don't edit ++# ++CONFIG_ARM=y ++# CONFIG_EISA is not set ++# CONFIG_SBUS is not set ++# CONFIG_MCA is not set ++CONFIG_UID16=y ++CONFIG_RWSEM_GENERIC_SPINLOCK=y ++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set ++# CONFIG_GENERIC_BUST_SPINLOCK is not set ++# CONFIG_GENERIC_ISA_DMA is not set ++ ++# ++# Code maturity level options ++# ++CONFIG_EXPERIMENTAL=y ++# CONFIG_OBSOLETE is not set ++ ++# ++# Loadable module support ++# ++CONFIG_MODULES=y ++# CONFIG_MODVERSIONS is not set ++CONFIG_KMOD=y ++ ++# ++# System Type ++# ++# CONFIG_ARCH_ANAKIN is not set ++# CONFIG_ARCH_ARCA5K is not set ++# CONFIG_ARCH_CLPS7500 is not set ++# CONFIG_ARCH_CLPS711X is not set ++# CONFIG_ARCH_CO285 is not set ++CONFIG_ARCH_PXA=y ++# CONFIG_ARCH_EBSA110 is not set ++# CONFIG_ARCH_CAMELOT is not set ++# CONFIG_ARCH_FOOTBRIDGE is not set ++# CONFIG_ARCH_INTEGRATOR is not set ++# CONFIG_ARCH_OMAHA is not set ++# CONFIG_ARCH_L7200 is not set ++# CONFIG_ARCH_MX1ADS is not set ++# CONFIG_ARCH_RPC is not set ++# CONFIG_ARCH_RISCSTATION is not set ++# CONFIG_ARCH_SA1100 is not set ++# CONFIG_ARCH_SHARK is not set ++# CONFIG_ARCH_AT91RM9200DK is not set ++ ++# ++# Archimedes/A5000 Implementations ++# ++# CONFIG_ARCH_ARC is not set ++# CONFIG_ARCH_A5K is not set ++ ++# ++# Footbridge Implementations ++# ++# CONFIG_ARCH_CATS is not set ++# CONFIG_ARCH_PERSONAL_SERVER is not set ++# CONFIG_ARCH_EBSA285_ADDIN is not set ++# CONFIG_ARCH_EBSA285_HOST is not set ++# CONFIG_ARCH_NETWINDER is not set ++ ++# ++# SA11x0 Implementations ++# ++# CONFIG_SA1100_ACCELENT is not set ++# CONFIG_SA1100_ASSABET is not set ++# CONFIG_ASSABET_NEPONSET is not set ++# CONFIG_SA1100_ADSBITSY is not set ++# CONFIG_SA1100_BRUTUS is not set ++# CONFIG_SA1100_CEP is not set ++# CONFIG_SA1100_CERF is not set ++# CONFIG_SA1100_H3100 is not set ++# CONFIG_SA1100_H3600 is not set ++# CONFIG_SA1100_H3800 is not set ++# CONFIG_SA1100_H3XXX is not set ++# CONFIG_SA1100_EXTENEX1 is not set ++# CONFIG_SA1100_FLEXANET is not set ++# CONFIG_SA1100_FREEBIRD is not set ++# CONFIG_SA1100_FRODO is not set ++# CONFIG_SA1100_GRAPHICSCLIENT is not set ++# CONFIG_SA1100_GRAPHICSMASTER is not set ++# CONFIG_SA1100_HACKKIT is not set ++# CONFIG_SA1100_BADGE4 is not set ++# CONFIG_SA1100_JORNADA720 is not set ++# CONFIG_SA1100_HUW_WEBPANEL is not set ++# CONFIG_SA1100_ITSY is not set ++# CONFIG_SA1100_LART is not set ++# CONFIG_SA1100_NANOENGINE is not set ++# CONFIG_SA1100_OMNIMETER is not set ++# CONFIG_SA1100_PANGOLIN is not set ++# CONFIG_SA1100_PLEB is not set ++# CONFIG_SA1100_PT_SYSTEM3 is not set ++# CONFIG_SA1100_SHANNON is not set ++# CONFIG_SA1100_SHERMAN is not set ++# CONFIG_SA1100_SIMPAD is not set ++# CONFIG_SA1100_SIMPUTER is not set ++# CONFIG_SA1100_PFS168 is not set ++# CONFIG_SA1100_VICTOR is not set ++# CONFIG_SA1100_XP860 is not set ++# CONFIG_SA1100_YOPY is not set ++# CONFIG_SA1100_USB is not set ++# CONFIG_SA1100_USB_NETLINK is not set ++# CONFIG_SA1100_USB_CHAR is not set ++# CONFIG_H3600_SLEEVE is not set ++ ++# ++# Intel PXA250/210 Board ++# ++# CONFIG_ARCH_PXA_IDP is not set ++CONFIG_ARCH_INNOKOM=y ++# CONFIG_ARCH_CSB226 is not set ++# CONFIG_ARCH_LUBBOCK is not set ++# CONFIG_ARCH_PXA_CERF is not set ++# CONFIG_PXA_USB is not set ++# CONFIG_PXA_USB_NETLINK is not set ++# CONFIG_PXA_USB_CHAR is not set ++ ++# ++# CLPS711X/EP721X Implementations ++# ++# CONFIG_ARCH_AUTCPU12 is not set ++# CONFIG_ARCH_CDB89712 is not set ++# CONFIG_ARCH_CLEP7312 is not set ++# CONFIG_ARCH_EDB7211 is not set ++# CONFIG_ARCH_P720T is not set ++# CONFIG_ARCH_FORTUNET is not set ++# CONFIG_ARCH_EP7211 is not set ++# CONFIG_ARCH_EP7212 is not set ++# CONFIG_ARCH_ACORN is not set ++# CONFIG_FOOTBRIDGE is not set ++# CONFIG_FOOTBRIDGE_HOST is not set ++# CONFIG_FOOTBRIDGE_ADDIN is not set ++CONFIG_CPU_32=y ++# CONFIG_CPU_26 is not set ++# CONFIG_CPU_ARM610 is not set ++# CONFIG_CPU_ARM710 is not set ++# CONFIG_CPU_ARM720T is not set ++# CONFIG_CPU_ARM920T is not set ++# CONFIG_CPU_ARM922T is not set ++# CONFIG_PLD is not set ++# CONFIG_CPU_ARM926T is not set ++# CONFIG_CPU_ARM1020 is not set ++# CONFIG_CPU_ARM1026 is not set ++# CONFIG_CPU_SA110 is not set ++# CONFIG_CPU_SA1100 is not set ++CONFIG_CPU_32v5=y ++CONFIG_CPU_XSCALE=y ++CONFIG_XSCALE_CACHE_ERRATA=y ++# CONFIG_CPU_32v3 is not set ++# CONFIG_CPU_32v4 is not set ++# CONFIG_DISCONTIGMEM is not set ++ ++# ++# General setup ++# ++# CONFIG_PCI is not set ++# CONFIG_ISA is not set ++# CONFIG_ISA_DMA is not set ++# CONFIG_ZBOOT_ROM is not set ++CONFIG_ZBOOT_ROM_TEXT=0 ++CONFIG_ZBOOT_ROM_BSS=0 ++# CONFIG_CPU_FREQ is not set ++# CONFIG_HOTPLUG is not set ++# CONFIG_PCMCIA is not set ++# CONFIG_MMC is not set ++CONFIG_NET=y ++CONFIG_SYSVIPC=y ++# CONFIG_BSD_PROCESS_ACCT is not set ++CONFIG_SYSCTL=y ++# CONFIG_XIP_KERNEL is not set ++CONFIG_FPE_NWFPE=y ++# CONFIG_FPE_FASTFPE is not set ++CONFIG_KCORE_ELF=y ++# CONFIG_KCORE_AOUT is not set ++# CONFIG_BINFMT_AOUT is not set ++CONFIG_BINFMT_ELF=y ++# CONFIG_BINFMT_MISC is not set ++# CONFIG_PM is not set ++# CONFIG_ARTHUR is not set ++CONFIG_CMDLINE="root=/dev/nfs mem=32M ip=dhcp console=ttyS0,19200" ++CONFIG_ALIGNMENT_TRAP=y ++CONFIG_ARM_HWTIMER=y ++ ++# ++# Parallel port support ++# ++# CONFIG_PARPORT is not set ++ ++# ++# Memory Technology Devices (MTD) ++# ++CONFIG_MTD=y ++# CONFIG_MTD_DEBUG is not set ++CONFIG_MTD_PARTITIONS=y ++# CONFIG_MTD_CONCAT is not set ++# CONFIG_MTD_REDBOOT_PARTS is not set ++CONFIG_MTD_CMDLINE_PARTS=y ++# CONFIG_MTD_AFS_PARTS is not set ++CONFIG_MTD_CHAR=y ++CONFIG_MTD_BLOCK=y ++# CONFIG_FTL is not set ++# CONFIG_NFTL is not set ++ ++# ++# RAM/ROM/Flash chip drivers ++# ++CONFIG_MTD_CFI=y ++# CONFIG_MTD_JEDECPROBE is not set ++CONFIG_MTD_GEN_PROBE=y ++# CONFIG_MTD_CFI_ADV_OPTIONS is not set ++CONFIG_MTD_CFI_INTELEXT=y ++CONFIG_MTD_CFI_AMDSTD=y ++# CONFIG_MTD_CFI_STAA is not set ++# CONFIG_MTD_RAM is not set ++# CONFIG_MTD_ROM is not set ++# CONFIG_MTD_ABSENT is not set ++# CONFIG_MTD_OBSOLETE_CHIPS is not set ++# CONFIG_MTD_AMDSTD is not set ++# CONFIG_MTD_SHARP is not set ++# CONFIG_MTD_JEDEC is not set ++ ++# ++# Mapping drivers for chip access ++# ++# CONFIG_MTD_PHYSMAP is not set ++# CONFIG_MTD_NORA is not set ++# CONFIG_MTD_ARM_INTEGRATOR is not set ++# CONFIG_MTD_CDB89712 is not set ++# CONFIG_MTD_SA1100 is not set ++# CONFIG_MTD_DC21285 is not set ++# CONFIG_MTD_IQ80310 is not set ++# CONFIG_MTD_LUBBOCK is not set ++# CONFIG_MTD_EPXA10DB is not set ++# CONFIG_MTD_FORTUNET is not set ++CONFIG_MTD_INNOKOM=y ++CONFIG_MTD_INNOKOM_16MB=y ++# CONFIG_MTD_INNOKOM_64MB is not set ++# CONFIG_MTD_AUTCPU12 is not set ++# CONFIG_MTD_EDB7312 is not set ++# CONFIG_MTD_IMPA7 is not set ++# CONFIG_MTD_CEIVA is not set ++# CONFIG_MTD_PCI is not set ++# CONFIG_MTD_PCMCIA is not set ++ ++# ++# Self-contained MTD device drivers ++# ++# CONFIG_MTD_PMC551 is not set ++# CONFIG_MTD_SLRAM is not set ++# CONFIG_MTD_MTDRAM is not set ++# CONFIG_MTD_BLKMTD is not set ++# CONFIG_MTD_DOC1000 is not set ++# CONFIG_MTD_DOC2000 is not set ++# CONFIG_MTD_DOC2001 is not set ++# CONFIG_MTD_DOCPROBE is not set ++ ++# ++# NAND Flash Device Drivers ++# ++# CONFIG_MTD_NAND is not set ++ ++# ++# Plug and Play configuration ++# ++# CONFIG_PNP is not set ++# CONFIG_ISAPNP is not set ++ ++# ++# Block devices ++# ++# CONFIG_BLK_DEV_FD is not set ++# CONFIG_BLK_DEV_XD is not set ++# CONFIG_PARIDE is not set ++# CONFIG_BLK_CPQ_DA is not set ++# CONFIG_BLK_CPQ_CISS_DA is not set ++# CONFIG_CISS_SCSI_TAPE is not set ++# CONFIG_BLK_DEV_DAC960 is not set ++# CONFIG_BLK_DEV_UMEM is not set ++# CONFIG_BLK_DEV_LOOP is not set ++# CONFIG_BLK_DEV_NBD is not set ++# CONFIG_BLK_DEV_RAM is not set ++# CONFIG_BLK_DEV_INITRD is not set ++ ++# ++# Multi-device support (RAID and LVM) ++# ++# CONFIG_MD is not set ++# CONFIG_BLK_DEV_MD is not set ++# CONFIG_MD_LINEAR is not set ++# CONFIG_MD_RAID0 is not set ++# CONFIG_MD_RAID1 is not set ++# CONFIG_MD_RAID5 is not set ++# CONFIG_MD_MULTIPATH is not set ++# CONFIG_BLK_DEV_LVM is not set ++ ++# ++# Networking options ++# ++# CONFIG_PACKET is not set ++# CONFIG_NETLINK_DEV is not set ++# CONFIG_NETFILTER is not set ++# CONFIG_FILTER is not set ++CONFIG_UNIX=y ++CONFIG_INET=y ++# CONFIG_IP_MULTICAST is not set ++# CONFIG_IP_ADVANCED_ROUTER is not set ++CONFIG_IP_PNP=y ++CONFIG_IP_PNP_DHCP=y ++# CONFIG_IP_PNP_BOOTP is not set ++# CONFIG_IP_PNP_RARP is not set ++# CONFIG_NET_IPIP is not set ++# CONFIG_NET_IPGRE is not set ++# CONFIG_ARPD is not set ++# CONFIG_INET_ECN is not set ++# CONFIG_SYN_COOKIES is not set ++# CONFIG_IPV6 is not set ++# CONFIG_KHTTPD is not set ++# CONFIG_ATM is not set ++# CONFIG_VLAN_8021Q is not set ++# CONFIG_IPX is not set ++# CONFIG_ATALK is not set ++ ++# ++# Appletalk devices ++# ++# CONFIG_DEV_APPLETALK is not set ++# CONFIG_DECNET is not set ++# CONFIG_BRIDGE is not set ++# CONFIG_X25 is not set ++# CONFIG_LAPB is not set ++# CONFIG_LLC is not set ++# CONFIG_NET_DIVERT is not set ++# CONFIG_ECONET is not set ++# CONFIG_WAN_ROUTER is not set ++# CONFIG_NET_FASTROUTE is not set ++# CONFIG_NET_HW_FLOWCONTROL is not set ++ ++# ++# QoS and/or fair queueing ++# ++# CONFIG_NET_SCHED is not set ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++ ++# ++# Network device support ++# ++CONFIG_NETDEVICES=y ++ ++# ++# ARCnet devices ++# ++# CONFIG_ARCNET is not set ++# CONFIG_DUMMY is not set ++# CONFIG_BONDING is not set ++# CONFIG_EQUALIZER is not set ++# CONFIG_TUN is not set ++# CONFIG_ETHERTAP is not set ++ ++# ++# Ethernet (10 or 100Mbit) ++# ++CONFIG_NET_ETHERNET=y ++# CONFIG_ARM_AM79C961A is not set ++# CONFIG_ARM_CIRRUS is not set ++# CONFIG_SUNLANCE is not set ++# CONFIG_SUNBMAC is not set ++# CONFIG_SUNQE is not set ++# CONFIG_SUNGEM is not set ++# CONFIG_NET_VENDOR_3COM is not set ++# CONFIG_LANCE is not set ++CONFIG_NET_VENDOR_SMC=y ++# CONFIG_WD80x3 is not set ++# CONFIG_ULTRAMCA is not set ++# CONFIG_ULTRA is not set ++# CONFIG_ULTRA32 is not set ++# CONFIG_SMC9194 is not set ++CONFIG_SMC91X=y ++# CONFIG_NET_VENDOR_RACAL is not set ++# CONFIG_NET_ISA is not set ++# CONFIG_NET_PCI is not set ++# CONFIG_NET_POCKET is not set ++ ++# ++# Ethernet (1000 Mbit) ++# ++# CONFIG_ACENIC is not set ++# CONFIG_DL2K is not set ++# CONFIG_MYRI_SBUS is not set ++# CONFIG_NS83820 is not set ++# CONFIG_HAMACHI is not set ++# CONFIG_YELLOWFIN is not set ++# CONFIG_SK98LIN is not set ++# CONFIG_TIGON3 is not set ++# CONFIG_FDDI is not set ++# CONFIG_HIPPI is not set ++# CONFIG_PLIP is not set ++# CONFIG_PPP is not set ++# CONFIG_SLIP is not set ++ ++# ++# Wireless LAN (non-hamradio) ++# ++# CONFIG_NET_RADIO is not set ++ ++# ++# Token Ring devices ++# ++# CONFIG_TR is not set ++# CONFIG_NET_FC is not set ++# CONFIG_RCPCI is not set ++# CONFIG_SHAPER is not set ++ ++# ++# Wan interfaces ++# ++# CONFIG_WAN is not set ++ ++# ++# Amateur Radio support ++# ++# CONFIG_HAMRADIO is not set ++ ++# ++# IrDA (infrared) support ++# ++# CONFIG_IRDA is not set ++ ++# ++# ATA/ATAPI/MFM/RLL support ++# ++# CONFIG_IDE is not set ++# CONFIG_BLK_DEV_IDE_MODES is not set ++# CONFIG_BLK_DEV_HD is not set ++ ++# ++# SCSI support ++# ++# CONFIG_SCSI is not set ++ ++# ++# I2O device support ++# ++# CONFIG_I2O is not set ++# CONFIG_I2O_BLOCK is not set ++# CONFIG_I2O_LAN is not set ++# CONFIG_I2O_SCSI is not set ++# CONFIG_I2O_PROC is not set ++ ++# ++# ISDN subsystem ++# ++# CONFIG_ISDN is not set ++ ++# ++# Input core support ++# ++# CONFIG_INPUT is not set ++# CONFIG_INPUT_KEYBDEV is not set ++# CONFIG_INPUT_MOUSEDEV is not set ++# CONFIG_INPUT_JOYDEV is not set ++# CONFIG_INPUT_EVDEV is not set ++ ++# ++# Character devices ++# ++# CONFIG_VT is not set ++CONFIG_SERIAL=y ++CONFIG_SERIAL_CONSOLE=y ++# CONFIG_SERIAL_EXTENDED is not set ++# CONFIG_SERIAL_NONSTANDARD is not set ++ ++# ++# Serial drivers ++# ++# CONFIG_SERIAL_ANAKIN is not set ++# CONFIG_SERIAL_ANAKIN_CONSOLE is not set ++# CONFIG_SERIAL_AMBA is not set ++# CONFIG_SERIAL_AMBA_CONSOLE is not set ++# CONFIG_SERIAL_CLPS711X is not set ++# CONFIG_SERIAL_CLPS711X_CONSOLE is not set ++# CONFIG_SERIAL_21285 is not set ++# CONFIG_SERIAL_21285_OLD is not set ++# CONFIG_SERIAL_21285_CONSOLE is not set ++# CONFIG_SERIAL_UART00 is not set ++# CONFIG_SERIAL_UART00_CONSOLE is not set ++# CONFIG_SERIAL_SA1100 is not set ++# CONFIG_SERIAL_SA1100_CONSOLE is not set ++# CONFIG_SERIAL_OMAHA is not set ++# CONFIG_SERIAL_OMAHA_CONSOLE is not set ++# CONFIG_SERIAL_8250 is not set ++# CONFIG_SERIAL_8250_CONSOLE is not set ++# CONFIG_SERIAL_8250_EXTENDED is not set ++# CONFIG_SERIAL_8250_MANY_PORTS is not set ++# CONFIG_SERIAL_8250_SHARE_IRQ is not set ++# CONFIG_SERIAL_8250_DETECT_IRQ is not set ++# CONFIG_SERIAL_8250_MULTIPORT is not set ++# CONFIG_SERIAL_8250_HUB6 is not set ++CONFIG_UNIX98_PTYS=y ++CONFIG_UNIX98_PTY_COUNT=256 ++ ++# ++# I2C support ++# ++CONFIG_I2C=y ++# CONFIG_I2C_ALGOBIT is not set ++# CONFIG_I2C_ALGOPCF is not set ++CONFIG_I2C_PXA_ALGO=y ++CONFIG_I2C_PXA_ADAP=y ++CONFIG_I2C_CHARDEV=y ++CONFIG_I2C_PROC=y ++# CONFIG_I2C_DS1307 is not set ++ ++# ++# L3 serial bus support ++# ++# CONFIG_L3 is not set ++# CONFIG_L3_ALGOBIT is not set ++# CONFIG_L3_BIT_SA1100_GPIO is not set ++# CONFIG_L3_SA1111 is not set ++# CONFIG_BIT_SA1100_GPIO is not set ++ ++# ++# Mice ++# ++# CONFIG_BUSMOUSE is not set ++# CONFIG_MOUSE is not set ++ ++# ++# Joysticks ++# ++# CONFIG_INPUT_GAMEPORT is not set ++# CONFIG_QIC02_TAPE is not set ++ ++# ++# Watchdog Cards ++# ++# CONFIG_WATCHDOG is not set ++# CONFIG_NVRAM is not set ++# CONFIG_RTC is not set ++# CONFIG_PXA_RTC is not set ++# CONFIG_DTLK is not set ++# CONFIG_R3964 is not set ++# CONFIG_APPLICOM is not set ++ ++# ++# Ftape, the floppy tape device driver ++# ++# CONFIG_FTAPE is not set ++# CONFIG_AGP is not set ++# CONFIG_DRM is not set ++ ++# ++# Multimedia devices ++# ++# CONFIG_VIDEO_DEV is not set ++ ++# ++# File systems ++# ++# CONFIG_QUOTA is not set ++# CONFIG_AUTOFS_FS is not set ++# CONFIG_AUTOFS4_FS is not set ++# CONFIG_REISERFS_FS is not set ++# CONFIG_REISERFS_CHECK is not set ++# CONFIG_REISERFS_PROC_INFO is not set ++# CONFIG_ADFS_FS is not set ++# CONFIG_ADFS_FS_RW is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_BFS_FS is not set ++# CONFIG_EXT3_FS is not set ++# CONFIG_JBD is not set ++# CONFIG_JBD_DEBUG is not set ++# CONFIG_FAT_FS is not set ++# CONFIG_MSDOS_FS is not set ++# CONFIG_UMSDOS_FS is not set ++# CONFIG_VFAT_FS is not set ++# CONFIG_EFS_FS is not set ++# CONFIG_JFFS_FS is not set ++CONFIG_JFFS2_FS=y ++CONFIG_JFFS2_FS_DEBUG=0 ++# CONFIG_JFFS2_FS_NAND is not set ++# CONFIG_CRAMFS is not set ++# CONFIG_TMPFS is not set ++CONFIG_RAMFS=y ++# CONFIG_ISO9660_FS is not set ++# CONFIG_JOLIET is not set ++# CONFIG_ZISOFS is not set ++# CONFIG_MINIX_FS is not set ++# CONFIG_VXFS_FS is not set ++# CONFIG_NTFS_FS is not set ++# CONFIG_NTFS_RW is not set ++# CONFIG_HPFS_FS is not set ++CONFIG_PROC_FS=y ++CONFIG_DEVFS_FS=y ++CONFIG_DEVFS_MOUNT=y ++# CONFIG_DEVFS_DEBUG is not set ++CONFIG_DEVPTS_FS=y ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_QNX4FS_RW is not set ++# CONFIG_ROMFS_FS is not set ++# CONFIG_EXT2_FS is not set ++# CONFIG_SYSV_FS is not set ++# CONFIG_UDF_FS is not set ++# CONFIG_UDF_RW is not set ++# CONFIG_UFS_FS is not set ++# CONFIG_UFS_FS_WRITE is not set ++ ++# ++# Network File Systems ++# ++# CONFIG_CODA_FS is not set ++# CONFIG_INTERMEZZO_FS is not set ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_ROOT_NFS=y ++# CONFIG_NFSD is not set ++# CONFIG_NFSD_V3 is not set ++CONFIG_SUNRPC=y ++CONFIG_LOCKD=y ++CONFIG_LOCKD_V4=y ++# CONFIG_SMB_FS is not set ++# CONFIG_NCP_FS is not set ++# CONFIG_NCPFS_PACKET_SIGNING is not set ++# CONFIG_NCPFS_IOCTL_LOCKING is not set ++# CONFIG_NCPFS_STRONG is not set ++# CONFIG_NCPFS_NFS_NS is not set ++# CONFIG_NCPFS_OS2_NS is not set ++# CONFIG_NCPFS_SMALLDOS is not set ++# CONFIG_NCPFS_NLS is not set ++# CONFIG_NCPFS_EXTRAS is not set ++# CONFIG_ZISOFS_FS is not set ++# CONFIG_ZLIB_FS_INFLATE is not set ++ ++# ++# Partition Types ++# ++CONFIG_PARTITION_ADVANCED=y ++# CONFIG_ACORN_PARTITION is not set ++# CONFIG_OSF_PARTITION is not set ++# CONFIG_AMIGA_PARTITION is not set ++# CONFIG_ATARI_PARTITION is not set ++# CONFIG_MAC_PARTITION is not set ++# CONFIG_MSDOS_PARTITION is not set ++# CONFIG_LDM_PARTITION is not set ++# CONFIG_SGI_PARTITION is not set ++# CONFIG_ULTRIX_PARTITION is not set ++# CONFIG_SUN_PARTITION is not set ++# CONFIG_SMB_NLS is not set ++# CONFIG_NLS is not set ++ ++# ++# Sound ++# ++# CONFIG_SOUND is not set ++ ++# ++# Multimedia Capabilities Port drivers ++# ++# CONFIG_MCP is not set ++# CONFIG_MCP_SA1100 is not set ++# CONFIG_MCP_UCB1200 is not set ++# CONFIG_MCP_UCB1200_AUDIO is not set ++# CONFIG_MCP_UCB1200_TS is not set ++# CONFIG_MCP_UCB1400_TS is not set ++ ++# ++# USB support ++# ++# CONFIG_USB is not set ++ ++# ++# Bluetooth support ++# ++# CONFIG_BLUEZ is not set ++ ++# ++# Kernel hacking ++# ++CONFIG_FRAME_POINTER=y ++CONFIG_DEBUG_USER=y ++CONFIG_DEBUG_INFO=y ++# CONFIG_NO_PGT_CACHE is not set ++CONFIG_DEBUG_KERNEL=y ++CONFIG_DEBUG_SLAB=y ++CONFIG_MAGIC_SYSRQ=y ++CONFIG_DEBUG_SPINLOCK=y ++CONFIG_DEBUG_WAITQ=y ++CONFIG_DEBUG_BUGVERBOSE=y ++CONFIG_DEBUG_ERRORS=y ++CONFIG_DEBUG_LL=y ++# CONFIG_DEBUG_DC21285_PORT is not set ++# CONFIG_DEBUG_CLPS711X_UART2 is not set +--- /dev/null ++++ linux-2.4.27/arch/arm/def-configs/lubbock +@@ -0,0 +1,971 @@ ++# ++# Automatically generated make config: don't edit ++# ++CONFIG_ARM=y ++# CONFIG_EISA is not set ++# CONFIG_SBUS is not set ++# CONFIG_MCA is not set ++CONFIG_UID16=y ++CONFIG_RWSEM_GENERIC_SPINLOCK=y ++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set ++# CONFIG_GENERIC_BUST_SPINLOCK is not set ++# CONFIG_GENERIC_ISA_DMA is not set ++ ++# ++# Code maturity level options ++# ++CONFIG_EXPERIMENTAL=y ++# CONFIG_OBSOLETE is not set ++ ++# ++# Loadable module support ++# ++CONFIG_MODULES=y ++# CONFIG_MODVERSIONS is not set ++# CONFIG_KMOD is not set ++ ++# ++# System Type ++# ++# CONFIG_ARCH_ANAKIN is not set ++# CONFIG_ARCH_ARCA5K is not set ++# CONFIG_ARCH_CLPS7500 is not set ++# CONFIG_ARCH_CLPS711X is not set ++# CONFIG_ARCH_CO285 is not set ++CONFIG_ARCH_PXA=y ++# CONFIG_ARCH_EBSA110 is not set ++# CONFIG_ARCH_CAMELOT is not set ++# CONFIG_ARCH_FOOTBRIDGE is not set ++# CONFIG_ARCH_INTEGRATOR is not set ++# CONFIG_ARCH_OMAHA is not set ++# CONFIG_ARCH_L7200 is not set ++# CONFIG_ARCH_MX1ADS is not set ++# CONFIG_ARCH_RPC is not set ++# CONFIG_ARCH_RISCSTATION is not set ++# CONFIG_ARCH_SA1100 is not set ++# CONFIG_ARCH_SHARK is not set ++# CONFIG_ARCH_AT91RM9200 is not set ++ ++# ++# Archimedes/A5000 Implementations ++# ++ ++# ++# Archimedes/A5000 Implementations (select only ONE) ++# ++# CONFIG_ARCH_ARC is not set ++# CONFIG_ARCH_A5K is not set ++ ++# ++# Footbridge Implementations ++# ++# CONFIG_ARCH_CATS is not set ++# CONFIG_ARCH_PERSONAL_SERVER is not set ++# CONFIG_ARCH_EBSA285_ADDIN is not set ++# CONFIG_ARCH_EBSA285_HOST is not set ++# CONFIG_ARCH_NETWINDER is not set ++ ++# ++# SA11x0 Implementations ++# ++# CONFIG_SA1100_ACCELENT is not set ++# CONFIG_SA1100_ASSABET is not set ++# CONFIG_ASSABET_NEPONSET is not set ++# CONFIG_SA1100_ADSAGC is not set ++# CONFIG_SA1100_ADSBITSY is not set ++# CONFIG_SA1100_ADSBITSYPLUS is not set ++# CONFIG_SA1100_BRUTUS is not set ++# CONFIG_SA1100_CEP is not set ++# CONFIG_SA1100_CERF is not set ++# CONFIG_SA1100_H3100 is not set ++# CONFIG_SA1100_H3600 is not set ++# CONFIG_SA1100_H3800 is not set ++# CONFIG_SA1100_H3XXX is not set ++# CONFIG_H3600_SLEEVE is not set ++# CONFIG_SA1100_EXTENEX1 is not set ++# CONFIG_SA1100_FLEXANET is not set ++# CONFIG_SA1100_FREEBIRD is not set ++# CONFIG_SA1100_FRODO is not set ++# CONFIG_SA1100_GRAPHICSCLIENT is not set ++# CONFIG_SA1100_GRAPHICSMASTER is not set ++# CONFIG_SA1100_HACKKIT is not set ++# CONFIG_SA1100_BADGE4 is not set ++# CONFIG_SA1100_JORNADA720 is not set ++# CONFIG_SA1100_HUW_WEBPANEL is not set ++# CONFIG_SA1100_ITSY is not set ++# CONFIG_SA1100_LART is not set ++# CONFIG_SA1100_NANOENGINE is not set ++# CONFIG_SA1100_OMNIMETER is not set ++# CONFIG_SA1100_PANGOLIN is not set ++# CONFIG_SA1100_PLEB is not set ++# CONFIG_SA1100_PT_SYSTEM3 is not set ++# CONFIG_SA1100_SHANNON is not set ++# CONFIG_SA1100_SHERMAN is not set ++# CONFIG_SA1100_SIMPAD is not set ++# CONFIG_SA1100_SIMPUTER is not set ++# CONFIG_SA1100_PFS168 is not set ++# CONFIG_SA1100_VICTOR is not set ++# CONFIG_SA1100_XP860 is not set ++# CONFIG_SA1100_YOPY is not set ++# CONFIG_SA1100_USB is not set ++# CONFIG_SA1100_USB_NETLINK is not set ++# CONFIG_SA1100_USB_CHAR is not set ++# CONFIG_SA1100_SSP is not set ++ ++# ++# AT91RM9200 Implementations ++# ++# CONFIG_ARCH_AT91RM9200DK is not set ++ ++# ++# Intel PXA250/210 Implementations ++# ++CONFIG_ARCH_LUBBOCK=y ++# CONFIG_ARCH_PXA_IDP is not set ++# CONFIG_ARCH_PXA_CERF is not set ++# CONFIG_ARCH_TRIZEPS2 is not set ++CONFIG_SA1111=y ++# CONFIG_PXA_USB is not set ++# CONFIG_PXA_USB_NETLINK is not set ++# CONFIG_PXA_USB_CHAR is not set ++ ++# ++# CLPS711X/EP721X Implementations ++# ++# CONFIG_ARCH_AUTCPU12 is not set ++# CONFIG_ARCH_CDB89712 is not set ++# CONFIG_ARCH_CLEP7312 is not set ++# CONFIG_ARCH_EDB7211 is not set ++# CONFIG_ARCH_FORTUNET is not set ++# CONFIG_ARCH_GUIDEA07 is not set ++# CONFIG_ARCH_P720T is not set ++# CONFIG_ARCH_EP7211 is not set ++# CONFIG_ARCH_EP7212 is not set ++# CONFIG_ARCH_ACORN is not set ++# CONFIG_FOOTBRIDGE is not set ++# CONFIG_FOOTBRIDGE_HOST is not set ++# CONFIG_FOOTBRIDGE_ADDIN is not set ++ ++# ++# Processor Type ++# ++CONFIG_CPU_32=y ++# CONFIG_CPU_26 is not set ++# CONFIG_CPU_ARM610 is not set ++# CONFIG_CPU_ARM710 is not set ++# CONFIG_CPU_ARM720T is not set ++# CONFIG_CPU_ARM920T is not set ++# CONFIG_CPU_ARM922T is not set ++# CONFIG_PLD is not set ++# CONFIG_CPU_ARM926T is not set ++# CONFIG_CPU_ARM1020 is not set ++# CONFIG_CPU_ARM1026 is not set ++# CONFIG_CPU_SA110 is not set ++# CONFIG_CPU_SA1100 is not set ++CONFIG_CPU_32v5=y ++CONFIG_CPU_XSCALE=y ++# CONFIG_XSCALE_CACHE_ERRATA is not set ++# CONFIG_CPU_32v3 is not set ++# CONFIG_CPU_32v4 is not set ++ ++# ++# Processor Features ++# ++# CONFIG_DISCONTIGMEM is not set ++ ++# ++# General setup ++# ++# CONFIG_PCI is not set ++# CONFIG_ISA is not set ++# CONFIG_ISA_DMA is not set ++# CONFIG_ZBOOT_ROM is not set ++CONFIG_ZBOOT_ROM_TEXT=0 ++CONFIG_ZBOOT_ROM_BSS=0 ++CONFIG_CPU_FREQ=y ++CONFIG_HOTPLUG=y ++ ++# ++# PCMCIA/CardBus support ++# ++CONFIG_PCMCIA=y ++# CONFIG_I82092 is not set ++# CONFIG_I82365 is not set ++# CONFIG_TCIC is not set ++# CONFIG_PCMCIA_CLPS6700 is not set ++# CONFIG_PCMCIA_SA1100 is not set ++CONFIG_PCMCIA_PXA=y ++ ++# ++# MMC device drivers ++# ++CONFIG_MMC=m ++CONFIG_MMC_PXA=m ++CONFIG_MMC_BLOCK=m ++CONFIG_MMC_PARTITIONS=y ++CONFIG_NET=y ++CONFIG_SYSVIPC=y ++# CONFIG_BSD_PROCESS_ACCT is not set ++CONFIG_SYSCTL=y ++# CONFIG_XIP_KERNEL is not set ++ ++# ++# At least one math emulation must be selected ++# ++CONFIG_FPE_NWFPE=y ++# CONFIG_FPE_NWFPE_XP is not set ++# CONFIG_FPE_FASTFPE is not set ++CONFIG_KCORE_ELF=y ++# CONFIG_KCORE_AOUT is not set ++# CONFIG_BINFMT_AOUT is not set ++CONFIG_BINFMT_ELF=y ++# CONFIG_BINFMT_MISC is not set ++CONFIG_PM=y ++# CONFIG_ARTHUR is not set ++CONFIG_CMDLINE="root=/dev/nfs ip=bootp console=ttyS0,115200 mem=32M" ++CONFIG_LEDS=y ++CONFIG_LEDS_TIMER=y ++CONFIG_LEDS_CPU=y ++CONFIG_ALIGNMENT_TRAP=y ++ ++# ++# Parallel port support ++# ++# CONFIG_PARPORT is not set ++ ++# ++# Memory Technology Devices (MTD) ++# ++CONFIG_MTD=y ++# CONFIG_MTD_DEBUG is not set ++CONFIG_MTD_PARTITIONS=y ++# CONFIG_MTD_CONCAT is not set ++CONFIG_MTD_REDBOOT_PARTS=y ++# CONFIG_MTD_CMDLINE_PARTS is not set ++# CONFIG_MTD_AFS_PARTS is not set ++ ++# ++# User Modules And Translation Layers ++# ++CONFIG_MTD_CHAR=y ++CONFIG_MTD_BLOCK=y ++# CONFIG_FTL is not set ++# CONFIG_NFTL is not set ++ ++# ++# RAM/ROM/Flash chip drivers ++# ++CONFIG_MTD_CFI=y ++# CONFIG_MTD_JEDECPROBE is not set ++CONFIG_MTD_GEN_PROBE=y ++CONFIG_MTD_CFI_ADV_OPTIONS=y ++CONFIG_MTD_CFI_NOSWAP=y ++# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set ++# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set ++CONFIG_MTD_CFI_GEOMETRY=y ++# CONFIG_MTD_CFI_B1 is not set ++CONFIG_MTD_CFI_B2=y ++CONFIG_MTD_CFI_B4=y ++# CONFIG_MTD_CFI_B8 is not set ++CONFIG_MTD_CFI_I1=y ++CONFIG_MTD_CFI_I2=y ++# CONFIG_MTD_CFI_I4 is not set ++# CONFIG_MTD_CFI_I8 is not set ++CONFIG_MTD_CFI_INTELEXT=y ++# CONFIG_MTD_CFI_AMDSTD is not set ++# CONFIG_MTD_CFI_STAA is not set ++# CONFIG_MTD_RAM is not set ++# CONFIG_MTD_ROM is not set ++# CONFIG_MTD_ABSENT is not set ++# CONFIG_MTD_OBSOLETE_CHIPS is not set ++# CONFIG_MTD_AMDSTD is not set ++# CONFIG_MTD_SHARP is not set ++# CONFIG_MTD_JEDEC is not set ++ ++# ++# Mapping drivers for chip access ++# ++# CONFIG_MTD_PHYSMAP is not set ++CONFIG_MTD_LUBBOCK=y ++# CONFIG_MTD_NORA is not set ++# CONFIG_MTD_ARM_INTEGRATOR is not set ++# CONFIG_MTD_CDB89712 is not set ++# CONFIG_MTD_SA1100 is not set ++# CONFIG_MTD_DC21285 is not set ++# CONFIG_MTD_IQ80310 is not set ++# CONFIG_MTD_FORTUNET is not set ++# CONFIG_MTD_EPXA is not set ++# CONFIG_MTD_AUTCPU12 is not set ++# CONFIG_MTD_EDB7312 is not set ++# CONFIG_MTD_IMPA7 is not set ++# CONFIG_MTD_CEIVA is not set ++# CONFIG_MTD_PCI is not set ++# CONFIG_MTD_PCMCIA is not set ++ ++# ++# Self-contained MTD device drivers ++# ++# CONFIG_MTD_PMC551 is not set ++# CONFIG_MTD_SLRAM is not set ++# CONFIG_MTD_MTDRAM is not set ++# CONFIG_MTD_BLKMTD is not set ++ ++# ++# Disk-On-Chip Device Drivers ++# ++# CONFIG_MTD_DOC1000 is not set ++# CONFIG_MTD_DOC2000 is not set ++# CONFIG_MTD_DOC2001 is not set ++# CONFIG_MTD_DOCPROBE is not set ++ ++# ++# NAND Flash Device Drivers ++# ++# CONFIG_MTD_NAND is not set ++ ++# ++# Plug and Play configuration ++# ++# CONFIG_PNP is not set ++# CONFIG_ISAPNP is not set ++ ++# ++# Block devices ++# ++# CONFIG_BLK_DEV_FD is not set ++# CONFIG_BLK_DEV_XD is not set ++# CONFIG_PARIDE is not set ++# CONFIG_BLK_CPQ_DA is not set ++# CONFIG_BLK_CPQ_CISS_DA is not set ++# CONFIG_CISS_SCSI_TAPE is not set ++# CONFIG_BLK_DEV_DAC960 is not set ++# CONFIG_BLK_DEV_UMEM is not set ++# CONFIG_BLK_DEV_LOOP is not set ++# CONFIG_BLK_DEV_NBD is not set ++# CONFIG_BLK_DEV_RAM is not set ++# CONFIG_BLK_DEV_INITRD is not set ++# CONFIG_BLK_STATS is not set ++ ++# ++# Multi-device support (RAID and LVM) ++# ++# CONFIG_MD is not set ++# CONFIG_BLK_DEV_MD is not set ++# CONFIG_MD_LINEAR is not set ++# CONFIG_MD_RAID0 is not set ++# CONFIG_MD_RAID1 is not set ++# CONFIG_MD_RAID5 is not set ++# CONFIG_MD_MULTIPATH is not set ++# CONFIG_BLK_DEV_LVM is not set ++ ++# ++# Networking options ++# ++# CONFIG_PACKET is not set ++# CONFIG_NETLINK_DEV is not set ++# CONFIG_NETFILTER is not set ++# CONFIG_FILTER is not set ++CONFIG_UNIX=y ++CONFIG_INET=y ++# CONFIG_IP_MULTICAST is not set ++# CONFIG_IP_ADVANCED_ROUTER is not set ++CONFIG_IP_PNP=y ++# CONFIG_IP_PNP_DHCP is not set ++CONFIG_IP_PNP_BOOTP=y ++# CONFIG_IP_PNP_RARP is not set ++# CONFIG_NET_IPIP is not set ++# CONFIG_NET_IPGRE is not set ++# CONFIG_ARPD is not set ++# CONFIG_INET_ECN is not set ++# CONFIG_SYN_COOKIES is not set ++# CONFIG_IPV6 is not set ++# CONFIG_KHTTPD is not set ++# CONFIG_ATM is not set ++# CONFIG_VLAN_8021Q is not set ++ ++# ++# ++# ++# CONFIG_IPX is not set ++# CONFIG_ATALK is not set ++ ++# ++# Appletalk devices ++# ++# CONFIG_DEV_APPLETALK is not set ++# CONFIG_DECNET is not set ++# CONFIG_BRIDGE is not set ++# CONFIG_X25 is not set ++# CONFIG_LAPB is not set ++# CONFIG_LLC is not set ++# CONFIG_NET_DIVERT is not set ++# CONFIG_ECONET is not set ++# CONFIG_WAN_ROUTER is not set ++# CONFIG_NET_FASTROUTE is not set ++# CONFIG_NET_HW_FLOWCONTROL is not set ++ ++# ++# QoS and/or fair queueing ++# ++# CONFIG_NET_SCHED is not set ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++ ++# ++# Network device support ++# ++CONFIG_NETDEVICES=y ++ ++# ++# ARCnet devices ++# ++# CONFIG_ARCNET is not set ++# CONFIG_DUMMY is not set ++# CONFIG_BONDING is not set ++# CONFIG_EQUALIZER is not set ++# CONFIG_TUN is not set ++# CONFIG_ETHERTAP is not set ++ ++# ++# Ethernet (10 or 100Mbit) ++# ++CONFIG_NET_ETHERNET=y ++# CONFIG_ARM_AM79C961A is not set ++# CONFIG_ARM_CIRRUS is not set ++# CONFIG_SUNLANCE is not set ++# CONFIG_SUNBMAC is not set ++# CONFIG_SUNQE is not set ++# CONFIG_SUNGEM is not set ++# CONFIG_NET_VENDOR_3COM is not set ++# CONFIG_LANCE is not set ++CONFIG_NET_VENDOR_SMC=y ++# CONFIG_WD80x3 is not set ++# CONFIG_ULTRAMCA is not set ++# CONFIG_ULTRA is not set ++# CONFIG_ULTRA32 is not set ++# CONFIG_SMC9194 is not set ++CONFIG_SMC91X=y ++# CONFIG_NET_VENDOR_RACAL is not set ++# CONFIG_NET_ISA is not set ++# CONFIG_NET_PCI is not set ++# CONFIG_NET_POCKET is not set ++ ++# ++# Ethernet (1000 Mbit) ++# ++# CONFIG_ACENIC is not set ++# CONFIG_DL2K is not set ++# CONFIG_E1000 is not set ++# CONFIG_MYRI_SBUS is not set ++# CONFIG_NS83820 is not set ++# CONFIG_HAMACHI is not set ++# CONFIG_YELLOWFIN is not set ++# CONFIG_R8169 is not set ++# CONFIG_SK98LIN is not set ++# CONFIG_TIGON3 is not set ++# CONFIG_FDDI is not set ++# CONFIG_HIPPI is not set ++# CONFIG_PLIP is not set ++# CONFIG_PPP is not set ++# CONFIG_SLIP is not set ++ ++# ++# Wireless LAN (non-hamradio) ++# ++# CONFIG_NET_RADIO is not set ++ ++# ++# Token Ring devices ++# ++# CONFIG_TR is not set ++# CONFIG_NET_FC is not set ++# CONFIG_RCPCI is not set ++# CONFIG_SHAPER is not set ++ ++# ++# Wan interfaces ++# ++# CONFIG_WAN is not set ++ ++# ++# PCMCIA network device support ++# ++CONFIG_NET_PCMCIA=y ++# CONFIG_PCMCIA_3C589 is not set ++# CONFIG_PCMCIA_3C574 is not set ++# CONFIG_PCMCIA_FMVJ18X is not set ++CONFIG_PCMCIA_PCNET=y ++# CONFIG_PCMCIA_AXNET is not set ++# CONFIG_PCMCIA_NMCLAN is not set ++# CONFIG_PCMCIA_SMC91C92 is not set ++# CONFIG_PCMCIA_XIRC2PS is not set ++# CONFIG_ARCNET_COM20020_CS is not set ++# CONFIG_PCMCIA_IBMTR is not set ++# CONFIG_NET_PCMCIA_RADIO is not set ++ ++# ++# Amateur Radio support ++# ++# CONFIG_HAMRADIO is not set ++ ++# ++# IrDA (infrared) support ++# ++# CONFIG_IRDA is not set ++ ++# ++# ATA/ATAPI/MFM/RLL support ++# ++CONFIG_IDE=y ++ ++# ++# IDE, ATA and ATAPI Block devices ++# ++CONFIG_BLK_DEV_IDE=y ++ ++# ++# Please see Documentation/ide.txt for help/info on IDE drives ++# ++# CONFIG_BLK_DEV_HD_IDE is not set ++# CONFIG_BLK_DEV_HD is not set ++CONFIG_BLK_DEV_IDEDISK=y ++# CONFIG_IDEDISK_MULTI_MODE is not set ++# CONFIG_IDEDISK_STROKE is not set ++CONFIG_BLK_DEV_IDECS=y ++# CONFIG_BLK_DEV_IDECD is not set ++# CONFIG_BLK_DEV_IDETAPE is not set ++# CONFIG_BLK_DEV_IDEFLOPPY is not set ++# CONFIG_BLK_DEV_IDESCSI is not set ++# CONFIG_IDE_TASK_IOCTL is not set ++ ++# ++# IDE chipset support/bugfixes ++# ++# CONFIG_BLK_DEV_CMD640 is not set ++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set ++# CONFIG_BLK_DEV_ISAPNP is not set ++# CONFIG_IDE_CHIPSETS is not set ++# CONFIG_IDEDMA_AUTO is not set ++# CONFIG_DMA_NONPCI is not set ++CONFIG_BLK_DEV_IDE_MODES=y ++# CONFIG_BLK_DEV_ATARAID is not set ++# CONFIG_BLK_DEV_ATARAID_PDC is not set ++# CONFIG_BLK_DEV_ATARAID_HPT is not set ++# CONFIG_BLK_DEV_ATARAID_SII is not set ++ ++# ++# SCSI support ++# ++# CONFIG_SCSI is not set ++ ++# ++# I2O device support ++# ++# CONFIG_I2O is not set ++# CONFIG_I2O_BLOCK is not set ++# CONFIG_I2O_LAN is not set ++# CONFIG_I2O_SCSI is not set ++# CONFIG_I2O_PROC is not set ++ ++# ++# ISDN subsystem ++# ++# CONFIG_ISDN is not set ++ ++# ++# Input core support ++# ++CONFIG_INPUT=y ++# CONFIG_INPUT_KEYBDEV is not set ++# CONFIG_INPUT_MOUSEDEV is not set ++# CONFIG_INPUT_JOYDEV is not set ++CONFIG_INPUT_EVDEV=y ++# CONFIG_INPUT_MX1TS is not set ++ ++# ++# Character devices ++# ++CONFIG_VT=y ++# CONFIG_VT_CONSOLE is not set ++CONFIG_SERIAL=y ++CONFIG_SERIAL_CONSOLE=y ++# CONFIG_SERIAL_EXTENDED is not set ++# CONFIG_SERIAL_NONSTANDARD is not set ++ ++# ++# Serial drivers ++# ++# CONFIG_SERIAL_ANAKIN is not set ++# CONFIG_SERIAL_ANAKIN_CONSOLE is not set ++# CONFIG_SERIAL_AMBA is not set ++# CONFIG_SERIAL_AMBA_CONSOLE is not set ++# CONFIG_SERIAL_CLPS711X is not set ++# CONFIG_SERIAL_CLPS711X_CONSOLE is not set ++# CONFIG_SERIAL_21285 is not set ++# CONFIG_SERIAL_21285_OLD is not set ++# CONFIG_SERIAL_21285_CONSOLE is not set ++# CONFIG_SERIAL_UART00 is not set ++# CONFIG_SERIAL_UART00_CONSOLE is not set ++# CONFIG_SERIAL_SA1100 is not set ++# CONFIG_SERIAL_SA1100_CONSOLE is not set ++# CONFIG_SERIAL_OMAHA is not set ++# CONFIG_SERIAL_OMAHA_CONSOLE is not set ++# CONFIG_SERIAL_AT91 is not set ++# CONFIG_SERIAL_AT91_CONSOLE is not set ++# CONFIG_SERIAL_8250 is not set ++# CONFIG_SERIAL_8250_CONSOLE is not set ++# CONFIG_SERIAL_8250_EXTENDED is not set ++# CONFIG_SERIAL_8250_MANY_PORTS is not set ++# CONFIG_SERIAL_8250_SHARE_IRQ is not set ++# CONFIG_SERIAL_8250_DETECT_IRQ is not set ++# CONFIG_SERIAL_8250_MULTIPORT is not set ++# CONFIG_SERIAL_8250_HUB6 is not set ++CONFIG_UNIX98_PTYS=y ++CONFIG_UNIX98_PTY_COUNT=256 ++ ++# ++# I2C support ++# ++# CONFIG_I2C is not set ++ ++# ++# L3 serial bus support ++# ++# CONFIG_L3 is not set ++# CONFIG_L3_ALGOBIT is not set ++# CONFIG_L3_BIT_SA1100_GPIO is not set ++ ++# ++# Other L3 adapters ++# ++# CONFIG_L3_SA1111 is not set ++# CONFIG_BIT_SA1100_GPIO is not set ++ ++# ++# Mice ++# ++CONFIG_BUSMOUSE=y ++# CONFIG_ATIXL_BUSMOUSE is not set ++# CONFIG_LOGIBUSMOUSE is not set ++# CONFIG_MS_BUSMOUSE is not set ++CONFIG_MOUSE=y ++CONFIG_PSMOUSE=y ++# CONFIG_82C710_MOUSE is not set ++# CONFIG_PC110_PAD is not set ++# CONFIG_MK712_MOUSE is not set ++ ++# ++# Joysticks ++# ++# CONFIG_INPUT_GAMEPORT is not set ++# CONFIG_INPUT_NS558 is not set ++# CONFIG_INPUT_LIGHTNING is not set ++# CONFIG_INPUT_PCIGAME is not set ++# CONFIG_INPUT_CS461X is not set ++# CONFIG_INPUT_EMU10K1 is not set ++# CONFIG_INPUT_SERIO is not set ++# CONFIG_INPUT_SERPORT is not set ++ ++# ++# Joysticks ++# ++# CONFIG_INPUT_ANALOG is not set ++# CONFIG_INPUT_A3D is not set ++# CONFIG_INPUT_ADI is not set ++# CONFIG_INPUT_COBRA is not set ++# CONFIG_INPUT_GF2K is not set ++# CONFIG_INPUT_GRIP is not set ++# CONFIG_INPUT_INTERACT is not set ++# CONFIG_INPUT_TMDC is not set ++# CONFIG_INPUT_SIDEWINDER is not set ++# CONFIG_INPUT_IFORCE_USB is not set ++# CONFIG_INPUT_IFORCE_232 is not set ++# CONFIG_INPUT_WARRIOR is not set ++# CONFIG_INPUT_MAGELLAN is not set ++# CONFIG_INPUT_SPACEORB is not set ++# CONFIG_INPUT_SPACEBALL is not set ++# CONFIG_INPUT_STINGER is not set ++# CONFIG_INPUT_DB9 is not set ++# CONFIG_INPUT_GAMECON is not set ++# CONFIG_INPUT_TURBOGRAFX is not set ++# CONFIG_QIC02_TAPE is not set ++# CONFIG_IPMI_HANDLER is not set ++# CONFIG_IPMI_PANIC_EVENT is not set ++# CONFIG_IPMI_DEVICE_INTERFACE is not set ++# CONFIG_IPMI_KCS is not set ++# CONFIG_IPMI_WATCHDOG is not set ++ ++# ++# Watchdog Cards ++# ++# CONFIG_WATCHDOG is not set ++# CONFIG_SCx200_GPIO is not set ++# CONFIG_AMD_PM768 is not set ++# CONFIG_NVRAM is not set ++# CONFIG_RTC is not set ++CONFIG_PXA_RTC=y ++# CONFIG_DTLK is not set ++# CONFIG_R3964 is not set ++# CONFIG_APPLICOM is not set ++ ++# ++# Ftape, the floppy tape device driver ++# ++# CONFIG_FTAPE is not set ++# CONFIG_AGP is not set ++# CONFIG_DRM is not set ++ ++# ++# PCMCIA character devices ++# ++# CONFIG_PCMCIA_SERIAL_CS is not set ++# CONFIG_SYNCLINK_CS is not set ++ ++# ++# Multimedia devices ++# ++# CONFIG_VIDEO_DEV is not set ++ ++# ++# File systems ++# ++# CONFIG_QUOTA is not set ++# CONFIG_AUTOFS_FS is not set ++# CONFIG_AUTOFS4_FS is not set ++# CONFIG_REISERFS_FS is not set ++# CONFIG_REISERFS_CHECK is not set ++# CONFIG_REISERFS_PROC_INFO is not set ++# CONFIG_ADFS_FS is not set ++# CONFIG_ADFS_FS_RW is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_BEFS_FS is not set ++# CONFIG_BEFS_DEBUG is not set ++# CONFIG_BFS_FS is not set ++# CONFIG_EXT3_FS is not set ++# CONFIG_JBD is not set ++# CONFIG_JBD_DEBUG is not set ++CONFIG_FAT_FS=y ++CONFIG_MSDOS_FS=y ++# CONFIG_UMSDOS_FS is not set ++# CONFIG_VFAT_FS is not set ++# CONFIG_EFS_FS is not set ++# CONFIG_JFFS_FS is not set ++CONFIG_JFFS2_FS=y ++CONFIG_JFFS2_FS_DEBUG=0 ++# CONFIG_CRAMFS is not set ++# CONFIG_CRAMFS_LINEAR is not set ++# CONFIG_CRAMFS_LINEAR_XIP is not set ++# CONFIG_ROOT_CRAMFS_LINEAR is not set ++# CONFIG_TMPFS is not set ++CONFIG_RAMFS=y ++# CONFIG_ISO9660_FS is not set ++# CONFIG_JOLIET is not set ++# CONFIG_ZISOFS is not set ++# CONFIG_JFS_FS is not set ++# CONFIG_JFS_DEBUG is not set ++# CONFIG_JFS_STATISTICS is not set ++# CONFIG_MINIX_FS is not set ++# CONFIG_VXFS_FS is not set ++# CONFIG_NTFS_FS is not set ++# CONFIG_NTFS_RW is not set ++# CONFIG_HPFS_FS is not set ++CONFIG_PROC_FS=y ++CONFIG_DEVFS_FS=y ++CONFIG_DEVFS_MOUNT=y ++# CONFIG_DEVFS_DEBUG is not set ++CONFIG_DEVPTS_FS=y ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_QNX4FS_RW is not set ++# CONFIG_ROMFS_FS is not set ++CONFIG_EXT2_FS=y ++# CONFIG_SYSV_FS is not set ++# CONFIG_UDF_FS is not set ++# CONFIG_UDF_RW is not set ++# CONFIG_UFS_FS is not set ++# CONFIG_UFS_FS_WRITE is not set ++ ++# ++# Network File Systems ++# ++# CONFIG_CODA_FS is not set ++# CONFIG_INTERMEZZO_FS is not set ++CONFIG_NFS_FS=y ++# CONFIG_NFS_V3 is not set ++CONFIG_ROOT_NFS=y ++# CONFIG_NFSD is not set ++# CONFIG_NFSD_V3 is not set ++# CONFIG_NFSD_TCP is not set ++CONFIG_SUNRPC=y ++CONFIG_LOCKD=y ++# CONFIG_SMB_FS is not set ++# CONFIG_NCP_FS is not set ++# CONFIG_NCPFS_PACKET_SIGNING is not set ++# CONFIG_NCPFS_IOCTL_LOCKING is not set ++# CONFIG_NCPFS_STRONG is not set ++# CONFIG_NCPFS_NFS_NS is not set ++# CONFIG_NCPFS_OS2_NS is not set ++# CONFIG_NCPFS_SMALLDOS is not set ++# CONFIG_NCPFS_NLS is not set ++# CONFIG_NCPFS_EXTRAS is not set ++# CONFIG_ZISOFS_FS is not set ++ ++# ++# Partition Types ++# ++# CONFIG_PARTITION_ADVANCED is not set ++CONFIG_MSDOS_PARTITION=y ++# CONFIG_SMB_NLS is not set ++CONFIG_NLS=y ++ ++# ++# Native Language Support ++# ++CONFIG_NLS_DEFAULT="iso8859-1" ++# CONFIG_NLS_CODEPAGE_437 is not set ++# CONFIG_NLS_CODEPAGE_737 is not set ++# CONFIG_NLS_CODEPAGE_775 is not set ++# CONFIG_NLS_CODEPAGE_850 is not set ++# CONFIG_NLS_CODEPAGE_852 is not set ++# CONFIG_NLS_CODEPAGE_855 is not set ++# CONFIG_NLS_CODEPAGE_857 is not set ++# CONFIG_NLS_CODEPAGE_860 is not set ++# CONFIG_NLS_CODEPAGE_861 is not set ++# CONFIG_NLS_CODEPAGE_862 is not set ++# CONFIG_NLS_CODEPAGE_863 is not set ++# CONFIG_NLS_CODEPAGE_864 is not set ++# CONFIG_NLS_CODEPAGE_865 is not set ++# CONFIG_NLS_CODEPAGE_866 is not set ++# CONFIG_NLS_CODEPAGE_869 is not set ++# CONFIG_NLS_CODEPAGE_936 is not set ++# CONFIG_NLS_CODEPAGE_950 is not set ++# CONFIG_NLS_CODEPAGE_932 is not set ++# CONFIG_NLS_CODEPAGE_949 is not set ++# CONFIG_NLS_CODEPAGE_874 is not set ++# CONFIG_NLS_ISO8859_8 is not set ++# CONFIG_NLS_CODEPAGE_1250 is not set ++# CONFIG_NLS_CODEPAGE_1251 is not set ++CONFIG_NLS_ISO8859_1=y ++# CONFIG_NLS_ISO8859_2 is not set ++# CONFIG_NLS_ISO8859_3 is not set ++# CONFIG_NLS_ISO8859_4 is not set ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++# CONFIG_NLS_UTF8 is not set ++ ++# ++# Console drivers ++# ++CONFIG_PC_KEYMAP=y ++# CONFIG_VGA_CONSOLE is not set ++ ++# ++# Frame-buffer support ++# ++CONFIG_FB=y ++CONFIG_DUMMY_CONSOLE=y ++# CONFIG_FB_ACORN is not set ++# CONFIG_FB_ANAKIN is not set ++# CONFIG_FB_CLPS711X is not set ++# CONFIG_FB_SA1100 is not set ++# CONFIG_FB_DBMX1 is not set ++CONFIG_FB_PXA=y ++# CONFIG_FB_PXA_8BPP is not set ++CONFIG_FB_PXA_16BPP=y ++# CONFIG_FB_PXA_QVGA is not set ++# CONFIG_FB_CYBER2000 is not set ++# CONFIG_FB_VIRTUAL is not set ++# CONFIG_FBCON_ADVANCED is not set ++CONFIG_FBCON_CFB2=y ++CONFIG_FBCON_CFB4=y ++CONFIG_FBCON_CFB8=y ++CONFIG_FBCON_CFB16=y ++CONFIG_FBCON_FONTWIDTH8_ONLY=y ++# CONFIG_FBCON_FONTS is not set ++CONFIG_FONT_8x8=y ++CONFIG_FONT_8x16=y ++ ++# ++# Sound ++# ++CONFIG_SOUND=y ++# CONFIG_SOUND_ALI5455 is not set ++# CONFIG_SOUND_BT878 is not set ++# CONFIG_SOUND_CMPCI is not set ++# CONFIG_SOUND_EMU10K1 is not set ++# CONFIG_MIDI_EMU10K1 is not set ++# CONFIG_SOUND_FUSION is not set ++# CONFIG_SOUND_CS4281 is not set ++# CONFIG_SOUND_ES1370 is not set ++# CONFIG_SOUND_ES1371 is not set ++# CONFIG_SOUND_ESSSOLO1 is not set ++# CONFIG_SOUND_MAESTRO is not set ++# CONFIG_SOUND_MAESTRO3 is not set ++# CONFIG_SOUND_FORTE is not set ++# CONFIG_SOUND_ICH is not set ++# CONFIG_SOUND_RME96XX is not set ++# CONFIG_SOUND_SONICVIBES is not set ++# CONFIG_SOUND_TRIDENT is not set ++# CONFIG_SOUND_MSNDCLAS is not set ++# CONFIG_SOUND_MSNDPIN is not set ++# CONFIG_SOUND_VIA82CXXX is not set ++# CONFIG_MIDI_VIA82CXXX is not set ++# CONFIG_SOUND_OSS is not set ++# CONFIG_SOUND_VIDC is not set ++# CONFIG_SOUND_WAVEARTIST is not set ++CONFIG_SOUND_PXA_AC97=y ++# CONFIG_SOUND_TVMIXER is not set ++ ++# ++# Multimedia Capabilities Port drivers ++# ++# CONFIG_MCP is not set ++# CONFIG_MCP_SA1100 is not set ++# CONFIG_MCP_UCB1200 is not set ++# CONFIG_MCP_UCB1200_AUDIO is not set ++# CONFIG_MCP_UCB1200_TS is not set ++CONFIG_MCP_UCB1400_TS=y ++ ++# ++# USB support ++# ++# CONFIG_USB is not set ++ ++# ++# Bluetooth support ++# ++# CONFIG_BLUEZ is not set ++ ++# ++# Kernel hacking ++# ++CONFIG_FRAME_POINTER=y ++CONFIG_DEBUG_USER=y ++CONFIG_DEBUG_INFO=y ++# CONFIG_NO_PGT_CACHE is not set ++CONFIG_DEBUG_KERNEL=y ++# CONFIG_DEBUG_SLAB is not set ++CONFIG_MAGIC_SYSRQ=y ++# CONFIG_DEBUG_SPINLOCK is not set ++# CONFIG_DEBUG_WAITQ is not set ++CONFIG_DEBUG_BUGVERBOSE=y ++CONFIG_DEBUG_ERRORS=y ++CONFIG_DEBUG_LL=y ++# CONFIG_DEBUG_DC21285_PORT is not set ++# CONFIG_DEBUG_CLPS711X_UART2 is not set ++ ++# ++# Library routines ++# ++CONFIG_ZLIB_INFLATE=y ++CONFIG_ZLIB_DEFLATE=y +--- /dev/null ++++ linux-2.4.27/arch/arm/def-configs/pxa_idp +@@ -0,0 +1,933 @@ ++# ++# Automatically generated by make menuconfig: don't edit ++# ++CONFIG_ARM=y ++# CONFIG_EISA is not set ++# CONFIG_SBUS is not set ++# CONFIG_MCA is not set ++CONFIG_UID16=y ++CONFIG_RWSEM_GENERIC_SPINLOCK=y ++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set ++# CONFIG_GENERIC_BUST_SPINLOCK is not set ++# CONFIG_GENERIC_ISA_DMA is not set ++ ++# ++# Code maturity level options ++# ++CONFIG_EXPERIMENTAL=y ++# CONFIG_OBSOLETE is not set ++ ++# ++# Loadable module support ++# ++CONFIG_MODULES=y ++# CONFIG_MODVERSIONS is not set ++CONFIG_KMOD=y ++ ++# ++# System Type ++# ++# CONFIG_ARCH_ANAKIN is not set ++# CONFIG_ARCH_ARCA5K is not set ++# CONFIG_ARCH_CLPS7500 is not set ++# CONFIG_ARCH_CLPS711X is not set ++# CONFIG_ARCH_CO285 is not set ++CONFIG_ARCH_PXA=y ++# CONFIG_ARCH_EBSA110 is not set ++# CONFIG_ARCH_CAMELOT is not set ++# CONFIG_ARCH_FOOTBRIDGE is not set ++# CONFIG_ARCH_INTEGRATOR is not set ++# CONFIG_ARCH_OMAHA is not set ++# CONFIG_ARCH_L7200 is not set ++# CONFIG_ARCH_MX1ADS is not set ++# CONFIG_ARCH_RPC is not set ++# CONFIG_ARCH_RISCSTATION is not set ++# CONFIG_ARCH_SA1100 is not set ++# CONFIG_ARCH_SHARK is not set ++ ++# ++# Archimedes/A5000 Implementations ++# ++# CONFIG_ARCH_ARC is not set ++# CONFIG_ARCH_A5K is not set ++ ++# ++# Footbridge Implementations ++# ++# CONFIG_ARCH_CATS is not set ++# CONFIG_ARCH_PERSONAL_SERVER is not set ++# CONFIG_ARCH_EBSA285_ADDIN is not set ++# CONFIG_ARCH_EBSA285_HOST is not set ++# CONFIG_ARCH_NETWINDER is not set ++ ++# ++# SA11x0 Implementations ++# ++# CONFIG_SA1100_ACCELENT is not set ++# CONFIG_SA1100_ASSABET is not set ++# CONFIG_ASSABET_NEPONSET is not set ++# CONFIG_SA1100_ADSBITSY is not set ++# CONFIG_SA1100_BRUTUS is not set ++# CONFIG_SA1100_CEP is not set ++# CONFIG_SA1100_CERF is not set ++# CONFIG_SA1100_H3100 is not set ++# CONFIG_SA1100_H3600 is not set ++# CONFIG_SA1100_H3800 is not set ++# CONFIG_SA1100_H3XXX is not set ++# CONFIG_SA1100_EXTENEX1 is not set ++# CONFIG_SA1100_FLEXANET is not set ++# CONFIG_SA1100_FREEBIRD is not set ++# CONFIG_SA1100_FRODO is not set ++# CONFIG_SA1100_GRAPHICSCLIENT is not set ++# CONFIG_SA1100_GRAPHICSMASTER is not set ++# CONFIG_SA1100_BADGE4 is not set ++# CONFIG_SA1100_JORNADA720 is not set ++# CONFIG_SA1100_HUW_WEBPANEL is not set ++# CONFIG_SA1100_ITSY is not set ++# CONFIG_SA1100_LART is not set ++# CONFIG_SA1100_NANOENGINE is not set ++# CONFIG_SA1100_OMNIMETER is not set ++# CONFIG_SA1100_PANGOLIN is not set ++# CONFIG_SA1100_PLEB is not set ++# CONFIG_SA1100_PT_SYSTEM3 is not set ++# CONFIG_SA1100_SHANNON is not set ++# CONFIG_SA1100_SHERMAN is not set ++# CONFIG_SA1100_SIMPAD is not set ++# CONFIG_SA1100_SIMPUTER is not set ++# CONFIG_SA1100_PFS168 is not set ++# CONFIG_SA1100_VICTOR is not set ++# CONFIG_SA1100_XP860 is not set ++# CONFIG_SA1100_YOPY is not set ++# CONFIG_SA1100_USB is not set ++# CONFIG_SA1100_USB_NETLINK is not set ++# CONFIG_SA1100_USB_CHAR is not set ++# CONFIG_H3600_SLEEVE is not set ++ ++# ++# Intel PXA250/210 Implementations ++# ++# CONFIG_ARCH_LUBBOCK is not set ++CONFIG_ARCH_PXA_IDP=y ++# CONFIG_ARCH_PXA_CERF is not set ++CONFIG_PXA_USB=m ++CONFIG_PXA_USB_NETLINK=m ++CONFIG_PXA_USB_CHAR=m ++ ++# ++# CLPS711X/EP721X Implementations ++# ++# CONFIG_ARCH_AUTCPU12 is not set ++# CONFIG_ARCH_CDB89712 is not set ++# CONFIG_ARCH_CLEP7312 is not set ++# CONFIG_ARCH_EDB7211 is not set ++# CONFIG_ARCH_P720T is not set ++# CONFIG_ARCH_FORTUNET is not set ++# CONFIG_ARCH_EP7211 is not set ++# CONFIG_ARCH_EP7212 is not set ++# CONFIG_ARCH_ACORN is not set ++# CONFIG_FOOTBRIDGE is not set ++# CONFIG_FOOTBRIDGE_HOST is not set ++# CONFIG_FOOTBRIDGE_ADDIN is not set ++CONFIG_CPU_32=y ++# CONFIG_CPU_26 is not set ++# CONFIG_CPU_ARM610 is not set ++# CONFIG_CPU_ARM710 is not set ++# CONFIG_CPU_ARM720T is not set ++# CONFIG_CPU_ARM920T is not set ++# CONFIG_CPU_ARM922T is not set ++# CONFIG_PLD is not set ++# CONFIG_CPU_ARM926T is not set ++# CONFIG_CPU_ARM1020 is not set ++# CONFIG_CPU_ARM1026 is not set ++# CONFIG_CPU_SA110 is not set ++# CONFIG_CPU_SA1100 is not set ++CONFIG_CPU_32v5=y ++CONFIG_CPU_XSCALE=y ++# CONFIG_XSCALE_CACHE_ERRATA is not set ++# CONFIG_CPU_32v3 is not set ++# CONFIG_CPU_32v4 is not set ++# CONFIG_DISCONTIGMEM is not set ++ ++# ++# General setup ++# ++# CONFIG_PCI is not set ++# CONFIG_ISA is not set ++# CONFIG_ISA_DMA is not set ++# CONFIG_ZBOOT_ROM is not set ++CONFIG_ZBOOT_ROM_TEXT=0 ++CONFIG_ZBOOT_ROM_BSS=0 ++CONFIG_HOTPLUG=y ++ ++# ++# PCMCIA/CardBus support ++# ++CONFIG_PCMCIA=y ++# CONFIG_I82092 is not set ++# CONFIG_I82365 is not set ++# CONFIG_TCIC is not set ++# CONFIG_PCMCIA_CLPS6700 is not set ++# CONFIG_PCMCIA_SA1100 is not set ++CONFIG_PCMCIA_PXA=y ++CONFIG_NET=y ++CONFIG_SYSVIPC=y ++# CONFIG_BSD_PROCESS_ACCT is not set ++CONFIG_SYSCTL=y ++CONFIG_FPE_NWFPE=y ++# CONFIG_FPE_FASTFPE is not set ++CONFIG_KCORE_ELF=y ++# CONFIG_KCORE_AOUT is not set ++# CONFIG_BINFMT_AOUT is not set ++CONFIG_BINFMT_ELF=y ++# CONFIG_BINFMT_MISC is not set ++CONFIG_PM=y ++# CONFIG_ARTHUR is not set ++CONFIG_CMDLINE="root=/dev/mtdblock2 init=/linuxrc console=ttyS0,115200" ++CONFIG_LEDS=y ++CONFIG_LEDS_TIMER=y ++CONFIG_LEDS_CPU=y ++CONFIG_ALIGNMENT_TRAP=y ++ ++# ++# Parallel port support ++# ++# CONFIG_PARPORT is not set ++ ++# ++# Memory Technology Devices (MTD) ++# ++CONFIG_MTD=y ++# CONFIG_MTD_DEBUG is not set ++CONFIG_MTD_PARTITIONS=y ++# CONFIG_MTD_CONCAT is not set ++# CONFIG_MTD_REDBOOT_PARTS is not set ++# CONFIG_MTD_CMDLINE_PARTS is not set ++# CONFIG_MTD_AFS_PARTS is not set ++CONFIG_MTD_CHAR=y ++CONFIG_MTD_BLOCK=y ++# CONFIG_FTL is not set ++# CONFIG_NFTL is not set ++ ++# ++# RAM/ROM/Flash chip drivers ++# ++CONFIG_MTD_CFI=y ++# CONFIG_MTD_JEDECPROBE is not set ++CONFIG_MTD_GEN_PROBE=y ++CONFIG_MTD_CFI_ADV_OPTIONS=y ++CONFIG_MTD_CFI_NOSWAP=y ++# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set ++# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set ++CONFIG_MTD_CFI_GEOMETRY=y ++# CONFIG_MTD_CFI_B1 is not set ++# CONFIG_MTD_CFI_B2 is not set ++CONFIG_MTD_CFI_B4=y ++# CONFIG_MTD_CFI_B8 is not set ++# CONFIG_MTD_CFI_I1 is not set ++CONFIG_MTD_CFI_I2=y ++# CONFIG_MTD_CFI_I4 is not set ++# CONFIG_MTD_CFI_I8 is not set ++CONFIG_MTD_CFI_INTELEXT=y ++# CONFIG_MTD_CFI_AMDSTD is not set ++# CONFIG_MTD_RAM is not set ++# CONFIG_MTD_ROM is not set ++# CONFIG_MTD_ABSENT is not set ++# CONFIG_MTD_OBSOLETE_CHIPS is not set ++# CONFIG_MTD_AMDSTD is not set ++# CONFIG_MTD_SHARP is not set ++# CONFIG_MTD_JEDEC is not set ++ ++# ++# Mapping drivers for chip access ++# ++# CONFIG_MTD_PHYSMAP is not set ++CONFIG_MTD_LUBBOCK=y ++# CONFIG_MTD_NORA is not set ++# CONFIG_MTD_ARM_INTEGRATOR is not set ++# CONFIG_MTD_CDB89712 is not set ++# CONFIG_MTD_SA1100 is not set ++# CONFIG_MTD_DC21285 is not set ++# CONFIG_MTD_IQ80310 is not set ++# CONFIG_MTD_FORTUNET is not set ++# CONFIG_MTD_PXA_CERF is not set ++# CONFIG_MTD_EPXA10DB is not set ++# CONFIG_MTD_AUTCPU12 is not set ++# CONFIG_MTD_EDB7312 is not set ++# CONFIG_MTD_IMPA7 is not set ++CONFIG_ASI_MTD0_SIZE=40000 ++CONFIG_ASI_MTD1_SIZE=100000 ++CONFIG_ASI_MTD2_SIZE=1e00000 ++# CONFIG_MTD_PCI is not set ++ ++# ++# Self-contained MTD device drivers ++# ++# CONFIG_MTD_PMC551 is not set ++# CONFIG_MTD_SLRAM is not set ++# CONFIG_MTD_MTDRAM is not set ++# CONFIG_MTD_BLKMTD is not set ++# CONFIG_MTD_DOC1000 is not set ++# CONFIG_MTD_DOC2000 is not set ++# CONFIG_MTD_DOC2001 is not set ++# CONFIG_MTD_DOCPROBE is not set ++ ++# ++# NAND Flash Device Drivers ++# ++# CONFIG_MTD_NAND is not set ++ ++# ++# Plug and Play configuration ++# ++# CONFIG_PNP is not set ++# CONFIG_ISAPNP is not set ++ ++# ++# Block devices ++# ++# CONFIG_BLK_DEV_FD is not set ++# CONFIG_BLK_DEV_XD is not set ++# CONFIG_PARIDE is not set ++# CONFIG_BLK_CPQ_DA is not set ++# CONFIG_BLK_CPQ_CISS_DA is not set ++# CONFIG_CISS_SCSI_TAPE is not set ++# CONFIG_BLK_DEV_DAC960 is not set ++# CONFIG_BLK_DEV_UMEM is not set ++CONFIG_BLK_DEV_LOOP=y ++# CONFIG_BLK_DEV_NBD is not set ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_SIZE=4096 ++CONFIG_BLK_DEV_INITRD=y ++ ++# ++# Multi-device support (RAID and LVM) ++# ++# CONFIG_MD is not set ++# CONFIG_BLK_DEV_MD is not set ++# CONFIG_MD_LINEAR is not set ++# CONFIG_MD_RAID0 is not set ++# CONFIG_MD_RAID1 is not set ++# CONFIG_MD_RAID5 is not set ++# CONFIG_MD_MULTIPATH is not set ++# CONFIG_BLK_DEV_LVM is not set ++ ++# ++# Networking options ++# ++CONFIG_PACKET=y ++# CONFIG_PACKET_MMAP is not set ++# CONFIG_NETLINK_DEV is not set ++# CONFIG_NETFILTER is not set ++# CONFIG_FILTER is not set ++CONFIG_UNIX=y ++CONFIG_INET=y ++# CONFIG_IP_MULTICAST is not set ++# CONFIG_IP_ADVANCED_ROUTER is not set ++# CONFIG_IP_PNP is not set ++# CONFIG_NET_IPIP is not set ++# CONFIG_NET_IPGRE is not set ++# CONFIG_ARPD is not set ++# CONFIG_INET_ECN is not set ++# CONFIG_SYN_COOKIES is not set ++# CONFIG_IPV6 is not set ++# CONFIG_KHTTPD is not set ++# CONFIG_ATM is not set ++# CONFIG_VLAN_8021Q is not set ++# CONFIG_IPX is not set ++# CONFIG_ATALK is not set ++ ++# ++# Appletalk devices ++# ++# CONFIG_DEV_APPLETALK is not set ++# CONFIG_DECNET is not set ++# CONFIG_BRIDGE is not set ++# CONFIG_X25 is not set ++# CONFIG_LAPB is not set ++# CONFIG_LLC is not set ++# CONFIG_NET_DIVERT is not set ++# CONFIG_ECONET is not set ++# CONFIG_WAN_ROUTER is not set ++# CONFIG_NET_FASTROUTE is not set ++# CONFIG_NET_HW_FLOWCONTROL is not set ++ ++# ++# QoS and/or fair queueing ++# ++# CONFIG_NET_SCHED is not set ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++ ++# ++# Network device support ++# ++CONFIG_NETDEVICES=y ++ ++# ++# ARCnet devices ++# ++# CONFIG_ARCNET is not set ++# CONFIG_DUMMY is not set ++# CONFIG_BONDING is not set ++# CONFIG_EQUALIZER is not set ++# CONFIG_TUN is not set ++# CONFIG_ETHERTAP is not set ++ ++# ++# Ethernet (10 or 100Mbit) ++# ++CONFIG_NET_ETHERNET=y ++# CONFIG_ARM_AM79C961A is not set ++# CONFIG_ARM_CIRRUS is not set ++# CONFIG_SUNLANCE is not set ++# CONFIG_SUNBMAC is not set ++# CONFIG_SUNQE is not set ++# CONFIG_SUNGEM is not set ++# CONFIG_NET_VENDOR_3COM is not set ++# CONFIG_LANCE is not set ++CONFIG_NET_VENDOR_SMC=y ++# CONFIG_WD80x3 is not set ++# CONFIG_ULTRAMCA is not set ++# CONFIG_ULTRA is not set ++# CONFIG_ULTRA32 is not set ++# CONFIG_SMC9194 is not set ++CONFIG_SMC91111=m ++# CONFIG_NET_VENDOR_RACAL is not set ++# CONFIG_NET_ISA is not set ++# CONFIG_NET_PCI is not set ++CONFIG_NET_POCKET=y ++# CONFIG_DE600 is not set ++# CONFIG_DE620 is not set ++ ++# ++# Ethernet (1000 Mbit) ++# ++# CONFIG_ACENIC is not set ++# CONFIG_DL2K is not set ++# CONFIG_MYRI_SBUS is not set ++# CONFIG_NS83820 is not set ++# CONFIG_HAMACHI is not set ++# CONFIG_YELLOWFIN is not set ++# CONFIG_SK98LIN is not set ++# CONFIG_TIGON3 is not set ++# CONFIG_FDDI is not set ++# CONFIG_HIPPI is not set ++# CONFIG_PLIP is not set ++# CONFIG_PPP is not set ++# CONFIG_SLIP is not set ++ ++# ++# Wireless LAN (non-hamradio) ++# ++CONFIG_NET_RADIO=y ++# CONFIG_STRIP is not set ++CONFIG_WAVELAN=m ++# CONFIG_ARLAN is not set ++CONFIG_AIRONET4500=y ++# CONFIG_AIRONET4500_NONCS is not set ++# CONFIG_AIRONET4500_PROC is not set ++CONFIG_HERMES=m ++CONFIG_PCMCIA_HERMES=m ++CONFIG_AIRO_CS=m ++CONFIG_NET_WIRELESS=y ++ ++# ++# Token Ring devices ++# ++# CONFIG_TR is not set ++# CONFIG_NET_FC is not set ++# CONFIG_RCPCI is not set ++# CONFIG_SHAPER is not set ++ ++# ++# Wan interfaces ++# ++# CONFIG_WAN is not set ++ ++# ++# PCMCIA network device support ++# ++CONFIG_NET_PCMCIA=y ++# CONFIG_PCMCIA_3C589 is not set ++# CONFIG_PCMCIA_3C574 is not set ++# CONFIG_PCMCIA_FMVJ18X is not set ++CONFIG_PCMCIA_PCNET=m ++# CONFIG_PCMCIA_AXNET is not set ++CONFIG_PCMCIA_NMCLAN=m ++CONFIG_PCMCIA_SMC91C92=m ++CONFIG_PCMCIA_XIRC2PS=m ++# CONFIG_ARCNET_COM20020_CS is not set ++# CONFIG_PCMCIA_IBMTR is not set ++CONFIG_NET_PCMCIA_RADIO=y ++CONFIG_PCMCIA_RAYCS=m ++CONFIG_PCMCIA_NETWAVE=m ++CONFIG_PCMCIA_WAVELAN=m ++CONFIG_AIRONET4500_CS=m ++ ++# ++# Amateur Radio support ++# ++# CONFIG_HAMRADIO is not set ++ ++# ++# IrDA (infrared) support ++# ++CONFIG_IRDA=m ++CONFIG_IRLAN=m ++# CONFIG_IRNET is not set ++CONFIG_IRCOMM=m ++CONFIG_IRDA_ULTRA=y ++# CONFIG_IRDA_CACHE_LAST_LSAP is not set ++# CONFIG_IRDA_FAST_RR is not set ++CONFIG_IRDA_DEBUG=y ++ ++# ++# Infrared-port device drivers ++# ++CONFIG_IRTTY_SIR=m ++# CONFIG_IRPORT_SIR is not set ++# CONFIG_DONGLE is not set ++# CONFIG_USB_IRDA is not set ++# CONFIG_NSC_FIR is not set ++# CONFIG_WINBOND_FIR is not set ++# CONFIG_TOSHIBA_FIR is not set ++# CONFIG_SMC_IRCC_FIR is not set ++# CONFIG_ALI_FIR is not set ++# CONFIG_VLSI_FIR is not set ++CONFIG_PXA_FIR=m ++ ++# ++# ATA/ATAPI/MFM/RLL support ++# ++CONFIG_IDE=y ++ ++# ++# IDE, ATA and ATAPI Block devices ++# ++CONFIG_BLK_DEV_IDE=y ++# CONFIG_BLK_DEV_HD_IDE is not set ++# CONFIG_BLK_DEV_HD is not set ++CONFIG_BLK_DEV_IDEDISK=y ++# CONFIG_IDEDISK_MULTI_MODE is not set ++# CONFIG_IDEDISK_STROKE is not set ++# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set ++# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set ++# CONFIG_BLK_DEV_IDEDISK_IBM is not set ++# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set ++# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set ++# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set ++# CONFIG_BLK_DEV_IDEDISK_WD is not set ++# CONFIG_BLK_DEV_COMMERIAL is not set ++# CONFIG_BLK_DEV_TIVO is not set ++CONFIG_BLK_DEV_IDECS=m ++# CONFIG_BLK_DEV_IDECD is not set ++# CONFIG_BLK_DEV_IDETAPE is not set ++# CONFIG_BLK_DEV_IDEFLOPPY is not set ++# CONFIG_BLK_DEV_IDESCSI is not set ++# CONFIG_IDE_TASK_IOCTL is not set ++# CONFIG_BLK_DEV_CMD640 is not set ++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set ++# CONFIG_BLK_DEV_ISAPNP is not set ++# CONFIG_IDE_CHIPSETS is not set ++# CONFIG_IDEDMA_AUTO is not set ++# CONFIG_DMA_NONPCI is not set ++# CONFIG_BLK_DEV_IDE_MODES is not set ++# CONFIG_BLK_DEV_ATARAID is not set ++# CONFIG_BLK_DEV_ATARAID_PDC is not set ++# CONFIG_BLK_DEV_ATARAID_HPT is not set ++ ++# ++# SCSI support ++# ++# CONFIG_SCSI is not set ++ ++# ++# I2O device support ++# ++# CONFIG_I2O is not set ++# CONFIG_I2O_BLOCK is not set ++# CONFIG_I2O_LAN is not set ++# CONFIG_I2O_SCSI is not set ++# CONFIG_I2O_PROC is not set ++ ++# ++# ISDN subsystem ++# ++# CONFIG_ISDN is not set ++ ++# ++# Input core support ++# ++CONFIG_INPUT=y ++CONFIG_INPUT_KEYBDEV=m ++CONFIG_INPUT_MOUSEDEV=m ++CONFIG_INPUT_MOUSEDEV_SCREEN_X=640 ++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480 ++# CONFIG_INPUT_JOYDEV is not set ++CONFIG_INPUT_EVDEV=y ++ ++# ++# Character devices ++# ++CONFIG_VT=y ++# CONFIG_VT_CONSOLE is not set ++CONFIG_SERIAL=y ++CONFIG_SERIAL_CONSOLE=y ++# CONFIG_SERIAL_EXTENDED is not set ++# CONFIG_SERIAL_NONSTANDARD is not set ++ ++# ++# Serial drivers ++# ++# CONFIG_SERIAL_ANAKIN is not set ++# CONFIG_SERIAL_ANAKIN_CONSOLE is not set ++# CONFIG_SERIAL_AMBA is not set ++# CONFIG_SERIAL_AMBA_CONSOLE is not set ++# CONFIG_SERIAL_CLPS711X is not set ++# CONFIG_SERIAL_CLPS711X_CONSOLE is not set ++# CONFIG_SERIAL_21285 is not set ++# CONFIG_SERIAL_21285_OLD is not set ++# CONFIG_SERIAL_21285_CONSOLE is not set ++# CONFIG_SERIAL_UART00 is not set ++# CONFIG_SERIAL_UART00_CONSOLE is not set ++# CONFIG_SERIAL_SA1100 is not set ++# CONFIG_SERIAL_SA1100_CONSOLE is not set ++# CONFIG_SERIAL_OMAHA is not set ++# CONFIG_SERIAL_OMAHA_CONSOLE is not set ++# CONFIG_SERIAL_8250 is not set ++# CONFIG_SERIAL_8250_CONSOLE is not set ++# CONFIG_SERIAL_8250_EXTENDED is not set ++# CONFIG_SERIAL_8250_MANY_PORTS is not set ++# CONFIG_SERIAL_8250_SHARE_IRQ is not set ++# CONFIG_SERIAL_8250_DETECT_IRQ is not set ++# CONFIG_SERIAL_8250_MULTIPORT is not set ++# CONFIG_SERIAL_8250_HUB6 is not set ++# CONFIG_IDP_KEYB is not set ++CONFIG_MATRIX_KEYBOARD=y ++# CONFIG_SA1111_PS2_KEYB is not set ++CONFIG_UNIX98_PTYS=y ++CONFIG_UNIX98_PTY_COUNT=256 ++ ++# ++# I2C support ++# ++# CONFIG_I2C is not set ++ ++# ++# L3 serial bus support ++# ++# CONFIG_L3 is not set ++# CONFIG_L3_ALGOBIT is not set ++# CONFIG_L3_BIT_SA1100_GPIO is not set ++# CONFIG_L3_SA1111 is not set ++# CONFIG_BIT_SA1100_GPIO is not set ++ ++# ++# Mice ++# ++CONFIG_BUSMOUSE=y ++# CONFIG_ATIXL_BUSMOUSE is not set ++# CONFIG_LOGIBUSMOUSE is not set ++# CONFIG_MS_BUSMOUSE is not set ++CONFIG_MOUSE=y ++CONFIG_PSMOUSE=y ++# CONFIG_82C710_MOUSE is not set ++# CONFIG_PC110_PAD is not set ++# CONFIG_MK712_MOUSE is not set ++ ++# ++# Joysticks ++# ++# CONFIG_INPUT_GAMEPORT is not set ++# CONFIG_INPUT_NS558 is not set ++# CONFIG_INPUT_LIGHTNING is not set ++# CONFIG_INPUT_PCIGAME is not set ++# CONFIG_INPUT_CS461X is not set ++# CONFIG_INPUT_EMU10K1 is not set ++# CONFIG_INPUT_SERIO is not set ++# CONFIG_INPUT_SERPORT is not set ++# CONFIG_INPUT_ANALOG is not set ++# CONFIG_INPUT_A3D is not set ++# CONFIG_INPUT_ADI is not set ++# CONFIG_INPUT_COBRA is not set ++# CONFIG_INPUT_GF2K is not set ++# CONFIG_INPUT_GRIP is not set ++# CONFIG_INPUT_INTERACT is not set ++# CONFIG_INPUT_TMDC is not set ++# CONFIG_INPUT_SIDEWINDER is not set ++# CONFIG_INPUT_IFORCE_USB is not set ++# CONFIG_INPUT_IFORCE_232 is not set ++# CONFIG_INPUT_WARRIOR is not set ++# CONFIG_INPUT_MAGELLAN is not set ++# CONFIG_INPUT_SPACEORB is not set ++# CONFIG_INPUT_SPACEBALL is not set ++# CONFIG_INPUT_STINGER is not set ++# CONFIG_INPUT_DB9 is not set ++# CONFIG_INPUT_GAMECON is not set ++# CONFIG_INPUT_TURBOGRAFX is not set ++# CONFIG_QIC02_TAPE is not set ++ ++# ++# Watchdog Cards ++# ++# CONFIG_WATCHDOG is not set ++# CONFIG_NVRAM is not set ++# CONFIG_RTC is not set ++# CONFIG_PXA_RTC is not set ++# CONFIG_DTLK is not set ++# CONFIG_R3964 is not set ++# CONFIG_APPLICOM is not set ++ ++# ++# Ftape, the floppy tape device driver ++# ++# CONFIG_FTAPE is not set ++# CONFIG_AGP is not set ++# CONFIG_DRM is not set ++ ++# ++# PCMCIA character devices ++# ++CONFIG_PCMCIA_SERIAL_CS=m ++ ++# ++# Multimedia devices ++# ++# CONFIG_VIDEO_DEV is not set ++ ++# ++# File systems ++# ++# CONFIG_QUOTA is not set ++# CONFIG_AUTOFS_FS is not set ++# CONFIG_AUTOFS4_FS is not set ++# CONFIG_REISERFS_FS is not set ++# CONFIG_REISERFS_CHECK is not set ++# CONFIG_REISERFS_PROC_INFO is not set ++# CONFIG_ADFS_FS is not set ++# CONFIG_ADFS_FS_RW is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_BFS_FS is not set ++CONFIG_EXT3_FS=m ++CONFIG_JBD=m ++# CONFIG_JBD_DEBUG is not set ++CONFIG_FAT_FS=m ++CONFIG_MSDOS_FS=m ++# CONFIG_UMSDOS_FS is not set ++CONFIG_VFAT_FS=m ++# CONFIG_EFS_FS is not set ++# CONFIG_JFFS_FS is not set ++CONFIG_JFFS2_FS=y ++CONFIG_JFFS2_FS_DEBUG=0 ++CONFIG_CRAMFS=y ++# CONFIG_TMPFS is not set ++CONFIG_RAMFS=y ++# CONFIG_ISO9660_FS is not set ++# CONFIG_JOLIET is not set ++# CONFIG_ZISOFS is not set ++# CONFIG_MINIX_FS is not set ++# CONFIG_VXFS_FS is not set ++# CONFIG_NTFS_FS is not set ++# CONFIG_NTFS_RW is not set ++# CONFIG_HPFS_FS is not set ++CONFIG_PROC_FS=y ++CONFIG_DEVFS_FS=y ++CONFIG_DEVFS_MOUNT=y ++# CONFIG_DEVFS_DEBUG is not set ++CONFIG_DEVPTS_FS=y ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_QNX4FS_RW is not set ++# CONFIG_ROMFS_FS is not set ++CONFIG_EXT2_FS=y ++# CONFIG_SYSV_FS is not set ++# CONFIG_UDF_FS is not set ++# CONFIG_UDF_RW is not set ++# CONFIG_UFS_FS is not set ++# CONFIG_UFS_FS_WRITE is not set ++ ++# ++# Network File Systems ++# ++# CONFIG_CODA_FS is not set ++# CONFIG_INTERMEZZO_FS is not set ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++# CONFIG_ROOT_NFS is not set ++# CONFIG_NFSD is not set ++# CONFIG_NFSD_V3 is not set ++CONFIG_SUNRPC=y ++CONFIG_LOCKD=y ++CONFIG_LOCKD_V4=y ++# CONFIG_SMB_FS is not set ++# CONFIG_NCP_FS is not set ++# CONFIG_NCPFS_PACKET_SIGNING is not set ++# CONFIG_NCPFS_IOCTL_LOCKING is not set ++# CONFIG_NCPFS_STRONG is not set ++# CONFIG_NCPFS_NFS_NS is not set ++# CONFIG_NCPFS_OS2_NS is not set ++# CONFIG_NCPFS_SMALLDOS is not set ++# CONFIG_NCPFS_NLS is not set ++# CONFIG_NCPFS_EXTRAS is not set ++# CONFIG_ZISOFS_FS is not set ++CONFIG_ZLIB_FS_INFLATE=y ++ ++# ++# Partition Types ++# ++CONFIG_PARTITION_ADVANCED=y ++# CONFIG_ACORN_PARTITION is not set ++# CONFIG_OSF_PARTITION is not set ++# CONFIG_AMIGA_PARTITION is not set ++# CONFIG_ATARI_PARTITION is not set ++# CONFIG_MAC_PARTITION is not set ++CONFIG_MSDOS_PARTITION=y ++# CONFIG_BSD_DISKLABEL is not set ++# CONFIG_MINIX_SUBPARTITION is not set ++# CONFIG_SOLARIS_X86_PARTITION is not set ++# CONFIG_UNIXWARE_DISKLABEL is not set ++# CONFIG_LDM_PARTITION is not set ++# CONFIG_SGI_PARTITION is not set ++# CONFIG_ULTRIX_PARTITION is not set ++# CONFIG_SUN_PARTITION is not set ++# CONFIG_SMB_NLS is not set ++CONFIG_NLS=y ++ ++# ++# Native Language Support ++# ++CONFIG_NLS_DEFAULT="iso8859-1" ++CONFIG_NLS_CODEPAGE_437=m ++# CONFIG_NLS_CODEPAGE_737 is not set ++# CONFIG_NLS_CODEPAGE_775 is not set ++# CONFIG_NLS_CODEPAGE_850 is not set ++# CONFIG_NLS_CODEPAGE_852 is not set ++# CONFIG_NLS_CODEPAGE_855 is not set ++# CONFIG_NLS_CODEPAGE_857 is not set ++# CONFIG_NLS_CODEPAGE_860 is not set ++# CONFIG_NLS_CODEPAGE_861 is not set ++# CONFIG_NLS_CODEPAGE_862 is not set ++# CONFIG_NLS_CODEPAGE_863 is not set ++# CONFIG_NLS_CODEPAGE_864 is not set ++# CONFIG_NLS_CODEPAGE_865 is not set ++# CONFIG_NLS_CODEPAGE_866 is not set ++# CONFIG_NLS_CODEPAGE_869 is not set ++# CONFIG_NLS_CODEPAGE_936 is not set ++# CONFIG_NLS_CODEPAGE_950 is not set ++# CONFIG_NLS_CODEPAGE_932 is not set ++# CONFIG_NLS_CODEPAGE_949 is not set ++# CONFIG_NLS_CODEPAGE_874 is not set ++# CONFIG_NLS_ISO8859_8 is not set ++# CONFIG_NLS_CODEPAGE_1250 is not set ++# CONFIG_NLS_CODEPAGE_1251 is not set ++CONFIG_NLS_ISO8859_1=y ++# CONFIG_NLS_ISO8859_2 is not set ++# CONFIG_NLS_ISO8859_3 is not set ++# CONFIG_NLS_ISO8859_4 is not set ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++# CONFIG_NLS_UTF8 is not set ++ ++# ++# Console drivers ++# ++CONFIG_PC_KEYMAP=y ++# CONFIG_VGA_CONSOLE is not set ++ ++# ++# Frame-buffer support ++# ++CONFIG_FB=y ++CONFIG_DUMMY_CONSOLE=y ++# CONFIG_FB_ACORN is not set ++# CONFIG_FB_ANAKIN is not set ++# CONFIG_FB_CLPS711X is not set ++# CONFIG_FB_SA1100 is not set ++CONFIG_FB_PXA=y ++# CONFIG_FB_CYBER2000 is not set ++# CONFIG_FB_VIRTUAL is not set ++# CONFIG_FBCON_ADVANCED is not set ++CONFIG_FBCON_CFB2=y ++CONFIG_FBCON_CFB4=y ++CONFIG_FBCON_CFB8=y ++CONFIG_FBCON_CFB16=y ++# CONFIG_FBCON_FONTWIDTH8_ONLY is not set ++# CONFIG_FBCON_FONTS is not set ++CONFIG_FONT_8x8=y ++CONFIG_FONT_8x16=y ++ ++# ++# Sound ++# ++CONFIG_SOUND=y ++# CONFIG_SOUND_BT878 is not set ++# CONFIG_SOUND_CMPCI is not set ++# CONFIG_SOUND_EMU10K1 is not set ++# CONFIG_MIDI_EMU10K1 is not set ++# CONFIG_SOUND_FUSION is not set ++# CONFIG_SOUND_CS4281 is not set ++# CONFIG_SOUND_ES1370 is not set ++# CONFIG_SOUND_ES1371 is not set ++# CONFIG_SOUND_ESSSOLO1 is not set ++# CONFIG_SOUND_MAESTRO is not set ++# CONFIG_SOUND_MAESTRO3 is not set ++# CONFIG_SOUND_ICH is not set ++# CONFIG_SOUND_RME96XX is not set ++# CONFIG_SOUND_SONICVIBES is not set ++# CONFIG_SOUND_TRIDENT is not set ++# CONFIG_SOUND_MSNDCLAS is not set ++# CONFIG_SOUND_MSNDPIN is not set ++# CONFIG_SOUND_VIA82CXXX is not set ++# CONFIG_MIDI_VIA82CXXX is not set ++# CONFIG_SOUND_OSS is not set ++# CONFIG_SOUND_WAVEARTIST is not set ++CONFIG_SOUND_PXA_AC97=y ++# CONFIG_SOUND_TVMIXER is not set ++ ++# ++# Multimedia Capabilities Port drivers ++# ++# CONFIG_MCP is not set ++# CONFIG_MCP_SA1100 is not set ++# CONFIG_MCP_UCB1200 is not set ++# CONFIG_MCP_UCB1200_AUDIO is not set ++# CONFIG_MCP_UCB1200_TS is not set ++CONFIG_MCP_UCB1400_TS=m ++ ++# ++# USB support ++# ++# CONFIG_USB is not set ++ ++# ++# Bluetooth support ++# ++# CONFIG_BLUEZ is not set ++ ++# ++# Kernel hacking ++# ++CONFIG_FRAME_POINTER=y ++CONFIG_DEBUG_USER=y ++# CONFIG_DEBUG_INFO is not set ++# CONFIG_NO_PGT_CACHE is not set ++CONFIG_DEBUG_KERNEL=y ++CONFIG_DEBUG_SLAB=y ++# CONFIG_MAGIC_SYSRQ is not set ++# CONFIG_DEBUG_SPINLOCK is not set ++# CONFIG_DEBUG_WAITQ is not set ++CONFIG_DEBUG_BUGVERBOSE=y ++CONFIG_DEBUG_ERRORS=y ++# CONFIG_DEBUG_LL is not set ++# CONFIG_DEBUG_DC21285_PORT is not set ++# CONFIG_DEBUG_CLPS711X_UART2 is not set +--- /dev/null ++++ linux-2.4.27/arch/arm/def-configs/trizeps2 +@@ -0,0 +1,873 @@ ++# ++# Automatically generated by make menuconfig: don't edit ++# ++CONFIG_ARM=y ++# CONFIG_EISA is not set ++# CONFIG_SBUS is not set ++# CONFIG_MCA is not set ++CONFIG_UID16=y ++CONFIG_RWSEM_GENERIC_SPINLOCK=y ++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set ++# CONFIG_GENERIC_BUST_SPINLOCK is not set ++# CONFIG_GENERIC_ISA_DMA is not set ++ ++# ++# Code maturity level options ++# ++CONFIG_EXPERIMENTAL=y ++# CONFIG_OBSOLETE is not set ++ ++# ++# Loadable module support ++# ++CONFIG_MODULES=y ++# CONFIG_MODVERSIONS is not set ++CONFIG_KMOD=y ++ ++# ++# System Type ++# ++# CONFIG_ARCH_ANAKIN is not set ++# CONFIG_ARCH_ARCA5K is not set ++# CONFIG_ARCH_CLPS7500 is not set ++# CONFIG_ARCH_CLPS711X is not set ++# CONFIG_ARCH_CO285 is not set ++CONFIG_ARCH_PXA=y ++# CONFIG_ARCH_EBSA110 is not set ++# CONFIG_ARCH_CAMELOT is not set ++# CONFIG_ARCH_FOOTBRIDGE is not set ++# CONFIG_ARCH_INTEGRATOR is not set ++# CONFIG_ARCH_OMAHA is not set ++# CONFIG_ARCH_L7200 is not set ++# CONFIG_ARCH_MX1ADS is not set ++# CONFIG_ARCH_RPC is not set ++# CONFIG_ARCH_RISCSTATION is not set ++# CONFIG_ARCH_SA1100 is not set ++# CONFIG_ARCH_SHARK is not set ++ ++# ++# Archimedes/A5000 Implementations ++# ++# CONFIG_ARCH_ARC is not set ++# CONFIG_ARCH_A5K is not set ++ ++# ++# Footbridge Implementations ++# ++# CONFIG_ARCH_CATS is not set ++# CONFIG_ARCH_PERSONAL_SERVER is not set ++# CONFIG_ARCH_EBSA285_ADDIN is not set ++# CONFIG_ARCH_EBSA285_HOST is not set ++# CONFIG_ARCH_NETWINDER is not set ++ ++# ++# SA11x0 Implementations ++# ++# CONFIG_SA1100_ACCELENT is not set ++# CONFIG_SA1100_ASSABET is not set ++# CONFIG_ASSABET_NEPONSET is not set ++# CONFIG_SA1100_ADSBITSY is not set ++# CONFIG_SA1100_BRUTUS is not set ++# CONFIG_SA1100_CEP is not set ++# CONFIG_SA1100_CERF is not set ++# CONFIG_SA1100_H3100 is not set ++# CONFIG_SA1100_H3600 is not set ++# CONFIG_SA1100_H3800 is not set ++# CONFIG_SA1100_H3XXX is not set ++# CONFIG_SA1100_EXTENEX1 is not set ++# CONFIG_SA1100_FLEXANET is not set ++# CONFIG_SA1100_FREEBIRD is not set ++# CONFIG_SA1100_FRODO is not set ++# CONFIG_SA1100_GRAPHICSCLIENT is not set ++# CONFIG_SA1100_GRAPHICSMASTER is not set ++# CONFIG_SA1100_BADGE4 is not set ++# CONFIG_SA1100_JORNADA720 is not set ++# CONFIG_SA1100_HUW_WEBPANEL is not set ++# CONFIG_SA1100_ITSY is not set ++# CONFIG_SA1100_LART is not set ++# CONFIG_SA1100_NANOENGINE is not set ++# CONFIG_SA1100_OMNIMETER is not set ++# CONFIG_SA1100_PANGOLIN is not set ++# CONFIG_SA1100_PLEB is not set ++# CONFIG_SA1100_PT_SYSTEM3 is not set ++# CONFIG_SA1100_SHANNON is not set ++# CONFIG_SA1100_SHERMAN is not set ++# CONFIG_SA1100_SIMPAD is not set ++# CONFIG_SA1100_SIMPUTER is not set ++# CONFIG_SA1100_PFS168 is not set ++# CONFIG_SA1100_VICTOR is not set ++# CONFIG_SA1100_XP860 is not set ++# CONFIG_SA1100_YOPY is not set ++# CONFIG_SA1100_USB is not set ++# CONFIG_SA1100_USB_NETLINK is not set ++# CONFIG_SA1100_USB_CHAR is not set ++# CONFIG_H3600_SLEEVE is not set ++ ++# ++# Intel PXA250/210 Implementations ++# ++# CONFIG_ARCH_LUBBOCK is not set ++# CONFIG_ARCH_PXA_IDP is not set ++# CONFIG_ARCH_PXA_CERF is not set ++CONFIG_ARCH_TRIZEPS2=y ++CONFIG_TRIZEPS2=y ++CONFIG_PXA_USB=y ++# CONFIG_PXA_USB_NETLINK is not set ++# CONFIG_PXA_USB_CHAR is not set ++ ++# ++# CLPS711X/EP721X Implementations ++# ++# CONFIG_ARCH_AUTCPU12 is not set ++# CONFIG_ARCH_CDB89712 is not set ++# CONFIG_ARCH_CLEP7312 is not set ++# CONFIG_ARCH_EDB7211 is not set ++# CONFIG_ARCH_P720T is not set ++# CONFIG_ARCH_FORTUNET is not set ++# CONFIG_ARCH_EP7211 is not set ++# CONFIG_ARCH_EP7212 is not set ++# CONFIG_ARCH_ACORN is not set ++# CONFIG_FOOTBRIDGE is not set ++# CONFIG_FOOTBRIDGE_HOST is not set ++# CONFIG_FOOTBRIDGE_ADDIN is not set ++CONFIG_CPU_32=y ++# CONFIG_CPU_26 is not set ++# CONFIG_CPU_ARM610 is not set ++# CONFIG_CPU_ARM710 is not set ++# CONFIG_CPU_ARM720T is not set ++# CONFIG_CPU_ARM920T is not set ++# CONFIG_CPU_ARM922T is not set ++# CONFIG_PLD is not set ++# CONFIG_CPU_ARM926T is not set ++# CONFIG_CPU_ARM1020 is not set ++# CONFIG_CPU_ARM1026 is not set ++# CONFIG_CPU_SA110 is not set ++# CONFIG_CPU_SA1100 is not set ++CONFIG_CPU_32v5=y ++CONFIG_CPU_XSCALE=y ++# CONFIG_XSCALE_CACHE_ERRATA is not set ++# CONFIG_CPU_32v3 is not set ++# CONFIG_CPU_32v4 is not set ++# CONFIG_DISCONTIGMEM is not set ++ ++# ++# General setup ++# ++# CONFIG_PCI is not set ++# CONFIG_ISA is not set ++# CONFIG_ISA_DMA is not set ++# CONFIG_ZBOOT_ROM is not set ++CONFIG_ZBOOT_ROM_TEXT=0 ++CONFIG_ZBOOT_ROM_BSS=0 ++CONFIG_HOTPLUG=y ++ ++# ++# PCMCIA/CardBus support ++# ++CONFIG_PCMCIA=y ++# CONFIG_I82092 is not set ++# CONFIG_I82365 is not set ++# CONFIG_TCIC is not set ++# CONFIG_PCMCIA_CLPS6700 is not set ++# CONFIG_PCMCIA_SA1100 is not set ++CONFIG_PCMCIA_PXA=y ++CONFIG_NET=y ++CONFIG_SYSVIPC=y ++# CONFIG_BSD_PROCESS_ACCT is not set ++CONFIG_SYSCTL=y ++CONFIG_FPE_NWFPE=y ++# CONFIG_FPE_FASTFPE is not set ++CONFIG_KCORE_ELF=y ++# CONFIG_KCORE_AOUT is not set ++# CONFIG_BINFMT_AOUT is not set ++CONFIG_BINFMT_ELF=y ++# CONFIG_BINFMT_MISC is not set ++# CONFIG_PM is not set ++# CONFIG_ARTHUR is not set ++CONFIG_CMDLINE="root=/dev/mtdblock3 rw console=ttyS0,38400 mem=32M noinitrd init=/linuxrc" ++CONFIG_ALIGNMENT_TRAP=y ++ ++# ++# Parallel port support ++# ++# CONFIG_PARPORT is not set ++ ++# ++# Memory Technology Devices (MTD) ++# ++CONFIG_MTD=y ++# CONFIG_MTD_DEBUG is not set ++CONFIG_MTD_PARTITIONS=y ++# CONFIG_MTD_CONCAT is not set ++CONFIG_MTD_REDBOOT_PARTS=y ++CONFIG_MTD_CMDLINE_PARTS=y ++# CONFIG_MTD_AFS_PARTS is not set ++CONFIG_MTD_CHAR=y ++CONFIG_MTD_BLOCK=y ++# CONFIG_FTL is not set ++# CONFIG_NFTL is not set ++ ++# ++# RAM/ROM/Flash chip drivers ++# ++CONFIG_MTD_CFI=y ++# CONFIG_MTD_JEDECPROBE is not set ++CONFIG_MTD_GEN_PROBE=y ++# CONFIG_MTD_CFI_ADV_OPTIONS is not set ++CONFIG_MTD_CFI_INTELEXT=y ++# CONFIG_MTD_CFI_AMDSTD is not set ++# CONFIG_MTD_RAM is not set ++# CONFIG_MTD_ROM is not set ++# CONFIG_MTD_ABSENT is not set ++# CONFIG_MTD_OBSOLETE_CHIPS is not set ++# CONFIG_MTD_AMDSTD is not set ++# CONFIG_MTD_SHARP is not set ++# CONFIG_MTD_JEDEC is not set ++ ++# ++# Mapping drivers for chip access ++# ++# CONFIG_MTD_PHYSMAP is not set ++# CONFIG_MTD_LUBBOCK is not set ++# CONFIG_MTD_NORA is not set ++# CONFIG_MTD_ARM_INTEGRATOR is not set ++# CONFIG_MTD_CDB89712 is not set ++# CONFIG_MTD_SA1100 is not set ++# CONFIG_MTD_DC21285 is not set ++# CONFIG_MTD_IQ80310 is not set ++# CONFIG_MTD_FORTUNET is not set ++# CONFIG_MTD_PXA_CERF is not set ++# CONFIG_MTD_EPXA10DB is not set ++# CONFIG_MTD_AUTCPU12 is not set ++# CONFIG_MTD_EDB7312 is not set ++# CONFIG_MTD_IMPA7 is not set ++CONFIG_MTD_TRIZEPS2=y ++# CONFIG_MTD_PCI is not set ++ ++# ++# Self-contained MTD device drivers ++# ++# CONFIG_MTD_PMC551 is not set ++# CONFIG_MTD_SLRAM is not set ++# CONFIG_MTD_MTDRAM is not set ++# CONFIG_MTD_BLKMTD is not set ++# CONFIG_MTD_DOC1000 is not set ++# CONFIG_MTD_DOC2000 is not set ++# CONFIG_MTD_DOC2001 is not set ++# CONFIG_MTD_DOCPROBE is not set ++ ++# ++# NAND Flash Device Drivers ++# ++# CONFIG_MTD_NAND is not set ++ ++# ++# Plug and Play configuration ++# ++# CONFIG_PNP is not set ++# CONFIG_ISAPNP is not set ++ ++# ++# Block devices ++# ++# CONFIG_BLK_DEV_FD is not set ++# CONFIG_BLK_DEV_XD is not set ++# CONFIG_PARIDE is not set ++# CONFIG_BLK_CPQ_DA is not set ++# CONFIG_BLK_CPQ_CISS_DA is not set ++# CONFIG_CISS_SCSI_TAPE is not set ++# CONFIG_BLK_DEV_DAC960 is not set ++# CONFIG_BLK_DEV_UMEM is not set ++CONFIG_BLK_DEV_LOOP=y ++# CONFIG_BLK_DEV_NBD is not set ++# CONFIG_BLK_DEV_RAM is not set ++# CONFIG_BLK_DEV_INITRD is not set ++ ++# ++# Multi-device support (RAID and LVM) ++# ++# CONFIG_MD is not set ++# CONFIG_BLK_DEV_MD is not set ++# CONFIG_MD_LINEAR is not set ++# CONFIG_MD_RAID0 is not set ++# CONFIG_MD_RAID1 is not set ++# CONFIG_MD_RAID5 is not set ++# CONFIG_MD_MULTIPATH is not set ++# CONFIG_BLK_DEV_LVM is not set ++ ++# ++# Networking options ++# ++# CONFIG_PACKET is not set ++# CONFIG_NETLINK_DEV is not set ++# CONFIG_NETFILTER is not set ++# CONFIG_FILTER is not set ++CONFIG_UNIX=y ++CONFIG_INET=y ++# CONFIG_IP_MULTICAST is not set ++# CONFIG_IP_ADVANCED_ROUTER is not set ++CONFIG_IP_PNP=y ++# CONFIG_IP_PNP_DHCP is not set ++CONFIG_IP_PNP_BOOTP=y ++# CONFIG_IP_PNP_RARP is not set ++# CONFIG_NET_IPIP is not set ++# CONFIG_NET_IPGRE is not set ++# CONFIG_ARPD is not set ++# CONFIG_INET_ECN is not set ++# CONFIG_SYN_COOKIES is not set ++# CONFIG_IPV6 is not set ++# CONFIG_KHTTPD is not set ++# CONFIG_ATM is not set ++# CONFIG_VLAN_8021Q is not set ++# CONFIG_IPX is not set ++# CONFIG_ATALK is not set ++ ++# ++# Appletalk devices ++# ++# CONFIG_DEV_APPLETALK is not set ++# CONFIG_DECNET is not set ++# CONFIG_BRIDGE is not set ++# CONFIG_X25 is not set ++# CONFIG_LAPB is not set ++# CONFIG_LLC is not set ++# CONFIG_NET_DIVERT is not set ++# CONFIG_ECONET is not set ++# CONFIG_WAN_ROUTER is not set ++# CONFIG_NET_FASTROUTE is not set ++# CONFIG_NET_HW_FLOWCONTROL is not set ++ ++# ++# QoS and/or fair queueing ++# ++# CONFIG_NET_SCHED is not set ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++ ++# ++# Network device support ++# ++CONFIG_NETDEVICES=y ++ ++# ++# ARCnet devices ++# ++# CONFIG_ARCNET is not set ++# CONFIG_DUMMY is not set ++# CONFIG_BONDING is not set ++# CONFIG_EQUALIZER is not set ++# CONFIG_TUN is not set ++# CONFIG_ETHERTAP is not set ++ ++# ++# Ethernet (10 or 100Mbit) ++# ++CONFIG_NET_ETHERNET=y ++# CONFIG_ARM_AM79C961A is not set ++# CONFIG_ARM_CIRRUS is not set ++# CONFIG_SUNLANCE is not set ++# CONFIG_SUNBMAC is not set ++# CONFIG_SUNQE is not set ++# CONFIG_SUNGEM is not set ++# CONFIG_NET_VENDOR_3COM is not set ++# CONFIG_LANCE is not set ++CONFIG_NET_VENDOR_SMC=y ++# CONFIG_WD80x3 is not set ++# CONFIG_ULTRAMCA is not set ++# CONFIG_ULTRA is not set ++# CONFIG_ULTRA32 is not set ++CONFIG_SMC9194=y ++# CONFIG_NET_VENDOR_RACAL is not set ++# CONFIG_NET_ISA is not set ++# CONFIG_NET_PCI is not set ++# CONFIG_NET_POCKET is not set ++ ++# ++# Ethernet (1000 Mbit) ++# ++# CONFIG_ACENIC is not set ++# CONFIG_DL2K is not set ++# CONFIG_MYRI_SBUS is not set ++# CONFIG_NS83820 is not set ++# CONFIG_HAMACHI is not set ++# CONFIG_YELLOWFIN is not set ++# CONFIG_SK98LIN is not set ++# CONFIG_TIGON3 is not set ++# CONFIG_FDDI is not set ++# CONFIG_HIPPI is not set ++# CONFIG_PLIP is not set ++CONFIG_PPP=m ++# CONFIG_PPP_MULTILINK is not set ++# CONFIG_PPP_FILTER is not set ++CONFIG_PPP_ASYNC=m ++CONFIG_PPP_SYNC_TTY=m ++CONFIG_PPP_DEFLATE=m ++CONFIG_PPP_BSDCOMP=m ++# CONFIG_PPPOE is not set ++# CONFIG_SLIP is not set ++ ++# ++# Wireless LAN (non-hamradio) ++# ++CONFIG_NET_RADIO=y ++# CONFIG_STRIP is not set ++# CONFIG_WAVELAN is not set ++# CONFIG_ARLAN is not set ++# CONFIG_AIRONET4500 is not set ++# CONFIG_AIRONET4500_NONCS is not set ++# CONFIG_AIRONET4500_PROC is not set ++# CONFIG_HERMES is not set ++# CONFIG_PCMCIA_HERMES is not set ++CONFIG_AIRO_CS=m ++CONFIG_NET_WIRELESS=y ++ ++# ++# Token Ring devices ++# ++# CONFIG_TR is not set ++# CONFIG_NET_FC is not set ++# CONFIG_RCPCI is not set ++# CONFIG_SHAPER is not set ++ ++# ++# Wan interfaces ++# ++# CONFIG_WAN is not set ++ ++# ++# PCMCIA network device support ++# ++CONFIG_NET_PCMCIA=y ++# CONFIG_PCMCIA_3C589 is not set ++CONFIG_PCMCIA_3C574=m ++# CONFIG_PCMCIA_FMVJ18X is not set ++# CONFIG_PCMCIA_PCNET is not set ++# CONFIG_PCMCIA_AXNET is not set ++# CONFIG_PCMCIA_NMCLAN is not set ++# CONFIG_PCMCIA_SMC91C92 is not set ++# CONFIG_PCMCIA_XIRC2PS is not set ++# CONFIG_ARCNET_COM20020_CS is not set ++# CONFIG_PCMCIA_IBMTR is not set ++CONFIG_NET_PCMCIA_RADIO=y ++# CONFIG_PCMCIA_RAYCS is not set ++# CONFIG_PCMCIA_NETWAVE is not set ++# CONFIG_PCMCIA_WAVELAN is not set ++# CONFIG_AIRONET4500_CS is not set ++ ++# ++# Amateur Radio support ++# ++# CONFIG_HAMRADIO is not set ++ ++# ++# IrDA (infrared) support ++# ++# CONFIG_IRDA is not set ++ ++# ++# ATA/ATAPI/MFM/RLL support ++# ++CONFIG_IDE=m ++ ++# ++# IDE, ATA and ATAPI Block devices ++# ++CONFIG_BLK_DEV_IDE=m ++# CONFIG_BLK_DEV_HD_IDE is not set ++# CONFIG_BLK_DEV_HD is not set ++CONFIG_BLK_DEV_IDEDISK=m ++# CONFIG_IDEDISK_MULTI_MODE is not set ++# CONFIG_IDEDISK_STROKE is not set ++# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set ++# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set ++# CONFIG_BLK_DEV_IDEDISK_IBM is not set ++# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set ++# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set ++# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set ++# CONFIG_BLK_DEV_IDEDISK_WD is not set ++# CONFIG_BLK_DEV_COMMERIAL is not set ++# CONFIG_BLK_DEV_TIVO is not set ++CONFIG_BLK_DEV_IDECS=m ++# CONFIG_BLK_DEV_IDECD is not set ++# CONFIG_BLK_DEV_IDETAPE is not set ++# CONFIG_BLK_DEV_IDEFLOPPY is not set ++# CONFIG_BLK_DEV_IDESCSI is not set ++# CONFIG_IDE_TASK_IOCTL is not set ++# CONFIG_BLK_DEV_CMD640 is not set ++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set ++# CONFIG_BLK_DEV_ISAPNP is not set ++# CONFIG_IDE_CHIPSETS is not set ++# CONFIG_IDEDMA_AUTO is not set ++# CONFIG_DMA_NONPCI is not set ++# CONFIG_BLK_DEV_IDE_MODES is not set ++# CONFIG_BLK_DEV_ATARAID is not set ++# CONFIG_BLK_DEV_ATARAID_PDC is not set ++# CONFIG_BLK_DEV_ATARAID_HPT is not set ++ ++# ++# SCSI support ++# ++# CONFIG_SCSI is not set ++ ++# ++# I2O device support ++# ++# CONFIG_I2O is not set ++# CONFIG_I2O_BLOCK is not set ++# CONFIG_I2O_LAN is not set ++# CONFIG_I2O_SCSI is not set ++# CONFIG_I2O_PROC is not set ++ ++# ++# ISDN subsystem ++# ++# CONFIG_ISDN is not set ++ ++# ++# Input core support ++# ++# CONFIG_INPUT is not set ++# CONFIG_INPUT_KEYBDEV is not set ++# CONFIG_INPUT_MOUSEDEV is not set ++# CONFIG_INPUT_JOYDEV is not set ++# CONFIG_INPUT_EVDEV is not set ++ ++# ++# Character devices ++# ++CONFIG_VT=y ++# CONFIG_VT_CONSOLE is not set ++CONFIG_SERIAL=y ++CONFIG_SERIAL_CONSOLE=y ++# CONFIG_SERIAL_EXTENDED is not set ++# CONFIG_SERIAL_NONSTANDARD is not set ++ ++# ++# Serial drivers ++# ++# CONFIG_SERIAL_ANAKIN is not set ++# CONFIG_SERIAL_ANAKIN_CONSOLE is not set ++# CONFIG_SERIAL_AMBA is not set ++# CONFIG_SERIAL_AMBA_CONSOLE is not set ++# CONFIG_SERIAL_CLPS711X is not set ++# CONFIG_SERIAL_CLPS711X_CONSOLE is not set ++# CONFIG_SERIAL_21285 is not set ++# CONFIG_SERIAL_21285_OLD is not set ++# CONFIG_SERIAL_21285_CONSOLE is not set ++# CONFIG_SERIAL_UART00 is not set ++# CONFIG_SERIAL_UART00_CONSOLE is not set ++# CONFIG_SERIAL_SA1100 is not set ++# CONFIG_SERIAL_SA1100_CONSOLE is not set ++# CONFIG_SERIAL_OMAHA is not set ++# CONFIG_SERIAL_OMAHA_CONSOLE is not set ++# CONFIG_SERIAL_8250 is not set ++# CONFIG_SERIAL_8250_CONSOLE is not set ++# CONFIG_SERIAL_8250_EXTENDED is not set ++# CONFIG_SERIAL_8250_MANY_PORTS is not set ++# CONFIG_SERIAL_8250_SHARE_IRQ is not set ++# CONFIG_SERIAL_8250_DETECT_IRQ is not set ++# CONFIG_SERIAL_8250_MULTIPORT is not set ++# CONFIG_SERIAL_8250_HUB6 is not set ++CONFIG_UNIX98_PTYS=y ++CONFIG_UNIX98_PTY_COUNT=256 ++ ++# ++# I2C support ++# ++CONFIG_I2C=y ++# CONFIG_I2C_ALGOBIT is not set ++# CONFIG_I2C_ALGOPCF is not set ++CONFIG_I2C_PXA_ALGO=y ++CONFIG_I2C_PXA_ADAP=y ++CONFIG_I2C_CHARDEV=y ++CONFIG_I2C_PROC=y ++# CONFIG_I2C_DS1307 is not set ++ ++# ++# L3 serial bus support ++# ++# CONFIG_L3 is not set ++# CONFIG_L3_ALGOBIT is not set ++# CONFIG_L3_BIT_SA1100_GPIO is not set ++# CONFIG_L3_SA1111 is not set ++# CONFIG_BIT_SA1100_GPIO is not set ++ ++# ++# Mice ++# ++# CONFIG_BUSMOUSE is not set ++# CONFIG_MOUSE is not set ++ ++# ++# Joysticks ++# ++# CONFIG_INPUT_GAMEPORT is not set ++# CONFIG_QIC02_TAPE is not set ++ ++# ++# Watchdog Cards ++# ++# CONFIG_WATCHDOG is not set ++# CONFIG_NVRAM is not set ++# CONFIG_RTC is not set ++CONFIG_PXA_RTC=y ++# CONFIG_DTLK is not set ++# CONFIG_R3964 is not set ++# CONFIG_APPLICOM is not set ++ ++# ++# Ftape, the floppy tape device driver ++# ++# CONFIG_FTAPE is not set ++# CONFIG_AGP is not set ++# CONFIG_DRM is not set ++ ++# ++# PCMCIA character devices ++# ++# CONFIG_PCMCIA_SERIAL_CS is not set ++CONFIG_TRIZEPS2_TTLIO=m ++ ++# ++# Multimedia devices ++# ++# CONFIG_VIDEO_DEV is not set ++ ++# ++# File systems ++# ++# CONFIG_QUOTA is not set ++# CONFIG_AUTOFS_FS is not set ++# CONFIG_AUTOFS4_FS is not set ++# CONFIG_REISERFS_FS is not set ++# CONFIG_REISERFS_CHECK is not set ++# CONFIG_REISERFS_PROC_INFO is not set ++# CONFIG_ADFS_FS is not set ++# CONFIG_ADFS_FS_RW is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_BFS_FS is not set ++CONFIG_EXT3_FS=y ++CONFIG_JBD=y ++# CONFIG_JBD_DEBUG is not set ++CONFIG_FAT_FS=m ++CONFIG_MSDOS_FS=m ++# CONFIG_UMSDOS_FS is not set ++CONFIG_VFAT_FS=m ++# CONFIG_EFS_FS is not set ++# CONFIG_JFFS_FS is not set ++CONFIG_JFFS2_FS=y ++CONFIG_JFFS2_FS_DEBUG=0 ++# CONFIG_CRAMFS is not set ++CONFIG_TMPFS=y ++CONFIG_RAMFS=y ++# CONFIG_ISO9660_FS is not set ++# CONFIG_JOLIET is not set ++# CONFIG_ZISOFS is not set ++# CONFIG_MINIX_FS is not set ++# CONFIG_VXFS_FS is not set ++# CONFIG_NTFS_FS is not set ++# CONFIG_NTFS_RW is not set ++# CONFIG_HPFS_FS is not set ++CONFIG_PROC_FS=y ++# CONFIG_DEVFS_FS is not set ++# CONFIG_DEVFS_MOUNT is not set ++# CONFIG_DEVFS_DEBUG is not set ++CONFIG_DEVPTS_FS=y ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_QNX4FS_RW is not set ++# CONFIG_ROMFS_FS is not set ++CONFIG_EXT2_FS=y ++# CONFIG_SYSV_FS is not set ++# CONFIG_UDF_FS is not set ++# CONFIG_UDF_RW is not set ++# CONFIG_UFS_FS is not set ++# CONFIG_UFS_FS_WRITE is not set ++ ++# ++# Network File Systems ++# ++# CONFIG_CODA_FS is not set ++# CONFIG_INTERMEZZO_FS is not set ++CONFIG_NFS_FS=m ++# CONFIG_NFS_V3 is not set ++# CONFIG_ROOT_NFS is not set ++# CONFIG_NFSD is not set ++# CONFIG_NFSD_V3 is not set ++CONFIG_SUNRPC=m ++CONFIG_LOCKD=m ++# CONFIG_SMB_FS is not set ++# CONFIG_NCP_FS is not set ++# CONFIG_NCPFS_PACKET_SIGNING is not set ++# CONFIG_NCPFS_IOCTL_LOCKING is not set ++# CONFIG_NCPFS_STRONG is not set ++# CONFIG_NCPFS_NFS_NS is not set ++# CONFIG_NCPFS_OS2_NS is not set ++# CONFIG_NCPFS_SMALLDOS is not set ++# CONFIG_NCPFS_NLS is not set ++# CONFIG_NCPFS_EXTRAS is not set ++# CONFIG_ZISOFS_FS is not set ++# CONFIG_ZLIB_FS_INFLATE is not set ++ ++# ++# Partition Types ++# ++# CONFIG_PARTITION_ADVANCED is not set ++CONFIG_MSDOS_PARTITION=y ++# CONFIG_SMB_NLS is not set ++CONFIG_NLS=y ++ ++# ++# Native Language Support ++# ++CONFIG_NLS_DEFAULT="iso8859-1" ++# CONFIG_NLS_CODEPAGE_437 is not set ++# CONFIG_NLS_CODEPAGE_737 is not set ++# CONFIG_NLS_CODEPAGE_775 is not set ++# CONFIG_NLS_CODEPAGE_850 is not set ++# CONFIG_NLS_CODEPAGE_852 is not set ++# CONFIG_NLS_CODEPAGE_855 is not set ++# CONFIG_NLS_CODEPAGE_857 is not set ++# CONFIG_NLS_CODEPAGE_860 is not set ++# CONFIG_NLS_CODEPAGE_861 is not set ++# CONFIG_NLS_CODEPAGE_862 is not set ++# CONFIG_NLS_CODEPAGE_863 is not set ++# CONFIG_NLS_CODEPAGE_864 is not set ++# CONFIG_NLS_CODEPAGE_865 is not set ++# CONFIG_NLS_CODEPAGE_866 is not set ++# CONFIG_NLS_CODEPAGE_869 is not set ++# CONFIG_NLS_CODEPAGE_936 is not set ++# CONFIG_NLS_CODEPAGE_950 is not set ++# CONFIG_NLS_CODEPAGE_932 is not set ++# CONFIG_NLS_CODEPAGE_949 is not set ++# CONFIG_NLS_CODEPAGE_874 is not set ++# CONFIG_NLS_ISO8859_8 is not set ++# CONFIG_NLS_CODEPAGE_1250 is not set ++# CONFIG_NLS_CODEPAGE_1251 is not set ++CONFIG_NLS_ISO8859_1=y ++# CONFIG_NLS_ISO8859_2 is not set ++# CONFIG_NLS_ISO8859_3 is not set ++# CONFIG_NLS_ISO8859_4 is not set ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++# CONFIG_NLS_UTF8 is not set ++ ++# ++# Console drivers ++# ++CONFIG_PC_KEYMAP=y ++# CONFIG_VGA_CONSOLE is not set ++ ++# ++# Frame-buffer support ++# ++CONFIG_FB=y ++CONFIG_DUMMY_CONSOLE=y ++# CONFIG_FB_ACORN is not set ++# CONFIG_FB_ANAKIN is not set ++# CONFIG_FB_CLPS711X is not set ++# CONFIG_FB_SA1100 is not set ++CONFIG_FB_PXA=y ++# CONFIG_FB_CYBER2000 is not set ++# CONFIG_FB_VIRTUAL is not set ++CONFIG_FBCON_ADVANCED=y ++# CONFIG_FBCON_MFB is not set ++# CONFIG_FBCON_CFB2 is not set ++# CONFIG_FBCON_CFB4 is not set ++# CONFIG_FBCON_CFB8 is not set ++CONFIG_FBCON_CFB16=y ++# CONFIG_FBCON_CFB24 is not set ++# CONFIG_FBCON_CFB32 is not set ++# CONFIG_FBCON_AFB is not set ++# CONFIG_FBCON_ILBM is not set ++# CONFIG_FBCON_IPLAN2P2 is not set ++# CONFIG_FBCON_IPLAN2P4 is not set ++# CONFIG_FBCON_IPLAN2P8 is not set ++# CONFIG_FBCON_MAC is not set ++# CONFIG_FBCON_VGA_PLANES is not set ++# CONFIG_FBCON_VGA is not set ++# CONFIG_FBCON_HGA is not set ++CONFIG_FBCON_FONTWIDTH8_ONLY=y ++CONFIG_FBCON_FONTS=y ++# CONFIG_FONT_8x8 is not set ++# CONFIG_FONT_8x16 is not set ++# CONFIG_FONT_SUN8x16 is not set ++# CONFIG_FONT_PEARL_8x8 is not set ++CONFIG_FONT_ACORN_8x8=y ++ ++# ++# Sound ++# ++CONFIG_SOUND=y ++# CONFIG_SOUND_BT878 is not set ++# CONFIG_SOUND_CMPCI is not set ++# CONFIG_SOUND_EMU10K1 is not set ++# CONFIG_MIDI_EMU10K1 is not set ++# CONFIG_SOUND_FUSION is not set ++# CONFIG_SOUND_CS4281 is not set ++# CONFIG_SOUND_ES1370 is not set ++# CONFIG_SOUND_ES1371 is not set ++# CONFIG_SOUND_ESSSOLO1 is not set ++# CONFIG_SOUND_MAESTRO is not set ++# CONFIG_SOUND_MAESTRO3 is not set ++# CONFIG_SOUND_ICH is not set ++# CONFIG_SOUND_RME96XX is not set ++# CONFIG_SOUND_SONICVIBES is not set ++# CONFIG_SOUND_TRIDENT is not set ++# CONFIG_SOUND_MSNDCLAS is not set ++# CONFIG_SOUND_MSNDPIN is not set ++# CONFIG_SOUND_VIA82CXXX is not set ++# CONFIG_MIDI_VIA82CXXX is not set ++# CONFIG_SOUND_OSS is not set ++# CONFIG_SOUND_WAVEARTIST is not set ++CONFIG_SOUND_PXA_AC97=y ++# CONFIG_SOUND_TVMIXER is not set ++ ++# ++# Multimedia Capabilities Port drivers ++# ++CONFIG_MCP=y ++# CONFIG_MCP_SA1100 is not set ++# CONFIG_MCP_UCB1200 is not set ++# CONFIG_MCP_UCB1200_AUDIO is not set ++# CONFIG_MCP_UCB1200_TS is not set ++CONFIG_MCP_UCB1400_TS=y ++CONFIG_MCP_UCB1X00_TS_COMPAT=y ++ ++# ++# USB support ++# ++# CONFIG_USB is not set ++ ++# ++# Bluetooth support ++# ++# CONFIG_BLUEZ is not set ++ ++# ++# Kernel hacking ++# ++CONFIG_FRAME_POINTER=y ++CONFIG_DEBUG_USER=y ++CONFIG_DEBUG_INFO=y ++# CONFIG_NO_PGT_CACHE is not set ++CONFIG_DEBUG_KERNEL=y ++# CONFIG_DEBUG_SLAB is not set ++CONFIG_MAGIC_SYSRQ=y ++# CONFIG_DEBUG_SPINLOCK is not set ++# CONFIG_DEBUG_WAITQ is not set ++CONFIG_DEBUG_BUGVERBOSE=y ++CONFIG_DEBUG_ERRORS=y ++CONFIG_DEBUG_LL=y ++# CONFIG_DEBUG_DC21285_PORT is not set ++# CONFIG_DEBUG_CLPS711X_UART2 is not set +--- linux-2.4.27/arch/arm/kernel/Makefile~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/arch/arm/kernel/Makefile +@@ -10,7 +10,7 @@ + HEAD_OBJ = head-$(PROCESSOR).o + ENTRY_OBJ = entry-$(PROCESSOR).o + +-AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) ++AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -DDATAADDR=$(DATAADDR) + AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) + + # This is depreciated. +@@ -45,7 +45,7 @@ + $(CONFIG_FOOTBRIDGE) $(CONFIG_ARCH_EBSA110) \ + $(CONFIG_ARCH_SA1100) $(CONFIG_ARCH_CAMELOT) \ + $(CONFIG_ARCH_MX1ADS) $(CONFIG_ARCH_OMAHA) \ +- $(CONFIG_ARCH_AT91RM9200) ++ $(CONFIG_ARCH_AT91RM9200) $(CONFIG_ARCH_PXA) + + ifneq ($(findstring y,$(no-irq-arch)),y) + obj-y += irq-arch.o +--- linux-2.4.27/arch/arm/kernel/debug-armv.S~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/arch/arm/kernel/debug-armv.S +@@ -221,6 +221,31 @@ + bne 1001b + .endm + ++#elif defined(CONFIG_ARCH_PXA) ++ ++ .macro addruart,rx ++ mrc p15, 0, \rx, c1, c0 ++ tst \rx, #1 @ MMU enabled? ++ moveq \rx, #0x40000000 @ physical ++ movne \rx, #io_p2v(0x40000000) @ virtual ++ orr \rx, \rx, #0x00100000 @ FFUART ++ .endm ++ ++ .macro senduart,rd,rx ++ str \rd, [\rx, #0] ++ .endm ++ ++ .macro busyuart,rd,rx ++1002: ldr \rd, [\rx, #0x14] ++ tst \rd, #(1 << 6) ++ beq 1002b ++ .endm ++ ++ .macro waituart,rd,rx ++1001: ldr \rd, [\rx, #0x14] ++ tst \rd, #(1 << 5) ++ beq 1001b ++ .endm + #elif defined(CONFIG_ARCH_CLPS7500) + .macro addruart,rx + mov \rx, #0xe0000000 +--- linux-2.4.27/arch/arm/kernel/entry-armv.S~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/arch/arm/kernel/entry-armv.S +@@ -615,6 +615,27 @@ + .text + .endm + ++#elif CONFIG_ARCH_PXA ++ ++ .macro disable_fiq ++ .endm ++ ++ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp ++ mov \base, #io_p2v(0x40000000) @ IIR Ctl = 0x40d00000 ++ add \base, \base, #0x00d00000 ++ ldr \irqstat, [\base, #0] @ ICIP ++ ldr \irqnr, [\base, #4] @ ICMR ++ ands \irqstat, \irqstat, \irqnr ++ beq 1001f ++ rsb \irqnr, \irqstat, #0 ++ and \irqstat, \irqstat, \irqnr ++ clz \irqnr, \irqstat ++ rsb \irqnr, \irqnr, #(31 - PXA_IRQ_SKIP) ++1001: ++ .endm ++ ++ .macro irq_prio_table ++ .endm + #else + #error Unknown architecture + #endif +@@ -891,9 +912,17 @@ + stmfd sp!, {r4 - sl, fp, lr} @ Store most regs on stack + mrs ip, cpsr + str ip, [sp, #-4]! @ Save cpsr_SVC ++#ifdef CONFIG_CPU_XSCALE ++ mra r4, r5, acc0 ++ stmfd sp!, {r4, r5} ++#endif + str sp, [r0, #TSS_SAVE] @ Save sp_SVC + ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC + ldr r2, [r1, #TSS_DOMAIN] ++#ifdef CONFIG_CPU_XSCALE ++ ldmfd sp!, {r4, r5} ++ mar acc0, r4, r5 ++#endif + ldr ip, [sp], #4 + mcr p15, 0, r2, c3, c0 @ Set domain register + msr spsr, ip @ Save tasks CPSR into SPSR for this return +--- linux-2.4.27/arch/arm/kernel/head-armv.S~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/arch/arm/kernel/head-armv.S +@@ -30,6 +30,7 @@ + * + * swapper_pg_dir, pgtbl and krnladr are all closely related. + */ ++#ifndef CONFIG_XIP_KERNEL + #if (TEXTADDR & 0xffff) != 0x8000 + #error TEXTADDR must start at 0xXXXX8000 + #endif +@@ -41,6 +42,26 @@ + adr \reg, stext + sub \reg, \reg, #0x4000 + .endm ++#else ++#if (DATAADDR & 0xffff) != 0x8000 ++#error DATAADDR must start at 0xXXXX8000 ++#endif ++ ++#define PAGE_OFFSET 0xc0000000 ++#ifdef CONFIG_ARCH_LUBBOCK ++#define PHYS_OFFSET 0xa0000000 ++#elif CONFIG_ARCH_OMAP ++#define PHYS_OFFSET 0x10000000 ++#endif ++ ++ .globl SYMBOL_NAME(swapper_pg_dir) ++ .equ SYMBOL_NAME(swapper_pg_dir), DATAADDR - 0x4000 ++ ++ .macro pgtbl, reg, rambase ++ ldr \reg, PGTBL ++ add \reg, \reg, #PHYS_OFFSET - PAGE_OFFSET ++ .endm ++#endif + + /* + * Since the page table is closely related to the kernel start address, we +@@ -131,6 +152,32 @@ + mov r1, #MACH_TYPE_L7200 + #endif + ++#ifdef CONFIG_XIP_KERNEL ++ ++#if defined(CONFIG_ARCH_LUBBOCK) ++ mov r1, #MACH_TYPE_LUBBOCK ++#endif ++ ++ @ Data cache might be active. ++ @ Be sure to flush kernel binary out of the cache, ++ @ whatever state it is, before it is turned off. ++ @ This is done by fetching through currently executed ++ @ memory to be sure we hit the same cache. ++ bic r2, pc, #0x1f ++ add r3, r2, #0x10000 @ 64 kb is quite enough... ++1: ldr r0, [r2], #32 ++ teq r2, r3 ++ bne 1b ++ mcr p15, 0, r0, c7, c10, 4 @ drain WB ++ mcr p15, 0, r0, c7, c7, 0 @ flush I & D caches ++ ++ @ disabling MMU and caches ++ mrc p15, 0, r0, c1, c0, 0 @ read control reg ++ bic r0, r0, #0x05 @ clear DC, MMU ++ bic r0, r0, #0x1000 @ clear Icache ++ mcr p15, 0, r0, c1, c0, 0 ++#endif ++ + mov r0, #F_BIT | I_BIT | MODE_SVC @ make sure svc mode + msr cpsr_c, r0 @ and all irqs disabled + bl __lookup_processor_type +@@ -179,6 +226,17 @@ + */ + .align 5 + __mmap_switched: ++#ifdef CONFIG_XIP_KERNEL ++ ldr r3, ETEXT @ data section copy ++ ldr r4, SDATA ++ ldr r5, EDATA ++1: ++ ldr r6, [r3], #4 ++ str r6, [r4], #4 ++ cmp r4, r5 ++ blo 1b ++#endif ++ + adr r3, __switch_data + 4 + ldmia r3, {r4, r5, r6, r7, r8, sp}@ r2 = compat + @ sp = stack pointer +@@ -233,6 +291,8 @@ + teq r0, r2 + bne 1b + ++#ifndef CONFIG_XIP_KERNEL ++ + /* + * Create identity mapping for first MB of kernel to + * cater for the MMU enable. This identity mapping +@@ -271,6 +331,43 @@ + add r3, r8, r2 @ flags + rambase + str r3, [r0] + ++#else /* CONFIG_XIP_KERNEL */ ++ ++ mov r3, pc, lsr #20 ++ mov r3, r3, lsl #20 @ phys kernel start ++ ++ add r0, r4, r3, lsr #18 ++ orr r3, r3, r8 ++ str r3, [r0] ++ ++ mov r0, #TEXTADDR & 0xff000000 ++ add r0, r0, #TEXTADDR & 0x00f00000 @ virt kernel start ++ add r0, r4, r0, lsr #18 ++ add r2, r3, #4 << 20 @ kernel + 4MB ++ ++1: ++ str r3, [r0], #4 ++ add r3, r3, #1 << 20 ++ cmp r3, r2 ++ bne 1b ++ ++ bic r3, r4, #0x000ff000 @ ram start ++ add r0, r4, r3, lsr #18 ++ orr r3, r3, r8 ++ str r3, [r0], #4 ++ ++ add r0, r3, #PAGE_OFFSET - PHYS_OFFSET ++ add r0, r4, r0, lsr #18 ++ add r2, r3, #4 << 20 @ ram + 4MB ++ ++1: ++ str r3, [r0], #4 ++ add r3, r3, #1 << 20 ++ cmp r3, r2 ++ bne 1b ++ ++#endif /* CONFIG_XIP_KERNEL */ ++ + bic r8, r8, #0x0c @ turn off cacheable + @ and bufferable bits + #ifdef CONFIG_DEBUG_LL +@@ -433,3 +530,13 @@ + mov pc, lr + 2: ldmib r4, {r5, r6, r7} @ found, get results + mov pc, lr ++ ++#ifdef CONFIG_XIP_KERNEL ++ ++PGTBL: .long SYMBOL_NAME(swapper_pg_dir) ++ ++ETEXT: .long SYMBOL_NAME(_endtext) ++SDATA: .long SYMBOL_NAME(_sdata) ++EDATA: .long SYMBOL_NAME(__bss_start) ++ ++#endif +--- linux-2.4.27/arch/arm/kernel/setup.c~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/arch/arm/kernel/setup.c +@@ -55,6 +55,10 @@ + extern void reboot_setup(char *str); + extern int root_mountflags; + extern int _stext, _text, _etext, _edata, _end; ++#ifdef CONFIG_XIP_KERNEL ++extern int _endtext, _sdata; ++#endif ++ + + unsigned int processor_id; + unsigned int __machine_arch_type; +@@ -105,6 +109,109 @@ + #define lp1 io_res[1] + #define lp2 io_res[2] + ++#ifdef CONFIG_CPU_32 ++static const char *cache_types[16] = { ++ "write-through", ++ "write-back", ++ "write-back", ++ "undefined 3", ++ "undefined 4", ++ "undefined 5", ++ "write-back", ++ "write-back", ++ "undefined 8", ++ "undefined 9", ++ "undefined 10", ++ "undefined 11", ++ "undefined 12", ++ "undefined 13", ++ "undefined 14", ++ "undefined 15", ++}; ++ ++static const char *cache_clean[16] = { ++ "not required", ++ "read-block", ++ "cp15 c7 ops", ++ "undefined 3", ++ "undefined 4", ++ "undefined 5", ++ "cp15 c7 ops", ++ "cp15 c7 ops", ++ "undefined 8", ++ "undefined 9", ++ "undefined 10", ++ "undefined 11", ++ "undefined 12", ++ "undefined 13", ++ "undefined 14", ++ "undefined 15", ++}; ++ ++static const char *cache_lockdown[16] = { ++ "not supported", ++ "not supported", ++ "not supported", ++ "undefined 3", ++ "undefined 4", ++ "undefined 5", ++ "format A", ++ "format B", ++ "undefined 8", ++ "undefined 9", ++ "undefined 10", ++ "undefined 11", ++ "undefined 12", ++ "undefined 13", ++ "undefined 14", ++ "undefined 15", ++}; ++ ++#define CACHE_TYPE(x) (((x) >> 25) & 15) ++#define CACHE_S(x) ((x) & (1 << 24)) ++#define CACHE_DSIZE(x) (((x) >> 12) & 4095) /* only if S=1 */ ++#define CACHE_ISIZE(x) ((x) & 4095) ++ ++#define CACHE_SIZE(y) (((y) >> 6) & 7) ++#define CACHE_ASSOC(y) (((y) >> 3) & 7) ++#define CACHE_M(y) ((y) & (1 << 2)) ++#define CACHE_LINE(y) ((y) & 3) ++ ++static inline void dump_cache(const char *prefix, unsigned int cache) ++{ ++ unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0); ++ ++ printk("%s size %dK associativity %d line length %d sets %d\n", ++ prefix, ++ mult << (8 + CACHE_SIZE(cache)), ++ (mult << CACHE_ASSOC(cache)) >> 1, ++ 8 << CACHE_LINE(cache), ++ 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) - ++ CACHE_LINE(cache))); ++} ++ ++static inline void dump_cpu_cache_id(void) ++{ ++ unsigned int cache_info; ++ ++ asm("mrc p15, 0, %0, c0, c0, 1" : "=r" (cache_info)); ++ ++ if (cache_info == processor_id) ++ return; ++ ++ printk("CPU: D %s cache\n", cache_types[CACHE_TYPE(cache_info)]); ++ if (CACHE_S(cache_info)) { ++ dump_cache("CPU: I cache", CACHE_ISIZE(cache_info)); ++ dump_cache("CPU: D cache", CACHE_DSIZE(cache_info)); ++ } else { ++ dump_cache("CPU: cache", CACHE_ISIZE(cache_info)); ++ } ++} ++ ++#else ++#define dump_cpu_cache_id() do { } while (0) ++#endif ++ + static void __init setup_processor(void) + { + extern struct proc_info_list __proc_info_begin, __proc_info_end; +@@ -272,7 +379,11 @@ + + kernel_code.start = __virt_to_phys(init_mm.start_code); + kernel_code.end = __virt_to_phys(init_mm.end_code - 1); ++#ifndef CONFIG_XIP_KERNEL + kernel_data.start = __virt_to_phys(init_mm.end_code); ++#else ++ kernel_data.start = __virt_to_phys(init_mm.start_data); ++#endif + kernel_data.end = __virt_to_phys(init_mm.brk - 1); + + for (i = 0; i < mi->nr_banks; i++) { +@@ -531,7 +642,12 @@ + } + + init_mm.start_code = (unsigned long) &_text; ++#ifndef CONFIG_XIP_KERNEL + init_mm.end_code = (unsigned long) &_etext; ++#else ++ init_mm.end_code = (unsigned long) &_endtext; ++ init_mm.start_data = (unsigned long) &_sdata; ++#endif + init_mm.end_data = (unsigned long) &_edata; + init_mm.brk = (unsigned long) &_end; + +@@ -568,6 +684,41 @@ + NULL + }; + ++static const char *proc_arch[16] = { ++ "undefined 0", ++ "4", ++ "4T", ++ "5", ++ "5T", ++ "5TE", ++ "undefined 6", ++ "undefined 7", ++ "undefined 8", ++ "undefined 9", ++ "undefined 10", ++ "undefined 11", ++ "undefined 12", ++ "undefined 13", ++ "undefined 14", ++ "undefined 15" ++}; ++ ++static void ++c_show_cache(struct seq_file *m, const char *type, unsigned int cache) ++{ ++ unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0); ++ ++ seq_printf(m, "%s size\t\t: %d\n" ++ "%s assoc\t\t: %d\n" ++ "%s line length\t: %d\n" ++ "%s sets\t\t: %d\n", ++ type, mult << (8 + CACHE_SIZE(cache)), ++ type, (mult << CACHE_ASSOC(cache)) >> 1, ++ type, 8 << CACHE_LINE(cache), ++ type, 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) - ++ CACHE_LINE(cache))); ++} ++ + static int c_show(struct seq_file *m, void *v) + { + int i; +@@ -586,7 +737,60 @@ + if (elf_hwcap & (1 << i)) + seq_printf(m, "%s ", hwcap_str[i]); + +- seq_puts(m, "\n\n"); ++ seq_puts(m, "\n"); ++ ++ if ((processor_id & 0x0000f000) == 0x00000000) { ++ /* pre-ARM7 */ ++ seq_printf(m, "CPU part\t\t: %07x\n", processor_id >> 4); ++ } else if ((processor_id & 0x0000f000) == 0x00007000) { ++ /* ARM7 */ ++ seq_printf(m, "CPU implementor\t: 0x%02x\n" ++ "CPU architecture: %s\n" ++ "CPU variant\t: 0x%02x\n" ++ "CPU part\t: 0x%03x\n", ++ processor_id >> 24, ++ processor_id & (1 << 23) ? "4T" : "3", ++ (processor_id >> 16) & 127, ++ (processor_id >> 4) & 0xfff); ++ } else { ++ /* post-ARM7 */ ++ seq_printf(m, "CPU implementor\t: 0x%02x\n" ++ "CPU architecture: %s\n" ++ "CPU variant\t: 0x%x\n" ++ "CPU part\t: 0x%03x\n", ++ processor_id >> 24, ++ proc_arch[(processor_id >> 16) & 15], ++ (processor_id >> 20) & 15, ++ (processor_id >> 4) & 0xfff); ++ } ++ seq_printf(m, "CPU revision\t: %d\n", processor_id & 15); ++ ++#ifdef CONFIG_CPU_32 ++ { ++ unsigned int cache_info; ++ ++ asm("mrc p15, 0, %0, c0, c0, 1" : "=r" (cache_info)); ++ if (cache_info != processor_id) { ++ seq_printf(m, "Cache type\t: %s\n" ++ "Cache clean\t: %s\n" ++ "Cache lockdown\t: %s\n" ++ "Cache unified\t: %s\n", ++ cache_types[CACHE_TYPE(cache_info)], ++ cache_clean[CACHE_TYPE(cache_info)], ++ cache_lockdown[CACHE_TYPE(cache_info)], ++ CACHE_S(cache_info) ? "harvard" : "unified"); ++ ++ if (CACHE_S(cache_info)) { ++ c_show_cache(m, "I", CACHE_ISIZE(cache_info)); ++ c_show_cache(m, "D", CACHE_DSIZE(cache_info)); ++ } else { ++ c_show_cache(m, "Cache", CACHE_ISIZE(cache_info)); ++ } ++ } ++ } ++#endif ++ ++ seq_puts(m, "\n"); + + seq_printf(m, "Hardware\t: %s\n", machine_name); + seq_printf(m, "Revision\t: %04x\n", system_rev); +--- linux-2.4.27/arch/arm/lib/copy_page.S~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/arch/arm/lib/copy_page.S +@@ -13,6 +13,8 @@ + #include <asm/assembler.h> + #include <asm/constants.h> + ++#define COPY_COUNT (PAGE_SZ/64 PLD( -1 )) ++ + .text + .align 5 + /* +@@ -23,9 +25,13 @@ + */ + ENTRY(copy_page) + stmfd sp!, {r4, lr} @ 2 +- mov r2, #PAGE_SZ/64 @ 1 ++ PLD( pld [r1, #0] ) ++ PLD( pld [r1, #32] ) ++ mov r2, #COPY_COUNT @ 1 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 +-1: stmia r0!, {r3, r4, ip, lr} @ 4 ++1: PLD( pld [r1, #64] ) ++ PLD( pld [r1, #96] ) ++2: stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 +@@ -33,6 +39,8 @@ + ldmia r1!, {r3, r4, ip, lr} @ 4 + subs r2, r2, #1 @ 1 + stmia r0!, {r3, r4, ip, lr} @ 4 +- ldmneia r1!, {r3, r4, ip, lr} @ 4 +- bne 1b @ 1 ++ ldmgtia r1!, {r3, r4, ip, lr} @ 4 ++ bgt 1b @ 1 ++ PLD( ldmeqia r1!, {r3, r4, ip, lr} ) ++ PLD( beq 2b ) + LOADREGS(fd, sp!, {r4, pc}) @ 3 +--- linux-2.4.27/arch/arm/lib/findbit.S~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/arch/arm/lib/findbit.S +@@ -43,7 +43,15 @@ + /* + * One or more bits in the LSB of r3 are assumed to be set. + */ +-.found: tst r3, #0x0f ++.found: ++#if __LINUX_ARM_ARCH__ >= 5 ++ rsb r1, r3, #0 ++ and r3, r3, r1 ++ clz r3, r3 ++ rsb r3, r3, #31 ++ add r0, r2, r3 ++#else ++ tst r3, #0x0f + addeq r2, r2, #4 + movne r3, r3, lsl #4 + tst r3, #0x30 +@@ -52,5 +60,6 @@ + tst r3, #0x40 + addeq r2, r2, #1 + mov r0, r2 ++#endif + RETINSTR(mov,pc,lr) + +--- linux-2.4.27/arch/arm/lib/getuser.S~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/arch/arm/lib/getuser.S +@@ -18,7 +18,7 @@ + * Inputs: r0 contains the address + * Outputs: r0 is the error code + * r1, r2 contains the zero-extended value +- * lr corrupted ++ * ip, lr corrupted + * + * No other registers must be altered. (see include/asm-arm/uaccess.h + * for specific ASM register usage). +@@ -42,14 +42,14 @@ + + .global __get_user_2 + __get_user_2: +- bic r2, sp, #0x1f00 +- bic r2, r2, #0x00ff +- ldr r2, [r2, #TSK_ADDR_LIMIT] +- sub r2, r2, #2 +- cmp r0, r2 ++ bic ip, sp, #0x1f00 ++ bic ip, ip, #0x00ff ++ ldr ip, [ip, #TSK_ADDR_LIMIT] ++ sub ip, ip, #2 ++ cmp r0, ip + 2: ldrlsbt r1, [r0], #1 +-3: ldrlsbt r2, [r0] +- orrls r1, r1, r2, lsl #8 ++3: ldrlsbt ip, [r0] ++ orrls r1, r1, ip, lsl #8 + movls r0, #0 + movls pc, lr + b __get_user_bad +--- linux-2.4.27/arch/arm/lib/memcpy.S~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/arch/arm/lib/memcpy.S +@@ -8,6 +8,9 @@ + * published by the Free Software Foundation. + * + * ASM optimised string functions ++ * ++ * Big Endian, prefetching and code factorization provided by Nicolas Pitre: ++ * Copyright (C) 2002-2003 MontaVista Software, Inc. + */ + #include <linux/linkage.h> + #include <asm/assembler.h> +@@ -27,15 +30,16 @@ + + /* + * Prototype: void memcpy(void *to,const void *from,unsigned long n); +- * ARM3: cant use memcopy here!!! + */ + ENTRY(memcpy) + ENTRY(memmove) + ENTER +- cmp r1, r0 +- bcc 19f ++ subs ip, r0, r1 ++ cmphi r2, ip ++ bhi 18f + subs r2, r2, #4 + blt 6f ++ PLD( pld [r1, #0] ) + ands ip, r0, #3 + bne 7f + ands ip, r1, #3 +@@ -43,29 +47,59 @@ + + 1: subs r2, r2, #8 + blt 5f +- subs r2, r2, #0x14 +- blt 3f +-2: ldmia r1!,{r3 - r9, ip} +- stmia r0!,{r3 - r9, ip} ++ subs r2, r2, #20 ++ blt 4f ++ ++ PLD( subs r2, r2, #65 ) ++ PLD( blt 3f ) ++ PLD( pld [r1, #32] ) ++ ++ PLD( @ cache alignment ) ++ PLD( ands ip, r1, #31 ) ++ PLD( pld [r1, #64] ) ++ PLD( beq 2f ) ++ PLD( rsb ip, ip, #32 ) ++ PLD( cmp r2, ip ) ++ PLD( pld [r1, #96] ) ++ PLD( blt 2f ) ++ PLD( cmp ip, #16 ) ++ PLD( sub r2, r2, ip ) ++ PLD( ldmgeia r1!, {r3 - r6} ) ++ PLD( stmgeia r0!, {r3 - r6} ) ++ PLD( beq 2f ) ++ PLD( and ip, ip, #15 ) ++ PLD( cmp ip, #8 ) ++ PLD( ldr r3, [r1], #4 ) ++ PLD( ldrge r4, [r1], #4 ) ++ PLD( ldrgt r5, [r1], #4 ) ++ PLD( str r3, [r0], #4 ) ++ PLD( strge r4, [r0], #4 ) ++ PLD( strgt r5, [r0], #4 ) ++ ++2: PLD( pld [r1, #96] ) ++3: ldmia r1!, {r3 - r9, ip} + subs r2, r2, #32 ++ stmia r0!, {r3 - r9, ip} + bge 2b +- cmn r2, #16 ++ PLD( cmn r2, #65 ) ++ PLD( bge 3b ) ++ PLD( add r2, r2, #65 ) ++4: cmn r2, #16 + ldmgeia r1!, {r3 - r6} ++ subge r2, r2, #16 + stmgeia r0!, {r3 - r6} +- subge r2, r2, #0x10 +-3: adds r2, r2, #0x14 +-4: ldmgeia r1!, {r3 - r5} ++ adds r2, r2, #20 ++ ldmgeia r1!, {r3 - r5} ++ subge r2, r2, #12 + stmgeia r0!, {r3 - r5} +- subges r2, r2, #12 +- bge 4b + 5: adds r2, r2, #8 + blt 6f + subs r2, r2, #4 + ldrlt r3, [r1], #4 + ldmgeia r1!, {r4, r5} ++ subge r2, r2, #4 + strlt r3, [r0], #4 + stmgeia r0!, {r4, r5} +- subge r2, r2, #4 + + 6: adds r2, r2, #4 + EXITEQ +@@ -92,122 +126,175 @@ + beq 1b + + 8: bic r1, r1, #3 +- ldr r7, [r1], #4 + cmp ip, #2 +- bgt 15f +- beq 11f ++ ldr lr, [r1], #4 ++ bgt 17f ++ beq 16f ++ ++ ++ .macro forward_copy_shift pull push ++ + cmp r2, #12 +- blt 10f +- sub r2, r2, #12 +-9: mov r3, r7, lsr #8 +- ldmia r1!, {r4 - r7} +- orr r3, r3, r4, lsl #24 +- mov r4, r4, lsr #8 +- orr r4, r4, r5, lsl #24 +- mov r5, r5, lsr #8 +- orr r5, r5, r6, lsl #24 +- mov r6, r6, lsr #8 +- orr r6, r6, r7, lsl #24 ++ PLD( pld [r1, #0] ) ++ blt 14f ++ subs r2, r2, #28 ++ blt 12f ++ ++ PLD( subs r2, r2, #97 ) ++ PLD( blt 11f ) ++ PLD( pld [r1, #32] ) ++ ++ PLD( @ cache alignment ) ++ PLD( rsb ip, r1, #36 ) ++ PLD( pld [r1, #64] ) ++ PLD( ands ip, ip, #31 ) ++ PLD( pld [r1, #96] ) ++ PLD( beq 10f ) ++ PLD( cmp r2, ip ) ++ PLD( pld [r1, #128] ) ++ PLD( blt 10f ) ++ PLD( sub r2, r2, ip ) ++9: PLD( mov r3, lr, pull #\pull ) ++ PLD( ldr lr, [r1], #4 ) ++ PLD( subs ip, ip, #4 ) ++ PLD( orr r3, r3, lr, push #\push ) ++ PLD( str r3, [r0], #4 ) ++ PLD( bgt 9b ) ++ ++10: PLD( pld [r1, #128] ) ++11: mov r3, lr, pull #\pull ++ ldmia r1!, {r4 - r9, ip, lr} ++ subs r2, r2, #32 ++ orr r3, r3, r4, push #\push ++ mov r4, r4, pull #\pull ++ orr r4, r4, r5, push #\push ++ mov r5, r5, pull #\pull ++ orr r5, r5, r6, push #\push ++ mov r6, r6, pull #\pull ++ orr r6, r6, r7, push #\push ++ mov r7, r7, pull #\pull ++ orr r7, r7, r8, push #\push ++ mov r8, r8, pull #\pull ++ orr r8, r8, r9, push #\push ++ mov r9, r9, pull #\pull ++ orr r9, r9, ip, push #\push ++ mov ip, ip, pull #\pull ++ orr ip, ip, lr, push #\push ++ stmia r0!, {r3 - r9, ip} ++ bge 10b ++ PLD( cmn r2, #97 ) ++ PLD( bge 11b ) ++ PLD( add r2, r2, #97 ) ++ cmn r2, #16 ++ blt 13f ++12: mov r3, lr, pull #\pull ++ ldmia r1!, {r4 - r6, lr} ++ sub r2, r2, #16 ++ orr r3, r3, r4, push #\push ++ mov r4, r4, pull #\pull ++ orr r4, r4, r5, push #\push ++ mov r5, r5, pull #\pull ++ orr r5, r5, r6, push #\push ++ mov r6, r6, pull #\pull ++ orr r6, r6, lr, push #\push + stmia r0!, {r3 - r6} +- subs r2, r2, #16 +- bge 9b +- adds r2, r2, #12 +- blt 100f +-10: mov r3, r7, lsr #8 +- ldr r7, [r1], #4 ++13: adds r2, r2, #28 ++ blt 15f ++14: mov r3, lr, pull #\pull ++ ldr lr, [r1], #4 + subs r2, r2, #4 +- orr r3, r3, r7, lsl #24 ++ orr r3, r3, lr, push #\push + str r3, [r0], #4 +- bge 10b +-100: sub r1, r1, #3 ++ bge 14b ++15: ++ .endm ++ ++ ++ forward_copy_shift pull=8 push=24 ++ sub r1, r1, #3 + b 6b + +-11: cmp r2, #12 +- blt 13f /* */ +- sub r2, r2, #12 +-12: mov r3, r7, lsr #16 +- ldmia r1!, {r4 - r7} +- orr r3, r3, r4, lsl #16 +- mov r4, r4, lsr #16 +- orr r4, r4, r5, lsl #16 +- mov r5, r5, lsr #16 +- orr r5, r5, r6, lsl #16 +- mov r6, r6, lsr #16 +- orr r6, r6, r7,LSL#16 +- stmia r0!, {r3 - r6} +- subs r2, r2, #16 +- bge 12b +- adds r2, r2, #12 +- blt 14f +-13: mov r3, r7, lsr #16 +- ldr r7, [r1], #4 +- subs r2, r2, #4 +- orr r3, r3, r7, lsl #16 +- str r3, [r0], #4 +- bge 13b +-14: sub r1, r1, #2 ++16: forward_copy_shift pull=16 push=16 ++ sub r1, r1, #2 + b 6b + +-15: cmp r2, #12 +- blt 17f +- sub r2, r2, #12 +-16: mov r3, r7, lsr #24 +- ldmia r1!,{r4 - r7} +- orr r3, r3, r4, lsl #8 +- mov r4, r4, lsr #24 +- orr r4, r4, r5, lsl #8 +- mov r5, r5, lsr #24 +- orr r5, r5, r6, lsl #8 +- mov r6, r6, lsr #24 +- orr r6, r6, r7, lsl #8 +- stmia r0!, {r3 - r6} +- subs r2, r2, #16 +- bge 16b +- adds r2, r2, #12 +- blt 18f +-17: mov r3, r7, lsr #24 +- ldr r7, [r1], #4 +- subs r2, r2, #4 +- orr r3, r3, r7, lsl#8 +- str r3, [r0], #4 +- bge 17b +-18: sub r1, r1, #1 ++17: forward_copy_shift pull=24 push=8 ++ sub r1, r1, #1 + b 6b + + +-19: add r1, r1, r2 ++18: add r1, r1, r2 + add r0, r0, r2 + subs r2, r2, #4 + blt 24f ++ PLD( pld [r1, #-4] ) + ands ip, r0, #3 + bne 25f + ands ip, r1, #3 + bne 26f + +-20: subs r2, r2, #8 ++19: subs r2, r2, #8 + blt 23f +- subs r2, r2, #0x14 ++ subs r2, r2, #20 + blt 22f +-21: ldmdb r1!, {r3 - r9, ip} +- stmdb r0!, {r3 - r9, ip} ++ ++ PLD( subs r2, r2, #96 ) ++ PLD( pld [r1, #-32] ) ++ PLD( blt 21f ) ++ ++ PLD( @ cache alignment ) ++ PLD( ands ip, r1, #31 ) ++ PLD( pld [r1, #-64] ) ++ PLD( beq 20f ) ++ PLD( cmp r2, ip ) ++ PLD( pld [r1, #-96] ) ++ PLD( blt 20f ) ++ PLD( cmp ip, #16 ) ++ PLD( sub r2, r2, ip ) ++ PLD( ldmgedb r1!, {r3 - r6} ) ++ PLD( stmgedb r0!, {r3 - r6} ) ++ PLD( beq 20f ) ++ PLD( and ip, ip, #15 ) ++ PLD( cmp ip, #8 ) ++ PLD( ldr r3, [r1, #-4]! ) ++ PLD( ldrge r4, [r1, #-4]! ) ++ PLD( ldrgt r5, [r1, #-4]! ) ++ PLD( str r3, [r0, #-4]! ) ++ PLD( strge r4, [r0, #-4]! ) ++ PLD( strgt r5, [r0, #-4]! ) ++ ++20: PLD( pld [r1, #-96] ) ++ PLD( pld [r1, #-128] ) ++21: ldmdb r1!, {r3 - r6} + subs r2, r2, #32 +- bge 21b +-22: cmn r2, #16 ++ stmdb r0!, {r3 - r6} ++ ldmdb r1!, {r3 - r6} ++ stmgedb r0!, {r3 - r6} + ldmgedb r1!, {r3 - r6} + stmgedb r0!, {r3 - r6} ++ ldmgedb r1!, {r3 - r6} ++ subges r2, r2, #32 ++ stmdb r0!, {r3 - r6} ++ bge 20b ++ PLD( cmn r2, #96 ) ++ PLD( bge 21b ) ++ PLD( add r2, r2, #96 ) ++22: cmn r2, #16 ++ ldmgedb r1!, {r3 - r6} + subge r2, r2, #16 ++ stmgedb r0!, {r3 - r6} + adds r2, r2, #20 + ldmgedb r1!, {r3 - r5} +- stmgedb r0!, {r3 - r5} + subge r2, r2, #12 ++ stmgedb r0!, {r3 - r5} + 23: adds r2, r2, #8 + blt 24f + subs r2, r2, #4 + ldrlt r3, [r1, #-4]! + ldmgedb r1!, {r4, r5} ++ subge r2, r2, #4 + strlt r3, [r0, #-4]! + stmgedb r0!, {r4, r5} +- subge r2, r2, #4 + + 24: adds r2, r2, #4 + EXITEQ +@@ -230,89 +317,101 @@ + subs r2, r2, ip + blt 24b + ands ip, r1, #3 +- beq 20b ++ beq 19b + + 26: bic r1, r1, #3 +- ldr r3, [r1], #0 + cmp ip, #2 +- blt 34f +- beq 30f +- cmp r2, #12 +- blt 28f +- sub r2, r2, #12 +-27: mov r7, r3, lsl #8 +- ldmdb r1!, {r3, r4, r5, r6} +- orr r7, r7, r6, lsr #24 +- mov r6, r6, lsl #8 +- orr r6, r6, r5, lsr #24 +- mov r5, r5, lsl #8 +- orr r5, r5, r4, lsr #24 +- mov r4, r4, lsl #8 +- orr r4, r4, r3, lsr #24 +- stmdb r0!, {r4, r5, r6, r7} +- subs r2, r2, #16 +- bge 27b +- adds r2, r2, #12 +- blt 29f +-28: mov ip, r3, lsl #8 +- ldr r3, [r1, #-4]! +- subs r2, r2, #4 +- orr ip, ip, r3, lsr #24 +- str ip, [r0, #-4]! +- bge 28b +-29: add r1, r1, #3 +- b 24b ++ ldr r3, [r1], #0 ++ blt 35f ++ beq 34f + +-30: cmp r2, #12 ++ ++ .macro backward_copy_shift push pull ++ ++ cmp r2, #12 ++ PLD( pld [r1, #-4] ) + blt 32f +- sub r2, r2, #12 +-31: mov r7, r3, lsl #16 +- ldmdb r1!, {r3, r4, r5, r6} +- orr r7, r7, r6, lsr #16 +- mov r6, r6, lsl #16 +- orr r6, r6, r5, lsr #16 +- mov r5, r5, lsl #16 +- orr r5, r5, r4, lsr #16 +- mov r4, r4, lsl #16 +- orr r4, r4, r3, lsr #16 +- stmdb r0!, {r4, r5, r6, r7} +- subs r2, r2, #16 +- bge 31b +- adds r2, r2, #12 ++ subs r2, r2, #28 ++ blt 30f ++ ++ PLD( subs r2, r2, #96 ) ++ PLD( pld [r1, #-32] ) ++ PLD( blt 29f ) ++ PLD( pld [r1, #-64] ) ++ ++ PLD( @ cache alignment ) ++ PLD( ands ip, r1, #31 ) ++ PLD( pld [r1, #-96] ) ++ PLD( beq 28f ) ++ PLD( cmp r2, ip ) ++ PLD( pld [r1, #-128] ) ++ PLD( blt 28f ) ++ PLD( sub r2, r2, ip ) ++27: PLD( mov r4, r3, push #\push ) ++ PLD( ldr r3, [r1, #-4]! ) ++ PLD( subs ip, ip, #4 ) ++ PLD( orr r4, r4, r3, pull #\pull ) ++ PLD( str r4, [r0, #-4]! ) ++ PLD( bgt 27b ) ++ ++28: PLD( pld [r1, #-128] ) ++29: mov lr, r3, push #\push ++ ldmdb r1!, {r3 - r9, ip} ++ subs r2, r2, #32 ++ orr lr, lr, ip, pull #\pull ++ mov ip, ip, push #\push ++ orr ip, ip, r9, pull #\pull ++ mov r9, r9, push #\push ++ orr r9, r9, r8, pull #\pull ++ mov r8, r8, push #\push ++ orr r8, r8, r7, pull #\pull ++ mov r7, r7, push #\push ++ orr r7, r7, r6, pull #\pull ++ mov r6, r6, push #\push ++ orr r6, r6, r5, pull #\pull ++ mov r5, r5, push #\push ++ orr r5, r5, r4, pull #\pull ++ mov r4, r4, push #\push ++ orr r4, r4, r3, pull #\pull ++ stmdb r0!, {r4 - r9, ip, lr} ++ bge 28b ++ PLD( cmn r2, #96 ) ++ PLD( bge 29b ) ++ PLD( add r2, r2, #96 ) ++ cmn r2, #16 ++ blt 31f ++30: mov r7, r3, push #\push ++ ldmdb r1!, {r3 - r6} ++ sub r2, r2, #16 ++ orr r7, r7, r6, pull #\pull ++ mov r6, r6, push #\push ++ orr r6, r6, r5, pull #\pull ++ mov r5, r5, push #\push ++ orr r5, r5, r4, pull #\pull ++ mov r4, r4, push #\push ++ orr r4, r4, r3, pull #\pull ++ stmdb r0!, {r4 - r7} ++31: adds r2, r2, #28 + blt 33f +-32: mov ip, r3, lsl #16 ++32: mov r4, r3, push #\push + ldr r3, [r1, #-4]! + subs r2, r2, #4 +- orr ip, ip, r3, lsr #16 +- str ip, [r0, #-4]! ++ orr r4, r4, r3, pull #\pull ++ str r4, [r0, #-4]! + bge 32b +-33: add r1, r1, #2 ++33: ++ .endm ++ ++ ++ backward_copy_shift push=8 pull=24 ++ add r1, r1, #3 + b 24b + +-34: cmp r2, #12 +- blt 36f +- sub r2, r2, #12 +-35: mov r7, r3, lsl #24 +- ldmdb r1!, {r3, r4, r5, r6} +- orr r7, r7, r6, lsr #8 +- mov r6, r6, lsl #24 +- orr r6, r6, r5, lsr #8 +- mov r5, r5, lsl #24 +- orr r5, r5, r4, lsr #8 +- mov r4, r4, lsl #24 +- orr r4, r4, r3, lsr #8 +- stmdb r0!, {r4, r5, r6, r7} +- subs r2, r2, #16 +- bge 35b +- adds r2, r2, #12 +- blt 37f +-36: mov ip, r3, lsl #24 +- ldr r3, [r1, #-4]! +- subs r2, r2, #4 +- orr ip, ip, r3, lsr #8 +- str ip, [r0, #-4]! +- bge 36b +-37: add r1, r1, #1 ++34: backward_copy_shift push=16 pull=16 ++ add r1, r1, #2 ++ b 24b ++ ++35: backward_copy_shift push=24 pull=8 ++ add r1, r1, #1 + b 24b + +- .align +--- linux-2.4.27/arch/arm/lib/uaccess.S~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/arch/arm/lib/uaccess.S +@@ -43,6 +43,8 @@ + stmfd sp!, {r2, r4 - r7, lr} + cmp r2, #4 + blt .c2u_not_enough ++ PLD( pld [r1, #0] ) ++ PLD( pld [r0, #0] ) + ands ip, r0, #3 + bne .c2u_dest_not_aligned + .c2u_dest_aligned: +@@ -71,13 +73,26 @@ + sub r2, r2, ip + subs ip, ip, #32 + blt .c2u_0rem8lp ++ PLD( pld [r1, #28] ) ++ PLD( pld [r0, #28] ) ++ PLD( subs ip, ip, #64 ) ++ PLD( blt .c2u_0cpynopld ) ++ PLD( pld [r1, #60] ) ++ PLD( pld [r0, #60] ) + +-.c2u_0cpy8lp: ldmia r1!, {r3 - r6} ++.c2u_0cpy8lp: ++ PLD( pld [r1, #92] ) ++ PLD( pld [r0, #92] ) ++.c2u_0cpynopld: ldmia r1!, {r3 - r6} + stmia r0!, {r3 - r6} @ Shouldnt fault + ldmia r1!, {r3 - r6} +- stmia r0!, {r3 - r6} @ Shouldnt fault + subs ip, ip, #32 ++ stmia r0!, {r3 - r6} @ Shouldnt fault + bpl .c2u_0cpy8lp ++ PLD( cmn ip, #64 ) ++ PLD( bge .c2u_0cpynopld ) ++ PLD( add ip, ip, #64 ) ++ + .c2u_0rem8lp: cmn ip, #16 + ldmgeia r1!, {r3 - r6} + stmgeia r0!, {r3 - r6} @ Shouldnt fault +@@ -115,9 +130,9 @@ + .c2u_1fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .c2u_1nowords +- mov r3, r7, lsr #8 ++ mov r3, r7, pull #8 + ldr r7, [r1], #4 +- orr r3, r3, r7, lsl #24 ++ orr r3, r3, r7, push #24 + USER( strt r3, [r0], #4) @ May fault + mov ip, r0, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 +@@ -128,50 +143,63 @@ + sub r2, r2, ip + subs ip, ip, #16 + blt .c2u_1rem8lp ++ PLD( pld [r1, #12] ) ++ PLD( pld [r0, #12] ) ++ PLD( subs ip, ip, #32 ) ++ PLD( blt .c2u_1cpynopld ) ++ PLD( pld [r1, #28] ) ++ PLD( pld [r0, #28] ) + +-.c2u_1cpy8lp: mov r3, r7, lsr #8 ++.c2u_1cpy8lp: ++ PLD( pld [r1, #44] ) ++ PLD( pld [r0, #44] ) ++.c2u_1cpynopld: mov r3, r7, pull #8 + ldmia r1!, {r4 - r7} +- orr r3, r3, r4, lsl #24 +- mov r4, r4, lsr #8 +- orr r4, r4, r5, lsl #24 +- mov r5, r5, lsr #8 +- orr r5, r5, r6, lsl #24 +- mov r6, r6, lsr #8 +- orr r6, r6, r7, lsl #24 +- stmia r0!, {r3 - r6} @ Shouldnt fault + subs ip, ip, #16 ++ orr r3, r3, r4, push #24 ++ mov r4, r4, pull #8 ++ orr r4, r4, r5, push #24 ++ mov r5, r5, pull #8 ++ orr r5, r5, r6, push #24 ++ mov r6, r6, pull #8 ++ orr r6, r6, r7, push #24 ++ stmia r0!, {r3 - r6} @ Shouldnt fault + bpl .c2u_1cpy8lp ++ PLD( cmn ip, #32 ) ++ PLD( bge .c2u_1cpynopld ) ++ PLD( add ip, ip, #32 ) ++ + .c2u_1rem8lp: tst ip, #8 +- movne r3, r7, lsr #8 ++ movne r3, r7, pull #8 + ldmneia r1!, {r4, r7} +- orrne r3, r3, r4, lsl #24 +- movne r4, r4, lsr #8 +- orrne r4, r4, r7, lsl #24 ++ orrne r3, r3, r4, push #24 ++ movne r4, r4, pull #8 ++ orrne r4, r4, r7, push #24 + stmneia r0!, {r3 - r4} @ Shouldnt fault + tst ip, #4 +- movne r3, r7, lsr #8 ++ movne r3, r7, pull #8 + ldrne r7, [r1], #4 +- orrne r3, r3, r7, lsl #24 ++ orrne r3, r3, r7, push #24 + strnet r3, [r0], #4 @ Shouldnt fault + ands ip, ip, #3 + beq .c2u_1fupi +-.c2u_1nowords: mov r3, r7, lsr #8 ++.c2u_1nowords: mov r3, r7, lsr #byte(1) + teq ip, #0 + beq .c2u_finished + cmp ip, #2 + USER( strbt r3, [r0], #1) @ May fault +- movge r3, r3, lsr #8 ++ movge r3, r7, lsr #byte(2) + USER( strgebt r3, [r0], #1) @ May fault +- movgt r3, r3, lsr #8 ++ movgt r3, r7, lsr #byte(3) + USER( strgtbt r3, [r0], #1) @ May fault + b .c2u_finished + + .c2u_2fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .c2u_2nowords +- mov r3, r7, lsr #16 ++ mov r3, r7, pull #16 + ldr r7, [r1], #4 +- orr r3, r3, r7, lsl #16 ++ orr r3, r3, r7, push #16 + USER( strt r3, [r0], #4) @ May fault + mov ip, r0, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 +@@ -182,39 +210,52 @@ + sub r2, r2, ip + subs ip, ip, #16 + blt .c2u_2rem8lp ++ PLD( pld [r1, #12] ) ++ PLD( pld [r0, #12] ) ++ PLD( subs ip, ip, #32 ) ++ PLD( blt .c2u_2cpynopld ) ++ PLD( pld [r1, #28] ) ++ PLD( pld [r0, #28] ) + +-.c2u_2cpy8lp: mov r3, r7, lsr #16 ++.c2u_2cpy8lp: ++ PLD( pld [r1, #44] ) ++ PLD( pld [r0, #44] ) ++.c2u_2cpynopld: mov r3, r7, pull #16 + ldmia r1!, {r4 - r7} +- orr r3, r3, r4, lsl #16 +- mov r4, r4, lsr #16 +- orr r4, r4, r5, lsl #16 +- mov r5, r5, lsr #16 +- orr r5, r5, r6, lsl #16 +- mov r6, r6, lsr #16 +- orr r6, r6, r7, lsl #16 +- stmia r0!, {r3 - r6} @ Shouldnt fault + subs ip, ip, #16 ++ orr r3, r3, r4, push #16 ++ mov r4, r4, pull #16 ++ orr r4, r4, r5, push #16 ++ mov r5, r5, pull #16 ++ orr r5, r5, r6, push #16 ++ mov r6, r6, pull #16 ++ orr r6, r6, r7, push #16 ++ stmia r0!, {r3 - r6} @ Shouldnt fault + bpl .c2u_2cpy8lp ++ PLD( cmn ip, #32 ) ++ PLD( bge .c2u_2cpynopld ) ++ PLD( add ip, ip, #32 ) ++ + .c2u_2rem8lp: tst ip, #8 +- movne r3, r7, lsr #16 ++ movne r3, r7, pull #16 + ldmneia r1!, {r4, r7} +- orrne r3, r3, r4, lsl #16 +- movne r4, r4, lsr #16 +- orrne r4, r4, r7, lsl #16 ++ orrne r3, r3, r4, push #16 ++ movne r4, r4, pull #16 ++ orrne r4, r4, r7, push #16 + stmneia r0!, {r3 - r4} @ Shouldnt fault + tst ip, #4 +- movne r3, r7, lsr #16 ++ movne r3, r7, pull #16 + ldrne r7, [r1], #4 +- orrne r3, r3, r7, lsl #16 ++ orrne r3, r3, r7, push #16 + strnet r3, [r0], #4 @ Shouldnt fault + ands ip, ip, #3 + beq .c2u_2fupi +-.c2u_2nowords: mov r3, r7, lsr #16 ++.c2u_2nowords: mov r3, r7, lsr #byte(2) + teq ip, #0 + beq .c2u_finished + cmp ip, #2 + USER( strbt r3, [r0], #1) @ May fault +- movge r3, r3, lsr #8 ++ movge r3, r7, lsr #byte(3) + USER( strgebt r3, [r0], #1) @ May fault + ldrgtb r3, [r1], #0 + USER( strgtbt r3, [r0], #1) @ May fault +@@ -223,9 +264,9 @@ + .c2u_3fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .c2u_3nowords +- mov r3, r7, lsr #24 ++ mov r3, r7, pull #24 + ldr r7, [r1], #4 +- orr r3, r3, r7, lsl #8 ++ orr r3, r3, r7, push #8 + USER( strt r3, [r0], #4) @ May fault + mov ip, r0, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 +@@ -236,41 +277,54 @@ + sub r2, r2, ip + subs ip, ip, #16 + blt .c2u_3rem8lp ++ PLD( pld [r1, #12] ) ++ PLD( pld [r0, #12] ) ++ PLD( subs ip, ip, #32 ) ++ PLD( blt .c2u_3cpynopld ) ++ PLD( pld [r1, #28] ) ++ PLD( pld [r0, #28] ) + +-.c2u_3cpy8lp: mov r3, r7, lsr #24 ++.c2u_3cpy8lp: ++ PLD( pld [r1, #44] ) ++ PLD( pld [r0, #44] ) ++.c2u_3cpynopld: mov r3, r7, pull #24 + ldmia r1!, {r4 - r7} +- orr r3, r3, r4, lsl #8 +- mov r4, r4, lsr #24 +- orr r4, r4, r5, lsl #8 +- mov r5, r5, lsr #24 +- orr r5, r5, r6, lsl #8 +- mov r6, r6, lsr #24 +- orr r6, r6, r7, lsl #8 +- stmia r0!, {r3 - r6} @ Shouldnt fault + subs ip, ip, #16 ++ orr r3, r3, r4, push #8 ++ mov r4, r4, pull #24 ++ orr r4, r4, r5, push #8 ++ mov r5, r5, pull #24 ++ orr r5, r5, r6, push #8 ++ mov r6, r6, pull #24 ++ orr r6, r6, r7, push #8 ++ stmia r0!, {r3 - r6} @ Shouldnt fault + bpl .c2u_3cpy8lp ++ PLD( cmn ip, #32 ) ++ PLD( bge .c2u_3cpynopld ) ++ PLD( add ip, ip, #32 ) ++ + .c2u_3rem8lp: tst ip, #8 +- movne r3, r7, lsr #24 ++ movne r3, r7, pull #24 + ldmneia r1!, {r4, r7} +- orrne r3, r3, r4, lsl #8 +- movne r4, r4, lsr #24 +- orrne r4, r4, r7, lsl #8 ++ orrne r3, r3, r4, push #8 ++ movne r4, r4, pull #24 ++ orrne r4, r4, r7, push #8 + stmneia r0!, {r3 - r4} @ Shouldnt fault + tst ip, #4 +- movne r3, r7, lsr #24 ++ movne r3, r7, pull #24 + ldrne r7, [r1], #4 +- orrne r3, r3, r7, lsl #8 ++ orrne r3, r3, r7, push #8 + strnet r3, [r0], #4 @ Shouldnt fault + ands ip, ip, #3 + beq .c2u_3fupi +-.c2u_3nowords: mov r3, r7, lsr #24 ++.c2u_3nowords: mov r3, r7, lsr #byte(3) + teq ip, #0 + beq .c2u_finished + cmp ip, #2 + USER( strbt r3, [r0], #1) @ May fault +- ldrge r3, [r1], #0 ++ ldrgeb r3, [r1], #1 + USER( strgebt r3, [r0], #1) @ May fault +- movgt r3, r3, lsr #8 ++ ldrgtb r3, [r1], #0 + USER( strgtbt r3, [r0], #1) @ May fault + b .c2u_finished + +@@ -302,6 +356,8 @@ + stmfd sp!, {r0, r2, r4 - r7, lr} + cmp r2, #4 + blt .cfu_not_enough ++ PLD( pld [r1, #0] ) ++ PLD( pld [r0, #0] ) + ands ip, r0, #3 + bne .cfu_dest_not_aligned + .cfu_dest_aligned: +@@ -329,13 +385,26 @@ + sub r2, r2, ip + subs ip, ip, #32 + blt .cfu_0rem8lp ++ PLD( pld [r1, #28] ) ++ PLD( pld [r0, #28] ) ++ PLD( subs ip, ip, #64 ) ++ PLD( blt .cfu_0cpynopld ) ++ PLD( pld [r1, #60] ) ++ PLD( pld [r0, #60] ) + +-.cfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldnt fault ++.cfu_0cpy8lp: ++ PLD( pld [r1, #92] ) ++ PLD( pld [r0, #92] ) ++.cfu_0cpynopld: ldmia r1!, {r3 - r6} @ Shouldnt fault + stmia r0!, {r3 - r6} + ldmia r1!, {r3 - r6} @ Shouldnt fault +- stmia r0!, {r3 - r6} + subs ip, ip, #32 ++ stmia r0!, {r3 - r6} + bpl .cfu_0cpy8lp ++ PLD( cmn ip, #64 ) ++ PLD( bge .cfu_0cpynopld ) ++ PLD( add ip, ip, #64 ) ++ + .cfu_0rem8lp: cmn ip, #16 + ldmgeia r1!, {r3 - r6} @ Shouldnt fault + stmgeia r0!, {r3 - r6} +@@ -374,9 +443,9 @@ + .cfu_1fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .cfu_1nowords +- mov r3, r7, lsr #8 ++ mov r3, r7, pull #8 + USER( ldrt r7, [r1], #4) @ May fault +- orr r3, r3, r7, lsl #24 ++ orr r3, r3, r7, push #24 + str r3, [r0], #4 + mov ip, r1, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 +@@ -387,50 +456,63 @@ + sub r2, r2, ip + subs ip, ip, #16 + blt .cfu_1rem8lp ++ PLD( pld [r1, #12] ) ++ PLD( pld [r0, #12] ) ++ PLD( subs ip, ip, #32 ) ++ PLD( blt .cfu_1cpynopld ) ++ PLD( pld [r1, #28] ) ++ PLD( pld [r0, #28] ) + +-.cfu_1cpy8lp: mov r3, r7, lsr #8 ++.cfu_1cpy8lp: ++ PLD( pld [r1, #44] ) ++ PLD( pld [r0, #44] ) ++.cfu_1cpynopld: mov r3, r7, pull #8 + ldmia r1!, {r4 - r7} @ Shouldnt fault +- orr r3, r3, r4, lsl #24 +- mov r4, r4, lsr #8 +- orr r4, r4, r5, lsl #24 +- mov r5, r5, lsr #8 +- orr r5, r5, r6, lsl #24 +- mov r6, r6, lsr #8 +- orr r6, r6, r7, lsl #24 +- stmia r0!, {r3 - r6} + subs ip, ip, #16 ++ orr r3, r3, r4, push #24 ++ mov r4, r4, pull #8 ++ orr r4, r4, r5, push #24 ++ mov r5, r5, pull #8 ++ orr r5, r5, r6, push #24 ++ mov r6, r6, pull #8 ++ orr r6, r6, r7, push #24 ++ stmia r0!, {r3 - r6} + bpl .cfu_1cpy8lp ++ PLD( cmn ip, #32 ) ++ PLD( bge .cfu_1cpynopld ) ++ PLD( add ip, ip, #32 ) ++ + .cfu_1rem8lp: tst ip, #8 +- movne r3, r7, lsr #8 ++ movne r3, r7, pull #8 + ldmneia r1!, {r4, r7} @ Shouldnt fault +- orrne r3, r3, r4, lsl #24 +- movne r4, r4, lsr #8 +- orrne r4, r4, r7, lsl #24 ++ orrne r3, r3, r4, push #24 ++ movne r4, r4, pull #8 ++ orrne r4, r4, r7, push #24 + stmneia r0!, {r3 - r4} + tst ip, #4 +- movne r3, r7, lsr #8 ++ movne r3, r7, pull #8 + USER( ldrnet r7, [r1], #4) @ May fault +- orrne r3, r3, r7, lsl #24 ++ orrne r3, r3, r7, push #24 + strne r3, [r0], #4 + ands ip, ip, #3 + beq .cfu_1fupi +-.cfu_1nowords: mov r3, r7, lsr #8 ++.cfu_1nowords: mov r3, r7, lsr #byte(1) + teq ip, #0 + beq .cfu_finished + cmp ip, #2 + strb r3, [r0], #1 +- movge r3, r3, lsr #8 ++ movge r3, r7, lsr #byte(2) + strgeb r3, [r0], #1 +- movgt r3, r3, lsr #8 ++ movgt r3, r7, lsr #byte(3) + strgtb r3, [r0], #1 + b .cfu_finished + + .cfu_2fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .cfu_2nowords +- mov r3, r7, lsr #16 ++ mov r3, r7, pull #16 + USER( ldrt r7, [r1], #4) @ May fault +- orr r3, r3, r7, lsl #16 ++ orr r3, r3, r7, push #16 + str r3, [r0], #4 + mov ip, r1, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 +@@ -441,39 +523,52 @@ + sub r2, r2, ip + subs ip, ip, #16 + blt .cfu_2rem8lp ++ PLD( pld [r1, #12] ) ++ PLD( pld [r0, #12] ) ++ PLD( subs ip, ip, #32 ) ++ PLD( blt .cfu_2cpynopld ) ++ PLD( pld [r1, #28] ) ++ PLD( pld [r0, #28] ) + +-.cfu_2cpy8lp: mov r3, r7, lsr #16 ++.cfu_2cpy8lp: ++ PLD( pld [r1, #44] ) ++ PLD( pld [r0, #44] ) ++.cfu_2cpynopld: mov r3, r7, pull #16 + ldmia r1!, {r4 - r7} @ Shouldnt fault +- orr r3, r3, r4, lsl #16 +- mov r4, r4, lsr #16 +- orr r4, r4, r5, lsl #16 +- mov r5, r5, lsr #16 +- orr r5, r5, r6, lsl #16 +- mov r6, r6, lsr #16 +- orr r6, r6, r7, lsl #16 +- stmia r0!, {r3 - r6} + subs ip, ip, #16 ++ orr r3, r3, r4, push #16 ++ mov r4, r4, pull #16 ++ orr r4, r4, r5, push #16 ++ mov r5, r5, pull #16 ++ orr r5, r5, r6, push #16 ++ mov r6, r6, pull #16 ++ orr r6, r6, r7, push #16 ++ stmia r0!, {r3 - r6} + bpl .cfu_2cpy8lp ++ PLD( cmn ip, #32 ) ++ PLD( bge .cfu_2cpynopld ) ++ PLD( add ip, ip, #32 ) ++ + .cfu_2rem8lp: tst ip, #8 +- movne r3, r7, lsr #16 ++ movne r3, r7, pull #16 + ldmneia r1!, {r4, r7} @ Shouldnt fault +- orrne r3, r3, r4, lsl #16 +- movne r4, r4, lsr #16 +- orrne r4, r4, r7, lsl #16 ++ orrne r3, r3, r4, push #16 ++ movne r4, r4, pull #16 ++ orrne r4, r4, r7, push #16 + stmneia r0!, {r3 - r4} + tst ip, #4 +- movne r3, r7, lsr #16 ++ movne r3, r7, pull #16 + USER( ldrnet r7, [r1], #4) @ May fault +- orrne r3, r3, r7, lsl #16 ++ orrne r3, r3, r7, push #16 + strne r3, [r0], #4 + ands ip, ip, #3 + beq .cfu_2fupi +-.cfu_2nowords: mov r3, r7, lsr #16 ++.cfu_2nowords: mov r3, r7, lsr #byte(2) + teq ip, #0 + beq .cfu_finished + cmp ip, #2 + strb r3, [r0], #1 +- movge r3, r3, lsr #8 ++ movge r3, r7, lsr #byte(3) + strgeb r3, [r0], #1 + USER( ldrgtbt r3, [r1], #0) @ May fault + strgtb r3, [r0], #1 +@@ -482,9 +577,9 @@ + .cfu_3fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .cfu_3nowords +- mov r3, r7, lsr #24 ++ mov r3, r7, pull #24 + USER( ldrt r7, [r1], #4) @ May fault +- orr r3, r3, r7, lsl #8 ++ orr r3, r3, r7, push #8 + str r3, [r0], #4 + mov ip, r1, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 +@@ -495,41 +590,54 @@ + sub r2, r2, ip + subs ip, ip, #16 + blt .cfu_3rem8lp ++ PLD( pld [r1, #12] ) ++ PLD( pld [r0, #12] ) ++ PLD( subs ip, ip, #32 ) ++ PLD( blt .cfu_3cpynopld ) ++ PLD( pld [r1, #28] ) ++ PLD( pld [r0, #28] ) + +-.cfu_3cpy8lp: mov r3, r7, lsr #24 ++.cfu_3cpy8lp: ++ PLD( pld [r1, #44] ) ++ PLD( pld [r0, #44] ) ++.cfu_3cpynopld: mov r3, r7, pull #24 + ldmia r1!, {r4 - r7} @ Shouldnt fault +- orr r3, r3, r4, lsl #8 +- mov r4, r4, lsr #24 +- orr r4, r4, r5, lsl #8 +- mov r5, r5, lsr #24 +- orr r5, r5, r6, lsl #8 +- mov r6, r6, lsr #24 +- orr r6, r6, r7, lsl #8 ++ orr r3, r3, r4, push #8 ++ mov r4, r4, pull #24 ++ orr r4, r4, r5, push #8 ++ mov r5, r5, pull #24 ++ orr r5, r5, r6, push #8 ++ mov r6, r6, pull #24 ++ orr r6, r6, r7, push #8 + stmia r0!, {r3 - r6} + subs ip, ip, #16 + bpl .cfu_3cpy8lp ++ PLD( cmn ip, #32 ) ++ PLD( bge .cfu_3cpynopld ) ++ PLD( add ip, ip, #32 ) ++ + .cfu_3rem8lp: tst ip, #8 +- movne r3, r7, lsr #24 ++ movne r3, r7, pull #24 + ldmneia r1!, {r4, r7} @ Shouldnt fault +- orrne r3, r3, r4, lsl #8 +- movne r4, r4, lsr #24 +- orrne r4, r4, r7, lsl #8 ++ orrne r3, r3, r4, push #8 ++ movne r4, r4, pull #24 ++ orrne r4, r4, r7, push #8 + stmneia r0!, {r3 - r4} + tst ip, #4 +- movne r3, r7, lsr #24 ++ movne r3, r7, pull #24 + USER( ldrnet r7, [r1], #4) @ May fault +- orrne r3, r3, r7, lsl #8 ++ orrne r3, r3, r7, push #8 + strne r3, [r0], #4 + ands ip, ip, #3 + beq .cfu_3fupi +-.cfu_3nowords: mov r3, r7, lsr #24 ++.cfu_3nowords: mov r3, r7, lsr #byte(3) + teq ip, #0 + beq .cfu_finished + cmp ip, #2 + strb r3, [r0], #1 +-USER( ldrget r3, [r1], #0) @ May fault ++USER( ldrgebt r3, [r1], #1) @ May fault + strgeb r3, [r0], #1 +- movgt r3, r3, lsr #8 ++USER( ldrgtbt r3, [r1], #1) @ May fault + strgtb r3, [r0], #1 + b .cfu_finished + +@@ -544,7 +652,7 @@ + ldr r1, [sp], #4 @ unsigned long count + subs r4, r1, r2 @ bytes left to copy + movne r1, r4 +- blne SYMBOL_NAME(__memzero) ++ blne __memzero + mov r0, r4 + LOADREGS(fd,sp!, {r4 - r7, pc}) + .previous +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/Makefile +@@ -0,0 +1,56 @@ ++# ++# Makefile for the linux kernel. ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++ ++USE_STANDARD_AS_RULE := true ++ ++O_TARGET := pxa.o ++ ++obj-y := ++obj-m := ++obj-n := ++obj- := ++ ++export-objs := generic.o irq.o dma.o sa1111.o \ ++ usb_ctl.o usb_recv.o usb_send.o ++ ++# Common support (must be linked before board specific support) ++obj-y += generic.o irq.o dma.o ++obj-$(CONFIG_SA1111) += sa1111.o ++ ++# Specific board support ++obj-$(CONFIG_ARCH_CSB226) += csb226.o ++obj-$(CONFIG_ARCH_INNOKOM) += innokom.o ++obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o ++obj-$(CONFIG_ARCH_PXA_CERF) += cerf.o ++obj-$(CONFIG_ARCH_PXA_IDP) += idp.o ++obj-$(CONFIG_ARCH_TRIZEPS2) += trizeps2.o ++ ++# Support for blinky lights ++leds-y := leds.o ++leds-$(CONFIG_ARCH_CSB226) += leds-csb226.o ++leds-$(CONFIG_ARCH_INNOKOM) += leds-innokom.o ++leds-$(CONFIG_ARCH_LUBBOCK) += leds-lubbock.o ++leds-$(CONFIG_ARCH_PXA_IDP) += leds-idp.o ++leds-$(CONFIG_ARCH_PXA_CERF) += leds-cerf.o ++ ++obj-$(CONFIG_LEDS) += $(leds-y) ++ ++# PXA USB client support ++list-multi += pxausb_core.o ++pxausb_core-objs := usb_ctl.o usb_ep0.o usb_recv.o usb_send.o ++obj-$(CONFIG_PXA_USB) += pxausb_core.o ++obj-$(CONFIG_PXA_USB_NETLINK) += usb-eth.o ++obj-$(CONFIG_PXA_USB_CHAR) += usb-char.o ++ ++# Misc features ++obj-$(CONFIG_PM) += pm.o sleep.o ++obj-$(CONFIG_CPU_FREQ) += cpu-pxa.o ++ ++include $(TOPDIR)/Rules.make ++ ++pxausb_core.o: $(pxausb_core-objs) ++ $(LD) -r -o $@ $(pxausb_core-objs) +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/cerf.c +@@ -0,0 +1,266 @@ ++/* ++ * linux/arch/arm/mach-pxa/cerf.c ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/init.h> ++#include <linux/major.h> ++#include <linux/fs.h> ++#include <linux/interrupt.h> ++#include <linux/sched.h> ++ ++#include <asm/types.h> ++#include <asm/setup.h> ++#include <asm/memory.h> ++#include <asm/mach-types.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/io.h> ++#include <asm/arch/irq.h> ++ ++#include "generic.h" ++ ++/* ++ * Set this to zero to remove all the debug statements via ++ * dead code elimination. ++ */ ++#define DEBUGGING 1 ++ ++#if DEBUGGING ++static unsigned int cerf_debug = DEBUGGING; ++#else ++#define cerf_debug 0 ++#endif ++ ++static void __init cerf_init_irq(void) ++{ ++ pxa_init_irq(); ++ ++ if( cerf_debug > 1) ++ { ++#if 0 ++ GPDR0 = 0xc05b9130; ++ GPDR1 = 0xfcffab82; ++ GPDR2 = 0x0001ffff; ++#endif ++ ++ printk(KERN_INFO "Pin directions:\n"); ++ printk(KERN_INFO "GPDR0 0x%08x\n", GPDR0); ++ printk(KERN_INFO "GPDR1 0x%08x\n", GPDR1); ++ printk(KERN_INFO "GPDR2 0x%08x\n", GPDR2); ++ ++ printk(KERN_INFO "Pin State:\n"); ++ printk(KERN_INFO "GPLR0 0x%08x\n", GPLR0); ++ printk(KERN_INFO "GPLR1 0x%08x\n", GPLR1); ++ printk(KERN_INFO "GPLR2 0x%08x\n", GPLR2); ++ ++ printk(KERN_INFO "Rising Edge:\n"); ++ printk(KERN_INFO "GRER0 0x%08x\n", GRER0); ++ printk(KERN_INFO "GRER1 0x%08x\n", GRER1); ++ printk(KERN_INFO "GRER2 0x%08x\n", GRER2); ++ ++ printk(KERN_INFO "Falling Edge:\n"); ++ printk(KERN_INFO "GFER0 0x%08x\n", GFER0); ++ printk(KERN_INFO "GFER1 0x%08x\n", GFER1); ++ printk(KERN_INFO "GFER2 0x%08x\n", GFER2); ++ } ++ ++ /* set_GPIO_IRQ_edge has to be called before an irq can be requested */ ++ set_GPIO_IRQ_edge( 0, GPIO_FALLING_EDGE); /* CPLD */ ++#ifdef CONFIG_PXA_CERF_PDA ++ set_GPIO_IRQ_edge( 2, GPIO_RISING_EDGE); /* UART B Interrupt */ ++ set_GPIO_IRQ_edge( 3, GPIO_RISING_EDGE); /* UART A Interrupt */ ++ set_GPIO_IRQ_edge( 32, GPIO_RISING_EDGE); /* UCB1400 Interrupt */ ++#endif ++ set_GPIO_IRQ_edge( 14, GPIO_FALLING_EDGE); /* PCMCIA Card Detect */ ++ set_GPIO_IRQ_edge( 21, GPIO_RISING_EDGE); /* Ethernet Interrupt */ ++} ++ ++static int __init cerf_init(void) ++{ ++ /* ++ * All of the code that was here was SA1111 init code ++ * which we do not have. ++ */ ++ return 0; ++} ++ ++__initcall(cerf_init); ++ ++static void __init ++fixup_cerf(struct machine_desc *desc, struct param_struct *params, ++ char **cmdline, struct meminfo *mi) ++{ ++ SET_BANK (0, CERF_RAM_BASE, CERF_RAM_SIZE); ++ mi->nr_banks = 1; ++ ++#if 0 // Enable this stuff if you plan on not using jffs2 ++ setup_ramdisk (1, 0, 0, 8192); ++ setup_initrd (__phys_to_virt(0xa1000000), 4*1024*1024); ++ ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); ++#endif ++} ++ ++/* ++ * IO map for the devices. ++ */ ++static struct map_desc cerf_io_desc[] __initdata = { ++ /* virtual physical length domain r w c b */ ++ { CERF_FLASH_BASE , CERF_FLASH_PHYS , CERF_FLASH_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, ++ { CERF_ETH_BASE , CERF_ETH_PHYS , CERF_ETH_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, ++#ifdef CONFIG_PXA_CERF_PDA ++ { CERF_BT_BASE , CERF_BT_PHYS , CERF_BT_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, ++ { CERF_SERIAL_BASE, CERF_SERIAL_PHYS, CERF_SERIAL_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, ++ { CERF_CPLD_BASE , CERF_CPLD_PHYS , CERF_CPLD_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, ++#endif ++ ++ LAST_DESC ++}; ++ ++static void __init cerf_map_io(void) ++{ ++ pxa_map_io(); ++ iotable_init(cerf_io_desc); ++ ++ if( cerf_debug > 1) ++ { ++ printk(KERN_INFO "origMCS0 = 0x%08x\n", MSC0); ++ printk(KERN_INFO "origMCS1 = 0x%08x\n", MSC1); ++ printk(KERN_INFO "origMCS2 = 0x%08x\n", MSC2); ++ } ++ ++ /* setup memory timing for CS0/1 */ ++ MSC0 = MSC_CS(0, MSC_RBUFF(MSC_RBUFF_SLOW) | ++ MSC_RRR(3) | ++ MSC_RDN(15) | ++ MSC_RDF(13) | ++ MSC_RBW(0) | ++ MSC_RT(0)) | ++#ifdef CONFIG_PXA_CERF_PDA ++ MSC_CS(1, MSC_RBUFF(MSC_RBUFF_SLOW) | ++ MSC_RRR(7) | ++ MSC_RDN(15) | ++ MSC_RDF(15) | ++ MSC_RBW(1) | ++ MSC_RT(0)); ++#elif defined(CONFIG_PXA_CERF_BOARD) ++ MSC_CS(1, MSC_RBUFF(MSC_RBUFF_SLOW) | ++ MSC_RRR(1) | ++ MSC_RDN(2) | ++ MSC_RDF(4) | ++ MSC_RBW(0) | ++ MSC_RT(4)); ++#endif ++ printk(KERN_INFO "MCS0 = 0x%08x\n", MSC0); ++ ++ /* setup memory timing for CS2/3 */ ++ MSC1 = MSC_CS(2, MSC_RBUFF(MSC_RBUFF_SLOW) | ++ MSC_RRR(5) | ++ MSC_RDN(10) | ++ MSC_RDF(10) | ++ MSC_RBW(1) | ++ MSC_RT(0)) | ++ MSC_CS(3, MSC_RBUFF(MSC_RBUFF_SLOW) | ++ MSC_RRR(5) | ++ MSC_RDN(10) | ++ MSC_RDF(10) | ++ MSC_RBW(1) | ++ MSC_RT(0)); ++ printk(KERN_INFO "MCS1 = 0x%08x\n", MSC1); ++ ++ /* setup memory timing for CS4/5 */ ++ MSC2 = MSC_CS(4, MSC_RBUFF(MSC_RBUFF_SLOW) | ++ MSC_RRR(2) | ++ MSC_RDN(4) | ++ MSC_RDF(4) | ++ MSC_RBW(1) | ++ MSC_RT(0)) | ++ MSC_CS(5, MSC_RBUFF(MSC_RBUFF_SLOW) | ++ MSC_RRR(2) | ++ MSC_RDN(4) | ++ MSC_RDF(4) | ++ MSC_RBW(1) | ++ MSC_RT(0)); ++ printk(KERN_INFO "MCS2 = 0x%08x\n", MSC2); ++ ++#ifdef CONFIG_SOUND_PXA_AC97 ++ printk(KERN_INFO "Enabling sound amp for pxa cerf pda.\n"); ++ outw( CERF_PDA_SOUND_ENABLE, CERF_CPLD_BASE+CERF_PDA_CPLD_SOUND_ENA); ++#endif ++ ++#ifdef CONFIG_FB_PXA ++ printk(KERN_INFO "Setting LCD to brightness to %d/15\n", CERF_PDA_DEFAULT_BRIGHTNESS); ++ outw( CERF_PDA_DEFAULT_BRIGHTNESS, CERF_CPLD_BASE+CERF_PDA_CPLD_BRIGHTNESS); ++#endif ++ ++#ifdef CONFIG_IRDA ++ /* Enable IrDA UART (SIR)*/ ++ CKEN |= CKEN5_STUART; ++ ++ /* We want to get our goods from the STUART */ ++ set_GPIO_mode(GPIO46_STRXD_MD); ++ set_GPIO_mode(GPIO47_STTXD_MD); ++ ++ /* make sure FIR ICP is off */ ++ ICCR0 = 0; ++ ++ /* configure STUART to for SIR ++ * NOTE: RCVEIR and XMITIR must not be set at the same time! ++ * Start with receive in IR mode, and switch transmit to IR only ++ * when we need to send something in serial driver. ++ */ ++ STISR = IrSR_IR_RECEIVE_ON; ++#endif ++ ++#if 0 ++ /* Connect FIR ICP to GPIO pins */ ++ CKEN |= CKEN13_FICP; ++ set_GPIO_mode(GPIO46_ICPRXD_MD); ++ set_GPIO_mode(GPIO47_ICPTXD_MD); ++ ICCR0 = 0x1 | 0x18; //ICP unit enable ++#endif ++ ++#if 0 ++ /* Enable BT UART */ ++ CKEN |= CKEN7_BTUART; ++ set_GPIO_mode(GPIO42_BTRXD_MD); ++ set_GPIO_mode(GPIO43_BTTXD_MD); ++ set_GPIO_mode(GPIO44_BTCTS_MD); ++ set_GPIO_mode(GPIO45_BTRTS_MD); ++#endif ++ ++ if( cerf_debug > 1) ++ { ++ printk(KERN_INFO "GPDR0 0x%08x\n", GPDR0); ++ printk(KERN_INFO "GPDR1 0x%08x\n", GPDR1); ++ printk(KERN_INFO "GPDR2 0x%08x\n", GPDR2); ++ printk(KERN_INFO "GPLR0 0x%08x\n", GPLR0); ++ printk(KERN_INFO "GPLR1 0x%08x\n", GPLR1); ++ printk(KERN_INFO "GPLR2 0x%08x\n", GPLR2); ++ printk(KERN_INFO "GAFR0_L 0x%08x\n", GAFR0_L); ++ printk(KERN_INFO "GAFR0_U 0x%08x\n", GAFR0_U); ++ printk(KERN_INFO "GAFR1_L 0x%08x\n", GAFR1_L); ++ printk(KERN_INFO "GAFR1_U 0x%08x\n", GAFR1_U); ++ printk(KERN_INFO "GAFR2_L 0x%08x\n", GAFR2_L); ++ printk(KERN_INFO "GAFR2_U 0x%08x\n", GAFR2_U); ++ printk(KERN_INFO "CKEN = 0x%08x\n", CKEN); ++ printk(KERN_INFO "ICCR0 = 0x%08x\n", ICCR0); ++ printk(KERN_INFO "STISR = 0x%08x\n", STISR); ++ } ++} ++ ++MACHINE_START(PXA_CERF, "CerfBoard PXA Reference Board") ++ MAINTAINER("Intrinsyc Software Inc.") ++ BOOT_MEM(0xa0000000, 0x40000000, 0xfc000000) ++ BOOT_PARAMS(0xa0000100) ++ FIXUP(fixup_cerf) ++ MAPIO(cerf_map_io) ++ INITIRQ(cerf_init_irq) ++MACHINE_END +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/cpu-pxa.c +@@ -0,0 +1,240 @@ ++/* ++ * linux/arch/arm/mach-pxa/cpu-pxa.c ++ * ++ * Copyright (C) 2002,2003 Intrinsyc Software ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * History: ++ * 31-Jul-2002 : Initial version [FB] ++ * 29-Jan-2003 : added PXA255 support [FB] ++ * ++ * Note: ++ * ++ * Quote from erratum 134: ++ * ""If the operation of these peripherals would be adversely affected, ++ * then these peripherals would have to be disabled during a frequency ++ * change. (MMC,FFUART,STUART,BTUART,IRDA,SSP,UDC,AC97)"" ++ * ++ * This sounds like they are not sure what the bug is... ++ * If you run into problems with any of these peripherals, the effected ++ * driver should register with cpu freq notification and disable/enable ++ * the peripheral on CPUFREQ_PRECHANGE and CPUFREQ_POSTCHANGE. ++ * ++ * So far I've tested this code only under light load. It works for me. ++ * ++ * TODO: ++ * - determine min/max freq at runtime ++ * - determine pxbus value at runtime ++ * ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/sched.h> ++#include <linux/init.h> ++#include <linux/cpufreq.h> ++ ++#include <asm/hardware.h> ++ ++#define DEBUGGING 1 ++ ++#if DEBUGGING ++static unsigned int freq_debug = DEBUGGING; ++#else ++#define freq_debug 0 ++#endif ++ ++typedef struct ++{ ++ unsigned int khz; ++ unsigned int cccr; ++ unsigned int pxbus; ++} pxa_freqs_t; ++ ++#define CCLKCFG_TURBO 0x1 ++#define CCLKCFG_FCS 0x2 ++ ++#define PXA250_REV_A1 0x1 ++#define PXA250_REV_B2 0x4 ++#define PXA25x_MIN_FREQ 99000 ++ ++//#define PXA25x_ALLOW_OVERCLOCK ++ ++#ifdef PXA25x_ALLOW_OVERCLOCK ++#warning *** Overclocking enabled - this may fry your hardware - you have been warned *** ++#define OC(x...) x ++#define PXA25x_MAX_FREQ 471000 ++#else ++#define OC(x...) ++#define PXA25x_MAX_FREQ 400000 ++#endif ++ ++/* If CONFIG_CPU_FREQ is turned on but we find (at runtime) ++ * we can't support scaling, try to handle requests gracefully. ++ */ ++static int supported; ++ ++static pxa_freqs_t pxa250_valid_freqs[] = ++{ ++ {199100, 0x141, 99}, /* mem= 99, run=199, turbo=199, PXbus= 99 */ ++ {298600, 0x1c1, 99}, /* mem= 99, run=199, turbo=298, PXbus= 99 */ ++ {398100, 0x241, 99}, /* mem= 99, run=199, turbo=398, PXbus= 99 */ ++ {0,0} ++}; ++ ++static pxa_freqs_t pxa255_valid_freqs[] = ++{ ++ { 99000, 0x121, 50}, /* mem= 99, run= 99, turbo= 99, PXbus= 50 */ ++OC( {118000, 0x122, 59},)/* mem=118, run=118, turbo=118, PXbus= 59 OC'd mem */ ++ {199100, 0x141, 99}, /* mem= 99, run=199, turbo=199, PXbus= 99 */ ++OC( {236000, 0x142,118},)/* mem=118, run=236, turbo=236, PXbus=118 OC'd mem */ ++ {298600, 0x1c1, 99}, /* mem= 99, run=199, turbo=298, PXbus= 99 */ ++OC( {354000, 0x1c2,118},)/* mem=118, run=236, turbo=354, PXbus=118 OC'd mem */ ++ {398099, 0x241, 99}, /* mem= 99, run=199, turbo=398, PXbus= 99 */ ++ {398100, 0x161,196}, /* mem= 99, run=398, turbo=398, PXbus=196 */ ++OC( {471000, 0x162,236},)/* mem=118, run=471, turbo=471, PXbus=236 OC'd mem/core/bus */ ++ {0,0} ++}; ++ ++static pxa_freqs_t *pxa_valid_freqs; ++ ++/* This should be called with a valid freq point that was ++ * obtained via pxa_validate_speed ++ */ ++static pxa_freqs_t * pxa_get_freq_info( unsigned int khz) ++{ ++ int i=0; ++ while( pxa_valid_freqs[i].khz) ++ { ++ if( pxa_valid_freqs[i].khz == khz) ++ return &pxa_valid_freqs[i]; ++ i++; ++ } ++ ++ /* shouldn't get here */ ++ return 0; ++} ++ ++/* find a valid frequency point */ ++static unsigned int pxa_validate_speed(unsigned int khz) ++{ ++ int i=0; ++ unsigned int vfreq = 0; ++ while( pxa_valid_freqs[i].khz && (khz >= pxa_valid_freqs[i].khz)) ++ { ++ vfreq = pxa_valid_freqs[i].khz; ++ i++; ++ } ++ return vfreq; ++} ++ ++/* This should be called with a valid freq point that was ++ * obtained via pxa_validate_speed ++ */ ++static void pxa_setspeed(unsigned int khz) ++{ ++ unsigned long flags; ++ unsigned int unused; ++ void *ramstart = phys_to_virt(0xa0000000); ++ pxa_freqs_t *freq_info; ++ ++ if( ! supported) return; ++ ++ freq_info = pxa_get_freq_info( khz); ++ ++ if( ! freq_info) return; ++ ++ CCCR = freq_info->cccr; ++ if( freq_debug) ++ printk(KERN_INFO "Changing CPU frequency to %d Mhz (PXbus=%dMhz).\n", ++ khz/1000, freq_info->pxbus); ++ ++ local_irq_save(flags); ++ __asm__ __volatile__("\ ++ ldr r4, [%1] @load MDREFR \n\ ++ b 2f \n\ ++ .align 5 \n\ ++1: \n\ ++ mcr p14, 0, %2, c6, c0, 0 @ set CCLKCFG[FCS] \n\ ++ \n\ ++ @ restart sdcke 0 / 1 \n\ ++ bic r5, r4, #(0x00001000 | 0x00008000) @ MDREFR_E0PIN | MDREFR_E1PIN \n\ ++ str r5, [%1] @clear \n\ ++ str r4, [%1] @restore \n\ ++ \n\ ++ @ Generate refresh cycles for all banks \n\ ++ ldr r4, [%3] \n\ ++ str r4, [%3] \n\ ++ str r4, [%3] \n\ ++ str r4, [%3] \n\ ++ str r4, [%3] \n\ ++ str r4, [%3] \n\ ++ str r4, [%3] \n\ ++ str r4, [%3] \n\ ++ str r4, [%3] \n\ ++ \n\ ++ b 3f \n\ ++2: b 1b \n\ ++3: nop \n\ ++ " ++ : "=&r" (unused) ++ : "r" (&MDREFR), "r" (CCLKCFG_TURBO|CCLKCFG_FCS), "r" (ramstart) ++ : "r4", "r5"); ++ local_irq_restore(flags); ++} ++ ++static int pxa_init_freqs( void) ++{ ++ int cpu_ver; ++ asm("mrc%? p15, 0, %0, c0, c0" : "=r" (cpu_ver)); ++ ++ if( (cpu_ver & 0xf) <= PXA250_REV_A1) ++ { ++ return 0; ++ } ++ ++ if( (cpu_ver & 0xf) <= PXA250_REV_B2) ++ { ++ if( freq_debug) printk(KERN_INFO "Using PXA250 frequency points.\n"); ++ pxa_valid_freqs = pxa250_valid_freqs; ++ } ++ else /* C0 and above */ ++ { ++ if( freq_debug) printk(KERN_INFO "Using PXA255 frequency points.\n"); ++ pxa_valid_freqs = pxa255_valid_freqs; ++ } ++ ++ return 1; ++} ++ ++static int __init pxa_clk_init(void) ++{ ++ if( pxa_init_freqs()) ++ { ++ if( freq_debug) printk(KERN_INFO "Registering CPU frequency change support.\n"); ++ supported = 1; ++ ++ cpufreq_init( get_clk_frequency_khz(0), PXA25x_MIN_FREQ, PXA25x_MAX_FREQ); ++ cpufreq_setfunctions(pxa_validate_speed, pxa_setspeed); ++ } ++ else ++ { ++ if( freq_debug) printk(KERN_INFO "Disabling CPU frequency change support.\n"); ++ /* Note that we have to initialize the generic code in order to ++ * release a lock (cpufreq_sem). Any registration for freq changes ++ * (e.g. lcd driver) will get blocked otherwise. ++ */ ++ cpufreq_init( 0, 0, 0); ++ cpufreq_setfunctions(pxa_validate_speed, pxa_setspeed); ++ } ++ ++ return 0; ++} ++ ++module_init(pxa_clk_init); ++ ++MODULE_AUTHOR ("Intrinsyc Software Inc."); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/csb226.c +@@ -0,0 +1,180 @@ ++/* ++ * linux/arch/arm/mach-pxa/csb226.c ++ * ++ * (c) 2003 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/init.h> ++#include <linux/major.h> ++#include <linux/fs.h> ++#include <linux/interrupt.h> ++#include <linux/sched.h> ++ ++#include <asm/types.h> ++#include <asm/setup.h> ++#include <asm/memory.h> ++#include <asm/mach-types.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/irq.h> ++#include <asm/arch/irqs.h> ++#include <asm/hardware/sa1111.h> ++ ++#include "generic.h" ++ ++static unsigned long csb226_irq_en_mask; ++ ++static void csb226_mask_and_ack_irq(unsigned int irq) ++{ ++ int csb226_irq = (irq - CSB226_IRQ(0)); ++ csb226_irq_en_mask &= ~(1 << csb226_irq); ++ CSB226_IRQ_MASK_EN &= ~(1 << csb226_irq); ++ CSB226_IRQ_SET_CLR &= ~(1 << csb226_irq); ++} ++ ++static void csb226_mask_irq(unsigned int irq) ++{ ++ int csb226_irq = (irq - CSB226_IRQ(0)); ++ csb226_irq_en_mask &= ~(1 << csb226_irq); ++ CSB226_IRQ_MASK_EN &= ~(1 << csb226_irq); ++} ++ ++static void csb226_unmask_irq(unsigned int irq) ++{ ++ int csb226_irq = (irq - CSB226_IRQ(0)); ++ csb226_irq_en_mask |= (1 << csb226_irq); ++ CSB226_IRQ_MASK_EN |= (1 << csb226_irq); ++} ++ ++void csb226_irq_demux(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ unsigned long irq_status; ++ int i; ++ ++ while ((irq_status = CSB226_IRQ_SET_CLR & csb226_irq_en_mask)) { ++ for (i = 0; i < 6; i++) { ++ if(irq_status & (1<<i)) ++ do_IRQ(CSB226_IRQ(i), regs); ++ } ++ } ++} ++ ++/* FIXME: this should not be necessary on csb226 */ ++static struct irqaction csb226_irq = { ++ name: "CSB226 FPGA", ++ handler: csb226_irq_demux, ++ flags: SA_INTERRUPT ++}; ++ ++static void __init csb226_init_irq(void) ++{ ++ int irq; ++ ++ pxa_init_irq(); ++ ++ /* setup extra csb226 irqs */ ++/* RS: ??? ++ for(irq = CSB226_IRQ(0); irq <= CSB226_IRQ(5); irq++) ++ { ++ irq_desc[irq].valid = 1; ++ irq_desc[irq].probe_ok = 1; ++ irq_desc[irq].mask_ack = csb226_mask_and_ack_irq; ++ irq_desc[irq].mask = csb226_mask_irq; ++ irq_desc[irq].unmask = csb226_unmask_irq; ++ } ++ ++ set_GPIO_IRQ_edge(GPIO_CSB226_IRQ, GPIO_FALLING_EDGE); ++ setup_arm_irq(IRQ_GPIO_CSB226_IRQ, &csb226_irq); ++*/ ++} ++ ++/* FIXME: not necessary on CSB226? */ ++static int __init csb226_init(void) ++{ ++ int ret; ++ ++ return 0; ++} ++ ++__initcall(csb226_init); ++ ++static void __init ++fixup_csb226(struct machine_desc *desc, struct param_struct *params, ++ char **cmdline, struct meminfo *mi) ++{ ++ SET_BANK (0, 0xa0000000, 64*1024*1024); ++ mi->nr_banks = 1; ++#if 0 ++ setup_ramdisk (1, 0, 0, 8192); ++ setup_initrd (__phys_to_virt(0xa1000000), 4*1024*1024); ++ ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); ++#endif ++} ++ ++/* FIXME: shouldn't this be moved to arch/arm/mach-pxa/mm.c? [RS] */ ++static struct map_desc csb226_io_desc[] __initdata = { ++ /* virtual physical length domain r w c b */ ++// { 0xf4000000, 0x04000000, 0x00ffffff, DOMAIN_IO, 1, 1, 0, 0 }, /* HT4562B PS/2 controller */ ++ { 0xf8000000, 0x08000000, 1024*1024, DOMAIN_IO, 0, 1, 0, 0 }, /* CS8900 LAN controller */ ++// { 0xe0000000, 0x20000000, 0x0fffffff, DOMAIN_IO, 1, 1, 0, 0 }, /* CompactFlash */ ++#if 0 ++ { 0xf0000000, 0x08000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */ ++ { 0xf1000000, 0x0c000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 IO */ ++ { 0xf1100000, 0x0e000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 Attr */ ++ { 0xf4000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA1111 */ ++#endif ++ LAST_DESC ++}; ++ ++static void __init csb226_map_io(void) ++{ ++ pxa_map_io(); ++ iotable_init(csb226_io_desc); ++ ++ /* This enables the BTUART */ ++ CKEN |= CKEN7_BTUART; ++ set_GPIO_mode(GPIO42_BTRXD_MD); ++ set_GPIO_mode(GPIO43_BTTXD_MD); ++ set_GPIO_mode(GPIO44_BTCTS_MD); ++ set_GPIO_mode(GPIO45_BTRTS_MD); ++ ++ /* This is for the CS8900 chip select */ ++ set_GPIO_mode(GPIO78_nCS_2_MD); ++ ++ /* setup sleep mode values */ ++ PWER = 0x00000002; ++ PFER = 0x00000000; ++ PRER = 0x00000002; ++ PGSR0 = 0x00008000; ++ PGSR1 = 0x003F0202; ++ PGSR2 = 0x0001C000; ++ PCFR |= PCFR_OPDE; ++} ++ ++MACHINE_START(CSB226, "Cogent CSB226 Development Platform") ++ MAINTAINER("Robert Schwebel, Pengutronix") ++ BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000)) ++ BOOT_PARAMS(0xa0000100) ++ FIXUP(fixup_csb226) ++ MAPIO(csb226_map_io) ++ INITIRQ(csb226_init_irq) ++MACHINE_END +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/dma.c +@@ -0,0 +1,131 @@ ++/* ++ * linux/arch/arm/mach-pxa/dma.c ++ * ++ * PXA DMA registration and IRQ dispatching ++ * ++ * Author: Nicolas Pitre ++ * Created: Nov 15, 2001 ++ * Copyright: MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++ ++#include <asm/system.h> ++#include <asm/irq.h> ++#include <asm/hardware.h> ++#include <asm/dma.h> ++ ++ ++static struct dma_channel { ++ char *name; ++ void (*irq_handler)(int, void *, struct pt_regs *); ++ void *data; ++} dma_channels[16]; ++ ++ ++int pxa_request_dma (char *name, pxa_dma_prio prio, ++ void (*irq_handler)(int, void *, struct pt_regs *), ++ void *data) ++{ ++ unsigned long flags; ++ int i, found = 0; ++ ++ /* basic sanity checks */ ++ if (!name || !irq_handler) ++ return -EINVAL; ++ ++ local_irq_save(flags); ++ ++ /* try grabbing a DMA channel with the requested priority */ ++ for (i = prio; i < prio + (prio == DMA_PRIO_LOW) ? 8 : 4; i++) { ++ if (!dma_channels[i].name) { ++ found = 1; ++ break; ++ } ++ } ++ ++ if (!found) { ++ /* requested prio group is full, try hier priorities */ ++ for (i = prio-1; i >= 0; i--) { ++ if (!dma_channels[i].name) { ++ found = 1; ++ break; ++ } ++ } ++ } ++ ++ if (found) { ++ DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; ++ dma_channels[i].name = name; ++ dma_channels[i].irq_handler = irq_handler; ++ dma_channels[i].data = data; ++ } else { ++ printk (KERN_WARNING "No more available DMA channels for %s\n", name); ++ i = -ENODEV; ++ } ++ ++ local_irq_restore(flags); ++ return i; ++} ++ ++void pxa_free_dma (int dma_ch) ++{ ++ unsigned long flags; ++ ++ if (!dma_channels[dma_ch].name) { ++ printk (KERN_CRIT __FUNCTION__ ++ ": trying to free channel %d which is already freed\n", ++ dma_ch); ++ return; ++ } ++ ++ local_irq_save(flags); ++ DCSR(dma_ch) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; ++ dma_channels[dma_ch].name = NULL; ++ local_irq_restore(flags); ++} ++ ++static void dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ int i, dint = DINT; ++ ++ for (i = 0; i < 16; i++) { ++ if (dint & (1 << i)) { ++ struct dma_channel *channel = &dma_channels[i]; ++ if (channel->name && channel->irq_handler) { ++ channel->irq_handler(i, channel->data, regs); ++ } else { ++ /* ++ * IRQ for an unregistered DMA channel: ++ * let's clear the interrupts and disable it. ++ */ ++ printk (KERN_WARNING "spurious IRQ for DMA channel %d\n", i); ++ DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR; ++ } ++ } ++ } ++} ++ ++static int __init pxa_dma_init (void) ++{ ++ int ret; ++ ++ ret = request_irq (IRQ_DMA, dma_irq_handler, 0, "DMA", NULL); ++ if (ret) ++ printk (KERN_CRIT "Wow! Can't register IRQ for DMA\n"); ++ return ret; ++} ++ ++__initcall(pxa_dma_init); ++ ++EXPORT_SYMBOL(pxa_request_dma); ++EXPORT_SYMBOL(pxa_free_dma); ++ +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/generic.c +@@ -0,0 +1,142 @@ ++/* ++ * linux/arch/arm/mach-pxa/generic.c ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista Software Inc. ++ * ++ * Code common to all PXA machines. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Since this file should be linked before any other machine specific file, ++ * the __initcall() here will be executed first. This serves as default ++ * initialization stuff for PXA machines which can be overriden later if ++ * need be. ++ */ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/pm.h> ++ ++#include <asm/hardware.h> ++#include <asm/system.h> ++#include <asm/pgtable.h> ++#include <asm/mach/map.h> ++ ++#include "generic.h" ++ ++/* ++ * Various clock factors driven by the CCCR register. ++ */ ++ ++/* Crystal Frequency to Memory Frequency Multiplier (L) */ ++static unsigned char L_clk_mult[32] = { 0, 27, 32, 36, 40, 45, 0, }; ++ ++/* Memory Frequency to Run Mode Frequency Multiplier (M) */ ++static unsigned char M_clk_mult[4] = { 0, 1, 2, 4 }; ++ ++/* Run Mode Frequency to Turbo Mode Frequency Multiplier (N) */ ++/* Note: we store the value N * 2 here. */ ++static unsigned char N2_clk_mult[8] = { 0, 0, 2, 3, 4, 0, 6, 0 }; ++ ++/* Crystal clock */ ++#define BASE_CLK 3686400 ++ ++/* ++ * Get the clock frequency as reflected by CCCR and the turbo flag. ++ * We assume these values have been applied via a fcs. ++ * If info is not 0 we also display the current settings. ++ */ ++unsigned int get_clk_frequency_khz( int info) ++{ ++ unsigned long cccr, turbo; ++ unsigned int l, L, m, M, n2, N; ++ ++ cccr = CCCR; ++ asm( "mrc\tp14, 0, %0, c6, c0, 0" : "=r" (turbo) ); ++ ++ l = L_clk_mult[(cccr >> 0) & 0x1f]; ++ m = M_clk_mult[(cccr >> 5) & 0x03]; ++ n2 = N2_clk_mult[(cccr >> 7) & 0x07]; ++ ++ L = l * BASE_CLK; ++ M = m * L; ++ N = n2 * M / 2; ++ ++ if( info) ++ { ++ L += 5000; ++ printk( KERN_INFO "Memory clock: %d.%02dMHz (*%d)\n", ++ L / 1000000, (L % 1000000) / 10000, l ); ++ M += 5000; ++ printk( KERN_INFO "Run Mode clock: %d.%02dMHz (*%d)\n", ++ M / 1000000, (M % 1000000) / 10000, m ); ++ N += 5000; ++ printk( KERN_INFO "Turbo Mode clock: %d.%02dMHz (*%d.%d, %sactive)\n", ++ N / 1000000, (N % 1000000) / 10000, n2 / 2, (n2 % 2) * 5, ++ (turbo & 1) ? "" : "in" ); ++ } ++ ++ return (turbo & 1) ? (N/1000) : (M/1000); ++} ++ ++EXPORT_SYMBOL(get_clk_frequency_khz); ++ ++/* ++ * Return the current lclk requency in units of 10kHz ++ */ ++unsigned int get_lclk_frequency_10khz(void) ++{ ++ return L_clk_mult[(CCCR >> 0) & 0x1f] * BASE_CLK / 10000; ++} ++ ++EXPORT_SYMBOL(get_lclk_frequency_10khz); ++ ++/* ++ * Handy function to set GPIO alternate functions ++ */ ++ ++void set_GPIO_mode(int gpio_mode) ++{ ++ long flags; ++ int gpio = gpio_mode & GPIO_MD_MASK_NR; ++ int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8; ++ int gafr; ++ ++ local_irq_save(flags); ++ if (gpio_mode & GPIO_MD_MASK_DIR) ++ GPDR(gpio) |= GPIO_bit(gpio); ++ else ++ GPDR(gpio) &= ~GPIO_bit(gpio); ++ gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2)); ++ GAFR(gpio) = gafr | (fn << (((gpio) & 0xf)*2)); ++ local_irq_restore(flags); ++} ++ ++EXPORT_SYMBOL(set_GPIO_mode); ++ ++/* ++ * Note that 0xfffe0000-0xffffffff is reserved for the vector table and ++ * cache flush area. ++ */ ++static struct map_desc standard_io_desc[] __initdata = { ++ /* virtual physical length domain r w c b */ ++ { 0xf6000000, 0x20000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 IO */ ++ { 0xf7000000, 0x30000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 IO */ ++ { 0xf8000000, 0x40000000, 0x01800000, DOMAIN_IO, 0, 1, 0, 0 }, /* Devs */ ++ { 0xfa000000, 0x44000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LCD */ ++ { 0xfc000000, 0x48000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Mem Ctl */ ++ { 0xff000000, 0x00000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* UNCACHED_PHYS_0 */ ++ LAST_DESC ++}; ++ ++void __init pxa_map_io(void) ++{ ++ iotable_init(standard_io_desc); ++ get_clk_frequency_khz( 1); ++} +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/generic.h +@@ -0,0 +1,19 @@ ++/* ++ * linux/arch/arm/mach-pxa/generic.h ++ * ++ * Author: Nicolas Pitre ++ * Copyright: MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++extern void __init pxa_map_io(void); ++extern void __init pxa_init_irq(void); ++ ++#define SET_BANK(__nr,__start,__size) \ ++ mi->bank[__nr].start = (__start), \ ++ mi->bank[__nr].size = (__size), \ ++ mi->bank[__nr].node = (((unsigned)(__start) - PHYS_OFFSET) >> 27) ++ +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/idp.c +@@ -0,0 +1,142 @@ ++/* ++ * linux/arch/arm/mach-pxa/idp.c ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Copyright (c) 2001 Cliff Brake, Accelent Systems Inc. ++ * ++ * 2001-09-13: Cliff Brake <cbrake@accelent.com> ++ * Initial code ++ */ ++#include <linux/init.h> ++#include <linux/major.h> ++#include <linux/fs.h> ++#include <linux/interrupt.h> ++#include <linux/sched.h> ++ ++#include <asm/types.h> ++#include <asm/setup.h> ++#include <asm/memory.h> ++#include <asm/mach-types.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/irq.h> ++ ++#include "generic.h" ++ ++#define PXA_IDP_REV02 ++ ++#ifndef PXA_IDP_REV02 ++/* shadow registers for write only registers */ ++unsigned int idp_cpld_led_control_shadow = 0x1; ++unsigned int idp_cpld_periph_pwr_shadow = 0xd; ++unsigned int ipd_cpld_cir_shadow = 0; ++unsigned int idp_cpld_kb_col_high_shadow = 0; ++unsigned int idp_cpld_kb_col_low_shadow = 0; ++unsigned int idp_cpld_pccard_en_shadow = 0xC3; ++unsigned int idp_cpld_gpioh_dir_shadow = 0; ++unsigned int idp_cpld_gpioh_value_shadow = 0; ++unsigned int idp_cpld_gpiol_dir_shadow = 0; ++unsigned int idp_cpld_gpiol_value_shadow = 0; ++ ++/* ++ * enable all LCD signals -- they should still be on ++ * write protect flash ++ * enable all serial port transceivers ++ */ ++ ++unsigned int idp_control_port_shadow = ((0x7 << 21) | /* LCD power */ ++ (0x1 << 19) | /* disable flash write enable */ ++ (0x7 << 9)); /* enable serial port transeivers */ ++ ++#endif ++ ++static int __init idp_init(void) ++{ ++ printk("idp_init()\n"); ++ return 0; ++} ++ ++__initcall(idp_init); ++ ++static void __init idp_init_irq(void) ++{ ++ pxa_init_irq(); ++} ++ ++static void __init ++fixup_idp(struct machine_desc *desc, struct param_struct *params, ++ char **cmdline, struct meminfo *mi) ++{ ++#ifdef PXA_IDP_REV02 ++ SET_BANK (0, 0xa0000000, 64*1024*1024); ++#else ++ SET_BANK (0, 0xa0000000, 32*1024*1024); ++#endif ++ mi->nr_banks = 1; ++#if 0 ++ setup_ramdisk (1, 0, 0, 8192); ++ setup_initrd (__phys_to_virt(0xa1000000), 4*1024*1024); ++ ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); ++#endif ++} ++ ++static struct map_desc idp_io_desc[] __initdata = { ++ /* virtual physical length domain r w c b */ ++ ++ ++#ifndef PXA_IDP_REV02 ++ { IDP_CTRL_PORT_BASE, ++ IDP_CTRL_PORT_PHYS, ++ IDP_CTRL_PORT_SIZE, ++ DOMAIN_IO, ++ 0, 1, 0, 0 }, ++#endif ++ ++ { IDP_IDE_BASE, ++ IDP_IDE_PHYS, ++ IDP_IDE_SIZE, ++ DOMAIN_IO, ++ 0, 1, 0, 0 }, ++ { IDP_ETH_BASE, ++ IDP_ETH_PHYS, ++ IDP_ETH_SIZE, ++ DOMAIN_IO, ++ 0, 1, 0, 0 }, ++ { IDP_COREVOLT_BASE, ++ IDP_COREVOLT_PHYS, ++ IDP_COREVOLT_SIZE, ++ DOMAIN_IO, ++ 0, 1, 0, 0 }, ++ { IDP_CPLD_BASE, ++ IDP_CPLD_PHYS, ++ IDP_CPLD_SIZE, ++ DOMAIN_IO, ++ 0, 1, 0, 0 }, ++ ++ LAST_DESC ++}; ++ ++static void __init idp_map_io(void) ++{ ++ pxa_map_io(); ++ iotable_init(idp_io_desc); ++ ++ set_GPIO_IRQ_edge(IRQ_TO_GPIO(TOUCH_PANEL_IRQ), TOUCH_PANEL_IRQ_EDGE); ++ set_GPIO_IRQ_edge(IRQ_TO_GPIO(SMC_IRQ), GPIO_RISING_EDGE); ++} ++ ++MACHINE_START(PXA_IDP, "Accelent Xscale IDP") ++ MAINTAINER("Accelent Systems Inc.") ++ BOOT_MEM(0xa0000000, 0x40000000, 0xfc000000) ++ FIXUP(fixup_idp) ++ MAPIO(idp_map_io) ++ INITIRQ(idp_init_irq) ++MACHINE_END +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/innokom.c +@@ -0,0 +1,129 @@ ++/* ++ * linux/arch/arm/mach-pxa/innokom.c ++ * ++ * (c) 2003 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/init.h> ++#include <linux/major.h> ++#include <linux/fs.h> ++#include <linux/interrupt.h> ++#include <linux/sched.h> ++ ++#include <asm/types.h> ++#include <asm/setup.h> ++#include <asm/memory.h> ++#include <asm/mach-types.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/irq.h> ++#include <asm/arch/irqs.h> ++#include <asm/hardware/sa1111.h> ++ ++#include "generic.h" ++ ++ ++static void __init innokom_init_irq(void) ++{ ++ pxa_init_irq(); ++} ++ ++ ++void sw_update_handler( int irq, void* dev_id,struct pt_regs* regs) ++{ ++} ++ ++ ++void reset_handler( int irq, void* dev_id,struct pt_regs* regs) ++{ ++} ++ ++ ++static int __init innokom_init(void) ++{ ++ int sw_irq = GPIO_2_80_TO_IRQ(11); /* software update button */ ++ int reset_irq = GPIO_2_80_TO_IRQ(3); /* reset button */ ++ ++ set_GPIO_IRQ_edge(11,GPIO_FALLING_EDGE); ++ if (request_irq(sw_irq,sw_update_handler,SA_INTERRUPT,"software update button",NULL)) ++ printk(KERN_INFO "innokom: can't get assigned irq %i\n",sw_irq); ++ ++ set_GPIO_IRQ_edge(3,GPIO_FALLING_EDGE); ++ if (request_irq(reset_irq,reset_handler,SA_INTERRUPT,"reset button",NULL)) ++ printk(KERN_INFO "innokom: can't get assigned irq %i\n",reset_irq); ++ ++ return 0; ++} ++ ++ ++__initcall(innokom_init); ++ ++ ++static void __init ++fixup_innokom(struct machine_desc *desc, struct param_struct *params, ++ char **cmdline, struct meminfo *mi) ++{ ++ /* we probably want to get this information from the bootloader later */ ++ SET_BANK (0, 0xa0000000, 64*1024*1024); ++ mi->nr_banks = 1; ++} ++ ++ ++/* memory mapping */ ++static struct map_desc innokom_io_desc[] __initdata = { ++/* virtual physical length domain r w c b */ ++ { INNOKOM_ETH_BASE, INNOKOM_ETH_PHYS, INNOKOM_ETH_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, /* ETH SMSC 91111 */ ++ LAST_DESC ++}; ++ ++static void __init innokom_map_io(void) ++{ ++ pxa_map_io(); ++ iotable_init(innokom_io_desc); ++ ++ /* Enable the BTUART */ ++ CKEN |= CKEN7_BTUART; ++ set_GPIO_mode(GPIO42_BTRXD_MD); ++ set_GPIO_mode(GPIO43_BTTXD_MD); ++ set_GPIO_mode(GPIO44_BTCTS_MD); ++ set_GPIO_mode(GPIO45_BTRTS_MD); ++ ++ set_GPIO_mode(GPIO33_nCS_5_MD); /* SMSC network chip */ ++ ++ /* setup sleep mode values */ ++ PWER = 0x00000002; ++ PFER = 0x00000000; ++ PRER = 0x00000002; ++ PGSR0 = 0x00008000; ++ PGSR1 = 0x003F0202; ++ PGSR2 = 0x0001C000; ++ PCFR |= PCFR_OPDE; ++} ++ ++MACHINE_START(INNOKOM, "Auerswald Innokom") ++ MAINTAINER("Robert Schwebel, Pengutronix") ++ BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000)) ++ BOOT_PARAMS(0xa0000100) ++ FIXUP(fixup_innokom) ++ MAPIO(innokom_map_io) ++ INITIRQ(innokom_init_irq) ++MACHINE_END +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/irq.c +@@ -0,0 +1,282 @@ ++/* ++ * linux/arch/arm/mach-pxa/irq.c ++ * ++ * Generic PXA IRQ handling, GPIO IRQ demultiplexing, etc. ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/ptrace.h> ++ ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/mach/irq.h> ++#include <asm/arch/irq.h> ++ ++#include "generic.h" ++ ++ ++/* ++ * PXA GPIO edge detection for IRQs: ++ * IRQs are generated on Falling-Edge, Rising-Edge, or both. ++ * This must be called *before* the appropriate IRQ is registered. ++ * Use this instead of directly setting GRER/GFER. ++ */ ++ ++static int GPIO_IRQ_rising_edge[3]; ++static int GPIO_IRQ_falling_edge[3]; ++ ++void set_GPIO_IRQ_edge (int gpio_nr, int edge) ++{ ++ long flags; ++ local_irq_save(flags); ++ set_GPIO_mode(gpio_nr | GPIO_IN); ++ if (edge & GPIO_FALLING_EDGE) ++ set_bit (gpio_nr, GPIO_IRQ_falling_edge); ++ else ++ clear_bit (gpio_nr, GPIO_IRQ_falling_edge); ++ if (edge & GPIO_RISING_EDGE) ++ set_bit (gpio_nr, GPIO_IRQ_rising_edge); ++ else ++ clear_bit (gpio_nr, GPIO_IRQ_rising_edge); ++ irq_desc[IRQ_GPIO(gpio_nr)].valid = 1; ++ local_irq_restore(flags); ++} ++ ++EXPORT_SYMBOL(set_GPIO_IRQ_edge); ++ ++ ++/* ++ * We don't need to ACK IRQs on the PXA unless they're GPIOs ++ * this is for IRQs known as PXA_IRQ([10...31]). ++ */ ++ ++static void pxa_mask_irq(unsigned int irq) ++{ ++ ICMR &= ~(1 << (irq + PXA_IRQ_SKIP)); ++} ++ ++static void pxa_unmask_irq(unsigned int irq) ++{ ++ ICMR |= (1 << (irq + PXA_IRQ_SKIP)); ++} ++ ++/* ++ * GPIO IRQs must be acknoledged. This is for GPIO 0 and 1. ++ */ ++ ++static void pxa_mask_and_ack_GPIO_0_1_irq(unsigned int irq) ++{ ++ ICMR &= ~(1 << (irq + PXA_IRQ_SKIP)); ++ GEDR0 = (1 << (irq - IRQ_GPIO0)); ++} ++ ++static void pxa_mask_GPIO_0_1_irq(unsigned int irq) ++{ ++ ICMR &= ~(1 << (irq + PXA_IRQ_SKIP)); ++} ++ ++static void pxa_unmask_GPIO_0_1_irq(unsigned int irq) ++{ ++ int gpio = irq - IRQ_GPIO0; ++ GRER0 = (GRER0 & ~(1 << gpio))|(GPIO_IRQ_rising_edge[0] & (1 << gpio)); ++ GFER0 = (GFER0 & ~(1 << gpio))|(GPIO_IRQ_falling_edge[0] & (1 << gpio)); ++ ICMR |= (1 << (irq + PXA_IRQ_SKIP)); ++} ++ ++/* ++ * Demux handler for GPIO 2-80 edge detect interrupts ++ */ ++ ++static int GPIO_2_80_enabled[3]; /* enabled i.e. unmasked GPIO IRQs */ ++static int GPIO_2_80_spurious[3]; /* GPIOs that triggered when masked */ ++ ++static void pxa_GPIO_2_80_demux(int irq, void *dev_id, ++ struct pt_regs *regs) ++{ ++ int i, gedr, spurious; ++ ++ while ((gedr = (GEDR0 & ~3))) { ++ /* ++ * We don't want to clear GRER/GFER when the corresponding ++ * IRQ is masked because we could miss a level transition ++ * i.e. an IRQ which need servicing as soon as it is ++ * unmasked. However, such situation should happen only ++ * during the loop below. Thus all IRQs which aren't ++ * enabled at this point are considered spurious. Those ++ * are cleared but only de-activated if they happen twice. ++ */ ++ spurious = gedr & ~GPIO_2_80_enabled[0]; ++ if (spurious) { ++ GEDR0 = spurious; ++ GRER0 &= ~(spurious & GPIO_2_80_spurious[0]); ++ GFER0 &= ~(spurious & GPIO_2_80_spurious[0]); ++ GPIO_2_80_spurious[0] |= spurious; ++ gedr ^= spurious; ++ if (!gedr) continue; ++ } ++ ++ for (i = 2; i < 32; ++i) { ++ if (gedr & (1<<i)) { ++ do_IRQ (IRQ_GPIO(2) + i - 2, regs); ++ } ++ } ++ } ++ while ((gedr = GEDR1)) { ++ spurious = gedr & ~GPIO_2_80_enabled[1]; ++ if (spurious) { ++ GEDR1 = spurious; ++ GRER1 &= ~(spurious & GPIO_2_80_spurious[1]); ++ GFER1 &= ~(spurious & GPIO_2_80_spurious[1]); ++ GPIO_2_80_spurious[1] |= spurious; ++ gedr ^= spurious; ++ if (!gedr) continue; ++ } ++ ++ for (i = 0; i < 32; ++i) { ++ if (gedr & (1<<i)) { ++ do_IRQ (IRQ_GPIO(32) + i, regs); ++ } ++ } ++ } ++ while ((gedr = (GEDR2 & 0x0001ffff))) { ++ spurious = gedr & ~GPIO_2_80_enabled[2]; ++ if (spurious) { ++ GEDR2 = spurious; ++ GRER2 &= ~(spurious & GPIO_2_80_spurious[2]); ++ GFER2 &= ~(spurious & GPIO_2_80_spurious[2]); ++ GPIO_2_80_spurious[2] |= spurious; ++ gedr ^= spurious; ++ if (!gedr) continue; ++ } ++ ++ for (i = 0; i < 17; ++i) { ++ if (gedr & (1<<i)) { ++ do_IRQ (IRQ_GPIO(64) + i, regs); ++ } ++ } ++ } ++} ++ ++static struct irqaction GPIO_2_80_irqaction = { ++ name: "GPIO 2-80", ++ handler: pxa_GPIO_2_80_demux, ++ flags: SA_INTERRUPT ++}; ++ ++#define GRER_x(i) (*(&GRER0 + (i))) ++#define GFER_x(i) (*(&GFER0 + (i))) ++#define GEDR_x(i) (*(&GEDR0 + (i))) ++#define GPLR_x(i) (*(&GPLR0 + (i))) ++ ++static void pxa_mask_and_ack_GPIO_2_80_irq(unsigned int irq) ++{ ++ int gpio_nr = IRQ_TO_GPIO_2_80(irq); ++ int mask = 1 << (gpio_nr & 0x1f); ++ int index = gpio_nr >> 5; ++ GPIO_2_80_spurious[index] &= ~mask; ++ GPIO_2_80_enabled[index] &= ~mask; ++ GEDR_x(index) = mask; ++} ++ ++static void pxa_mask_GPIO_2_80_irq(unsigned int irq) ++{ ++ int gpio_nr = IRQ_TO_GPIO_2_80(irq); ++ int mask = 1 << (gpio_nr & 0x1f); ++ int index = gpio_nr >> 5; ++ GPIO_2_80_spurious[index] &= ~mask; ++ GPIO_2_80_enabled[index] &= ~mask; ++} ++ ++static void pxa_unmask_GPIO_2_80_irq(unsigned int irq) ++{ ++ int gpio_nr = IRQ_TO_GPIO_2_80(irq); ++ int mask = 1 << (gpio_nr & 0x1f); ++ int index = gpio_nr >> 5; ++ if (GPIO_2_80_spurious[index] & mask) { ++ /* ++ * We don't want to miss an interrupt that would have occurred ++ * while it was masked. Simulate it if it is the case. ++ */ ++ int state = GPLR_x(index); ++ if (((state & GPIO_IRQ_rising_edge[index]) | ++ (~state & GPIO_IRQ_falling_edge[index])) & mask) ++ { ++ /* just in case it gets referenced: */ ++ struct pt_regs dummy; ++ ++ memzero(&dummy, sizeof(dummy)); ++ do_IRQ(irq, &dummy); ++ ++ /* we are being called recursively from do_IRQ() */ ++ return; ++ } ++ } ++ GPIO_2_80_enabled[index] |= mask; ++ GRER_x(index) = ++ (GRER_x(index) & ~mask) | (GPIO_IRQ_rising_edge[index] & mask); ++ GFER_x(index) = ++ (GFER_x(index) & ~mask) | (GPIO_IRQ_falling_edge[index] & mask); ++} ++ ++ ++void __init pxa_init_irq(void) ++{ ++ int irq; ++ ++ /* disable all IRQs */ ++ ICMR = 0; ++ ++ /* all IRQs are IRQ, not FIQ */ ++ ICLR = 0; ++ ++ /* clear all GPIO edge detects */ ++ GFER0 = GFER1 = GFER2 = 0; ++ GRER0 = GRER1 = GRER2 = 0; ++ GEDR0 = GEDR0; ++ GEDR1 = GEDR1; ++ GEDR2 = GEDR2; ++ ++ /* only unmasked interrupts kick us out of idle */ ++ ICCR = 1; ++ ++ for (irq = PXA_IRQ(PXA_IRQ_SKIP); irq <= PXA_IRQ(31); irq++) { ++ irq_desc[irq].valid = 1; ++ irq_desc[irq].probe_ok = 0; ++ irq_desc[irq].mask_ack = pxa_mask_irq; ++ irq_desc[irq].mask = pxa_mask_irq; ++ irq_desc[irq].unmask = pxa_unmask_irq; ++ } ++ ++ /* ++ * Note: GPIO IRQs are initially invalid until set_GPIO_IRQ_edge() ++ * is called at least once. ++ */ ++ ++ for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) { ++ irq_desc[irq].valid = 0; ++ irq_desc[irq].probe_ok = 1; ++ irq_desc[irq].mask_ack = pxa_mask_and_ack_GPIO_0_1_irq; ++ irq_desc[irq].mask = pxa_mask_GPIO_0_1_irq; ++ irq_desc[irq].unmask = pxa_unmask_GPIO_0_1_irq; ++ } ++ ++ for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(80); irq++) { ++ irq_desc[irq].valid = 0; ++ irq_desc[irq].probe_ok = 1; ++ irq_desc[irq].mask_ack = pxa_mask_and_ack_GPIO_2_80_irq; ++ irq_desc[irq].mask = pxa_mask_GPIO_2_80_irq; ++ irq_desc[irq].unmask = pxa_unmask_GPIO_2_80_irq; ++ } ++ setup_arm_irq( IRQ_GPIO_2_80, &GPIO_2_80_irqaction ); ++} +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/leds-cerf.c +@@ -0,0 +1,135 @@ ++/* ++ * linux/arch/arm/mach-pxa/leds-cerf.c ++ * ++ * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu> ++ * ++ * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com> ++ * ++ * Original (leds-footbridge.c) by Russell King ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++ ++#include <linux/config.h> ++#include <linux/init.h> ++ ++#include <asm/hardware.h> ++#include <asm/leds.h> ++#include <asm/system.h> ++ ++#include "leds.h" ++ ++ ++#define LED_STATE_ENABLED 1 ++#define LED_STATE_CLAIMED 2 ++ ++static unsigned int led_state; ++static unsigned int hw_led_state; ++ ++void pxa_cerf_leds_event(led_event_t evt) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ switch (evt) { ++ case led_start: ++ hw_led_state = CERF_HEARTBEAT_LED; ++ led_state = LED_STATE_ENABLED; ++ break; ++ ++ case led_stop: ++ led_state &= ~LED_STATE_ENABLED; ++ break; ++ ++ case led_claim: ++ led_state |= LED_STATE_CLAIMED; ++ hw_led_state = CERF_HEARTBEAT_LED; ++ break; ++ ++ case led_release: ++ led_state &= ~LED_STATE_CLAIMED; ++ hw_led_state = CERF_HEARTBEAT_LED; ++ break; ++ ++#ifdef CONFIG_LEDS_TIMER ++ case led_timer: ++ if (!(led_state & LED_STATE_CLAIMED)) ++ hw_led_state ^= CERF_HEARTBEAT_LED; ++ break; ++#endif ++ ++#ifdef CONFIG_LEDS_CPU ++ case led_idle_start: ++ if (!(led_state & LED_STATE_CLAIMED)) ++ hw_led_state |= CERF_SYS_BUSY_LED; ++ break; ++ ++ case led_idle_end: ++ if (!(led_state & LED_STATE_CLAIMED)) ++ hw_led_state &= ~CERF_SYS_BUSY_LED; ++ break; ++#endif ++ ++ case led_halted: ++ break; ++ ++ case led_green_on: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state &= ~CERF_HEARTBEAT_LED; ++ break; ++ ++ case led_green_off: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state |= CERF_HEARTBEAT_LED; ++ break; ++ ++ case led_amber_on: ++ break; ++ ++ case led_amber_off: ++ break; ++ ++#ifndef CONFIG_PXA_CERF_PDA ++ case led_red_on: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state &= ~CERF_SYS_BUSY_LED; ++ break; ++ ++ case led_red_off: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state |= CERF_SYS_BUSY_LED; ++ break; ++#endif ++ default: ++ break; ++ } ++ ++ if (led_state & LED_STATE_ENABLED) ++ { ++ switch (hw_led_state) { ++ case 0: // all on ++ CERF_HEARTBEAT_LED_ON; ++ CERF_SYS_BUSY_LED_ON; ++ break; ++ case 1: // turn off heartbeat, status on: ++ CERF_HEARTBEAT_LED_OFF; ++ CERF_SYS_BUSY_LED_ON; ++ break; ++ case 2: // status off, heartbeat on: ++ CERF_HEARTBEAT_LED_ON; ++ CERF_SYS_BUSY_LED_OFF; ++ break; ++ case 3: // turn them both off... ++ CERF_HEARTBEAT_LED_OFF; ++ CERF_SYS_BUSY_LED_OFF; ++ break; ++ default: ++ break; ++ } ++ } ++ local_irq_restore(flags); ++} +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/leds-idp.c +@@ -0,0 +1,112 @@ ++/* ++ * linux/arch/arm/mach-pxa/leds-idp.c ++ * ++ * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu> ++ * ++ * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com> ++ * ++ * Original (leds-footbridge.c) by Russell King ++ * ++ * Macros for actual LED manipulation should be in machine specific ++ * files in this 'mach' directory. ++ */ ++ ++ ++#include <linux/config.h> ++#include <linux/init.h> ++ ++#include <asm/hardware.h> ++#include <asm/leds.h> ++#include <asm/system.h> ++ ++#include "leds.h" ++ ++#define LED_STATE_ENABLED 1 ++#define LED_STATE_CLAIMED 2 ++ ++static unsigned int led_state; ++static unsigned int hw_led_state; ++ ++void idp_leds_event(led_event_t evt) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ switch (evt) { ++ case led_start: ++ hw_led_state = IDP_HB_LED | IDP_BUSY_LED; ++ led_state = LED_STATE_ENABLED; ++ break; ++ ++ case led_stop: ++ led_state &= ~LED_STATE_ENABLED; ++ break; ++ ++ case led_claim: ++ led_state |= LED_STATE_CLAIMED; ++ hw_led_state = IDP_HB_LED | IDP_BUSY_LED; ++ break; ++ ++ case led_release: ++ led_state &= ~LED_STATE_CLAIMED; ++ hw_led_state = IDP_HB_LED | IDP_BUSY_LED; ++ break; ++ ++#ifdef CONFIG_LEDS_TIMER ++ case led_timer: ++ if (!(led_state & LED_STATE_CLAIMED)) ++ hw_led_state ^= IDP_HB_LED; ++ break; ++#endif ++ ++#ifdef CONFIG_LEDS_CPU ++ case led_idle_start: ++ if (!(led_state & LED_STATE_CLAIMED)) ++ hw_led_state |= IDP_BUSY_LED; ++ break; ++ ++ case led_idle_end: ++ if (!(led_state & LED_STATE_CLAIMED)) ++ hw_led_state &= ~IDP_BUSY_LED; ++ break; ++#endif ++ ++ case led_halted: ++ break; ++ ++ case led_green_on: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state &= ~IDP_HB_LED; ++ break; ++ ++ case led_green_off: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state |= IDP_HB_LED; ++ break; ++ ++ case led_amber_on: ++ break; ++ ++ case led_amber_off: ++ break; ++ ++ case led_red_on: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state &= ~IDP_BUSY_LED; ++ break; ++ ++ case led_red_off: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state |= IDP_BUSY_LED; ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (led_state & LED_STATE_ENABLED) ++ IDP_WRITE_LEDS(hw_led_state); ++ ++ local_irq_restore(flags); ++} +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/leds-lubbock.c +@@ -0,0 +1,134 @@ ++/* ++ * linux/arch/arm/mach-pxa/leds-lubbock.c ++ * ++ * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu> ++ * ++ * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com> ++ * ++ * Original (leds-footbridge.c) by Russell King ++ * ++ * See leds.h for bit definitions. The first version defines D28 on the ++ * Lubbock dev board as the heartbeat, and D27 as the Sys_busy led. ++ * There's plenty more if you're interested in adding them :) ++ */ ++ ++ ++#include <linux/config.h> ++#include <linux/init.h> ++ ++#include <asm/hardware.h> ++#include <asm/leds.h> ++#include <asm/system.h> ++ ++#include "leds.h" ++ ++ ++#define LED_STATE_ENABLED 1 ++#define LED_STATE_CLAIMED 2 ++ ++static unsigned int led_state; ++static unsigned int hw_led_state; ++ ++void lubbock_leds_event(led_event_t evt) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ switch (evt) { ++ case led_start: ++ hw_led_state = HEARTBEAT_LED | SYS_BUSY_LED; ++ led_state = LED_STATE_ENABLED; ++ break; ++ ++ case led_stop: ++ led_state &= ~LED_STATE_ENABLED; ++ break; ++ ++ case led_claim: ++ led_state |= LED_STATE_CLAIMED; ++ hw_led_state = HEARTBEAT_LED | SYS_BUSY_LED; ++ break; ++ ++ case led_release: ++ led_state &= ~LED_STATE_CLAIMED; ++ hw_led_state = HEARTBEAT_LED | SYS_BUSY_LED; ++ break; ++ ++#ifdef CONFIG_LEDS_TIMER ++ case led_timer: ++ if (!(led_state & LED_STATE_CLAIMED)) ++ hw_led_state ^= HEARTBEAT_LED; ++ break; ++#endif ++ ++#ifdef CONFIG_LEDS_CPU ++ case led_idle_start: ++ if (!(led_state & LED_STATE_CLAIMED)) ++ hw_led_state |= SYS_BUSY_LED; ++ break; ++ ++ case led_idle_end: ++ if (!(led_state & LED_STATE_CLAIMED)) ++ hw_led_state &= ~SYS_BUSY_LED; ++ break; ++#endif ++ ++ case led_halted: ++ break; ++ ++ case led_green_on: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state &= ~HEARTBEAT_LED; ++ break; ++ ++ case led_green_off: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state |= HEARTBEAT_LED; ++ break; ++ ++ case led_amber_on: ++ break; ++ ++ case led_amber_off: ++ break; ++ ++ case led_red_on: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state &= ~SYS_BUSY_LED; ++ break; ++ ++ case led_red_off: ++ if (led_state & LED_STATE_CLAIMED) ++ hw_led_state |= SYS_BUSY_LED; ++ break; ++ ++ default: ++ break; ++ } ++ ++ if (led_state & LED_STATE_ENABLED) ++ { ++ switch (hw_led_state) { ++ case 0: // all on ++ HEARTBEAT_LED_ON; ++ SYS_BUSY_LED_ON; ++ break; ++ case 1: // turn off heartbeat, status on: ++ HEARTBEAT_LED_OFF; ++ SYS_BUSY_LED_ON; ++ break; ++ case 2: // status off, heartbeat on: ++ HEARTBEAT_LED_ON; ++ SYS_BUSY_LED_OFF; ++ break; ++ case 3: // turn them both off... ++ HEARTBEAT_LED_OFF; ++ SYS_BUSY_LED_OFF; ++ break; ++ default: ++ break; ++ } ++ } ++ local_irq_restore(flags); ++} +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/leds.c +@@ -0,0 +1,32 @@ ++/* ++ * linux/arch/arm/mach-pxa/leds.c ++ * ++ * xscale LEDs dispatcher ++ * ++ * Copyright (C) 2001 Nicolas Pitre ++ * ++ * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc. ++ */ ++#include <linux/config.h> ++#include <linux/init.h> ++ ++#include <asm/leds.h> ++#include <asm/mach-types.h> ++ ++#include "leds.h" ++ ++static int __init ++pxa_leds_init(void) ++{ ++ if (machine_is_lubbock()) ++ leds_event = lubbock_leds_event; ++ if (machine_is_pxa_idp()) ++ leds_event = idp_leds_event; ++ if (machine_is_pxa_cerf()) ++ leds_event = pxa_cerf_leds_event; ++ ++ leds_event(led_start); ++ return 0; ++} ++ ++__initcall(pxa_leds_init); +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/leds.h +@@ -0,0 +1,12 @@ ++/* ++ * include/asm-arm/arch-pxa/leds.h ++ * ++ * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc. ++ * ++ * blinky lights for various PXA-based systems: ++ * ++ */ ++ ++extern void lubbock_leds_event(led_event_t evt); ++extern void idp_leds_event(led_event_t evt); ++extern void pxa_cerf_leds_event(led_event_t evt); +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/lubbock.c +@@ -0,0 +1,157 @@ ++/* ++ * linux/arch/arm/mach-pxa/lubbock.c ++ * ++ * Support for the Intel DBPXA250 Development Platform. ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/init.h> ++#include <linux/major.h> ++#include <linux/fs.h> ++#include <linux/interrupt.h> ++#include <linux/sched.h> ++#include <linux/bitops.h> ++ ++#include <asm/types.h> ++#include <asm/setup.h> ++#include <asm/memory.h> ++#include <asm/mach-types.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/irq.h> ++#include <asm/hardware/sa1111.h> ++ ++#include "generic.h" ++ ++#ifdef CONFIG_SA1111 ++ #include "sa1111.h" ++#endif ++ ++ ++static unsigned long lubbock_irq_enabled; ++ ++static void lubbock_mask_irq(unsigned int irq) ++{ ++ int lubbock_irq = (irq - LUBBOCK_IRQ(0)); ++ LUB_IRQ_MASK_EN = (lubbock_irq_enabled &= ~(1 << lubbock_irq)); ++} ++ ++static void lubbock_unmask_irq(unsigned int irq) ++{ ++ int lubbock_irq = (irq - LUBBOCK_IRQ(0)); ++ /* the irq can be acknowledged only if deasserted, so it's done here */ ++ LUB_IRQ_SET_CLR &= ~(1 << lubbock_irq); ++ LUB_IRQ_MASK_EN = (lubbock_irq_enabled |= (1 << lubbock_irq)); ++} ++ ++void lubbock_irq_demux(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ unsigned long pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled; ++ do { ++ GEDR(0) = GPIO_bit(0); /* clear useless edge notification */ ++ if (likely(pending)) ++ do_IRQ( LUBBOCK_IRQ(0) + __ffs(pending), regs ); ++ pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled; ++ } while (pending); ++} ++ ++static struct irqaction lubbock_irq = { ++ name: "Lubbock FPGA", ++ handler: lubbock_irq_demux, ++ flags: SA_INTERRUPT ++}; ++ ++static void __init lubbock_init_irq(void) ++{ ++ int irq; ++ ++ pxa_init_irq(); ++ ++ /* setup extra lubbock irqs */ ++ for(irq = LUBBOCK_IRQ(0); irq <= LUBBOCK_LAST_IRQ; irq++) { ++ irq_desc[irq].valid = 1; ++ irq_desc[irq].probe_ok = 1; ++ irq_desc[irq].mask_ack = lubbock_mask_irq; ++ irq_desc[irq].mask = lubbock_mask_irq; ++ irq_desc[irq].unmask = lubbock_unmask_irq; ++ } ++ ++ set_GPIO_IRQ_edge(GPIO_LUBBOCK_IRQ, GPIO_FALLING_EDGE); ++ setup_arm_irq(IRQ_GPIO_LUBBOCK_IRQ, &lubbock_irq); ++} ++ ++static int __init lubbock_init(void) ++{ ++ int ret; ++ ++ ret = sa1111_probe(LUBBOCK_SA1111_BASE); ++ if (ret) ++ return ret; ++ sa1111_wake(); ++ sa1111_init_irq(LUBBOCK_SA1111_IRQ); ++ return 0; ++} ++ ++__initcall(lubbock_init); ++ ++static void __init ++fixup_lubbock(struct machine_desc *desc, struct param_struct *params, ++ char **cmdline, struct meminfo *mi) ++{ ++ /* Some boards have 32MB some 64MB. Let's use a safe default */ ++ SET_BANK (0, 0xa0000000, 32*1024*1024); ++ mi->nr_banks = 1; ++} ++ ++static struct map_desc lubbock_io_desc[] __initdata = { ++ /* virtual physical length domain r w c b */ ++ { 0xf0000000, 0x08000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */ ++ { 0xf1000000, 0x0c000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 IO */ ++ { 0xf1100000, 0x0e000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 Attr */ ++ { 0xf4000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA1111 */ ++ LAST_DESC ++}; ++ ++static void __init lubbock_map_io(void) ++{ ++ pxa_map_io(); ++ iotable_init(lubbock_io_desc); ++ ++ /* This enables the BTUART */ ++ CKEN |= CKEN7_BTUART; ++ set_GPIO_mode(GPIO42_BTRXD_MD); ++ set_GPIO_mode(GPIO43_BTTXD_MD); ++ set_GPIO_mode(GPIO44_BTCTS_MD); ++ set_GPIO_mode(GPIO45_BTRTS_MD); ++ ++ /* This is for the SMC chip select */ ++ set_GPIO_mode(GPIO79_nCS_3_MD); ++ ++ /* setup sleep mode values */ ++ PWER = 0x00000002; ++ PFER = 0x00000000; ++ PRER = 0x00000002; ++ PGSR0 = 0x00008000; ++ PGSR1 = 0x003F0202; ++ PGSR2 = 0x0001C000; ++ PCFR |= PCFR_OPDE; ++} ++ ++MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform") ++ MAINTAINER("MontaVista Software Inc.") ++ BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000)) ++ FIXUP(fixup_lubbock) ++ MAPIO(lubbock_map_io) ++ INITIRQ(lubbock_init_irq) ++MACHINE_END +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/pm.c +@@ -0,0 +1,265 @@ ++/* ++ * PXA250/210 Power Management Routines ++ * ++ * Original code for the SA11x0: ++ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com> ++ * ++ * Modified for the PXA250 by Nicolas Pitre: ++ * Copyright (c) 2002 Monta Vista Software, Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License. ++ */ ++ ++#include <linux/config.h> ++#include <linux/init.h> ++#include <linux/pm.h> ++#include <linux/slab.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/sysctl.h> ++#include <linux/errno.h> ++ ++#include <asm/hardware.h> ++#include <asm/memory.h> ++#include <asm/system.h> ++#include <asm/leds.h> ++ ++ ++/* ++ * Debug macros ++ */ ++#undef DEBUG ++ ++extern void pxa_cpu_suspend(void); ++extern void pxa_cpu_resume(void); ++ ++#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x ++#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x] ++ ++/* ++ * List of global PXA peripheral registers to preserve. ++ * More ones like CP and general purpose register values are preserved ++ * with the stack pointer in sleep.S. ++ */ ++enum { SLEEP_SAVE_START = 0, ++ ++ SLEEP_SAVE_OSCR, SLEEP_SAVE_OIER, ++ SLEEP_SAVE_OSMR0, SLEEP_SAVE_OSMR1, SLEEP_SAVE_OSMR2, SLEEP_SAVE_OSMR3, ++ ++ SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, ++ SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, ++ SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, ++ SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR2_L, ++ SLEEP_SAVE_GAFR0_U, SLEEP_SAVE_GAFR1_U, SLEEP_SAVE_GAFR2_U, ++ ++ SLEEP_SAVE_FFIER, SLEEP_SAVE_FFLCR, SLEEP_SAVE_FFMCR, ++ SLEEP_SAVE_FFSPR, SLEEP_SAVE_FFISR, ++ SLEEP_SAVE_FFDLL, SLEEP_SAVE_FFDLH, ++ ++ SLEEP_SAVE_ICMR, ++ SLEEP_SAVE_CKEN, ++ ++ SLEEP_SAVE_CKSUM, ++ ++ SLEEP_SAVE_SIZE ++}; ++ ++ ++int pm_do_suspend(void) ++{ ++ unsigned long sleep_save[SLEEP_SAVE_SIZE]; ++ unsigned long checksum = 0; ++ int i; ++ ++ cli(); ++ clf(); ++ ++ leds_event(led_stop); ++ ++ /* preserve current time */ ++ RCNR = xtime.tv_sec; ++ ++ /* ++ * Temporary solution. This won't be necessary once ++ * we move pxa support into the serial/* driver ++ * Save the FF UART ++ */ ++ SAVE(FFIER); ++ SAVE(FFLCR); ++ SAVE(FFMCR); ++ SAVE(FFSPR); ++ SAVE(FFISR); ++ FFLCR |= 0x80; ++ SAVE(FFDLL); ++ SAVE(FFDLH); ++ FFLCR &= 0xef; ++ ++ /* save vital registers */ ++ SAVE(OSCR); ++ SAVE(OSMR0); ++ SAVE(OSMR1); ++ SAVE(OSMR2); ++ SAVE(OSMR3); ++ SAVE(OIER); ++ ++ SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2); ++ SAVE(GRER0); SAVE(GRER1); SAVE(GRER2); ++ SAVE(GFER0); SAVE(GFER1); SAVE(GFER2); ++ SAVE(GAFR0_L); SAVE(GAFR0_U); ++ SAVE(GAFR1_L); SAVE(GAFR1_U); ++ SAVE(GAFR2_L); SAVE(GAFR2_U); ++ ++ SAVE(ICMR); ++ ICMR = 0; ++ ++ SAVE(CKEN); ++ CKEN = 0; ++ ++ /* Note: wake up source are set up in each machine specific files */ ++ ++ /* clear GPIO transition detect bits */ ++ GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2; ++ ++ /* Clear sleep reset status */ ++ RCSR = RCSR_SMR; ++ ++ /* set resume return address */ ++ PSPR = virt_to_phys(pxa_cpu_resume); ++ ++ /* before sleeping, calculate and save a checksum */ ++ for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++) ++ checksum += sleep_save[i]; ++ sleep_save[SLEEP_SAVE_CKSUM] = checksum; ++ ++ /* *** go zzz *** */ ++ pxa_cpu_suspend(); ++ ++ /* after sleeping, validate the checksum */ ++ checksum = 0; ++ for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++) ++ checksum += sleep_save[i]; ++ ++ /* if invalid, display message and wait for a hardware reset */ ++ if (checksum != sleep_save[SLEEP_SAVE_CKSUM]) { ++#ifdef CONFIG_ARCH_LUBBOCK ++ LUB_HEXLED = 0xbadbadc5; ++#endif ++ while (1); ++ } ++ ++ /* ensure not to come back here if it wasn't intended */ ++ PSPR = 0; ++ ++ /* restore registers */ ++ RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2); ++ RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2); ++ RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2); ++ RESTORE(GAFR0_L); RESTORE(GAFR0_U); ++ RESTORE(GAFR1_L); RESTORE(GAFR1_U); ++ RESTORE(GAFR2_L); RESTORE(GAFR2_U); ++ ++ PSSR = PSSR_PH; ++ ++ RESTORE(OSMR0); ++ RESTORE(OSMR1); ++ RESTORE(OSMR2); ++ RESTORE(OSMR3); ++ RESTORE(OSCR); ++ RESTORE(OIER); ++ ++ RESTORE(CKEN); ++ ++ ICLR = 0; ++ ICCR = 1; ++ RESTORE(ICMR); ++ ++ /* ++ * Temporary solution. This won't be necessary once ++ * we move pxa support into the serial/* driver. ++ * Restore the FF UART. ++ */ ++ RESTORE(FFMCR); ++ RESTORE(FFSPR); ++ RESTORE(FFLCR); ++ FFLCR |= 0x80; ++ RESTORE(FFDLH); ++ RESTORE(FFDLL); ++ RESTORE(FFLCR); ++ RESTORE(FFISR); ++ FFFCR = 0x07; ++ RESTORE(FFIER); ++ ++ /* restore current time */ ++ xtime.tv_sec = RCNR; ++ ++#ifdef DEBUG ++ printk(KERN_DEBUG "*** made it back from resume\n"); ++#endif ++ ++ leds_event(led_start); ++ ++ sti(); ++ ++ return 0; ++} ++ ++unsigned long sleep_phys_sp(void *sp) ++{ ++ return virt_to_phys(sp); ++} ++ ++#ifdef CONFIG_SYSCTL ++/* ++ * ARGH! ACPI people defined CTL_ACPI in linux/acpi.h rather than ++ * linux/sysctl.h. ++ * ++ * This means our interface here won't survive long - it needs a new ++ * interface. Quick hack to get this working - use sysctl id 9999. ++ */ ++#warning ACPI broke the kernel, this interface needs to be fixed up. ++#define CTL_ACPI 9999 ++#define ACPI_S1_SLP_TYP 19 ++ ++/* ++ * Send us to sleep. ++ */ ++static int sysctl_pm_do_suspend(void) ++{ ++ int retval; ++ ++ retval = pm_send_all(PM_SUSPEND, (void *)3); ++ ++ if (retval == 0) { ++ retval = pm_do_suspend(); ++ ++ pm_send_all(PM_RESUME, (void *)0); ++ } ++ ++ return retval; ++} ++ ++static struct ctl_table pm_table[] = ++{ ++ {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, (proc_handler *)&sysctl_pm_do_suspend}, ++ {0} ++}; ++ ++static struct ctl_table pm_dir_table[] = ++{ ++ {CTL_ACPI, "pm", NULL, 0, 0555, pm_table}, ++ {0} ++}; ++ ++/* ++ * Initialize power interface ++ */ ++static int __init pm_init(void) ++{ ++ register_sysctl_table(pm_dir_table, 1); ++ return 0; ++} ++ ++__initcall(pm_init); ++ ++#endif +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/pxa_usb.h +@@ -0,0 +1,230 @@ ++/* ++ * pxa_usb.h ++ * ++ * Public interface to the pxa USB core. For use by client modules ++ * like usb-eth and usb-char. ++ * ++ * 02-May-2002 ++ * Frank Becker (Intrinsyc) - derived from sa1100_usb.h ++ * ++ */ ++ ++#ifndef _PXA_USB_H ++#define _PXA_USB_H ++#include <asm/byteorder.h> ++ ++typedef void (*usb_callback_t)(int flag, int size); ++ ++/* in usb_ctl.c (see also descriptor methods at bottom of file) */ ++ ++// Open the USB client for client and initialize data structures ++// to default values, but _do not_ start UDC. ++int pxa_usb_open( const char * client_name ); ++ ++// Start UDC running ++int pxa_usb_start( void ); ++ ++// Immediately stop udc, fire off completion routines w/-EINTR ++int pxa_usb_stop( void ) ; ++ ++// Disconnect client from usb core ++int pxa_usb_close( void ) ; ++ ++// set notify callback for when core reaches configured state ++// return previous pointer (if any) ++typedef void (*usb_notify_t)(void); ++usb_notify_t pxa_set_configured_callback( usb_notify_t callback ); ++ ++/* in usb_send.c */ ++int pxa_usb_xmitter_avail( void ); ++int pxa_usb_send(char *buf, int len, usb_callback_t callback); ++void sa110a_usb_send_reset(void); ++ ++/* in usb_recev.c */ ++int pxa_usb_recv(char *buf, int len, usb_callback_t callback); ++void pxa_usb_recv_reset(void); ++ ++////////////////////////////////////////////////////////////////////////////// ++// Descriptor Management ++////////////////////////////////////////////////////////////////////////////// ++ ++#define DescriptorHeader \ ++ __u8 bLength; \ ++ __u8 bDescriptorType ++ ++ ++// --- Device Descriptor ------------------- ++ ++typedef struct { ++ DescriptorHeader; ++ __u16 bcdUSB; /* USB specification revision number in BCD */ ++ __u8 bDeviceClass; /* USB class for entire device */ ++ __u8 bDeviceSubClass; /* USB subclass information for entire device */ ++ __u8 bDeviceProtocol; /* USB protocol information for entire device */ ++ __u8 bMaxPacketSize0; /* Max packet size for endpoint zero */ ++ __u16 idVendor; /* USB vendor ID */ ++ __u16 idProduct; /* USB product ID */ ++ __u16 bcdDevice; /* vendor assigned device release number */ ++ __u8 iManufacturer; /* index of manufacturer string */ ++ __u8 iProduct; /* index of string that describes product */ ++ __u8 iSerialNumber; /* index of string containing device serial number */ ++ __u8 bNumConfigurations; /* number fo configurations */ ++} __attribute__ ((packed)) device_desc_t; ++ ++// --- Configuration Descriptor ------------ ++ ++typedef struct { ++ DescriptorHeader; ++ __u16 wTotalLength; /* total # of bytes returned in the cfg buf 4 this cfg */ ++ __u8 bNumInterfaces; /* number of interfaces in this cfg */ ++ __u8 bConfigurationValue; /* used to uniquely ID this cfg */ ++ __u8 iConfiguration; /* index of string describing configuration */ ++ __u8 bmAttributes; /* bitmap of attributes for ths cfg */ ++ __u8 MaxPower; /* power draw in 2ma units */ ++} __attribute__ ((packed)) config_desc_t; ++ ++// bmAttributes: ++enum { ++ USB_CONFIG_REMOTEWAKE=0x20, ++ USB_CONFIG_SELFPOWERED=0x40, ++ USB_CONFIG_BUSPOWERED=0x80 ++}; ++ ++// MaxPower: ++#define USB_POWER( x) ((x)>>1) /* convert mA to descriptor units of A for MaxPower */ ++ ++// --- Interface Descriptor --------------- ++ ++typedef struct { ++ DescriptorHeader; ++ __u8 bInterfaceNumber; /* Index uniquely identfying this interface */ ++ __u8 bAlternateSetting; /* ids an alternate setting for this interface */ ++ __u8 bNumEndpoints; /* number of endpoints in this interface */ ++ __u8 bInterfaceClass; /* USB class info applying to this interface */ ++ __u8 bInterfaceSubClass; /* USB subclass info applying to this interface */ ++ __u8 bInterfaceProtocol; /* USB protocol info applying to this interface */ ++ __u8 iInterface; /* index of string describing interface */ ++} __attribute__ ((packed)) intf_desc_t; ++ ++// --- Endpoint Descriptor --------------- ++ ++typedef struct { ++ DescriptorHeader; ++ __u8 bEndpointAddress; /* 0..3 ep num, bit 7: 0 = 0ut 1= in */ ++ __u8 bmAttributes; /* 0..1 = 0: ctrl, 1: isoc, 2: bulk 3: intr */ ++ __u16 wMaxPacketSize; /* data payload size for this ep in this cfg */ ++ __u8 bInterval; /* polling interval for this ep in this cfg */ ++} __attribute__ ((packed)) ep_desc_t; ++ ++// bEndpointAddress: ++enum { ++ USB_OUT =0, ++ USB_IN =1 ++}; ++ ++#define USB_EP_ADDRESS(a,d) (((a)&0xf) | ((d) << 7)) ++// bmAttributes: ++enum { ++ USB_EP_CNTRL =0, ++ USB_EP_BULK =2, ++ USB_EP_INT =3, ++ USB_EP_ISO =4 ++}; ++ ++// --- String Descriptor ------------------- ++ ++typedef struct { ++ DescriptorHeader; ++ __u16 bString[1]; /* unicode string .. actaully 'n' __u16s */ ++} __attribute__ ((packed)) string_desc_t; ++ ++/*======================================================= ++ * Handy helpers when working with above ++ * ++ */ ++// these are x86-style 16 bit "words" ... ++#define make_word_c( w ) __constant_cpu_to_le16(w) ++#define make_word( w ) __cpu_to_le16(w) ++ ++// descriptor types ++enum { ++ USB_DESC_DEVICE = 1, ++ USB_DESC_CONFIG = 2, ++ USB_DESC_STRING = 3, ++ USB_DESC_INTERFACE = 4, ++ USB_DESC_ENDPOINT = 5 ++}; ++ ++ ++/*======================================================= ++ * Default descriptor layout for SA-1100 and SA-1110 UDC ++ */ ++ ++enum { ++ UNUSED = 0, ++ ++ BULK_IN1 = 1, ++ BULK_OUT1 = 2, ++ ISO_IN1 = 3, ++ ISO_OUT1 = 4, ++ INT_IN1 = 5, ++ ++ BULK_IN2 = 6, ++ BULK_OUT2 = 7, ++ ISO_IN2 = 8, ++ ISO_OUT2 = 9, ++ INT_IN2 = 10, ++ ++ BULK_IN3 = 11, ++ BULK_OUT3 = 12, ++ ISO_IN3 = 13, ++ ISO_OUT3 = 14, ++ INT_IN3 = 15 ++} /*endpoint_type*/; ++ ++/* "config descriptor buffer" - that is, one config, ++ ..one interface and 2 endpoints */ ++struct cdb { ++ config_desc_t cfg; ++ intf_desc_t intf; ++ ep_desc_t ep1; ++ ep_desc_t ep2; ++} __attribute__ ((packed)); ++ ++/* all SA device descriptors */ ++typedef struct { ++ device_desc_t dev; /* device descriptor */ ++ struct cdb b; /* bundle of descriptors for this cfg */ ++} __attribute__ ((packed)) desc_t; ++ ++ ++/*======================================================= ++ * Descriptor API ++ */ ++ ++/* Get the address of the statically allocated desc_t structure ++ in the usb core driver. Clients can modify this between ++ the time they call pxa_usb_open() and pxa_usb_start() ++*/ ++desc_t * ++pxa_usb_get_descriptor_ptr( void ); ++ ++ ++/* Set a pointer to the string descriptor at "index". The driver ++ ..has room for 8 string indicies internally. Index zero holds ++ ..a LANGID code and is set to US English by default. Inidices ++ ..1-7 are available for use in the config descriptors as client's ++ ..see fit. This pointer is assumed to be good as long as the ++ ..SA usb core is open (so statically allocate them). Returnes -EINVAL ++ ..if index out of range */ ++int pxa_usb_set_string_descriptor( int index, string_desc_t * p ); ++ ++/* reverse of above */ ++string_desc_t * ++pxa_usb_get_string_descriptor( int index ); ++ ++/* kmalloc() a string descriptor and convert "p" to unicode in it */ ++string_desc_t * ++pxa_usb_kmalloc_string_descriptor( const char * p ); ++ ++#endif /* _PXA_USB_H */ +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/sa1111.c +@@ -0,0 +1,3 @@ ++#include "../mach-sa1100/sa1111.c" ++ ++ +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/sa1111.h +@@ -0,0 +1,2 @@ ++#include "../mach-sa1100/sa1111.h" ++ +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/sleep.S +@@ -0,0 +1,150 @@ ++/* ++ * Low-level PXA250/210 sleep/wakeUp support ++ * ++ * Initial SA1110 code: ++ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com> ++ * ++ * Adapted for PXA by Nicolas Pitre: ++ * Copyright (c) 2002 Monta Vista Software, Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License. ++ */ ++ ++#include <linux/config.h> ++#include <linux/linkage.h> ++#include <asm/assembler.h> ++#include <asm/hardware.h> ++ ++ .text ++ ++/* ++ * pxa_cpu_suspend() ++ * ++ * Forces CPU into sleep state ++ */ ++ ++ENTRY(pxa_cpu_suspend) ++ ++ mra r2, r3, acc0 ++ stmfd sp!, {r2 - r12, lr} @ save registers on stack ++ ++ @ get coprocessor registers ++ mrc p15, 0, r4, c15, c1, 0 @ CP access reg ++ mrc p15, 0, r5, c13, c0, 0 @ PID ++ mrc p15, 0, r6, c3, c0, 0 @ domain ID ++ mrc p15, 0, r7, c2, c0, 0 @ translation table base addr ++ mrc p15, 0, r8, c1, c1, 0 @ auxiliary control reg ++ mrc p15, 0, r9, c1, c0, 0 @ control reg ++ ++ @ store them plus current virtual stack ptr on stack ++ mov r10, sp ++ stmfd sp!, {r4 - r10} ++ ++ @ preserve phys address of stack ++ mov r0, sp ++ bl sleep_phys_sp ++ ldr r1, =sleep_save_sp ++ str r0, [r1] ++ ++ @ clean data cache ++ bl cpu_xscale_cache_clean_invalidate_all ++ ++ @ Put the processor to sleep ++ @ (also workaround for sighting 28071) ++ ++ @ prepare value for sleep mode ++ mov r1, #3 @ sleep mode ++ ++ @ prepare to put SDRAM into self-refresh manually ++ ldr r4, =MDREFR ++ ldr r5, [r4] ++ orr r5, r5, #MDREFR_SLFRSH ++ ++ @ prepare pointer to physical address 0 (virtual mapping in generic.c) ++ mov r2, #UNCACHED_PHYS_0 ++ ++ @ align execution to a cache line ++ b 1f ++ ++ .ltorg ++ .align 5 ++1: ++ ++ @ All needed values are now in registers. ++ @ These last instructions should be in cache ++ ++ @ put SDRAM into self-refresh ++ str r5, [r4] ++ ++ @ force address lines low by reading at physical address 0 ++ ldr r3, [r2] ++ ++ @ enter sleep mode ++ mcr p14, 0, r1, c7, c0, 0 ++ ++20: nop ++ b 20b @ loop waiting for sleep ++ ++/* ++ * cpu_pxa_resume() ++ * ++ * entry point from bootloader into kernel during resume ++ * ++ * Note: Yes, part of the following code is located into the .data section. ++ * This is to allow sleep_save_sp to be accessed with a relative load ++ * while we can't rely on any MMU translation. We could have put ++ * sleep_save_sp in the .text section as well, but some setups might ++ * insist on it to be truely read-only. ++ */ ++ ++ .data ++ .align 5 ++ENTRY(pxa_cpu_resume) ++ mov r0, #I_BIT | F_BIT | MODE_SVC @ set SVC, irqs off ++ msr cpsr_c, r0 ++ ++ ldr r0, sleep_save_sp @ stack phys addr ++ ldr r2, =resume_after_mmu @ its absolute virtual address ++ ldmfd r0, {r4 - r9, sp} @ CP regs + virt stack ptr ++ ++ mov r1, #0 ++ mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs ++ mcr p15, 0, r1, c7, c7, 0 @ invalidate I & D caches, BTB ++ ++#ifdef CONFIG_XSCALE_CACHE_ERRATA ++ bic r9, r9, #0x0004 @ see cpu_xscale_proc_init ++#endif ++ ++ mcr p15, 0, r4, c15, c1, 0 @ CP access reg ++ mcr p15, 0, r5, c13, c0, 0 @ PID ++ mcr p15, 0, r6, c3, c0, 0 @ domain ID ++ mcr p15, 0, r7, c2, c0, 0 @ translation table base addr ++ mcr p15, 0, r8, c1, c1, 0 @ auxiliary control reg ++ b resume_turn_on_mmu @ cache align execution ++ ++ .align 5 ++resume_turn_on_mmu: ++ mcr p15, 0, r9, c1, c0, 0 @ turn on MMU, caches, etc. ++ ++ @ Let us ensure we jump to resume_after_mmu only when the mcr above ++ @ actually took effect. They call it the "cpwait" operation. ++ mrc p15, 0, r1, c2, c0, 0 @ queue a dependency on CP15 ++ sub pc, r2, r1, lsr #32 @ jump to virtual addr ++ nop ++ nop ++ nop ++ ++sleep_save_sp: ++ .word 0 @ preserve stack phys ptr here ++ ++ .text ++resume_after_mmu: ++#ifdef CONFIG_XSCALE_CACHE_ERRATA ++ bl cpu_xscale_proc_init ++#endif ++ ldmfd sp!, {r2, r3} ++ mar acc0, r2, r3 ++ ldmfd sp!, {r4 - r12, pc} @ return to caller ++ ++ +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/trizeps2.c +@@ -0,0 +1,105 @@ ++/* ++ * linux/arch/arm/mach-pxa/trizeps2.c ++ * ++ * Support for the Keith&Koep MT6N Development Platform. ++ * ++ * Author: Luc De Cock ++ * Created: Jan 13, 2003 ++ * Copyright: Teradyne DS, Ltd. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/init.h> ++#include <linux/major.h> ++#include <linux/fs.h> ++#include <linux/interrupt.h> ++#include <linux/sched.h> ++ ++#include <asm/types.h> ++#include <asm/setup.h> ++#include <asm/memory.h> ++#include <asm/mach-types.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/mach/irq.h> ++ ++#include <asm/arch/irq.h> ++ ++#include "generic.h" ++ ++static unsigned long trizeps2_irq_en_mask; ++unsigned short trizeps2_bcr_shadow = 0x50; // 0x70 ++ ++ ++static void __init trizeps2_init_irq(void) ++{ ++ int irq; ++ ++ pxa_init_irq(); ++ ++ set_GPIO_IRQ_edge(GPIO_ETHERNET_IRQ, GPIO_RISING_EDGE); ++} ++ ++static int __init trizeps2_init(void) ++{ ++ /* Configure the BCR register */ ++ unsigned short *bcr = (unsigned short *) TRIZEPS2_BCR_BASE; ++ ++ *bcr = trizeps2_bcr_shadow; ++ return 0; ++} ++ ++__initcall(trizeps2_init); ++ ++static void __init ++fixup_trizeps2(struct machine_desc *desc, struct param_struct *params, ++ char **cmdline, struct meminfo *mi) ++{ ++#ifdef TRIZEPS2_MEM_64MB ++ SET_BANK (0, 0xa0000000, 64*1024*1024); ++#else ++ SET_BANK (0, 0xa0000000, 32*1024*1024); ++#endif ++ mi->nr_banks = 1; ++} ++ ++static struct map_desc trizeps2_io_desc[] __initdata = { ++ /* virtual physical length domain r w c b */ ++ { 0xf0000000, 0x0e000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* BCR */ ++ { 0xf0100000, 0x0c000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA STATUS */ ++ { 0xf1000000, 0x0c800000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 IO */ ++ { 0xf1100000, 0x0e000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 Attr */ ++ { 0xf2000000, 0x0d800000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* TTL-IO */ ++ LAST_DESC ++}; ++ ++static void __init trizeps2_map_io(void) ++{ ++ pxa_map_io(); ++ iotable_init(trizeps2_io_desc); ++ ++ /* This is for the SMC chip select */ ++ set_GPIO_mode(GPIO79_nCS_3_MD); ++ ++ /* setup sleep mode values */ ++ PWER = 0x00000002; ++ PFER = 0x00000000; ++ PRER = 0x00000002; ++ PGSR0 = 0x00008000; ++ PGSR1 = 0x003F0202; ++ PGSR2 = 0x0001C000; ++ PCFR |= PCFR_OPDE; ++} ++ ++MACHINE_START(TRIZEPS2, "Keith-n-Koep MT6N Development Platform") ++ MAINTAINER("Luc De Cock") ++ BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000)) ++ FIXUP(fixup_trizeps2) ++ MAPIO(trizeps2_map_io) ++ INITIRQ(trizeps2_init_irq) ++MACHINE_END +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/usb-char.c +@@ -0,0 +1,719 @@ ++/* ++ * (C) Copyright 2000-2001 Extenex Corporation ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * usb-char.c ++ * ++ * Miscellaneous character device interface for SA1100 USB function ++ * driver. ++ * ++ * Background: ++ * The SA1100 function driver ported from the Compaq Itsy project ++ * has an interface, usb-eth.c, to feed network packets over the ++ * usb wire and into the Linux TCP/IP stack. ++ * ++ * This file replaces that one with a simple character device ++ * interface that allows unstructured "byte pipe" style reads and ++ * writes over the USB bulk endpoints by userspace programs. ++ * ++ * A new define, CONFIG_SA1100_USB_NETLINK, has been created that, ++ * when set, (the default) causes the ethernet interface to be used. ++ * When not set, this more pedestrian character interface is linked ++ * in instead. ++ * ++ * Please see linux/Documentation/arm/SA1100/SA1100_USB for details. ++ * ++ * ward.willats@extenex.com ++ * ++ * To do: ++ * - Can't dma into ring buffer directly with pci_map/unmap usb_recv ++ * uses and get bytes out at the same time DMA is going on. Investigate: ++ * a) changing usb_recv to use alloc_consistent() at client request; or ++ * b) non-ring-buffer based data structures. In the meantime, I am using ++ * a bounce buffer. Simple, but wasteful. ++ */ ++ ++#include <linux/module.h> ++#include <linux/config.h> ++#include <linux/miscdevice.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/cache.h> ++#include <linux/poll.h> ++#include <linux/circ_buf.h> ++#include <linux/timer.h> ++ ++#include <asm/io.h> ++#include <asm/semaphore.h> ++#include <asm/proc/page.h> ++#include <asm/mach-types.h> ++ ++#include "usb-char.h" ++#include "pxa_usb.h" ++ ++ ++ ++////////////////////////////////////////////////////////////////////////////// ++// Driver Options ++////////////////////////////////////////////////////////////////////////////// ++ ++#define VERSION "0.4" ++ ++ ++#define VERBOSITY 1 ++ ++#if VERBOSITY ++# define PRINTK(x, a...) printk (x, ## a) ++#else ++# define PRINTK(x, a...) /**/ ++#endif ++ ++////////////////////////////////////////////////////////////////////////////// ++// Globals - Macros - Enums - Structures ++////////////////////////////////////////////////////////////////////////////// ++#ifndef MIN ++#define MIN( a, b ) ((a)<(b)?(a):(b)) ++#endif ++ ++typedef int bool; enum { false = 0, true = 1 }; ++ ++static const char pszMe[] = "usbchr: "; ++ ++static wait_queue_head_t wq_read; ++static wait_queue_head_t wq_write; ++static wait_queue_head_t wq_poll; ++ ++/* Serialze multiple writers onto the transmit hardware ++.. since we sleep the writer during transmit to stay in ++.. sync. (Multiple writers don't make much sense, but..) */ ++static DECLARE_MUTEX( xmit_sem ); ++ ++// size of usb DATA0/1 packets. 64 is standard maximum ++// for bulk transport, though most hosts seem to be able ++// to handle larger. ++#define TX_PACKET_SIZE 64 ++#define RX_PACKET_SIZE 64 ++#define RBUF_SIZE (4*PAGE_SIZE) ++ ++static struct wcirc_buf { ++ char *buf; ++ int in; ++ int out; ++} rx_ring = { NULL, 0, 0 }; ++ ++static struct { ++ unsigned long cnt_rx_complete; ++ unsigned long cnt_rx_errors; ++ unsigned long bytes_rx; ++ unsigned long cnt_tx_timeouts; ++ unsigned long cnt_tx_errors; ++ unsigned long bytes_tx; ++} charstats; ++ ++ ++static char * tx_buf = NULL; ++static char * packet_buffer = NULL; ++static int sending = 0; ++static int usb_ref_count = 0; ++static int last_tx_result = 0; ++static int last_rx_result = 0; ++static int last_tx_size = 0; ++static struct timer_list tx_timer; ++ ++////////////////////////////////////////////////////////////////////////////// ++// Prototypes ++////////////////////////////////////////////////////////////////////////////// ++static char * what_the_f( int e ); ++static void free_txrx_buffers( void ); ++static void twiddle_descriptors( void ); ++static void free_string_descriptors( void ) ; ++static int usbc_open( struct inode *pInode, struct file *pFile ); ++static void rx_done_callback_packet_buffer( int flag, int size ); ++ ++static void tx_timeout( unsigned long ); ++static void tx_done_callback( int flag, int size ); ++ ++static ssize_t usbc_read( struct file *, char *, size_t, loff_t * ); ++static ssize_t usbc_write( struct file *, const char *, size_t, loff_t * ); ++static unsigned int usbc_poll( struct file *pFile, poll_table * pWait ); ++static int usbc_ioctl( struct inode *pInode, struct file *pFile, ++ unsigned int nCmd, unsigned long argument ); ++static int usbc_close( struct inode *pInode, struct file *pFile ); ++ ++#ifdef CONFIG_SA1100_EXTENEX1 ++static void extenex_configured_notify_proc( void ); ++#endif ++////////////////////////////////////////////////////////////////////////////// ++// Private Helpers ++////////////////////////////////////////////////////////////////////////////// ++ ++static char * what_the_f( int e ) ++{ ++ char * p; ++ switch( e ) { ++ case 0: ++ p = "noErr"; ++ break; ++ case -ENODEV: ++ p = "ENODEV - usb not in config state"; ++ break; ++ case -EBUSY: ++ p = "EBUSY - another request on the hardware"; ++ break; ++ case -EAGAIN: ++ p = "EAGAIN"; ++ break; ++ case -EINTR: ++ p = "EINTR - interrupted\n"; ++ break; ++ case -EPIPE: ++ p = "EPIPE - zero length xfer\n"; ++ break; ++ default: ++ p = "????"; ++ break; ++ } ++ return p; ++} ++ ++static void free_txrx_buffers( void ) ++{ ++ if ( rx_ring.buf != NULL ) { ++ kfree( rx_ring.buf ); ++ rx_ring.buf = NULL; ++ } ++ if ( packet_buffer != NULL ) { ++ kfree( packet_buffer ); ++ packet_buffer = NULL; ++ } ++ if ( tx_buf != NULL ) { ++ kfree( tx_buf ); ++ tx_buf = NULL; ++ } ++} ++ ++/* twiddle_descriptors() ++ * It is between open() and start(). Setup descriptors. ++ */ ++static void twiddle_descriptors( void ) ++{ ++ desc_t * pDesc = pxa_usb_get_descriptor_ptr(); ++ string_desc_t * pString; ++ ++ pDesc->b.ep1.wMaxPacketSize = make_word_c( RX_PACKET_SIZE ); ++ pDesc->b.ep1.bmAttributes = USB_EP_BULK; ++ pDesc->b.ep2.wMaxPacketSize = make_word_c( TX_PACKET_SIZE ); ++ pDesc->b.ep2.bmAttributes = USB_EP_BULK; ++ ++ if ( machine_is_extenex1() ) { ++#ifdef CONFIG_SA1100_EXTENEX1 ++ pDesc->dev.idVendor = make_word_c( 0xC9F ); ++ pDesc->dev.idProduct = 1; ++ pDesc->dev.bcdDevice = make_word_c( 0x0001 ); ++ pDesc->b.cfg.bmAttributes = USB_CONFIG_SELFPOWERED; ++ pDesc->b.cfg.MaxPower = 0; ++ ++ pString = pxa_usb_kmalloc_string_descriptor( "Extenex" ); ++ if ( pString ) { ++ pxa_usb_set_string_descriptor( 1, pString ); ++ pDesc->dev.iManufacturer = 1; ++ } ++ ++ pString = pxa_usb_kmalloc_string_descriptor( "Handheld Theater" ); ++ if ( pString ) { ++ pxa_usb_set_string_descriptor( 2, pString ); ++ pDesc->dev.iProduct = 2; ++ } ++ ++ pString = pxa_usb_kmalloc_string_descriptor( "00000000" ); ++ if ( pString ) { ++ pxa_usb_set_string_descriptor( 3, pString ); ++ pDesc->dev.iSerialNumber = 3; ++ } ++ ++ pString = pxa_usb_kmalloc_string_descriptor( "HHT Bulk Transfer" ); ++ if ( pString ) { ++ pxa_usb_set_string_descriptor( 4, pString ); ++ pDesc->b.intf.iInterface = 4; ++ } ++ pxa_set_configured_callback( extenex_configured_notify_proc ); ++#endif ++ } ++} ++ ++static void free_string_descriptors( void ) ++{ ++ if ( machine_is_extenex1() ) { ++ string_desc_t * pString; ++ int i; ++ for( i = 1 ; i <= 4 ; i++ ) { ++ pString = pxa_usb_get_string_descriptor( i ); ++ if ( pString ) ++ kfree( pString ); ++ } ++ } ++} ++ ++////////////////////////////////////////////////////////////////////////////// ++// ASYNCHRONOUS ++////////////////////////////////////////////////////////////////////////////// ++static void kick_start_rx( void ) ++{ ++ if ( usb_ref_count ) { ++ int total_space = CIRC_SPACE( rx_ring.in, rx_ring.out, RBUF_SIZE ); ++ if ( total_space >= RX_PACKET_SIZE ) { ++ pxa_usb_recv( packet_buffer, ++ RX_PACKET_SIZE, ++ rx_done_callback_packet_buffer ++ ); ++ } ++ } ++} ++/* ++ * rx_done_callback_packet_buffer() ++ * We have completed a DMA xfer into the temp packet buffer. ++ * Move to ring. ++ * ++ * flag values: ++ * on init, -EAGAIN ++ * on reset, -EINTR ++ * on RPE, -EIO ++ * on short packet -EPIPE ++ */ ++static void ++rx_done_callback_packet_buffer( int flag, int size ) ++{ ++ charstats.cnt_rx_complete++; ++ ++ if ( flag == 0 || flag == -EPIPE ) { ++ size_t n; ++ ++ charstats.bytes_rx += size; ++ ++ n = CIRC_SPACE_TO_END( rx_ring.in, rx_ring.out, RBUF_SIZE ); ++ n = MIN( n, size ); ++ size -= n; ++ ++ memcpy( &rx_ring.buf[ rx_ring.in ], packet_buffer, n ); ++ rx_ring.in = (rx_ring.in + n) & (RBUF_SIZE-1); ++ memcpy( &rx_ring.buf[ rx_ring.in ], packet_buffer + n, size ); ++ rx_ring.in = (rx_ring.in + size) & (RBUF_SIZE-1); ++ ++ wake_up_interruptible( &wq_read ); ++ wake_up_interruptible( &wq_poll ); ++ ++ last_rx_result = 0; ++ ++ kick_start_rx(); ++ ++ } else if ( flag != -EAGAIN ) { ++ charstats.cnt_rx_errors++; ++ last_rx_result = flag; ++ wake_up_interruptible( &wq_read ); ++ wake_up_interruptible( &wq_poll ); ++ } ++ else /* init, start a read */ ++ kick_start_rx(); ++} ++ ++ ++static void tx_timeout( unsigned long unused ) ++{ ++ printk( "%stx timeout\n", pszMe ); ++ pxa_usb_send_reset(); ++ charstats.cnt_tx_timeouts++; ++} ++ ++ ++// on init, -EAGAIN ++// on reset, -EINTR ++// on TPE, -EIO ++static void tx_done_callback( int flags, int size ) ++{ ++ if ( flags == 0 ) ++ charstats.bytes_tx += size; ++ else ++ charstats.cnt_tx_errors++; ++ last_tx_size = size; ++ last_tx_result = flags; ++ sending = 0; ++ wake_up_interruptible( &wq_write ); ++ wake_up_interruptible( &wq_poll ); ++} ++ ++ ++////////////////////////////////////////////////////////////////////////////// ++// Workers ++////////////////////////////////////////////////////////////////////////////// ++ ++static int usbc_open( struct inode *pInode, struct file *pFile ) ++{ ++ int retval = 0; ++ ++ PRINTK( KERN_DEBUG "%sopen()\n", pszMe ); ++ ++ /* start usb core */ ++ retval = pxa_usb_open( "usb-char" ); ++ if ( retval ) return retval; ++ ++ /* allocate memory */ ++ if ( usb_ref_count == 0 ) { ++ tx_buf = (char*) kmalloc( TX_PACKET_SIZE, GFP_KERNEL | GFP_DMA ); ++ if ( tx_buf == NULL ) { ++ printk( "%sARGHH! COULD NOT ALLOCATE TX BUFFER\n", pszMe ); ++ goto malloc_fail; ++ } ++ rx_ring.buf = ++ (char*) kmalloc( RBUF_SIZE, GFP_KERNEL ); ++ ++ if ( rx_ring.buf == NULL ) { ++ printk( "%sARGHH! COULD NOT ALLOCATE RX BUFFER\n", pszMe ); ++ goto malloc_fail; ++ } ++ ++ packet_buffer = ++ (char*) kmalloc( RX_PACKET_SIZE, GFP_KERNEL | GFP_DMA ); ++ ++ if ( packet_buffer == NULL ) { ++ printk( "%sARGHH! COULD NOT ALLOCATE RX PACKET BUFFER\n", pszMe ); ++ goto malloc_fail; ++ } ++ rx_ring.in = rx_ring.out = 0; ++ memset( &charstats, 0, sizeof( charstats ) ); ++ sending = 0; ++ last_tx_result = 0; ++ last_tx_size = 0; ++ } ++ ++ /* modify default descriptors */ ++ twiddle_descriptors(); ++ ++ retval = pxa_usb_start(); ++ if ( retval ) { ++ printk( "%sAGHH! Could not USB core\n", pszMe ); ++ free_txrx_buffers(); ++ return retval; ++ } ++ usb_ref_count++; /* must do _before_ kick_start() */ ++ MOD_INC_USE_COUNT; ++ kick_start_rx(); ++ return 0; ++ ++ malloc_fail: ++ free_txrx_buffers(); ++ return -ENOMEM; ++} ++ ++/* ++ * Read endpoint. Note that you can issue a read to an ++ * unconfigured endpoint. Eventually, the host may come along ++ * and configure underneath this module and data will appear. ++ */ ++static ssize_t usbc_read( struct file *pFile, char *pUserBuffer, ++ size_t stCount, loff_t *pPos ) ++{ ++ ssize_t retval; ++ int flags; ++ DECLARE_WAITQUEUE( wait, current ); ++ ++ PRINTK( KERN_DEBUG "%sread()\n", pszMe ); ++ ++ local_irq_save( flags ); ++ if ( last_rx_result == 0 ) { ++ local_irq_restore( flags ); ++ } else { /* an error happended and receiver is paused */ ++ local_irq_restore( flags ); ++ last_rx_result = 0; ++ kick_start_rx(); ++ } ++ ++ add_wait_queue( &wq_read, &wait ); ++ while( 1 ) { ++ ssize_t bytes_avail; ++ ssize_t bytes_to_end; ++ ++ set_current_state( TASK_INTERRUPTIBLE ); ++ ++ /* snap ring buf state */ ++ local_irq_save( flags ); ++ bytes_avail = CIRC_CNT( rx_ring.in, rx_ring.out, RBUF_SIZE ); ++ bytes_to_end = CIRC_CNT_TO_END( rx_ring.in, rx_ring.out, RBUF_SIZE ); ++ local_irq_restore( flags ); ++ ++ if ( bytes_avail != 0 ) { ++ ssize_t bytes_to_move = MIN( stCount, bytes_avail ); ++ retval = 0; // will be bytes transfered ++ if ( bytes_to_move != 0 ) { ++ size_t n = MIN( bytes_to_end, bytes_to_move ); ++ if ( copy_to_user( pUserBuffer, ++ &rx_ring.buf[ rx_ring.out ], ++ n ) ) { ++ retval = -EFAULT; ++ break; ++ } ++ bytes_to_move -= n; ++ retval += n; ++ // might go 1 char off end, so wrap ++ rx_ring.out = ( rx_ring.out + n ) & (RBUF_SIZE-1); ++ if ( copy_to_user( pUserBuffer + n, ++ &rx_ring.buf[ rx_ring.out ], ++ bytes_to_move ) ++ ) { ++ retval = -EFAULT; ++ break; ++ } ++ rx_ring.out += bytes_to_move; // cannot wrap ++ retval += bytes_to_move; ++ kick_start_rx(); ++ } ++ break; ++ } ++ else if ( last_rx_result ) { ++ retval = last_rx_result; ++ break; ++ } ++ else if ( pFile->f_flags & O_NONBLOCK ) { // no data, can't sleep ++ retval = -EAGAIN; ++ break; ++ } ++ else if ( signal_pending( current ) ) { // no data, can sleep, but signal ++ retval = -ERESTARTSYS; ++ break; ++ } ++ schedule(); // no data, can sleep ++ } ++ set_current_state( TASK_RUNNING ); ++ remove_wait_queue( &wq_read, &wait ); ++ ++ if ( retval < 0 ) ++ printk( "%sread error %d - %s\n", pszMe, retval, what_the_f( retval ) ); ++ return retval; ++} ++ ++/* ++ * Write endpoint. This routine attempts to break the passed in buffer ++ * into usb DATA0/1 packet size chunks and send them to the host. ++ * (The lower-level driver tries to do this too, but easier for us ++ * to manage things here.) ++ * ++ * We are at the mercy of the host here, in that it must send an IN ++ * token to us to pull this data back, so hopefully some higher level ++ * protocol is expecting traffic to flow in that direction so the host ++ * is actually polling us. To guard against hangs, a 5 second timeout ++ * is used. ++ * ++ * This routine takes some care to only report bytes sent that have ++ * actually made it across the wire. Thus we try to stay in lockstep ++ * with the completion routine and only have one packet on the xmit ++ * hardware at a time. Multiple simultaneous writers will get ++ * "undefined" results. ++ * ++ */ ++static ssize_t usbc_write( struct file *pFile, const char * pUserBuffer, ++ size_t stCount, loff_t *pPos ) ++{ ++ ssize_t retval = 0; ++ ssize_t stSent = 0; ++ ++ DECLARE_WAITQUEUE( wait, current ); ++ ++ PRINTK( KERN_DEBUG "%swrite() %d bytes\n", pszMe, stCount ); ++ ++ down( &xmit_sem ); // only one thread onto the hardware at a time ++ ++ while( stCount != 0 && retval == 0 ) { ++ int nThisTime = MIN( TX_PACKET_SIZE, stCount ); ++ copy_from_user( tx_buf, pUserBuffer, nThisTime ); ++ sending = nThisTime; ++ retval = pxa_usb_send( tx_buf, nThisTime, tx_done_callback ); ++ if ( retval < 0 ) { ++ char * p = what_the_f( retval ); ++ printk( "%sCould not queue xmission. rc=%d - %s\n", ++ pszMe, retval, p ); ++ sending = 0; ++ break; ++ } ++ /* now have something on the diving board */ ++ add_wait_queue( &wq_write, &wait ); ++ tx_timer.expires = jiffies + ( HZ * 5 ); ++ add_timer( &tx_timer ); ++ while( 1 ) { ++ set_current_state( TASK_INTERRUPTIBLE ); ++ if ( sending == 0 ) { /* it jumped into the pool */ ++ del_timer( &tx_timer ); ++ retval = last_tx_result; ++ if ( retval == 0 ) { ++ stSent += last_tx_size; ++ pUserBuffer += last_tx_size; ++ stCount -= last_tx_size; ++ } ++ else ++ printk( "%sxmission error rc=%d - %s\n", ++ pszMe, retval, what_the_f(retval) ); ++ break; ++ } ++ else if ( signal_pending( current ) ) { ++ del_timer( &tx_timer ); ++ printk( "%ssignal\n", pszMe ); ++ retval = -ERESTARTSYS; ++ break; ++ } ++ schedule(); ++ } ++ set_current_state( TASK_RUNNING ); ++ remove_wait_queue( &wq_write, &wait ); ++ } ++ ++ up( &xmit_sem ); ++ ++ if ( 0 == retval ) ++ retval = stSent; ++ return retval; ++} ++ ++static unsigned int usbc_poll( struct file *pFile, poll_table * pWait ) ++{ ++ unsigned int retval = 0; ++ ++ PRINTK( KERN_DEBUG "%poll()\n", pszMe ); ++ ++ poll_wait( pFile, &wq_poll, pWait ); ++ ++ if ( CIRC_CNT( rx_ring.in, rx_ring.out, RBUF_SIZE ) ) ++ retval |= POLLIN | POLLRDNORM; ++ if ( pxa_usb_xmitter_avail() ) ++ retval |= POLLOUT | POLLWRNORM; ++ return retval; ++} ++ ++static int usbc_ioctl( struct inode *pInode, struct file *pFile, ++ unsigned int nCmd, unsigned long argument ) ++{ ++ int retval = 0; ++ ++ switch( nCmd ) { ++ ++ case USBC_IOC_FLUSH_RECEIVER: ++ pxa_usb_recv_reset(); ++ rx_ring.in = rx_ring.out = 0; ++ break; ++ ++ case USBC_IOC_FLUSH_TRANSMITTER: ++ pxa_usb_send_reset(); ++ break; ++ ++ case USBC_IOC_FLUSH_ALL: ++ pxa_usb_recv_reset(); ++ rx_ring.in = rx_ring.out = 0; ++ pxa_usb_send_reset(); ++ break; ++ ++ default: ++ retval = -ENOIOCTLCMD; ++ break; ++ ++ } ++ return retval; ++} ++ ++ ++static int usbc_close( struct inode *pInode, struct file * pFile ) ++{ ++ PRINTK( KERN_DEBUG "%sclose()\n", pszMe ); ++ if ( --usb_ref_count == 0 ) { ++ down( &xmit_sem ); ++ pxa_usb_stop(); ++ free_txrx_buffers(); ++ free_string_descriptors(); ++ del_timer( &tx_timer ); ++ pxa_usb_close(); ++ up( &xmit_sem ); ++ } ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++#ifdef CONFIG_SA1100_EXTENEX1 ++#include "../../../drivers/char/ex_gpio.h" ++void extenex_configured_notify_proc( void ) ++{ ++ if ( exgpio_play_string( "440,1:698,1" ) == -EAGAIN ) ++ printk( "%sWanted to BEEP but ex_gpio not open\n", pszMe ); ++} ++#endif ++////////////////////////////////////////////////////////////////////////////// ++// Initialization ++////////////////////////////////////////////////////////////////////////////// ++ ++static struct file_operations usbc_fops = { ++ owner: THIS_MODULE, ++ open: usbc_open, ++ read: usbc_read, ++ write: usbc_write, ++ poll: usbc_poll, ++ ioctl: usbc_ioctl, ++ release: usbc_close, ++}; ++ ++static struct miscdevice usbc_misc_device = { ++ USBC_MINOR, "usb_char", &usbc_fops ++}; ++ ++/* ++ * usbc_init() ++ */ ++ ++int __init usbc_init( void ) ++{ ++ int rc; ++ ++ if ( (rc = misc_register( &usbc_misc_device )) != 0 ) { ++ printk( KERN_WARNING "%sCould not register device 10, " ++ "%d. (%d)\n", pszMe, USBC_MINOR, rc ); ++ return -EBUSY; ++ } ++ ++ // initialize wait queues ++ init_waitqueue_head( &wq_read ); ++ init_waitqueue_head( &wq_write ); ++ init_waitqueue_head( &wq_poll ); ++ ++ // initialize tx timeout timer ++ init_timer( &tx_timer ); ++ tx_timer.function = tx_timeout; ++ ++ printk( KERN_INFO "USB Function Character Driver Interface" ++ " - %s, (C) 2001, Extenex Corp.\n", VERSION ++ ); ++ ++ return rc; ++} ++ ++void __exit usbc_exit( void ) ++{ ++} ++ ++EXPORT_NO_SYMBOLS; ++ ++module_init(usbc_init); ++module_exit(usbc_exit); ++ ++ ++ ++// end: usb-char.c ++ ++ ++ +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/usb-char.h +@@ -0,0 +1,34 @@ ++/* ++ * Copyright (C) 2001 Extenex Corporation ++ * ++ * usb-char.h ++ * ++ * Character device emulation client for SA-1100 client usb core. ++ * ++ * ++ * ++ */ ++#ifndef _USB_CHAR_H ++#define _USB_CHAR_H ++ ++#define USBC_MAJOR 10 /* miscellaneous character device */ ++#define USBC_MINOR 240 /* in the "reserved for local use" range */ ++ ++#define USBC_MAGIC 0x8E ++ ++/* zap everything in receive ring buffer */ ++#define USBC_IOC_FLUSH_RECEIVER _IO( USBC_MAGIC, 0x01 ) ++ ++/* reset transmitter */ ++#define USBC_IOC_FLUSH_TRANSMITTER _IO( USBC_MAGIC, 0x02 ) ++ ++/* do both of above */ ++#define USBC_IOC_FLUSH_ALL _IO( USBC_MAGIC, 0x03 ) ++ ++ ++ ++ ++ ++ ++#endif /* _USB_CHAR_H */ ++ +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/usb-eth.c +@@ -0,0 +1,479 @@ ++/* ++ * Ethernet driver for the PXA USB client function ++ * Copyright (c) 2001 by Nicolas Pitre ++ * ++ * This code was loosely inspired by the original initial ethernet test driver ++ * Copyright (c) Compaq Computer Corporation, 1999 ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This is still work in progress... ++ * ++ * 19/02/2001 - Now we are compatible with generic usbnet driver. green@iXcelerator.com ++ * 09/03/2001 - Dropped 'framing' scheme, as it seems to cause a lot of problems with little benefit. ++ * Now, since we do not know what size of packet we are receiving ++ * last usb packet in sequence will always be less than max packet ++ * receive endpoint can accept. ++ * Now the only way to check correct start of frame is to compare ++ * MAC address. Also now we are stalling on each receive error. ++ * ++ * 15/03/2001 - Using buffer to get data from UDC. DMA needs to have 8 byte ++ * aligned buffer, but this breaks IP code (unaligned access). ++ * ++ * 01/04/2001 - stall endpoint operations appeared to be very unstable, so ++ * they are disabled now. ++ * ++ * 03/06/2001 - Readded "zerocopy" receive path (tunable). ++ * ++ */ ++ ++// Define DMA_NO_COPY if you want data to arrive directly into the ++// receive network buffers, instead of arriving into bounce buffer ++// and then get copied to network buffer. ++// This does not work correctly right now. ++#undef DMA_NO_COPY ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/sched.h> ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/timer.h> ++ ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/skbuff.h> ++#include <linux/random.h> ++ ++#include "pxa_usb.h" ++ ++ ++#define ETHERNET_VENDOR_ID 0x49f ++#define ETHERNET_PRODUCT_ID 0x505A ++#define MAX_PACKET 32768 ++#define MIN(a, b) (((a) < (b)) ? (a) : (b)) ++ ++// Should be global, so that insmod can change these ++int usb_rsize=64; ++int usb_wsize=64; ++ ++static struct usbe_info_t { ++ struct net_device *dev; ++ u16 packet_id; ++ struct net_device_stats stats; ++} usbe_info; ++ ++static char usb_eth_name[16] = "usbf"; ++static struct net_device usb_eth_device; ++static struct sk_buff *cur_tx_skb, *next_tx_skb; ++static struct sk_buff *cur_rx_skb, *next_rx_skb; ++static volatile int terminating; ++#ifndef DMA_NO_COPY ++static char *dmabuf; // we need that, as dma expect it's buffers to be aligned on 8 bytes boundary ++#endif ++ ++static int usb_change_mtu (struct net_device *net, int new_mtu) ++{ ++ if (new_mtu <= sizeof (struct ethhdr) || new_mtu > MAX_PACKET) ++ return -EINVAL; ++ // no second zero-length packet read wanted after mtu-sized packets ++ if (((new_mtu + sizeof (struct ethhdr)) % usb_rsize) == 0) ++ return -EDOM; ++ ++ net->mtu = new_mtu; ++ return 0; ++} ++ ++static struct sk_buff * ++usb_new_recv_skb(void) ++{ ++ struct sk_buff *skb = alloc_skb( 2 + sizeof (struct ethhdr) + usb_eth_device.mtu,GFP_ATOMIC); ++ ++ if (skb) { ++ skb_reserve(skb, 2); ++ } ++ return skb; ++} ++ ++static u8 bcast_hwaddr[ETH_ALEN]={0xff,0xff,0xff,0xff,0xff,0xff}; ++static void ++usb_recv_callback(int flag, int size) ++{ ++ struct sk_buff *skb; ++ ++ if (terminating) ++ return; ++ ++ skb = cur_rx_skb; ++ ++ /* flag validation */ ++ if (flag == 0) { ++ if ( skb_tailroom (skb) < size ) { // hey! we are overloaded!!! ++ usbe_info.stats.rx_over_errors++; ++ goto error; ++ } ++#ifndef DMA_NO_COPY ++ memcpy(skb->tail,dmabuf,size); ++#endif ++ skb_put(skb, size); ++ } else { ++ if (flag == -EIO) { ++ usbe_info.stats.rx_errors++; ++ } ++ goto error; ++ } ++ ++ ++ /* ++ * If the real size of the packet is divisible by usb_rsize ++ * an extra byte will be added. Thus size == usb_rsize ++ * should only happen if more data is to come. ++ */ ++ /* validate packet length */ ++ if (size == usb_rsize ) { ++ /* packet not complete yet */ ++ skb = NULL; ++ } ++ ++ /* ++ * At this point skb is non null if we have a complete packet. ++ * If so take a fresh skb right away and restart USB receive without ++ * further delays, then process the packet. Otherwise resume USB ++ * receive on the current skb and exit. ++ */ ++ ++ if (skb) ++ cur_rx_skb = next_rx_skb; ++#ifndef DMA_NO_COPY ++ pxa_usb_recv(dmabuf, usb_rsize, ++ usb_recv_callback); ++#else ++ pxa_usb_recv(cur_rx_skb->tail, MIN(usb_rsize, skb_tailroom (cur_rx_skb)), ++ usb_recv_callback); ++#endif ++ if (!skb) ++ return; ++ ++ next_rx_skb = usb_new_recv_skb(); ++ if (!next_rx_skb) { ++ /* ++ * We can't aford loosing buffer space... ++ * So we drop the current packet and recycle its skb. ++ */ ++ printk("%s: can't allocate new skb\n", __FUNCTION__); ++ usbe_info.stats.rx_dropped++; ++ skb_trim(skb, 0); ++ next_rx_skb = skb; ++ return; ++ } ++ if ( skb->len >= sizeof(struct ethhdr)) { ++ if (memcmp(skb->data,usb_eth_device.dev_addr,ETH_ALEN) && memcmp(skb->data,bcast_hwaddr,ETH_ALEN) ) { ++ // This frame is not for us. nor it is broadcast ++ usbe_info.stats.rx_frame_errors++; ++ kfree_skb(skb); ++ goto error; ++ } ++ ++#if 0 ++{ ++ int i; ++ ++ for (i = 0; i < skb->len; i++) ++ { ++ printk("%02X ", skb->data[i]); ++ if( (i%8)==7) printk("\n"); ++ } ++ printk("...\n"); ++} ++#endif ++ ++ } ++ ++ if (skb->len) { ++ int status; ++// FIXME: eth_copy_and_csum "small" packets to new SKB (small < ~200 bytes) ? ++ ++ skb->dev = &usb_eth_device; ++ skb->protocol = eth_type_trans (skb, &usb_eth_device); ++ usbe_info.stats.rx_packets++; ++ usbe_info.stats.rx_bytes += skb->len; ++ skb->ip_summed = CHECKSUM_NONE; ++ status = netif_rx (skb); ++ if (status != NET_RX_SUCCESS) ++ printk("netif_rx failed with code %d\n",status); ++ } else { ++error: ++//printk("ERROR... tailroom=%d size=%d len=%d flag=%d\n", skb_tailroom(skb), size, skb->len, flag); ++ /* ++ * Error due to HW addr mismatch, or IO error. ++ * Recycle the current skb and reset USB reception. ++ */ ++ skb_trim(cur_rx_skb, 0); ++// if ( flag == -EINTR || flag == -EAGAIN ) // only if we are coming out of stall ++#ifndef DMA_NO_COPY ++ pxa_usb_recv(dmabuf, usb_rsize, usb_recv_callback); ++#else ++ pxa_usb_recv(cur_rx_skb->tail, MIN(usb_rsize, skb_tailroom (cur_rx_skb)), usb_recv_callback); ++#endif ++ } ++} ++ ++ ++static void ++usb_send_callback(int flag, int size) ++{ ++ struct net_device *dev = usbe_info.dev; ++ struct net_device_stats *stats; ++ struct sk_buff *skb=cur_tx_skb; ++ int ret; ++ ++ if (terminating) ++ return; ++ ++ stats = &usbe_info.stats; ++ switch (flag) { ++ case 0: ++ stats->tx_packets++; ++ stats->tx_bytes += size; ++ break; ++ case -EIO: ++ stats->tx_errors++; ++ break; ++ default: ++ stats->tx_dropped++; ++ break; ++ } ++ ++ cur_tx_skb = next_tx_skb; ++ next_tx_skb = NULL; ++ dev_kfree_skb_irq(skb); ++ if (!cur_tx_skb) ++ return; ++ ++ dev->trans_start = jiffies; ++ ret = pxa_usb_send(cur_tx_skb->data, cur_tx_skb->len, usb_send_callback); ++ if (ret) { ++ /* If the USB core can't accept the packet, we drop it. */ ++ dev_kfree_skb_irq(cur_tx_skb); ++ cur_tx_skb = NULL; ++ usbe_info.stats.tx_carrier_errors++; ++ } ++ netif_wake_queue(dev); ++} ++ ++static int ++usb_eth_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ int ret; ++ long flags; ++ ++ if (next_tx_skb) { ++ printk("%s: called with next_tx_skb != NULL\n", __FUNCTION__); ++ return 1; ++ } ++ ++ if (skb_shared (skb)) { ++ struct sk_buff *skb2 = skb_unshare(skb, GFP_ATOMIC); ++ if (!skb2) { ++ usbe_info.stats.tx_dropped++; ++ dev_kfree_skb(skb); ++ return 1; ++ } ++ skb = skb2; ++ } ++ ++ if ((skb->len % usb_wsize) == 0) { ++ skb->len++; // other side will ignore this one, anyway. ++ } ++ ++ save_flags_cli(flags); ++ if (cur_tx_skb) { ++ next_tx_skb = skb; ++ netif_stop_queue(dev); ++ } else { ++ cur_tx_skb = skb; ++ dev->trans_start = jiffies; ++ ret = pxa_usb_send(skb->data, skb->len, usb_send_callback); ++ if (ret) { ++ /* If the USB core can't accept the packet, we drop it. */ ++ dev_kfree_skb(skb); ++ cur_tx_skb = NULL; ++ usbe_info.stats.tx_carrier_errors++; ++ } ++ } ++ restore_flags(flags); ++ return 0; ++} ++ ++static void ++usb_xmit_timeout(struct net_device *dev ) ++{ ++ pxa_usb_send_reset(); ++ dev->trans_start = jiffies; ++ netif_wake_queue(dev); ++} ++ ++ ++static int ++usb_eth_open(struct net_device *dev) ++{ ++ int rc; ++ rc = pxa_usb_open( "usb-eth" ); ++ if ( rc == 0 ) { ++ string_desc_t * pstr; ++ desc_t * pd = pxa_usb_get_descriptor_ptr(); ++ ++ pd->b.ep1.wMaxPacketSize = make_word( usb_rsize ); ++ pd->b.ep2.wMaxPacketSize = make_word( usb_wsize ); ++ pd->dev.idVendor = ETHERNET_VENDOR_ID; ++ pd->dev.idProduct = ETHERNET_PRODUCT_ID; ++ pstr = pxa_usb_kmalloc_string_descriptor( "PXA USB NIC" ); ++ if ( pstr ) { ++ pxa_usb_set_string_descriptor( 1, pstr ); ++ pd->dev.iProduct = 1; ++ } ++ rc = pxa_usb_start(); ++ } ++ ++ if( rc == 0) ++ { ++ terminating = 0; ++ cur_tx_skb = next_tx_skb = NULL; ++ cur_rx_skb = usb_new_recv_skb(); ++ next_rx_skb = usb_new_recv_skb(); ++ if (!cur_rx_skb || !next_rx_skb) { ++ printk("%s: can't allocate new skb\n", __FUNCTION__); ++ if (cur_rx_skb) ++ kfree_skb(cur_rx_skb); ++ if (next_rx_skb) ++ kfree_skb(next_rx_skb); ++ ++ pxa_usb_stop(); ++ pxa_usb_close(); ++ return -ENOMEM;; ++ } ++ ++ MOD_INC_USE_COUNT; ++#ifndef DMA_NO_COPY ++ pxa_usb_recv(dmabuf, usb_rsize, usb_recv_callback); ++#else ++ pxa_usb_recv(cur_rx_skb->tail, MIN(usb_rsize, skb_tailroom (cur_rx_skb)), ++ usb_recv_callback); ++#endif ++ } ++ ++ return rc; ++} ++ ++static int ++usb_eth_release(struct net_device *dev) ++{ ++ string_desc_t * pstr; ++ ++ terminating = 1; ++ pxa_usb_send_reset(); ++ pxa_usb_recv_reset(); ++ if (cur_tx_skb) ++ kfree_skb(cur_tx_skb); ++ if (next_tx_skb) ++ kfree_skb(next_tx_skb); ++ if (cur_rx_skb) ++ kfree_skb(cur_rx_skb); ++ if (next_rx_skb) ++ kfree_skb(next_rx_skb); ++ ++ pxa_usb_stop(); ++ pxa_usb_close(); ++ if ( (pstr = pxa_usb_get_string_descriptor(1)) != NULL ) ++ kfree( pstr ); ++ ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++static struct net_device_stats * ++usb_eth_stats(struct net_device *dev) ++{ ++ struct usbe_info_t *priv = (struct usbe_info_t*) dev->priv; ++ struct net_device_stats *stats=NULL; ++ ++ if (priv) ++ stats = &priv->stats; ++ return stats; ++} ++ ++static int ++usb_eth_probe(struct net_device *dev) ++{ ++ u8 node_id [ETH_ALEN]; ++ ++ get_random_bytes (node_id, sizeof node_id); ++ node_id [0] &= 0xfe; // clear multicast bit ++ ++ /* ++ * Assign the hardware address of the board: ++ * generate it randomly, as there can be many such ++ * devices on the bus. ++ */ ++ memcpy (dev->dev_addr, node_id, sizeof node_id); ++ ++ dev->open = usb_eth_open; ++ dev->change_mtu = usb_change_mtu; ++ dev->stop = usb_eth_release; ++ dev->hard_start_xmit = usb_eth_xmit; ++ dev->get_stats = usb_eth_stats; ++ dev->watchdog_timeo = 1*HZ; ++ dev->tx_timeout = usb_xmit_timeout; ++ dev->priv = &usbe_info; ++ ++ usbe_info.dev = dev; ++ ++ /* clear the statistics */ ++ memset(&usbe_info.stats, 0, sizeof(struct net_device_stats)); ++ ++ ether_setup(dev); ++ dev->flags &= ~IFF_MULTICAST; ++ dev->flags &= ~IFF_BROADCAST; ++ //dev->flags |= IFF_NOARP; ++ ++ return 0; ++} ++ ++#ifdef MODULE ++MODULE_PARM(usb_rsize, "1i"); ++MODULE_PARM_DESC(usb_rsize, "number of bytes in packets from host to pxa"); ++MODULE_PARM(usb_wsize, "1i"); ++MODULE_PARM_DESC(usb_wsize, "number of bytes in packets from pxa to host"); ++#endif ++ ++static int __init ++usb_eth_init(void) ++{ ++#ifndef DMA_NO_COPY ++ dmabuf = kmalloc( usb_rsize, GFP_KERNEL | GFP_DMA ); ++ if (!dmabuf) ++ return -ENOMEM; ++#endif ++ strncpy(usb_eth_device.name, usb_eth_name, IFNAMSIZ); ++ usb_eth_device.init = usb_eth_probe; ++ if (register_netdev(&usb_eth_device) != 0) ++ return -EIO; ++ ++ printk( KERN_INFO "USB Function Ethernet Driver Interface\n"); ++ ++ return 0; ++} ++ ++static void __exit ++usb_eth_cleanup(void) ++{ ++#ifndef DMA_NO_COPY ++ kfree(dmabuf); ++#endif ++ unregister_netdev(&usb_eth_device); ++} ++ ++module_init(usb_eth_init); ++module_exit(usb_eth_cleanup); +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/usb_ctl.c +@@ -0,0 +1,769 @@ ++/* ++ * Copyright (C) Compaq Computer Corporation, 1998, 1999 ++ * Copyright (C) Extenex Corporation, 2001 ++ * Copyright (C) Intrinsyc, Inc., 2002 ++ * ++ * PXA USB controller core driver. ++ * ++ * This file provides interrupt routing and overall coordination ++ * of the endpoints. ++ * ++ * Please see: ++ * linux/Documentation/arm/SA1100/SA1100_USB ++ * for more info. ++ * ++ * 02-May-2002 ++ * Frank Becker (Intrinsyc) - derived from sa1100 usb_ctl.c ++ * ++ */ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/proc_fs.h> ++#include <linux/tqueue.h> ++#include <linux/delay.h> ++#include <linux/slab.h> ++#include <asm/io.h> ++#include <asm/dma.h> ++#include <asm/irq.h> ++#include <asm/mach-types.h> ++ ++#include "pxa_usb.h" ++#include "usb_ctl.h" ++ ++//#define DEBUG 1 ++ ++#if DEBUG ++static unsigned int usb_debug = DEBUG; ++#else ++#define usb_debug 0 /* gcc will remove all the debug code for us */ ++#endif ++ ++////////////////////////////////////////////////////////////////////////////// ++// Prototypes ++////////////////////////////////////////////////////////////////////////////// ++ ++int usbctl_next_state_on_event( int event ); ++static void udc_int_hndlr(int, void *, struct pt_regs *); ++static void initialize_descriptors( void ); ++static void soft_connect_hook( int enable ); ++static void udc_disable(void); ++static void udc_enable(void); ++ ++#if CONFIG_PROC_FS ++#define PROC_NODE_NAME "driver/pxausb" ++static int usbctl_read_proc(char *page, char **start, off_t off, ++ int count, int *eof, void *data); ++#endif ++ ++////////////////////////////////////////////////////////////////////////////// ++// Globals ++////////////////////////////////////////////////////////////////////////////// ++static const char pszMe[] = "usbctl: "; ++struct usb_info_t usbd_info; /* global to ep0, usb_recv, usb_send */ ++ ++/* device descriptors */ ++static desc_t desc; ++ ++#define MAX_STRING_DESC 8 ++static string_desc_t * string_desc_array[ MAX_STRING_DESC ]; ++static string_desc_t sd_zero; /* special sd_zero holds language codes */ ++ ++// called when configured ++static usb_notify_t configured_callback = NULL; ++ ++enum { ++ kStateZombie = 0, ++ kStateZombieSuspend = 1, ++ kStateDefault = 2, ++ kStateDefaultSuspend = 3, ++ kStateAddr = 4, ++ kStateAddrSuspend = 5, ++ kStateConfig = 6, ++ kStateConfigSuspend = 7 ++}; ++ ++/* ++ * FIXME: The PXA UDC handles several host device requests without user ++ * notification/intervention. The table could be collapsed quite a bit... ++ */ ++static int device_state_machine[8][6] = { ++// suspend reset resume adddr config deconfig ++/* zombie */ { kStateZombieSuspend , kStateDefault, kStateZombie , kError , kError , kError }, ++/* zom sus */ { kStateZombieSuspend , kStateDefault, kStateZombie , kError , kError , kError }, ++/* default */ { kStateDefaultSuspend, kStateDefault, kStateDefault, kStateAddr, kStateConfig, kError }, ++/* def sus */ { kStateDefaultSuspend, kStateDefault, kStateDefault, kError , kError , kError }, ++/* addr */ { kStateAddrSuspend , kStateDefault, kStateAddr , kError , kStateConfig, kError }, ++/* addr sus */{ kStateAddrSuspend , kStateDefault, kStateAddr , kError , kError , kError }, ++/* config */ { kStateConfigSuspend , kStateDefault, kStateConfig , kError , kError , kStateDefault }, ++/* cfg sus */ { kStateConfigSuspend , kStateDefault, kStateConfig , kError , kError , kError } ++}; ++ ++/* "device state" is the usb device framework state, as opposed to the ++ "state machine state" which is whatever the driver needs and is much ++ more fine grained ++*/ ++static int sm_state_to_device_state[8] = { ++// zombie zom suspend ++USB_STATE_POWERED, USB_STATE_SUSPENDED, ++// default default sus ++USB_STATE_DEFAULT, USB_STATE_SUSPENDED, ++// addr addr sus ++USB_STATE_ADDRESS, USB_STATE_SUSPENDED, ++// config config sus ++USB_STATE_CONFIGURED, USB_STATE_SUSPENDED ++}; ++ ++static char * state_names[8] = ++{ "zombie", "zombie suspended", ++ "default", "default suspended", ++ "address", "address suspended", ++ "configured", "config suspended" ++}; ++ ++static char * event_names[6] = ++{ "suspend", "reset", "resume", ++ "address assigned", "configure", "de-configure" ++}; ++ ++static char * device_state_names[] = ++{ "not attached", "attached", "powered", "default", ++ "address", "configured", "suspended" }; ++ ++static int sm_state = kStateZombie; ++ ++////////////////////////////////////////////////////////////////////////////// ++// Async ++////////////////////////////////////////////////////////////////////////////// ++ ++/* The UDCCR reg contains mask and interrupt status bits, ++ * so using '|=' isn't safe as it may ack an interrupt. ++ */ ++ ++void udc_set_mask_UDCCR( int mask ) ++{ ++ UDCCR = (UDCCR & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS); ++} ++ ++void udc_clear_mask_UDCCR( int mask) ++{ ++ UDCCR = (UDCCR & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS); ++} ++ ++void udc_ack_int_UDCCR( int mask) ++{ ++ /* udccr contains the bits we dont want to change */ ++ __u32 udccr = UDCCR & UDCCR_MASK_BITS; ++ ++ UDCCR = udccr | (mask & ~UDCCR_MASK_BITS); ++} ++ ++static void ++udc_int_hndlr(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ __u32 status = UDCCR; ++ __u32 ir0_status = USIR0; ++ __u32 ir1_status = USIR1; ++ __u32 uicr0 = UICR0; ++ __u32 uicr1 = UICR1; ++ ++ //mask ints ++ udc_set_mask_UDCCR( UDCCR_REM | UDCCR_SRM); ++ UICR0 = 0xff; ++ UICR1 = 0xff; ++ ++ if( usb_debug > 2) ++ { ++ printk("%s--- udc_int_hndlr\n" ++ "UDCCR=0x%08x UDCCS0=0x%08x UDCCS1=0x%08x UDCCS2=0x%08x\n" ++ "USIR0=0x%08x USIR1=0x%08x UICR0=0x%08x UICR1=0x%08x\n", ++ pszMe, status, UDCCS0, UDCCS1, UDCCS2, ir0_status, ir1_status, uicr0, uicr1); ++ } ++ ++ /* SUSpend Interrupt Request */ ++ if ( status & UDCCR_SUSIR ) ++ { ++ udc_ack_int_UDCCR( UDCCR_SUSIR); ++ if( usb_debug) printk("%sSuspend...\n", pszMe); ++ usbctl_next_state_on_event( kEvSuspend ); ++ } ++ ++ /* RESume Interrupt Request */ ++ if ( status & UDCCR_RESIR ) ++ { ++ udc_ack_int_UDCCR( UDCCR_RESIR); ++ if( usb_debug) printk("%sResume...\n", pszMe); ++ usbctl_next_state_on_event( kEvResume ); ++ } ++ ++ /* ReSeT Interrupt Request - UDC has been reset */ ++ if ( status & UDCCR_RSTIR ) ++ { ++ /* clear the reset interrupt */ ++ udc_ack_int_UDCCR( UDCCR_RSTIR); ++ ++ /* check type of reset */ ++ if( (UDCCR & UDCCR_UDA) == 0) ++ { ++ /* reset assertion took place, nothing to do */ ++ if( usb_debug) printk("%sReset assertion...\n", pszMe); ++ } ++ ++ /* ok, it's a reset negation, go on with reset */ ++ else if ( usbctl_next_state_on_event( kEvReset ) != kError ) ++ { ++ /* starting reset sequence now... */ ++ if( usb_debug) printk("%sResetting\n", pszMe); ++ ++ ep0_reset(); ++ ep_bulk_in1_reset(); ++ ep_bulk_out1_reset(); ++ ++ usbctl_next_state_on_event( kEvConfig ); ++ } ++ else ++ { ++ printk("%sUnexpected reset\n", pszMe); ++ } ++ } ++ else ++ { ++ /* ep0 int */ ++ if (ir0_status & USIR0_IR0) ++ ep0_int_hndlr(); ++ ++ /* transmit bulk */ ++ if (ir0_status & USIR0_IR1) ++ ep_bulk_in1_int_hndlr(ir0_status); ++ ++ /* receive bulk */ ++ if ( ir0_status & USIR0_IR2) ++ ep_bulk_out1_int_hndlr(ir0_status); ++ ++ while (UDCCS2 & UDCCS_BO_RNE) ++ { ++ if( usb_debug) printk("More Bulk-out data...\n"); ++ ep_bulk_out1_int_hndlr(ir0_status); ++ } ++ } ++ ++ UICR0 = uicr0; ++ UICR1 = uicr1; ++ udc_clear_mask_UDCCR( UDCCR_SRM | UDCCR_REM); /* enable suspend/resume, reset */ ++ ++ /* clear all endpoint ints */ ++ USIR0 |= 0xff; ++ USIR1 |= 0xff; ++ ++ if( usb_debug > 2) ++ { ++ printk("%sudc_int_hndlr\n" ++ "UDCCR=0x%08x UDCCS0=0x%08x UDCCS1=0x%08x UDCCS2=0x%08x\n" ++ "USIR0=0x%08x USIR1=0x%08x UICR0=0x%08x UICR1=0x%08x\n", ++ pszMe, UDCCR, UDCCS0, UDCCS1, UDCCS2, USIR0, USIR1, UICR0, UICR1); ++ } ++} ++ ++////////////////////////////////////////////////////////////////////////////// ++// Public Interface ++////////////////////////////////////////////////////////////////////////////// ++ ++/* Open PXA usb core on behalf of a client, but don't start running */ ++ ++int ++pxa_usb_open( const char * client ) ++{ ++ if ( usbd_info.client_name != NULL ) ++ { ++ printk( "%sUnable to register %s (%s already registered).\n", ++ pszMe, client, usbd_info.client_name ); ++ return -EBUSY; ++ } ++ ++ usbd_info.client_name = (char*) client; ++ memset(&usbd_info.stats, 0, sizeof(struct usb_stats_t)); ++ memset(string_desc_array, 0, sizeof(string_desc_array)); ++ ++ /* hack to start in zombie suspended state */ ++ sm_state = kStateZombieSuspend; ++ usbd_info.state = USB_STATE_SUSPENDED; ++ ++ /* create descriptors for enumeration */ ++ initialize_descriptors(); ++ ++ printk( "%s%s registered.\n", pszMe, client ); ++ return 0; ++} ++ ++/* Start running. Must have called usb_open (above) first */ ++int ++pxa_usb_start( void ) ++{ ++ if ( usbd_info.client_name == NULL ) { ++ printk( "%s%s - no client registered\n", ++ pszMe, __FUNCTION__ ); ++ return -EPERM; ++ } ++ ++ /* start UDC internal machinery running */ ++ udc_enable(); ++ udelay( 100 ); ++ ++ /* flush DMA and fire through some -EAGAINs */ ++ ep_bulk_out1_init( usbd_info.dmach_rx ); ++ ep_bulk_in1_init( usbd_info.dmach_tx ); ++ ++ /* give endpoint notification we are starting */ ++ ep_bulk_out1_state_change_notify( USB_STATE_SUSPENDED ); ++ ep_bulk_in1_state_change_notify( USB_STATE_SUSPENDED ); ++ ++ /* enable any platform specific hardware */ ++ soft_connect_hook( 1 ); ++ ++ /* enable suspend/resume, reset */ ++ udc_clear_mask_UDCCR( UDCCR_SRM | UDCCR_REM); ++ /* enable ep0, ep1, ep2 */ ++ UICR0 &= ~(UICR0_IM0 | UICR0_IM1 | UICR0_IM2); ++ ++ if( usb_debug) printk( "%sStarted %s\n", pszMe, usbd_info.client_name ); ++ return 0; ++} ++ ++/* Stop USB core from running */ ++int ++pxa_usb_stop( void ) ++{ ++ if ( usbd_info.client_name == NULL ) { ++ printk( "%s%s - no client registered\n", ++ pszMe, __FUNCTION__ ); ++ return -EPERM; ++ } ++ /* mask everything */ ++ /* disable suspend/resume, reset */ ++ udc_set_mask_UDCCR( UDCCR_SRM | UDCCR_REM); ++ /* disable ep0, ep1, ep2 */ ++ UICR0 |= (UICR0_IM0 | UICR0_IM1 | UICR0_IM2); ++ ++ ep_bulk_out1_reset(); ++ ep_bulk_in1_reset(); ++ ++ udc_disable(); ++ if( usb_debug) printk( "%sStopped %s\n", pszMe, usbd_info.client_name ); ++ return 0; ++} ++ ++/* Tell PXA core client is through using it */ ++int ++pxa_usb_close( void ) ++{ ++ if ( usbd_info.client_name == NULL ) { ++ printk( "%s%s - no client registered\n", ++ pszMe, __FUNCTION__ ); ++ return -EPERM; ++ } ++ printk( "%s%s closed.\n", pszMe, (char*)usbd_info.client_name ); ++ usbd_info.client_name = NULL; ++ return 0; ++} ++ ++/* set a proc to be called when device is configured */ ++usb_notify_t pxa_set_configured_callback( usb_notify_t func ) ++{ ++ usb_notify_t retval = configured_callback; ++ configured_callback = func; ++ return retval; ++} ++ ++/*==================================================== ++ * Descriptor Manipulation. ++ * Use these between open() and start() above to setup ++ * the descriptors for your device. ++ * ++ */ ++ ++/* get pointer to static default descriptor */ ++desc_t * ++pxa_usb_get_descriptor_ptr( void ) { return &desc; } ++ ++/* optional: set a string descriptor */ ++int ++pxa_usb_set_string_descriptor( int i, string_desc_t * p ) ++{ ++ int retval; ++ if ( i < MAX_STRING_DESC ) { ++ string_desc_array[i] = p; ++ retval = 0; ++ } else { ++ retval = -EINVAL; ++ } ++ return retval; ++} ++ ++/* optional: get a previously set string descriptor */ ++string_desc_t * ++pxa_usb_get_string_descriptor( int i ) ++{ ++ return ( i < MAX_STRING_DESC ) ++ ? string_desc_array[i] ++ : NULL; ++} ++ ++ ++/* optional: kmalloc and unicode up a string descriptor */ ++string_desc_t * ++pxa_usb_kmalloc_string_descriptor( const char * p ) ++{ ++ string_desc_t * pResult = NULL; ++ ++ if ( p ) { ++ int len = strlen( p ); ++ int uni_len = len * sizeof( __u16 ); ++ pResult = (string_desc_t*) kmalloc( uni_len + 2, GFP_KERNEL ); /* ugh! */ ++ if ( pResult != NULL ) { ++ int i; ++ pResult->bLength = uni_len + 2; ++ pResult->bDescriptorType = USB_DESC_STRING; ++ for( i = 0; i < len ; i++ ) { ++ pResult->bString[i] = make_word( (__u16) p[i] ); ++ } ++ } ++ } ++ return pResult; ++} ++ ++////////////////////////////////////////////////////////////////////////////// ++// Exports to rest of driver ++////////////////////////////////////////////////////////////////////////////// ++ ++/* called by the int handler here and the two endpoint files when interesting ++ .."events" happen */ ++ ++int ++usbctl_next_state_on_event( int event ) ++{ ++ int next_state = device_state_machine[ sm_state ][ event ]; ++ if ( next_state != kError ) ++ { ++ int next_device_state = sm_state_to_device_state[ next_state ]; ++ if( usb_debug) printk( "%s%s --> [%s] --> %s. Device in %s state.\n", ++ pszMe, state_names[ sm_state ], event_names[ event ], ++ state_names[ next_state ], device_state_names[ next_device_state ] ); ++ ++ sm_state = next_state; ++ if ( usbd_info.state != next_device_state ) ++ { ++ if ( configured_callback != NULL ++ && ++ next_device_state == USB_STATE_CONFIGURED ++ && ++ usbd_info.state != USB_STATE_SUSPENDED ++ ) { ++ configured_callback(); ++ } ++ usbd_info.state = next_device_state; ++ ++ ep_bulk_out1_state_change_notify( next_device_state ); ++ ep_bulk_in1_state_change_notify( next_device_state ); ++ } ++ } ++#if 1 ++ else ++ printk( "%s%s --> [%s] --> ??? is an error.\n", ++ pszMe, state_names[ sm_state ], event_names[ event ] ); ++#endif ++ return next_state; ++} ++ ++////////////////////////////////////////////////////////////////////////////// ++// Private Helpers ++////////////////////////////////////////////////////////////////////////////// ++ ++/* setup default descriptors */ ++ ++static void ++initialize_descriptors(void) ++{ ++ desc.dev.bLength = sizeof( device_desc_t ); ++ desc.dev.bDescriptorType = USB_DESC_DEVICE; ++ desc.dev.bcdUSB = 0x100; /* 1.0 */ ++ desc.dev.bDeviceClass = 0xFF; /* vendor specific */ ++ desc.dev.bDeviceSubClass = 0; ++ desc.dev.bDeviceProtocol = 0; ++ desc.dev.bMaxPacketSize0 = 16; /* ep0 max fifo size */ ++ desc.dev.idVendor = 0; /* vendor ID undefined */ ++ desc.dev.idProduct = 0; /* product */ ++ desc.dev.bcdDevice = 0; /* vendor assigned device release num */ ++ desc.dev.iManufacturer = 0; /* index of manufacturer string */ ++ desc.dev.iProduct = 0; /* index of product description string */ ++ desc.dev.iSerialNumber = 0; /* index of string holding product s/n */ ++ desc.dev.bNumConfigurations = 1; ++ ++ desc.b.cfg.bLength = sizeof( config_desc_t ); ++ desc.b.cfg.bDescriptorType = USB_DESC_CONFIG; ++ desc.b.cfg.wTotalLength = make_word_c( sizeof(struct cdb) ); ++ desc.b.cfg.bNumInterfaces = 1; ++ desc.b.cfg.bConfigurationValue = 1; ++ desc.b.cfg.iConfiguration = 0; ++ desc.b.cfg.bmAttributes = USB_CONFIG_BUSPOWERED; ++ desc.b.cfg.MaxPower = USB_POWER( 500 ); ++ ++ desc.b.intf.bLength = sizeof( intf_desc_t ); ++ desc.b.intf.bDescriptorType = USB_DESC_INTERFACE; ++ desc.b.intf.bInterfaceNumber = 0; /* unique intf index*/ ++ desc.b.intf.bAlternateSetting = 0; ++ desc.b.intf.bNumEndpoints = 2; ++ desc.b.intf.bInterfaceClass = 0xFF; /* vendor specific */ ++ desc.b.intf.bInterfaceSubClass = 0; ++ desc.b.intf.bInterfaceProtocol = 0; ++ desc.b.intf.iInterface = 0; ++ ++/* ++ * FIXME... ++ * The host usbnet driver expects EP1=out EP2=in. On the PXA UDC EP1=in, EP2=out ++ */ ++ desc.b.ep1.bLength = sizeof( ep_desc_t ); ++ desc.b.ep1.bDescriptorType = USB_DESC_ENDPOINT; ++ desc.b.ep1.bEndpointAddress = USB_EP_ADDRESS( 1, USB_IN ); ++ desc.b.ep1.bmAttributes = USB_EP_BULK; ++ desc.b.ep1.wMaxPacketSize = make_word_c( 64 ); ++ desc.b.ep1.bInterval = 0; ++ ++ desc.b.ep2.bLength = sizeof( ep_desc_t ); ++ desc.b.ep2.bDescriptorType = USB_DESC_ENDPOINT; ++ desc.b.ep2.bEndpointAddress = USB_EP_ADDRESS( 2, USB_OUT ); ++ desc.b.ep2.bmAttributes = USB_EP_BULK; ++ desc.b.ep2.wMaxPacketSize = make_word_c( 64 ); ++ desc.b.ep2.bInterval = 0; ++ ++// FIXME: Add support for all endpoint... ++ ++ /* set language */ ++ /* See: http://www.usb.org/developers/data/USB_LANGIDs.pdf */ ++ sd_zero.bDescriptorType = USB_DESC_STRING; ++ sd_zero.bLength = sizeof( string_desc_t ); ++ sd_zero.bString[0] = make_word_c( 0x409 ); /* American English */ ++ pxa_usb_set_string_descriptor( 0, &sd_zero ); ++} ++ ++/* soft_connect_hook() ++ * Some devices have platform-specific circuitry to make USB ++ * not seem to be plugged in, even when it is. This allows ++ * software to control when a device 'appears' on the USB bus ++ * (after Linux has booted and this driver has loaded, for ++ * example). If you have such a circuit, control it here. ++ */ ++static void ++soft_connect_hook( int enable ) ++{ ++} ++ ++/* disable the UDC at the source */ ++static void ++udc_disable(void) ++{ ++ soft_connect_hook( 0 ); ++ /* clear UDC-enable */ ++ udc_clear_mask_UDCCR( UDCCR_UDE); ++ ++ /* Disable clock for USB device */ ++ CKEN &= ~CKEN11_USB; ++} ++ ++ ++/* enable the udc at the source */ ++static void ++udc_enable(void) ++{ ++ /* Enable clock for USB device */ ++ CKEN |= CKEN11_USB; ++ ++ /* try to clear these bits before we enable the udc */ ++ udc_ack_int_UDCCR( UDCCR_SUSIR); ++ udc_ack_int_UDCCR( UDCCR_RSTIR); ++ udc_ack_int_UDCCR( UDCCR_RESIR); ++ ++ /* set UDC-enable */ ++ udc_set_mask_UDCCR( UDCCR_UDE); ++ if( (UDCCR & UDCCR_UDA) == 0) ++ { ++ /* There's a reset on the bus, ++ * clear the interrupt bit and keep going ++ */ ++ udc_ack_int_UDCCR( UDCCR_RSTIR); ++ } ++ ++ /* "USB test mode" to work around errata 40-42 (stepping a0, a1) ++ * which could result in missing packets and interrupts. ++ * Supposedly this turns off double buffering for all endpoints. ++ */ ++ if( usb_debug) printk( "USB RES1=%x RES2=%x RES3=%x\n", UDC_RES1, UDC_RES2, UDC_RES3); ++ UDC_RES1 = 0x00; ++ UDC_RES2 = 0x00; ++ if( usb_debug) printk( "USB RES1=%x RES2=%x RES3=%x\n", UDC_RES1, UDC_RES2, UDC_RES3); ++} ++ ++////////////////////////////////////////////////////////////////////////////// ++// Proc Filesystem Support ++////////////////////////////////////////////////////////////////////////////// ++ ++#if CONFIG_PROC_FS ++ ++#define SAY( fmt, args... ) p += sprintf(p, fmt, ## args ) ++#define SAYV( num ) p += sprintf(p, num_fmt, "Value", num ) ++#define SAYC( label, yn ) p += sprintf(p, yn_fmt, label, yn ) ++#define SAYS( label, v ) p += sprintf(p, cnt_fmt, label, v ) ++ ++static int usbctl_read_proc(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ const char * num_fmt = "%25.25s: %8.8lX\n"; ++ const char * cnt_fmt = "%25.25s: %lu\n"; ++ const char * yn_fmt = "%25.25s: %s\n"; ++ const char * yes = "YES"; ++ const char * no = "NO"; ++ unsigned long v; ++ char * p = page; ++ int len; ++ ++ SAY( "PXA USB Controller Core\n" ); ++ SAY( "Active Client: %s\n", usbd_info.client_name ? usbd_info.client_name : "none"); ++ SAY( "USB state: %s (%s) %d\n", ++ device_state_names[ sm_state_to_device_state[ sm_state ] ], ++ state_names[ sm_state ], ++ sm_state ); ++ ++ SAYS( "ep0 bytes read", usbd_info.stats.ep0_bytes_read ); ++ SAYS( "ep0 bytes written", usbd_info.stats.ep0_bytes_written ); ++ SAYS( "ep0 FIFO read failures", usbd_info.stats.ep0_fifo_write_failures ); ++ SAYS( "ep0 FIFO write failures", usbd_info.stats.ep0_fifo_write_failures ); ++ ++ SAY( "\n" ); ++ ++ v = UDCCR; ++ SAY( "\nUDC Control Register\n" ); ++ SAYV( v ); ++ SAYC( "UDC Enabled", ( v & UDCCR_UDE ) ? yes : no ); ++ SAYC( "UDC Active", ( v & UDCCR_UDA ) ? yes : no ); ++ SAYC( "Suspend/Resume interrupts masked", ( v & UDCCR_SRM ) ? yes : no ); ++ SAYC( "Reset interrupts masked", ( v & UDCCR_REM ) ? yes : no ); ++ SAYC( "Reset pending", ( v & UDCCR_RSTIR ) ? yes : no ); ++ SAYC( "Suspend pending", ( v & UDCCR_SUSIR ) ? yes : no ); ++ SAYC( "Resume pending", ( v & UDCCR_RESIR ) ? yes : no ); ++ ++ len = ( p - page ) - off; ++ if ( len < 0 ) ++ len = 0; ++ *eof = ( len <=count ) ? 1 : 0; ++ *start = page + off; ++ return len; ++} ++ ++#endif /* CONFIG_PROC_FS */ ++ ++#if 0 ++static void irq_handler(int channel, void *data, struct pt_regs *regs) ++{ ++ if( channel == usbd_info.dmach_rx) ++ { ++ printk( "USB receive DMA\n"); ++ } ++ else if( channel == usbd_info.dmach_tx) ++ { ++ printk( "USB transmit DMA\n"); ++ } ++ else ++ { ++ printk( "USB unknown DMA channel\n"); ++ } ++} ++#endif ++ ++////////////////////////////////////////////////////////////////////////////// ++// Module Initialization and Shutdown ++////////////////////////////////////////////////////////////////////////////// ++/* ++ * usbctl_init() ++ * Module load time. Allocate dma and interrupt resources. Setup /proc fs ++ * entry. Leave UDC disabled. ++ */ ++int __init usbctl_init( void ) ++{ ++ int retval = 0; ++ ++ udc_disable(); ++ ++ memset( &usbd_info, 0, sizeof( usbd_info ) ); ++ ++#if CONFIG_PROC_FS ++ create_proc_read_entry ( PROC_NODE_NAME, 0, NULL, usbctl_read_proc, NULL); ++#endif ++ ++#if 0 ++ /* setup rx dma */ ++ usbd_info.dmach_rx = pxa_request_dma("USB receive", DMA_PRIO_MEDIUM, irq_handler, 0 /*data; DMA_Ser0UDCRd*/); ++ if (usbd_info.dmach_rx < 0) { ++ printk("%sunable to register for rx dma rc=%d\n", pszMe, usbd_info.dmach_rx ); ++ goto err_rx_dma; ++ } ++ ++ /* setup tx dma */ ++ usbd_info.dmach_tx = pxa_request_dma("USB receive", DMA_PRIO_MEDIUM, irq_handler, 0 /*data; DMA_Ser0UDCRd*/); ++ if (usbd_info.dmach_tx < 0) { ++ printk("%sunable to register for tx dma rc=%d\n",pszMe,usbd_info.dmach_tx); ++ goto err_tx_dma; ++ } ++#endif ++ ++ /* now allocate the IRQ. */ ++ retval = request_irq(IRQ_USB, udc_int_hndlr, SA_INTERRUPT, "PXA USB core", NULL); ++ if (retval) { ++ printk("%sCouldn't request USB irq rc=%d\n",pszMe, retval); ++ goto err_irq; ++ } ++ ++ printk( "PXA USB Controller Core Initialized\n"); ++ return 0; ++ ++err_irq: ++#if 0 ++ pxa_free_dma(usbd_info.dmach_tx); ++ usbd_info.dmach_tx = 0; ++err_tx_dma: ++ pxa_free_dma(usbd_info.dmach_rx); ++ usbd_info.dmach_rx = 0; ++err_rx_dma: ++#endif ++ return retval; ++} ++/* ++ * usbctl_exit() ++ * Release DMA and interrupt resources ++ */ ++void __exit usbctl_exit( void ) ++{ ++ printk("Unloading PXA USB Controller\n"); ++ ++ udc_disable(); ++ ++#if CONFIG_PROC_FS ++ remove_proc_entry ( PROC_NODE_NAME, NULL); ++#endif ++ ++ pxa_free_dma(usbd_info.dmach_rx); ++ pxa_free_dma(usbd_info.dmach_tx); ++ free_irq(IRQ_USB, NULL); ++} ++ ++module_init( usbctl_init ); ++module_exit( usbctl_exit ); ++ ++EXPORT_SYMBOL( pxa_usb_open ); ++EXPORT_SYMBOL( pxa_usb_start ); ++EXPORT_SYMBOL( pxa_usb_stop ); ++EXPORT_SYMBOL( pxa_usb_close ); ++EXPORT_SYMBOL( pxa_usb_get_descriptor_ptr ); ++EXPORT_SYMBOL( pxa_usb_set_string_descriptor ); ++EXPORT_SYMBOL( pxa_usb_get_string_descriptor ); ++EXPORT_SYMBOL( pxa_usb_kmalloc_string_descriptor ); +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/usb_ctl.h +@@ -0,0 +1,89 @@ ++/* ++ * Copyright (C) Compaq Computer Corporation, 1998, 1999 ++ * Copyright (C) Extenex Corporation 2001 ++ * Copyright (C) Intrinsyc, Inc., 2002 ++ * ++ * usb_ctl.h ++ * ++ * PRIVATE interface used to share info among components of the PXA USB ++ * core: usb_ctl, usb_ep0, usb_recv and usb_send. Clients of the USB core ++ * should use pxa_usb.h. ++ * ++ * 02-May-2002 ++ * Frank Becker (Intrinsyc) - derived from sa1100 usb_ctl.h ++ * ++ */ ++ ++#ifndef _USB_CTL_H ++#define _USB_CTL_H ++ ++/* Interrupt mask bits and UDC enable bit */ ++#define UDCCR_MASK_BITS (UDCCR_REM | UDCCR_SRM | UDCCR_UDE) ++ ++/* ++ * These states correspond to those in the USB specification v1.0 ++ * in chapter 8, Device Framework. ++ */ ++enum { ++ USB_STATE_NOTATTACHED =0, ++ USB_STATE_ATTACHED =1, ++ USB_STATE_POWERED =2, ++ USB_STATE_DEFAULT =3, ++ USB_STATE_ADDRESS =4, ++ USB_STATE_CONFIGURED =5, ++ USB_STATE_SUSPENDED =6 ++}; ++ ++struct usb_stats_t { ++ unsigned long ep0_fifo_write_failures; ++ unsigned long ep0_bytes_written; ++ unsigned long ep0_fifo_read_failures; ++ unsigned long ep0_bytes_read; ++}; ++ ++struct usb_info_t ++{ ++ char * client_name; ++ dmach_t dmach_tx, dmach_rx; ++ int state; ++ unsigned char address; ++ struct usb_stats_t stats; ++}; ++ ++/* in usb_ctl.c */ ++extern struct usb_info_t usbd_info; ++ ++/* ++ * Function Prototypes ++ */ ++enum { ++ kError =-1, ++ kEvSuspend =0, ++ kEvReset =1, ++ kEvResume =2, ++ kEvAddress =3, ++ kEvConfig =4, ++ kEvDeConfig =5 ++}; ++int usbctl_next_state_on_event( int event ); ++ ++/* endpoint zero */ ++void ep0_reset(void); ++void ep0_int_hndlr(void); ++ ++/* receiver */ ++void ep_bulk_out1_state_change_notify( int new_state ); ++int ep_bulk_out1_recv(void); ++int ep_bulk_out1_init(int chn); ++void ep_bulk_out1_int_hndlr(int status); ++void ep_bulk_out1_reset(void); ++void ep_bulk_out1_stall(void); ++ ++/* xmitter */ ++void ep_bulk_in1_state_change_notify( int new_state ); ++void ep_bulk_in1_reset(void); ++int ep_bulk_in1_init(int chn); ++void ep_bulk_in1_int_hndlr(int status); ++void ep_bulk_in1_stall(void); ++ ++#endif /* _USB_CTL_H */ +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/usb_ep0.c +@@ -0,0 +1,556 @@ ++/* ++ * Copyright (C) Extenex Corporation 2001 ++ * Copyright (C) Compaq Computer Corporation, 1998, 1999 ++ * Copyright (C) Intrinsyc, Inc., 2002 ++ * ++ * PXA USB controller driver - Endpoint zero management ++ * ++ * Please see: ++ * linux/Documentation/arm/SA1100/SA1100_USB ++ * for more info. ++ * ++ * 02-May-2002 ++ * Frank Becker (Intrinsyc) - derived from sa1100 usb_ctl.c ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/proc_fs.h> ++#include <linux/tqueue.h> ++#include <linux/delay.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <asm/io.h> ++#include <asm/dma.h> ++#include <asm/irq.h> ++ ++#include "pxa_usb.h" /* public interface */ ++#include "usb_ctl.h" /* private stuff */ ++#include "usb_ep0.h" ++ ++ ++// 1 == lots of trace noise, 0 = only "important' stuff ++#define VERBOSITY 0 ++ ++enum { true = 1, false = 0 }; ++typedef int bool; ++#ifndef MIN ++#define MIN( a, b ) ((a)<(b)?(a):(b)) ++#endif ++ ++#if 1 && !defined( ASSERT ) ++# define ASSERT(expr) \ ++if(!(expr)) { \ ++ printk( "Assertion failed! %s,%s,%s,line=%d\n",\ ++#expr,__FILE__,__FUNCTION__,__LINE__); \ ++} ++#else ++# define ASSERT(expr) ++#endif ++ ++#if VERBOSITY ++#define PRINTKD(fmt, args...) printk( fmt , ## args) ++#else ++#define PRINTKD(fmt, args...) ++#endif ++ ++static EP0_state ep0_state = EP0_IDLE; ++ ++/*************************************************************************** ++ Prototypes ++ ***************************************************************************/ ++/* "setup handlers" -- the main functions dispatched to by the ++ .. isr. These represent the major "modes" of endpoint 0 operation */ ++static void sh_setup_begin(void); /* setup begin (idle) */ ++static void sh_write( void ); /* writing data */ ++static int read_fifo( usb_dev_request_t * p ); ++static void write_fifo( void ); ++static void get_descriptor( usb_dev_request_t * pReq ); ++static void queue_and_start_write( void * p, int req, int act ); ++ ++/*************************************************************************** ++ Inline Helpers ++ ***************************************************************************/ ++ ++inline int type_code_from_request( __u8 by ) { return (( by >> 4 ) & 3); } ++ ++/* print string descriptor */ ++static inline void psdesc( string_desc_t * p ) ++{ ++ int i; ++ int nchars = ( p->bLength - 2 ) / sizeof( __u16 ); ++ printk( "'" ); ++ for( i = 0 ; i < nchars ; i++ ) { ++ printk( "%c", (char) p->bString[i] ); ++ } ++ printk( "'\n" ); ++} ++ ++#if VERBOSITY ++/* "pcs" == "print control status" */ ++static inline void pcs( void ) ++{ ++ __u32 foo = UDCCS0; ++ printk( "%08x: %s %s %s %s %s %s\n", ++ foo, ++ foo & UDCCS0_SA ? "SA" : "", ++ foo & UDCCS0_OPR ? "OPR" : "", ++ foo & UDCCS0_RNE ? "RNE" : "", ++ foo & UDCCS0_SST ? "SST" : "", ++ foo & UDCCS0_FST ? "FST" : "", ++ foo & UDCCS0_DRWF ? "DRWF" : "" ++ ); ++} ++static inline void preq( usb_dev_request_t * pReq ) ++{ ++ static char * tnames[] = { "dev", "intf", "ep", "oth" }; ++ static char * rnames[] = { "std", "class", "vendor", "???" }; ++ char * psz; ++ switch( pReq->bRequest ) { ++ case GET_STATUS: psz = "get stat"; break; ++ case CLEAR_FEATURE: psz = "clr feat"; break; ++ case SET_FEATURE: psz = "set feat"; break; ++ case SET_ADDRESS: psz = "set addr"; break; ++ case GET_DESCRIPTOR: psz = "get desc"; break; ++ case SET_DESCRIPTOR: psz = "set desc"; break; ++ case GET_CONFIGURATION: psz = "get cfg"; break; ++ case SET_CONFIGURATION: psz = "set cfg"; break; ++ case GET_INTERFACE: psz = "get intf"; break; ++ case SET_INTERFACE: psz = "set intf"; break; ++ case SYNCH_FRAME: psz = "synch frame"; break; ++ default: psz = "unknown"; break; ++ } ++ printk( "- [%s: %s req to %s. dir=%s]\n", psz, ++ rnames[ (pReq->bmRequestType >> 5) & 3 ], ++ tnames[ pReq->bmRequestType & 3 ], ++ ( pReq->bmRequestType & 0x80 ) ? "in" : "out" ); ++} ++ ++#else ++static inline void pcs( void ){} ++static inline void preq( usb_dev_request_t *x){} ++#endif ++ ++/*************************************************************************** ++ Globals ++ ***************************************************************************/ ++static const char pszMe[] = "usbep0: "; ++ ++/* pointer to current setup handler */ ++static void (*current_handler)(void) = sh_setup_begin; ++ ++/* global write struct to keep write ++ ..state around across interrupts */ ++static struct { ++ unsigned char *p; ++ int bytes_left; ++} wr; ++ ++/*************************************************************************** ++ Public Interface ++ ***************************************************************************/ ++ ++/* reset received from HUB (or controller just went nuts and reset by itself!) ++ so udc core has been reset, track this state here */ ++void ep0_reset(void) ++{ ++ PRINTKD( "%sep0_reset\n", pszMe); ++ /* reset state machine */ ++ current_handler = sh_setup_begin; ++ wr.p = NULL; ++ wr.bytes_left = 0; ++ usbd_info.address=0; ++} ++ ++/* handle interrupt for endpoint zero */ ++void ep0_int_hndlr( void ) ++{ ++ PRINTKD( "%sep0_int_hndlr\n", pszMe); ++ pcs(); ++ (*current_handler)(); ++} ++ ++/*************************************************************************** ++ Setup Handlers ++ ***************************************************************************/ ++/* ++ * sh_setup_begin() ++ * This setup handler is the "idle" state of endpoint zero. It looks for OPR ++ * (OUT packet ready) to see if a setup request has been been received from the ++ * host. ++ * ++ */ ++static void sh_setup_begin( void ) ++{ ++ usb_dev_request_t req; ++ int request_type; ++ int n; ++ __u32 cs_reg_in = UDCCS0; ++ ++ PRINTKD( "%ssh_setup_begin\n", pszMe); ++ ++ /* Be sure out packet ready, otherwise something is wrong */ ++ if ( (cs_reg_in & UDCCS0_OPR) == 0 ) { ++ /* we can get here early...if so, we'll int again in a moment */ ++ PRINTKD( "%ssetup begin: no OUT packet available. Exiting\n", pszMe ); ++ goto sh_sb_end; ++ } ++ ++ if( ((cs_reg_in & UDCCS0_SA) == 0) && (ep0_state == EP0_IN_DATA_PHASE)) ++ { ++ PRINTKD( "%ssetup begin: premature status\n", pszMe ); ++ ++ /* premature status, reset tx fifo and go back to idle state*/ ++ UDCCS0 = UDCCS0_OPR | UDCCS0_FTF; ++ ++ ep0_state = EP0_IDLE; ++ return; ++ } ++ ++ if( (UDCCS0 & UDCCS0_RNE) == 0) ++ { ++ /* zero-length OUT? */ ++ printk( "%ssetup begin: zero-length OUT?\n", pszMe ); ++ goto sh_sb_end; ++ } ++ ++ /* read the setup request */ ++ n = read_fifo( &req ); ++ if ( n != sizeof( req ) ) { ++ printk( "%ssetup begin: fifo READ ERROR wanted %d bytes got %d. " ++ " Stalling out...\n", ++ pszMe, sizeof( req ), n ); ++ /* force stall, serviced out */ ++ UDCCS0 = UDCCS0_FST; ++ goto sh_sb_end; ++ } ++ ++ /* Is it a standard request? (not vendor or class request) */ ++ request_type = type_code_from_request( req.bmRequestType ); ++ if ( request_type != 0 ) { ++ printk( "%ssetup begin: unsupported bmRequestType: %d ignored\n", ++ pszMe, request_type ); ++ goto sh_sb_end; ++ } ++ ++#if VERBOSITY ++ { ++ unsigned char * pdb = (unsigned char *) &req; ++ PRINTKD( "%2.2X %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X ", ++ pdb[0], pdb[1], pdb[2], pdb[3], pdb[4], pdb[5], pdb[6], pdb[7] ++ ); ++ preq( &req ); ++ } ++#endif ++ ++ /* Handle it */ ++ switch( req.bRequest ) { ++ ++ case SET_ADDRESS: ++ PRINTKD( "%sSET_ADDRESS handled by UDC\n", pszMe); ++ break; ++#if 0 /* NOT_NEEDED */ ++ ++ case SET_FEATURE: ++ PRINTKD( "%sSET_FEATURE handled by UDC\n", pszMe); ++ break; ++ ++ case CLEAR_FEATURE: ++ PRINTKD( "%sCLEAR_FEATURE handled by UDC\n", pszMe); ++ break; ++ ++ case GET_CONFIGURATION: ++ PRINTKD( "%sGET_CONFIGURATION handled by UDC\n", pszMe ); ++ break; ++ ++ case GET_STATUS: ++ PRINTKD( "%s%sGET_STATUS handled by UDC\n", pszMe ); ++ break; ++ ++ case GET_INTERFACE: ++ PRINTKD( "%sGET_INTERFACE handled by UDC\n", pszMe); ++ break; ++ ++ case SYNCH_FRAME: ++ PRINTKD( "%sSYNCH_FRAME handled by UDC\n", pszMe ); ++ break; ++#endif ++ ++ case GET_DESCRIPTOR: ++ PRINTKD( "%sGET_DESCRIPTOR\n", pszMe ); ++ get_descriptor( &req ); ++ break; ++ ++ case SET_INTERFACE: ++ PRINTKD( "%sSET_INTERFACE TODO...\n", pszMe); ++ break; ++ ++ case SET_DESCRIPTOR: ++ PRINTKD( "%sSET_DESCRIPTOR TODO...\n", pszMe ); ++ break; ++ ++ case SET_CONFIGURATION: ++ PRINTKD( "%sSET_CONFIGURATION %d\n", pszMe, req.wValue); ++ ++/* ++ * FIXME: Something is not quite right here... I only ever get a ++ * de-configure from the host. Ignoring it for now, since usb ++ * ethernet won't do anything unless usb is 'configured'. ++ * ++ */ ++#if 0 ++ switch( req.wValue) ++ { ++ case 0: ++ /* configured */ ++ usbctl_next_state_on_event( kEvConfig ); ++ break; ++ case 1: ++ /* de-configured */ ++ usbctl_next_state_on_event( kEvDeConfig ); ++ break; ++ default: ++ PRINTKD( "%sSET_CONFIGURATION: unknown configuration value (%d)\n", pszMe, req.wValue); ++ break; ++ } ++#endif ++ break; ++ default : ++ printk("%sunknown request 0x%x\n", pszMe, req.bRequest); ++ break; ++ } /* switch( bRequest ) */ ++ ++sh_sb_end: ++ return; ++} ++ ++/* ++ * sh_write() ++ * ++ * Due to UDC bugs we push everything into the fifo in one go. ++ * Using interrupts just didn't work right... ++ * This should be ok, since control request are small. ++ */ ++static void sh_write() ++{ ++ PRINTKD( "sh_write\n" ); ++ do ++ { ++ write_fifo(); ++ } while( ep0_state != EP0_END_XFER); ++} ++ ++/*************************************************************************** ++ Other Private Subroutines ++ ***************************************************************************/ ++/* ++ * queue_and_start_write() ++ * data == data to send ++ * req == bytes host requested ++ * act == bytes we actually have ++ * ++ * Sets up the global "wr"-ite structure and load the outbound FIFO ++ * with data. ++ * ++ */ ++static void queue_and_start_write( void * data, int req, int act ) ++{ ++ PRINTKD( "write start: bytes requested=%d actual=%d\n", req, act); ++ ++ wr.p = (unsigned char*) data; ++ wr.bytes_left = MIN( act, req ); ++ ++ ep0_state = EP0_IN_DATA_PHASE; ++ sh_write(); ++ ++ return; ++} ++/* ++ * write_fifo() ++ * Stick bytes in the endpoint zero FIFO. ++ * ++ */ ++static void write_fifo( void ) ++{ ++ int bytes_this_time = MIN( wr.bytes_left, EP0_FIFO_SIZE ); ++ int bytes_written = 0; ++ ++ while( bytes_this_time-- ) { ++// PRINTKD( "%2.2X ", *wr.p ); ++ UDDR0 = *wr.p++; ++ bytes_written++; ++ } ++ wr.bytes_left -= bytes_written; ++ ++ usbd_info.stats.ep0_bytes_written += bytes_written; ++ ++ if( (wr.bytes_left==0)) ++ { ++ wr.p = NULL; /* be anal */ ++ ++ if(bytes_written < EP0_FIFO_SIZE) ++ { ++ int count; ++ int udccs0; ++ ++ /* We always end the transfer with a short or zero length packet */ ++ ep0_state = EP0_END_XFER; ++ current_handler = sh_setup_begin; ++ ++ /* Let the packet go... */ ++ UDCCS0 = UDCCS0_IPR; ++ ++ /* Wait until we get to status-stage, then ack. ++ * ++ * When the UDC sets the UDCCS0[OPR] bit, an interrupt ++ * is supposed to be generated (see 12.5.1 step 14ff, PXA Dev Manual). ++ * That approach didn't work out. Usually a new SETUP command was ++ * already in the fifo. I tried many approaches but was always losing ++ * at least some OPR interrupts. Thus the polling below... ++ */ ++ count = 1000; ++ udccs0 = UDCCS0; ++ do ++ { ++ if( (UDCCS0 & UDCCS0_OPR)) ++ { ++ /* clear OPR, generate ack */ ++ UDCCS0 = UDCCS0_OPR; ++ break; ++ } ++ count--; ++ udelay(1); ++ } while( count); ++ ++ PRINTKD( "write fifo: count=%d UDCCS0=%x UDCCS0=%x\n", count, udccs0, UDCCS0); ++ } ++ } ++ /* something goes poopy if I dont wait here ... */ ++ udelay(500); ++ ++ PRINTKD( "write fifo: bytes sent=%d, bytes left=%d\n", bytes_written, wr.bytes_left); ++} ++ ++/* ++ * read_fifo() ++ * Read bytes out of FIFO and put in request. ++ * Called to do the initial read of setup requests ++ * from the host. Return number of bytes read. ++ * ++ */ ++static int read_fifo( usb_dev_request_t * request ) ++{ ++ int bytes_read = 0; ++ unsigned char * pOut = (unsigned char*) request; ++ ++ int udccs0 = UDCCS0; ++ ++ if( (udccs0 & SETUP_READY) == SETUP_READY) ++ { ++ /* ok it's a setup command */ ++ while( UDCCS0 & UDCCS0_RNE) ++ { ++ if( bytes_read >= sizeof( usb_dev_request_t)) ++ { ++ /* We've already read enought o fill usb_dev_request_t. ++ * Our tummy is full. Go barf... ++ */ ++ printk( "%sread_fifo(): read failure\n", pszMe ); ++ usbd_info.stats.ep0_fifo_read_failures++; ++ break; ++ } ++ ++ *pOut++ = UDDR0; ++ bytes_read++; ++ } ++ } ++ PRINTKD( "read_fifo %d bytes\n", bytes_read ); ++ ++ /* clear SA & OPR */ ++ UDCCS0 = SETUP_READY; ++ ++ usbd_info.stats.ep0_bytes_read += bytes_read; ++ return bytes_read; ++} ++ ++/* ++ * get_descriptor() ++ * Called from sh_setup_begin to handle data return ++ * for a GET_DESCRIPTOR setup request. ++ */ ++static void get_descriptor( usb_dev_request_t * pReq ) ++{ ++ string_desc_t * pString; ++ ep_desc_t * pEndpoint = 0; ++ ++ desc_t * pDesc = pxa_usb_get_descriptor_ptr(); ++ int type = pReq->wValue >> 8; ++ int idx = pReq->wValue & 0xFF; ++ ++// PRINTKD( "%sget_descriptor for %d\n", pszMe, type ); ++ switch( type ) { ++ case USB_DESC_DEVICE: ++ queue_and_start_write( &pDesc->dev, ++ pReq->wLength, ++ pDesc->dev.bLength ); ++ break; ++ ++ // return config descriptor buffer, cfg, intf, 2 ep ++ case USB_DESC_CONFIG: ++ queue_and_start_write( &pDesc->b, ++ pReq->wLength, ++ sizeof( struct cdb ) ); ++ break; ++ ++ // not quite right, since doesn't do language code checking ++ case USB_DESC_STRING: ++ pString = pxa_usb_get_string_descriptor( idx ); ++ if ( pString ) { ++ if ( idx != 0 ) { // if not language index ++ printk( "%sReturn string %d: ", pszMe, idx ); ++ psdesc( pString ); ++ } ++ queue_and_start_write( pString, ++ pReq->wLength, ++ pString->bLength ); ++ } ++ else { ++ printk("%sunkown string index %d Stall.\n", pszMe, idx ); ++ } ++ break; ++ ++ case USB_DESC_INTERFACE: ++ if ( idx == pDesc->b.intf.bInterfaceNumber ) { ++ queue_and_start_write( &pDesc->b.intf, ++ pReq->wLength, ++ pDesc->b.intf.bLength ); ++ } ++ break; ++ ++ case USB_DESC_ENDPOINT: /* correct? 21Feb01ww */ ++ if ( idx == 1 ) ++ pEndpoint = &pDesc->b.ep1; //[BULK_IN1]; ++ else if ( idx == 2 ) ++ pEndpoint = &pDesc->b.ep2; //[BULK_OUT1]; ++ else ++ pEndpoint = NULL; ++ if ( pEndpoint ) { ++ queue_and_start_write( pEndpoint, ++ pReq->wLength, ++ pEndpoint->bLength ); ++ } else { ++ printk("%sunkown endpoint index %d Stall.\n", pszMe, idx ); ++ } ++ break; ++ ++ ++ default : ++ printk("%sunknown descriptor type %d. Stall.\n", pszMe, type ); ++ break; ++ ++ } ++} ++ ++/* end usb_ep0.c - who needs this comment? */ +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/usb_ep0.h +@@ -0,0 +1,66 @@ ++/* ++ * Copyright (C) Intrinsyc, Inc., 2002 ++ * ++ * usb_ep0.h - PXA USB controller driver. ++ * Endpoint zero management ++ * ++ * Please see: ++ * linux/Documentation/arm/SA1100/SA1100_USB ++ * for details. ++ * ++ * 02-May-2002 ++ * Frank Becker (Intrinsyc) - ++ * ++ */ ++ ++#ifndef __USB_EP0_H ++#define __USB_EP0_H ++ ++#define EP0_FIFO_SIZE 16 ++#define SETUP_READY (UDCCS0_SA | UDCCS0_OPR) ++ ++/*================================================ ++ * USB Protocol Stuff ++ */ ++ ++/* Request Codes */ ++enum { ++ GET_STATUS =0, ++ CLEAR_FEATURE =1, ++ /* reserved =2 */ ++ SET_FEATURE =3, ++ /* reserved =4 */ ++ SET_ADDRESS =5, ++ GET_DESCRIPTOR =6, ++ SET_DESCRIPTOR =7, ++ GET_CONFIGURATION =8, ++ SET_CONFIGURATION =9, ++ GET_INTERFACE =10, ++ SET_INTERFACE =11, ++ SYNCH_FRAME =12 ++}; ++ ++typedef enum { ++ EP0_IDLE, ++ EP0_IN_DATA_PHASE, ++ EP0_END_XFER, ++ EP0_OUT_DATA_PHASE ++} EP0_state; ++ ++/* USB Device Requests */ ++typedef struct ++{ ++ __u8 bmRequestType; ++ __u8 bRequest; ++ __u16 wValue; ++ __u16 wIndex; ++ __u16 wLength; ++} usb_dev_request_t __attribute__ ((packed)); ++ ++/* Data extraction from usb_request_t fields */ ++enum { ++ kTargetDevice =0, ++ kTargetInterface=1, ++ kTargetEndpoint =2 ++}; ++#endif +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/usb_recv.c +@@ -0,0 +1,173 @@ ++/* ++ * Generic receive layer for the PXA USB client function ++ * ++ * This code was loosely inspired by the original version which was ++ * Copyright (c) Compaq Computer Corporation, 1998-1999 ++ * Copyright (c) 2001 by Nicolas Pitre ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * 02-May-2002 ++ * Frank Becker (Intrinsyc) - derived from sa1100 usb_recv.c ++ * ++ * TODO: Add support for DMA. ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/pci.h> ++#include <linux/errno.h> ++#include <asm/dma.h> ++#include <asm/system.h> ++ ++#include "pxa_usb.h" ++#include "usb_ctl.h" ++ ++#if DEBUG ++static unsigned int usb_debug = DEBUG; ++#else ++#define usb_debug 0 /* gcc will remove all the debug code for us */ ++#endif ++ ++static char *ep_bulk_out1_buf; ++static int ep_bulk_out1_len; ++static int ep_bulk_out1_remain; ++static usb_callback_t ep_bulk_out1_callback; ++static int rx_pktsize; ++ ++static void ++ep_bulk_out1_start(void) ++{ ++ /* disable DMA */ ++ UDCCS2 &= ~UDCCS_BO_DME; ++ ++ /* enable interrupts for endpoint 2 (bulk out) */ ++ UICR0 &= ~UICR0_IM2; ++} ++ ++static void ++ep_bulk_out1_done(int flag) ++{ ++ int size = ep_bulk_out1_len - ep_bulk_out1_remain; ++ ++ if (!ep_bulk_out1_len) ++ return; ++ ++ ep_bulk_out1_len = 0; ++ if (ep_bulk_out1_callback) { ++ ep_bulk_out1_callback(flag, size); ++ } ++} ++ ++void ++ep_bulk_out1_state_change_notify( int new_state ) ++{ ++} ++ ++void ++ep_bulk_out1_stall( void ) ++{ ++ /* SET_FEATURE force stall at UDC */ ++ UDCCS2 |= UDCCS_BO_FST; ++} ++ ++int ++ep_bulk_out1_init(int chn) ++{ ++ desc_t * pd = pxa_usb_get_descriptor_ptr(); ++ rx_pktsize = __le16_to_cpu( pd->b.ep1.wMaxPacketSize ); ++ ep_bulk_out1_done(-EAGAIN); ++ return 0; ++} ++ ++void ++ep_bulk_out1_reset(void) ++{ ++ desc_t * pd = pxa_usb_get_descriptor_ptr(); ++ rx_pktsize = __le16_to_cpu( pd->b.ep1.wMaxPacketSize ); ++ UDCCS2 &= ~UDCCS_BO_FST; ++ ep_bulk_out1_done(-EINTR); ++} ++ ++void ++ep_bulk_out1_int_hndlr(int udcsr) ++{ ++ int status = UDCCS2; ++ if( usb_debug) printk("ep_bulk_out1_int_hndlr: UDCCS2=%x\n", status); ++ ++ if( (status & (UDCCS_BO_RNE | UDCCS_BO_RSP)) == UDCCS_BO_RSP) ++ { ++ /* zero-length packet */ ++ } ++ ++ if( status & UDCCS_BO_RNE) ++ { ++ int len; ++ int i; ++ char *buf = ep_bulk_out1_buf + ep_bulk_out1_len - ep_bulk_out1_remain; ++ ++ /* bytes in FIFO */ ++ len = (UBCR2 & 0xff) +1; ++ ++ if( usb_debug) printk("usb_recv: " ++ "len=%d out1_len=%d out1_remain=%d\n", ++ len,ep_bulk_out1_len,ep_bulk_out1_remain); ++ ++ if( len > ep_bulk_out1_remain) ++ { ++ /* FIXME: if this happens, we need a temporary overflow buffer */ ++ printk("usb_recv: Buffer overwrite warning...\n"); ++ len = ep_bulk_out1_remain; ++ } ++ ++ /* read data out of fifo */ ++ for( i=0; i<len; i++) ++ { ++ *buf++ = UDDR2 & 0xff; ++ } ++ ++ ep_bulk_out1_remain -= len; ++ ep_bulk_out1_done((len) ? 0 : -EPIPE); ++ } ++ ++ /* ack RPC - FIXME: '|=' we may ack SST here, too */ ++ UDCCS2 |= UDCCS_BO_RPC; ++ return; ++} ++ ++int ++pxa_usb_recv(char *buf, int len, usb_callback_t callback) ++{ ++ int flags; ++ ++ if (ep_bulk_out1_len) ++ return -EBUSY; ++ ++ local_irq_save(flags); ++ ep_bulk_out1_buf = buf; ++ ep_bulk_out1_len = len; ++ ep_bulk_out1_callback = callback; ++ ep_bulk_out1_remain = len; ++ ep_bulk_out1_start(); ++ local_irq_restore(flags); ++ ++ return 0; ++} ++ ++void ++pxa_usb_recv_reset(void) ++{ ++ ep_bulk_out1_reset(); ++} ++ ++void ++pxa_usb_recv_stall(void) ++{ ++ ep_bulk_out1_stall(); ++} ++ ++EXPORT_SYMBOL(pxa_usb_recv_stall); ++EXPORT_SYMBOL(pxa_usb_recv); ++EXPORT_SYMBOL(pxa_usb_recv_reset); +--- /dev/null ++++ linux-2.4.27/arch/arm/mach-pxa/usb_send.c +@@ -0,0 +1,190 @@ ++/* ++ * Generic xmit layer for the PXA USB client function ++ * ++ * This code was loosely inspired by the original version which was ++ * Copyright (c) Compaq Computer Corporation, 1998-1999 ++ * Copyright (c) 2001 by Nicolas Pitre ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * 02-May-2002 ++ * Frank Becker (Intrinsyc) - derived from sa1100 usb_send.c ++ * ++ * TODO: Add support for DMA. ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/pci.h> ++#include <linux/errno.h> ++#include <asm/hardware.h> ++#include <asm/dma.h> ++#include <asm/system.h> ++#include <asm/byteorder.h> ++ ++#include "pxa_usb.h" ++#include "usb_ctl.h" ++ ++#if DEBUG ++static unsigned int usb_debug = DEBUG; ++#else ++#define usb_debug 0 /* gcc will remove all the debug code for us */ ++#endif ++ ++static char *ep_bulk_in1_buf; ++static int ep_bulk_in1_len; ++static int ep_bulk_in1_remain; ++static usb_callback_t ep_bulk_in1_callback; ++static int tx_pktsize; ++ ++/* device state is changing, async */ ++void ++ep_bulk_in1_state_change_notify( int new_state ) ++{ ++} ++ ++/* set feature stall executing, async */ ++void ++ep_bulk_in1_stall( void ) ++{ ++ UDCCS1 |= UDCCS_BI_FST; ++} ++ ++static void ++ep_bulk_in1_send_packet(void) ++{ ++ int i; ++ char *buf = ep_bulk_in1_buf + ep_bulk_in1_len - ep_bulk_in1_remain; ++ int out_size = tx_pktsize; ++ ++ if( usb_debug) printk( "ep_bulk_in1_send_packet: UICR0=%x UDCCS1=%x\n", UICR0, UDCCS1); ++ ++ if( out_size > ep_bulk_in1_remain) ++ { ++ out_size = ep_bulk_in1_remain; ++ } ++ ++ for( i=0; i<out_size; i++) ++ { ++ UDDR1 = *buf++; ++ } ++ ++ UDCCS1 = UDCCS_BI_TPC; ++ if( out_size < tx_pktsize) ++ { ++ /* short packet */ ++ UDCCS1 = UDCCS_BI_TSP; ++ } ++ ep_bulk_in1_remain -= out_size; ++ ++ if( usb_debug) printk( "ep_bulk_in1_send_packet: " ++ "UICR0=%x UDCCS1=%x send bytes=%d left=%d\n", ++ UICR0, UDCCS1, out_size, ep_bulk_in1_remain); ++} ++ ++static void ++ep_bulk_in1_start(void) ++{ ++ if (!ep_bulk_in1_len) ++ return; ++ ++ UICR0 &= ~UICR0_IM1; ++ ++ ep_bulk_in1_send_packet(); ++} ++ ++static void ++ep_bulk_in1_done(int flag) ++{ ++ int size = ep_bulk_in1_len - ep_bulk_in1_remain; ++ if (ep_bulk_in1_len) { ++ ep_bulk_in1_len = 0; ++ if (ep_bulk_in1_callback) ++ ep_bulk_in1_callback(flag, size); ++ } ++} ++ ++int ++ep_bulk_in1_init(int chn) ++{ ++ desc_t * pd = pxa_usb_get_descriptor_ptr(); ++ tx_pktsize = __le16_to_cpu( pd->b.ep2.wMaxPacketSize ); ++ ep_bulk_in1_done(-EAGAIN); ++ return 0; ++} ++ ++void ++ep_bulk_in1_reset(void) ++{ ++ desc_t * pd = pxa_usb_get_descriptor_ptr(); ++ tx_pktsize = __le16_to_cpu( pd->b.ep2.wMaxPacketSize ); ++ UDCCS1 &= ~UDCCS_BI_FST; ++ ep_bulk_in1_done(-EINTR); ++} ++ ++void ++ep_bulk_in1_int_hndlr(int usir0) ++{ ++ int status = UDCCS1; ++ ++ if (ep_bulk_in1_remain != 0) { ++ /* more data to go */ ++ ep_bulk_in1_start(); ++ } else { ++ if( status & UDCCS_BI_TPC) ++ { ++ UDCCS1 = UDCCS_BI_TPC; ++ } ++ ep_bulk_in1_done(0); ++ } ++} ++ ++int ++pxa_usb_send(char *buf, int len, usb_callback_t callback) ++{ ++ int flags; ++ ++ if( usb_debug) printk( "pxa_usb_send: " ++ "data len=%d state=%d blen=%d\n", ++ len, usbd_info.state, ep_bulk_in1_len); ++ ++ if (usbd_info.state != USB_STATE_CONFIGURED) ++ return -ENODEV; ++ ++ if (ep_bulk_in1_len) ++ return -EBUSY; ++ ++ local_irq_save(flags); ++ ep_bulk_in1_buf = buf; ++ ep_bulk_in1_len = len; ++ ep_bulk_in1_callback = callback; ++ ep_bulk_in1_remain = len; ++ ep_bulk_in1_start(); ++ local_irq_restore(flags); ++ ++ return 0; ++} ++ ++ ++void ++pxa_usb_send_reset(void) ++{ ++ ep_bulk_in1_reset(); ++} ++ ++int ++pxa_usb_xmitter_avail( void ) ++{ ++ if (usbd_info.state != USB_STATE_CONFIGURED) ++ return -ENODEV; ++ if (ep_bulk_in1_len) ++ return -EBUSY; ++ return 0; ++} ++ ++ ++EXPORT_SYMBOL(pxa_usb_xmitter_avail); ++EXPORT_SYMBOL(pxa_usb_send); ++EXPORT_SYMBOL(pxa_usb_send_reset); +--- linux-2.4.27/arch/arm/mach-sa1100/sa1111-ohci.c~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/arch/arm/mach-sa1100/sa1111-ohci.c +@@ -54,7 +54,7 @@ + * address as its return value, and the DMA address via + * the dma_addr_t pointer. + */ +- vbuf = consistent_alloc(GFP_KERNEL | GFP_DMA, 4, &dma_buf); ++ vbuf = consistent_alloc(GFP_KERNEL | GFP_DMA, 4, &dma_buf, 0); + + SADTSA = (unsigned long)dma_buf; + SADTCA = 4; +--- linux-2.4.27/arch/arm/mach-sa1100/sa1111.c~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/arch/arm/mach-sa1100/sa1111.c +@@ -243,9 +243,15 @@ + * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111: + * (SA-1110 Developer's Manual, section 9.1.2.1) + */ ++#if CONFIG_ARCH_SA1100 + GAFR |= GPIO_32_768kHz; + GPDR |= GPIO_32_768kHz; + TUCR = TUCR_3_6864MHz; ++#elif CONFIG_ARCH_PXA ++ set_GPIO_mode(GPIO11_3_6MHz_MD); ++#else ++#error missing clock setup ++#endif + + /* + * Turn VCO on, and disable PLL Bypass. +@@ -300,6 +306,8 @@ + SBI_SMCR = smcr; + } + ++#ifdef CONFIG_ARCH_SA1100 ++ + /* + * Disable the memory bus request/grant signals on the SA1110 to + * ensure that we don't receive spurious memory requests. We set +@@ -341,5 +349,7 @@ + local_irq_restore(flags); + } + ++#endif ++ + EXPORT_SYMBOL(sa1111_wake); + EXPORT_SYMBOL(sa1111_doze); +--- linux-2.4.27/arch/arm/mm/Makefile~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/arch/arm/mm/Makefile +@@ -44,6 +44,7 @@ + p-$(CONFIG_CPU_ARM1026) += proc-arm1026.o + p-$(CONFIG_CPU_SA110) += proc-sa110.o + p-$(CONFIG_CPU_SA1100) += proc-sa110.o ++p-$(CONFIG_CPU_XSCALE) += proc-xscale.o + + # Integrator follows "new style" + # Soon, others will do too, and we can get rid of this +--- linux-2.4.27/arch/arm/mm/consistent.c~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/arch/arm/mm/consistent.c +@@ -37,7 +37,8 @@ + * + * Note that this does *not* zero the allocated area! + */ +-void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle) ++void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle, ++ unsigned long cache_flags) + { + struct page *page, *end, *free; + unsigned long order; +@@ -55,7 +56,7 @@ + goto no_page; + + *dma_handle = page_to_bus(page); +- ret = __ioremap(page_to_pfn(page) << PAGE_SHIFT, size, 0); ++ ret = __ioremap(page_to_pfn(page) << PAGE_SHIFT, size, cache_flags); + if (!ret) + goto no_remap; + +@@ -106,7 +107,7 @@ + #endif + gfp |= GFP_DMA; + +- return consistent_alloc(gfp, size, handle); ++ return consistent_alloc(gfp, size, handle, 0); + } + + /* +--- linux-2.4.27/arch/arm/mm/init.c~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/arch/arm/mm/init.c +@@ -49,6 +49,9 @@ + static unsigned long totalram_pages; + extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; + extern char _stext, _text, _etext, _end, __init_begin, __init_end; ++#ifdef CONFIG_XIP_KERNEL ++extern char _endtext, _sdata; ++#endif + extern unsigned long phys_initrd_start; + extern unsigned long phys_initrd_size; + +@@ -347,7 +350,11 @@ + * Register the kernel text and data with bootmem. + * Note that this can only be in node 0. + */ ++#ifdef CONFIG_XIP_KERNEL ++ reserve_bootmem_node(pgdat, __pa(&_sdata), &_end - &_sdata); ++#else + reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext); ++#endif + + #ifdef CONFIG_CPU_32 + /* +@@ -601,8 +608,13 @@ + unsigned int codepages, datapages, initpages; + int i, node; + ++#ifndef CONFIG_XIP_KERNEL + codepages = &_etext - &_text; + datapages = &_end - &_etext; ++#else ++ codepages = &_endtext - &_text; ++ datapages = &_end - &_sdata; ++#endif + initpages = &__init_end - &__init_begin; + + high_memory = (void *)__va(meminfo.end); +@@ -658,11 +670,13 @@ + + void free_initmem(void) + { ++#ifndef CONFIG_XIP_KERNEL + if (!machine_is_integrator()) { + free_area((unsigned long)(&__init_begin), + (unsigned long)(&__init_end), + "init"); + } ++#endif + } + + #ifdef CONFIG_BLK_DEV_INITRD +--- linux-2.4.27/arch/arm/mm/mm-armv.c~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/arch/arm/mm/mm-armv.c +@@ -356,6 +356,19 @@ + p ++; + #endif + ++#ifdef CONFIG_XIP_KERNEL ++ p->physical = KERNEL_XIP_BASE_PHYS; ++ p->virtual = KERNEL_XIP_BASE_VIRT; ++ p->length = PGDIR_SIZE * 8; ++ p->domain = DOMAIN_KERNEL; ++ p->prot_read = 0; /* r=0, b=0 --> read-only for kernel mode */ ++ p->prot_write = 0; ++ p->cacheable = 1; ++ p->bufferable = 1; ++ ++ p ++; ++#endif ++ + /* + * Go through the initial mappings, but clear out any + * pgdir entries that are not in the description. +@@ -386,7 +399,7 @@ + init_maps->prot_read = 0; + init_maps->prot_write = 0; + init_maps->cacheable = 1; +- init_maps->bufferable = 0; ++ init_maps->bufferable = 1; + + create_mapping(init_maps); + +--- /dev/null ++++ linux-2.4.27/arch/arm/mm/proc-xscale.S +@@ -0,0 +1,1086 @@ ++/* ++ * linux/arch/arm/mm/proc-xscale.S ++ * ++ * Author: Nicolas Pitre ++ * Created: November 2000 ++ * Copyright: (C) 2000, 2001 MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * MMU functions for the Intel XScale CPUs ++ * ++ * 2001 Aug 21: ++ * some contributions by Brett Gaines <brett.w.gaines@intel.com> ++ * Copyright 2001 by Intel Corp. ++ * ++ * 2001 Sep 08: ++ * Completely revisited, many important fixes ++ * Nicolas Pitre <nico@cam.org> ++ */ ++ ++#include <linux/config.h> ++#include <linux/linkage.h> ++#include <asm/assembler.h> ++#include <asm/constants.h> ++#include <asm/procinfo.h> ++#include <asm/hardware.h> ++#include <asm/proc/pgtable.h> ++ ++/* ++ * Some knobs for cache allocation policy. ++ * Allocate on write may or may not be beneficial depending on the memory ++ * usage pattern of your main application. Write through cache is definitely ++ * a performance loss in most cases, but might be used for special purposes. ++ */ ++#define PMD_CACHE_WRITE_ALLOCATE 1 ++#define PTE_CACHE_WRITE_ALLOCATE 1 ++#define CACHE_WRITE_THROUGH 0 ++ ++/* ++ * There are errata that say that dirty status bits in the cache may get ++ * corrupted. The workaround significantly affects performance, and the bug ++ * _might_ just not be that visible or critical to you, so it is configurable. ++ * Let's hope a future core revision will tell us this was only a bad dream. ++ * But in the mean time the risk and tradeoff is yours to decide.... ++ */ ++#ifdef CONFIG_XSCALE_CACHE_ERRATA ++#undef CACHE_WRITE_THROUGH ++#define CACHE_WRITE_THROUGH 1 ++#endif ++ ++/* ++ * This is the maximum size of an area which will be flushed. If the area ++ * is larger than this, then we flush the whole cache ++ */ ++#define MAX_AREA_SIZE 32768 ++ ++/* ++ * the cache line size of the I and D cache ++ */ ++#define CACHELINESIZE 32 ++ ++/* ++ * the size of the data cache ++ */ ++#define CACHESIZE 32768 ++ ++/* ++ * and the page size ++ */ ++#define PAGESIZE 4096 ++ ++/* ++ * Virtual address used to allocate the cache when flushed ++ * ++ * This must be an address range which is _never_ used. It should ++ * apparently have a mapping in the corresponding page table for ++ * compatibility with future CPUs that _could_ require it. For instance we ++ * don't care. ++ * ++ * This must be aligned on a 2*CACHESIZE boundary. The code selects one of ++ * the 2 areas in alternance each time the clean_d_cache macro is used. ++ * Without this the XScale core exhibits cache eviction problems and no one ++ * knows why. ++ * ++ * Reminder: the vector table is located at 0xffff0000-0xffff0fff. ++ */ ++#define CLEAN_ADDR 0xfffe0000 ++ ++/* ++ * This macro is used to wait for a CP15 write and is needed ++ * when we have to ensure that the last operation to the co-pro ++ * was completed before continuing with operation. ++ */ ++ .macro cpwait, rd ++ mrc p15, 0, \rd, c2, c0, 0 @ arbitrary read of cp15 ++ mov \rd, \rd @ wait for completion ++ sub pc, pc, #4 @ flush instruction pipeline ++ .endm ++ ++ .macro cpwait_ret, lr, rd ++ mrc p15, 0, \rd, c2, c0, 0 @ arbitrary read of cp15 ++ sub pc, \lr, \rd, LSR #32 @ wait for completion and ++ @ flush instruction pipeline ++ .endm ++ ++#if !CACHE_WRITE_THROUGH ++ ++/* ++ * This macro cleans the entire dcache using line allocate. ++ * The main loop has been unrolled to reduce loop overhead. ++ * rd and rs are two scratch registers. ++ */ ++ .macro clean_d_cache, rd, rs ++ ldr \rs, =clean_addr ++ ldr \rd, [\rs] ++ eor \rd, \rd, #CACHESIZE ++ str \rd, [\rs] ++ add \rs, \rd, #CACHESIZE ++1: mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line ++ add \rd, \rd, #CACHELINESIZE ++ mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line ++ add \rd, \rd, #CACHELINESIZE ++ mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line ++ add \rd, \rd, #CACHELINESIZE ++ mcr p15, 0, \rd, c7, c2, 5 @ allocate D cache line ++ add \rd, \rd, #CACHELINESIZE ++ teq \rd, \rs ++ bne 1b ++ .endm ++ ++ .macro clean_d_line, rd ++ mcr p15, 0, \rd, c7, c10, 1 ++ .endm ++ ++ .data ++clean_addr: .word CLEAN_ADDR ++ ++#else ++ ++/* ++ * If cache is write-through, there is no need to clean it. ++ * Simply invalidating will do. ++ */ ++ ++ .macro clean_d_cache, rd, rs ++ mcr p15, 0, \rd, c7, c6, 0 ++ .endm ++ ++ /* let's try to skip this needless operations at least within loops */ ++ .macro clean_d_line, rd ++ .endm ++ ++#endif ++ ++ .text ++ ++/* ++ * cpu_xscale_data_abort() ++ * ++ * obtain information about current aborted instruction. ++ * Note: we read user space. This means we might cause a data ++ * abort here if the I-TLB and D-TLB aren't seeing the same ++ * picture. Unfortunately, this does happen. We live with it. ++ * ++ * r2 = address of aborted instruction ++ * r3 = saved SPSR ++ * ++ * Returns: ++ * r0 = address of abort ++ * r1 = FSR, bit 11 = write ++ * r3 = corrupted ++ */ ++ .align 5 ++ENTRY(cpu_xscale_data_abort) ++ mrc p15, 0, r1, c5, c0, 0 @ get FSR ++ mrc p15, 0, r0, c6, c0, 0 @ get FAR ++ ldr r3, [r2] @ read aborted instruction ++ bic r1, r1, #1 << 11 @ clear bits 11 of FSR ++ tst r3, #1 << 20 @ check write ++ orreq r1, r1, #1 << 11 ++ mov pc, lr ++ ++/* ++ * cpu_xscale_check_bugs() ++ */ ++ENTRY(cpu_xscale_check_bugs) ++ mrs ip, cpsr ++ bic ip, ip, #F_BIT ++ msr cpsr, ip ++ mov pc, lr ++ ++#ifndef CONFIG_XSCALE_CACHE_ERRATA ++/* ++ * cpu_xscale_proc_init() ++ * ++ * Nothing too exciting at the moment ++ */ ++ENTRY(cpu_xscale_proc_init) ++ mov pc, lr ++#else ++/* ++ * We enable the cache here, but we make sure all the status bits for dirty ++ * lines are cleared as well (see PXA250 erratum #120). ++ */ ++ENTRY(cpu_xscale_proc_init) ++ @ enable data cache ++ ldr r0, cr_p ++ ldmia r0, {r1, r2} ++ orr r1, r1, #0x4 ++ orr r2, r2, #0x4 ++ stmia r0, {r1, r2} ++ mcr p15, 0, r1, c1, c0, 0 ++ cpwait r0 ++ ++ @ invalidate data cache ++ mcr p15, 0, r0, c7, c6, 0 ++ ++ @ fill main cache with write-through lines ++ bic r0, pc, #0x1f ++ add r1, r0, #CACHESIZE ++1: ldr r2, [r0], #32 ++ cmp r0, r1 ++ bne 1b ++ ++ @ enable test feature to force all fills to the mini-cache ++ mov r1, #0x8 ++ mcr p15, 0, r1, c15, c15, 3 ++ ++ @ fill mini-cache with write-through lines (2kbytes, 64 lines) ++ add r1, r0, #2048 ++2: ldr r2, [r0], #32 ++ cmp r0, r1 ++ bne 2b ++ ++ @ disable test feature to force all fills to the mini-cache ++ mov r1, #0x0 ++ mcr p15, 0, r1, c15, c15, 3 ++ ++ @ invalidate data cache again ++ mcr p15, 0, r1, c7, c6, 0 ++ mov pc, lr ++ ++cr_p: .long SYMBOL_NAME(cr_alignment) ++#endif ++ ++/* ++ * cpu_xscale_proc_fin() ++ */ ++ENTRY(cpu_xscale_proc_fin) ++ str lr, [sp, #-4]! ++ mov r0, #F_BIT|I_BIT|SVC_MODE ++ msr cpsr_c, r0 ++ mrc p15, 0, r0, c1, c0, 0 @ ctrl register ++ bic r0, r0, #0x1800 @ ...IZ........... ++ bic r0, r0, #0x0006 @ .............CA. ++ mcr p15, 0, r0, c1, c0, 0 @ disable caches ++ bl cpu_xscale_cache_clean_invalidate_all @ clean caches ++ ldr pc, [sp], #4 ++ ++/* ++ * cpu_xscale_reset(loc) ++ * ++ * Perform a soft reset of the system. Put the CPU into the ++ * same state as it would be if it had been reset, and branch ++ * to what would be the reset vector. ++ * ++ * loc: location to jump to for soft reset ++ */ ++ .align 5 ++ENTRY(cpu_xscale_reset) ++ mov r1, #F_BIT|I_BIT|SVC_MODE ++ msr cpsr_c, r1 @ reset CPSR ++ mrc p15, 0, r1, c1, c0, 0 @ ctrl register ++ bic r1, r1, #0x0086 @ ........B....CA. ++ bic r1, r1, #0x1900 @ ...IZ..S........ ++ mcr p15, 0, r1, c1, c0, 0 @ ctrl register ++ mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches & BTB ++ bic r1, r1, #0x0001 @ ...............M ++ mcr p15, 0, r1, c1, c0, 0 @ ctrl register ++ @ CAUTION: MMU turned off from this point. We count on the pipeline ++ @ already containing those two last instructions to survive. ++ mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs ++ mov pc, r0 ++ ++/* ++ * cpu_xscale_do_idle(type) ++ * ++ * Cause the processor to idle ++ * ++ * type: ++ * 0 = slow idle ++ * 1 = fast idle ++ * 2 = switch to slow processor clock ++ * 3 = switch to fast processor clock ++ * ++ * For now we do nothing but go to idle mode for every case ++ * ++ * XScale supports clock switching, but using idle mode support ++ * allows external hardware to react to system state changes. ++ */ ++ .align 5 ++ ++ENTRY(cpu_xscale_do_idle) ++ mov r0, #1 ++ mcr p14, 0, r0, c7, c0, 0 @ Go to IDLE ++ mov pc, lr ++ ++/* ================================= CACHE ================================ */ ++ ++/* ++ * cpu_xscale_cache_clean_invalidate_all (void) ++ * ++ * clean and invalidate all cache lines ++ * ++ * Note: ++ * 1. We should preserve r0 at all times. ++ * 2. Even if this function implies cache "invalidation" by its name, ++ * we don't need to actually use explicit invalidation operations ++ * since the goal is to discard all valid references from the cache ++ * and the cleaning of it already has that effect. ++ * 3. Because of 2 above and the fact that kernel space memory is always ++ * coherent across task switches there is no need to worry about ++ * inconsistencies due to interrupts, ence no irq disabling. ++ */ ++ .align 5 ++ENTRY(cpu_xscale_cache_clean_invalidate_all) ++ mov r2, #1 ++cpu_xscale_cache_clean_invalidate_all_r2: ++ clean_d_cache r0, r1 ++ teq r2, #0 ++ mcrne p15, 0, ip, c7, c5, 0 @ Invalidate I cache & BTB ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mov pc, lr ++ ++/* ++ * cpu_xscale_cache_clean_invalidate_range(start, end, flags) ++ * ++ * clean and invalidate all cache lines associated with this area of memory ++ * ++ * start: Area start address ++ * end: Area end address ++ * flags: nonzero for I cache as well ++ */ ++ .align 5 ++ENTRY(cpu_xscale_cache_clean_invalidate_range) ++ bic r0, r0, #CACHELINESIZE - 1 @ round down to cache line ++ sub r3, r1, r0 ++ cmp r3, #MAX_AREA_SIZE ++ bhi cpu_xscale_cache_clean_invalidate_all_r2 ++1: clean_d_line r0 @ Clean D cache line ++ mcr p15, 0, r0, c7, c6, 1 @ Invalidate D cache line ++ add r0, r0, #CACHELINESIZE ++ cmp r0, r1 ++ blo 1b ++ teq r2, #0 ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ moveq pc, lr ++ sub r0, r0, r3 ++1: mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line ++ add r0, r0, #CACHELINESIZE ++ cmp r0, r1 ++ blo 1b ++ mcr p15, 0, ip, c7, c5, 6 @ Invalidate BTB ++ mov pc, lr ++ ++/* ++ * cpu_xscale_flush_ram_page(page) ++ * ++ * clean all cache lines associated with this memory page ++ * ++ * page: page to clean ++ */ ++ .align 5 ++ENTRY(cpu_xscale_flush_ram_page) ++#if !CACHE_WRITE_THROUGH ++ mov r1, #PAGESIZE ++1: mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ add r0, r0, #CACHELINESIZE ++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ add r0, r0, #CACHELINESIZE ++ subs r1, r1, #2 * CACHELINESIZE ++ bne 1b ++#endif ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mov pc, lr ++ ++/* ================================ D-CACHE =============================== */ ++ ++/* ++ * cpu_xscale_dcache_invalidate_range(start, end) ++ * ++ * throw away all D-cached data in specified region without an obligation ++ * to write them back. Note however that on XScale we must clean all ++ * entries also due to hardware errata (80200 A0 & A1 only). ++ * ++ * start: virtual start address ++ * end: virtual end address ++ */ ++ .align 5 ++ENTRY(cpu_xscale_dcache_invalidate_range) ++ mrc p15, 0, r2, c0, c0, 0 @ Read part no. ++ eor r2, r2, #0x69000000 ++ eor r2, r2, #0x00052000 @ 80200 XX part no. ++ bics r2, r2, #0x1 @ Clear LSB in revision field ++ moveq r2, #0 ++ beq cpu_xscale_cache_clean_invalidate_range @ An 80200 A0 or A1 ++ ++ tst r0, #CACHELINESIZE - 1 ++ mcrne p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ tst r1, #CACHELINESIZE - 1 ++ mcrne p15, 0, r1, c7, c10, 1 @ Clean D cache line ++ bic r0, r0, #CACHELINESIZE - 1 @ round down to cache line ++1: mcr p15, 0, r0, c7, c6, 1 @ Invalidate D cache line ++ add r0, r0, #CACHELINESIZE ++ cmp r0, r1 ++ blo 1b ++ mov pc, lr ++ ++/* ++ * cpu_xscale_dcache_clean_range(start, end) ++ * ++ * For the specified virtual address range, ensure that all caches contain ++ * clean data, such that peripheral accesses to the physical RAM fetch ++ * correct data. ++ * ++ * start: virtual start address ++ * end: virtual end address ++ */ ++ .align 5 ++ENTRY(cpu_xscale_dcache_clean_range) ++#if !CACHE_WRITE_THROUGH ++ bic r0, r0, #CACHELINESIZE - 1 ++ sub r2, r1, r0 ++ cmp r2, #MAX_AREA_SIZE ++ movhi r2, #0 ++ bhi cpu_xscale_cache_clean_invalidate_all_r2 ++ ++1: mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ add r0, r0, #CACHELINESIZE ++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ add r0, r0, #CACHELINESIZE ++ cmp r0, r1 ++ blo 1b ++#endif ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mov pc, lr ++ ++/* ++ * cpu_xscale_clean_dcache_page(page) ++ * ++ * Cleans a single page of dcache so that if we have any future aliased ++ * mappings, they will be consistent at the time that they are created. ++ * ++ * Note: ++ * 1. we don't need to flush the write buffer in this case. [really? -Nico] ++ * 2. we don't invalidate the entries since when we write the page ++ * out to disk, the entries may get reloaded into the cache. ++ */ ++ .align 5 ++ENTRY(cpu_xscale_dcache_clean_page) ++#if !CACHE_WRITE_THROUGH ++ mov r1, #PAGESIZE ++1: mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ add r0, r0, #CACHELINESIZE ++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ add r0, r0, #CACHELINESIZE ++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ add r0, r0, #CACHELINESIZE ++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ add r0, r0, #CACHELINESIZE ++ subs r1, r1, #4 * CACHELINESIZE ++ bne 1b ++#endif ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mov pc, lr ++ ++/* ++ * cpu_xscale_dcache_clean_entry(addr) ++ * ++ * Clean the specified entry of any caches such that the MMU ++ * translation fetches will obtain correct data. ++ * ++ * addr: cache-unaligned virtual address ++ */ ++ .align 5 ++ENTRY(cpu_xscale_dcache_clean_entry) ++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mov pc, lr ++ ++/* ================================ I-CACHE =============================== */ ++ ++/* ++ * cpu_xscale_icache_invalidate_range(start, end) ++ * ++ * invalidate a range of virtual addresses from the Icache ++ * ++ * start: virtual start address ++ * end: virtual end address ++ * ++ * Note: This is vaguely defined as supposed to bring the dcache and the ++ * icache in sync by the way this function is used. ++ */ ++ .align 5 ++ENTRY(cpu_xscale_icache_invalidate_range) ++ bic r0, r0, #CACHELINESIZE - 1 ++1: clean_d_line r0 @ Clean D cache line ++ mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line ++ add r0, r0, #CACHELINESIZE ++ cmp r0, r1 ++ blo 1b ++ mcr p15, 0, ip, c7, c5, 6 @ Invalidate BTB ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mov pc, lr ++ ++/* ++ * cpu_xscale_icache_invalidate_page(page) ++ * ++ * invalidate all Icache lines associated with this area of memory ++ * ++ * page: page to invalidate ++ */ ++ .align 5 ++ENTRY(cpu_xscale_icache_invalidate_page) ++ mov r1, #PAGESIZE ++1: mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line ++ add r0, r0, #CACHELINESIZE ++ mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line ++ add r0, r0, #CACHELINESIZE ++ mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line ++ add r0, r0, #CACHELINESIZE ++ mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache line ++ add r0, r0, #CACHELINESIZE ++ subs r1, r1, #4 * CACHELINESIZE ++ bne 1b ++ mcr p15, 0, r0, c7, c5, 6 @ Invalidate BTB ++ mov pc, lr ++ ++/* ================================ CACHE LOCKING============================ ++ * ++ * The XScale MicroArchitecture implements support for locking entries into ++ * the data and instruction cache. The following functions implement the core ++ * low level instructions needed to accomplish the locking. The developer's ++ * manual states that the code that performs the locking must be in non-cached ++ * memory. To accomplish this, the code in xscale-cache-lock.c copies the ++ * following functions from the cache into a non-cached memory region that ++ * is allocated through consistent_alloc(). ++ * ++ */ ++ .align 5 ++/* ++ * xscale_icache_lock ++ * ++ * r0: starting address to lock ++ * r1: end address to lock ++ */ ++ENTRY(xscale_icache_lock) ++ ++iLockLoop: ++ bic r0, r0, #CACHELINESIZE - 1 ++ mcr p15, 0, r0, c9, c1, 0 @ lock into cache ++ cmp r0, r1 @ are we done? ++ add r0, r0, #CACHELINESIZE @ advance to next cache line ++ bls iLockLoop ++ mov pc, lr ++ ++/* ++ * xscale_icache_unlock ++ */ ++ENTRY(xscale_icache_unlock) ++ mcr p15, 0, r0, c9, c1, 1 @ Unlock icache ++ mov pc, lr ++ ++/* ++ * xscale_dcache_lock ++ * ++ * r0: starting address to lock ++ * r1: end address to lock ++ */ ++ENTRY(xscale_dcache_lock) ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mov r2, #1 ++ mcr p15, 0, r2, c9, c2, 0 @ Put dcache in lock mode ++ cpwait ip @ Wait for completion ++ ++ mrs r2, cpsr ++ orr r3, r2, #F_BIT | I_BIT ++dLockLoop: ++ msr cpsr_c, r3 ++ mcr p15, 0, r0, c7, c10, 1 @ Write back line if it is dirty ++ mcr p15, 0, r0, c7, c6, 1 @ Flush/invalidate line ++ msr cpsr_c, r2 ++ ldr ip, [r0], #CACHELINESIZE @ Preload 32 bytes into cache from ++ @ location [r0]. Post-increment ++ @ r3 to next cache line ++ cmp r0, r1 @ Are we done? ++ bls dLockLoop ++ ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mov r2, #0 ++ mcr p15, 0, r2, c9, c2, 0 @ Get out of lock mode ++ cpwait_ret lr, ip ++ ++/* ++ * xscale_dcache_unlock ++ */ ++ENTRY(xscale_dcache_unlock) ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mcr p15, 0, ip, c9, c2, 1 @ Unlock cache ++ mov pc, lr ++ ++/* ++ * Needed to determine the length of the code that needs to be copied. ++ */ ++ .align 5 ++ENTRY(xscale_cache_dummy) ++ mov pc, lr ++ ++/* ================================== TLB ================================= */ ++ ++/* ++ * cpu_xscale_tlb_invalidate_all() ++ * ++ * Invalidate all TLB entries ++ */ ++ .align 5 ++ENTRY(cpu_xscale_tlb_invalidate_all) ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs ++ cpwait_ret lr, ip ++ ++/* ++ * cpu_xscale_tlb_invalidate_range(start, end) ++ * ++ * invalidate TLB entries covering the specified range ++ * ++ * start: range start address ++ * end: range end address ++ */ ++ .align 5 ++ENTRY(cpu_xscale_tlb_invalidate_range) ++ bic r0, r0, #(PAGESIZE - 1) & 0x00ff ++ bic r0, r0, #(PAGESIZE - 1) & 0xff00 ++ sub r3, r1, r0 ++ cmp r3, #256 * PAGESIZE @ arbitrary, should be tuned ++ bhi cpu_xscale_tlb_invalidate_all ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry ++ mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry ++ add r0, r0, #PAGESIZE ++ cmp r0, r1 ++ blo 1b ++ cpwait_ret lr, ip ++ ++/* ++ * cpu_xscale_tlb_invalidate_page(page, flags) ++ * ++ * invalidate the TLB entries for the specified page. ++ * ++ * page: page to invalidate ++ * flags: non-zero if we include the I TLB ++ */ ++ .align 5 ++ENTRY(cpu_xscale_tlb_invalidate_page) ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ teq r1, #0 ++ mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry ++ mcrne p15, 0, r3, c8, c5, 1 @ invalidate I TLB entry ++ cpwait_ret lr, ip ++ ++/* ================================ TLB LOCKING============================== ++ * ++ * The XScale MicroArchitecture implements support for locking entries into ++ * the Instruction and Data TLBs. The following functions provide the ++ * low level support for supporting these under Linux. xscale-lock.c ++ * implements some higher level management code. Most of the following ++ * is taken straight out of the Developer's Manual. ++ */ ++ ++/* ++ * Lock I-TLB entry ++ * ++ * r0: Virtual address to translate and lock ++ */ ++ .align 5 ++ENTRY(xscale_itlb_lock) ++ mrs r2, cpsr ++ orr r3, r2, #F_BIT | I_BIT ++ msr cpsr_c, r3 @ Disable interrupts ++ mcr p15, 0, r0, c8, c5, 1 @ Invalidate I-TLB entry ++ mcr p15, 0, r0, c10, c4, 0 @ Translate and lock ++ msr cpsr_c, r2 @ Restore interrupts ++ cpwait_ret lr, ip ++ ++/* ++ * Lock D-TLB entry ++ * ++ * r0: Virtual address to translate and lock ++ */ ++ .align 5 ++ENTRY(xscale_dtlb_lock) ++ mrs r2, cpsr ++ orr r3, r2, #F_BIT | I_BIT ++ msr cpsr_c, r3 @ Disable interrupts ++ mcr p15, 0, r0, c8, c6, 1 @ Invalidate D-TLB entry ++ mcr p15, 0, r0, c10, c8, 0 @ Translate and lock ++ msr cpsr_c, r2 @ Restore interrupts ++ cpwait_ret lr, ip ++ ++/* ++ * Unlock all I-TLB entries ++ */ ++ .align 5 ++ENTRY(xscale_itlb_unlock) ++ mcr p15, 0, ip, c10, c4, 1 @ Unlock I-TLB ++ mcr p15, 0, ip, c8, c5, 0 @ Invalidate I-TLB ++ cpwait_ret lr, ip ++ ++/* ++ * Unlock all D-TLB entries ++ */ ++ENTRY(xscale_dtlb_unlock) ++ mcr p15, 0, ip, c10, c8, 1 @ Unlock D-TBL ++ mcr p15, 0, ip, c8, c6, 0 @ Invalidate D-TLB ++ cpwait_ret lr, ip ++ ++/* =============================== PageTable ============================== */ ++ ++/* ++ * cpu_xscale_set_pgd(pgd) ++ * ++ * Set the translation base pointer to be as described by pgd. ++ * ++ * pgd: new page tables ++ */ ++ .align 5 ++ENTRY(cpu_xscale_set_pgd) ++ clean_d_cache r1, r2 ++ mcr p15, 0, ip, c7, c5, 0 @ Invalidate I cache & BTB ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mcr p15, 0, r0, c2, c0, 0 @ load page table pointer ++ mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs ++ cpwait_ret lr, ip ++ ++/* ++ * cpu_xscale_set_pmd(pmdp, pmd) ++ * ++ * Set a level 1 translation table entry, and clean it out of ++ * any caches such that the MMUs can load it correctly. ++ * ++ * pmdp: pointer to PMD entry ++ * pmd: PMD value to store ++ */ ++ .align 5 ++ENTRY(cpu_xscale_set_pmd) ++#if PMD_CACHE_WRITE_ALLOCATE && !CACHE_WRITE_THROUGH ++ and r2, r1, #PMD_TYPE_MASK|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE ++ cmp r2, #PMD_TYPE_SECT|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE ++ orreq r1, r1, #PMD_SECT_TEX(1) ++#elif CACHE_WRITE_THROUGH ++ and r2, r1, #PMD_TYPE_MASK|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE ++ cmp r2, #PMD_TYPE_SECT|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE ++ biceq r1, r1, #PMD_SECT_BUFFERABLE ++#endif ++ str r1, [r0] ++ mov ip, #0 ++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mov pc, lr ++ ++/* ++ * cpu_xscale_set_pte(ptep, pte) ++ * ++ * Set a PTE and flush it out ++ * ++ * Errata 40: must set memory to write-through for user read-only pages. ++ */ ++ .align 5 ++ENTRY(cpu_xscale_set_pte) ++ str r1, [r0], #-1024 @ linux version ++ ++ bic r2, r1, #0xff0 ++ orr r2, r2, #PTE_TYPE_EXT @ extended page ++ ++ eor r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY ++ ++ tst r3, #L_PTE_USER | L_PTE_EXEC @ User or Exec? ++ orrne r2, r2, #PTE_EXT_AP_URO_SRW @ yes -> user r/o, system r/w ++ ++ tst r3, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty? ++ orreq r2, r2, #PTE_EXT_AP_UNO_SRW @ yes -> user n/a, system r/w ++ @ combined with user -> user r/w ++ ++ @ ++ @ Handle the X bit. We want to set this bit for the minicache ++ @ (U = E = B = W = 0, C = 1) or when write allocate is enabled, ++ @ and we have a writeable, cacheable region. If we ignore the ++ @ U and E bits, we can allow user space to use the minicache as ++ @ well. ++ @ ++ @ X = C & ~W & ~B ++ @ | C & W & B & write_allocate ++ @ ++ eor ip, r1, #L_PTE_CACHEABLE ++ tst ip, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE ++#if PTE_CACHE_WRITE_ALLOCATE && !CACHE_WRITE_THROUGH ++ eorne ip, r1, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE ++ tstne ip, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE ++#endif ++ orreq r2, r2, #PTE_EXT_TEX(1) ++ ++#if CACHE_WRITE_THROUGH ++ tst r1, #L_PTE_CACHEABLE ++ bicne r2, r2, #L_PTE_BUFFERABLE @ clear B only if C is set ++#else ++ @ ++ @ Errata 40: The B bit must be cleared for a user read-only ++ @ cacheable page. ++ @ ++ @ B = B & ~((U|E) & C & ~W) ++ @ ++ and ip, r1, #L_PTE_USER | L_PTE_EXEC | L_PTE_WRITE | L_PTE_CACHEABLE ++ teq ip, #L_PTE_USER | L_PTE_CACHEABLE ++ teqne ip, #L_PTE_EXEC | L_PTE_CACHEABLE ++ teqne ip, #L_PTE_USER | L_PTE_EXEC | L_PTE_CACHEABLE ++ biceq r2, r2, #PTE_BUFFERABLE ++#endif ++ ++ tst r3, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young? ++ movne r2, #0 @ no -> fault ++ ++ str r2, [r0] @ hardware version ++ ++ @ We try to map 64K page entries when possible. ++ @ We do that for kernel space only since the usage pattern from ++ @ the setting of VM area is quite simple. User space is not worth ++ @ the implied complexity because of ever randomly changing PTEs ++ @ (page aging, swapout, etc) requiring constant coherency checks. ++ @ Since PTEs are usually set in increasing order, we test the ++ @ possibility for a large page only when given the last PTE of a ++ @ 64K boundary. ++ tsteq r1, #L_PTE_USER ++ andeq r1, r0, #(15 << 2) ++ teqeq r1, #(15 << 2) ++ beq 1f ++ ++ mov ip, #0 ++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mov pc, lr ++ ++ @ See if we have 16 identical PTEs but with consecutive base addresses ++1: bic r3, r2, #0x0000f000 ++ mov r1, #0x0000f000 ++2: eor r2, r2, r3 ++ teq r2, r1 ++ bne 4f ++ subs r1, r1, #0x00001000 ++ ldr r2, [r0, #-4]! ++ bne 2b ++ eors r2, r2, r3 ++ bne 4f ++ ++ @ Now create our LARGE PTE from the current EXT one. ++ bic r3, r3, #PTE_TYPE_MASK ++ orr r3, r3, #PTE_TYPE_LARGE ++ and r2, r3, #0x30 @ EXT_AP --> LARGE_AP0 ++ orr r2, r2, r2, lsl #2 @ add LARGE_AP1 ++ orr r2, r2, r2, lsl #4 @ add LARGE_AP3 + LARGE_AP2 ++ and r1, r3, #0x3c0 @ EXT_TEX ++ bic r3, r3, #0x3c0 ++ orr r2, r2, r1, lsl #(12 - 6) @ --> LARGE_TEX ++ orr r2, r2, r3 @ add remaining bits ++ ++ @ then put it in the pagetable ++ mov r3, r2 ++3: strd r2, [r0], #8 ++ tst r0, #(15 << 2) ++ bne 3b ++ ++ @ Then sync the 2 corresponding cache lines ++ sub r0, r0, #(16 << 2) ++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++4: orr r0, r0, #(15 << 2) ++ mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line ++ mov ip, #0 ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mov pc, lr ++ ++ .ltorg ++ ++cpu_manu_name: ++ .asciz "Intel" ++ ++cpu_80200_name: ++ .asciz "XScale-80200" ++ ++cpu_pxa210_name: ++ .asciz "XScale-PXA210" ++ ++cpu_pxa250_name: ++ .asciz "XScale-PXA250" ++ ++cpu_pxa255_name: ++ .asciz "XScale-PXA255" ++ ++ .align ++ ++ .section ".text.init", #alloc, #execinstr ++ ++__xscale_setup: ++ mov r0, #F_BIT|I_BIT|SVC_MODE ++ msr cpsr_c, r0 ++ mcr p15, 0, ip, c7, c7, 0 @ invalidate I, D caches & BTB ++ mcr p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer ++ mcr p15, 0, ip, c8, c7, 0 @ invalidate I, D TLBs ++ mcr p15, 0, r4, c2, c0, 0 @ load page table pointer ++ mov r0, #0x1f @ Domains 0, 1 = client ++ mcr p15, 0, r0, c3, c0, 0 @ load domain access register ++ mov r0, #1 @ Allow user space to access ++ mcr p15, 0, r0, c15, c1, 0 @ ... CP 0 only. ++#if CACHE_WRITE_THROUGH ++ mov r0, #0x20 ++#else ++ mov r0, #0x00 ++#endif ++ mcr p15, 0, r0, c1, c1, 0 @ set auxiliary control reg ++ mrc p15, 0, r0, c1, c0, 0 @ get control register ++ bic r0, r0, #0x0200 @ ......R......... ++ bic r0, r0, #0x0082 @ ........B.....A. ++ orr r0, r0, #0x0005 @ .............C.M ++ orr r0, r0, #0x3900 @ ..VIZ..S........ ++#ifdef CONFIG_XSCALE_CACHE_ERRATA ++ bic r0, r0, #0x0004 @ see cpu_xscale_proc_init ++#endif ++ mov pc, lr ++ ++ .text ++ ++/* ++ * Purpose : Function pointers used to access above functions - all calls ++ * come through these ++ */ ++ ++ .type xscale_processor_functions, #object ++ENTRY(xscale_processor_functions) ++ .word cpu_xscale_data_abort ++ .word cpu_xscale_check_bugs ++ .word cpu_xscale_proc_init ++ .word cpu_xscale_proc_fin ++ .word cpu_xscale_reset ++ .word cpu_xscale_do_idle ++ ++ /* cache */ ++ .word cpu_xscale_cache_clean_invalidate_all ++ .word cpu_xscale_cache_clean_invalidate_range ++ .word cpu_xscale_flush_ram_page ++ ++ /* dcache */ ++ .word cpu_xscale_dcache_invalidate_range ++ .word cpu_xscale_dcache_clean_range ++ .word cpu_xscale_dcache_clean_page ++ .word cpu_xscale_dcache_clean_entry ++ ++ /* icache */ ++ .word cpu_xscale_icache_invalidate_range ++ .word cpu_xscale_icache_invalidate_page ++ ++ /* tlb */ ++ .word cpu_xscale_tlb_invalidate_all ++ .word cpu_xscale_tlb_invalidate_range ++ .word cpu_xscale_tlb_invalidate_page ++ ++ /* pgtable */ ++ .word cpu_xscale_set_pgd ++ .word cpu_xscale_set_pmd ++ .word cpu_xscale_set_pte ++ .size xscale_processor_functions, . - xscale_processor_functions ++ ++ .type cpu_80200_info, #object ++cpu_80200_info: ++ .long cpu_manu_name ++ .long cpu_80200_name ++ .size cpu_80200_info, . - cpu_80200_info ++ ++ .type cpu_pxa210_info, #object ++cpu_pxa210_info: ++ .long cpu_manu_name ++ .long cpu_pxa210_name ++ .size cpu_pxa210_info, . - cpu_pxa210_info ++ ++ .type cpu_pxa250_info, #object ++cpu_pxa250_info: ++ .long cpu_manu_name ++ .long cpu_pxa250_name ++ .size cpu_pxa250_info, . - cpu_pxa250_info ++ ++ .type cpu_pxa255_info, #object ++cpu_pxa255_info: ++ .long cpu_manu_name ++ .long cpu_pxa255_name ++ .size cpu_pxa255_info, . - cpu_pxa255_info ++ ++ .type cpu_arch_name, #object ++cpu_arch_name: ++ .asciz "armv5te" ++ .size cpu_arch_name, . - cpu_arch_name ++ ++ .type cpu_elf_name, #object ++cpu_elf_name: ++ .asciz "v5" ++ .size cpu_elf_name, . - cpu_elf_name ++ .align ++ ++ .section ".proc.info", #alloc, #execinstr ++ ++ .type __80200_proc_info,#object ++__80200_proc_info: ++ .long 0x69052000 ++ .long 0xfffffff0 ++#if CACHE_WRITE_THROUGH ++ .long 0x00000c0a ++#else ++ .long 0x00000c0e ++#endif ++ b __xscale_setup ++ .long cpu_arch_name ++ .long cpu_elf_name ++ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_XSCALE ++ .long cpu_80200_info ++ .long xscale_processor_functions ++ .size __80200_proc_info, . - __80200_proc_info ++ ++ .type __pxa210_proc_info,#object ++__pxa210_proc_info: ++ .long 0x69052120 ++ .long 0xfffff3f0 ++#if CACHE_WRITE_THROUGH ++ .long 0x00000c0a ++#else ++ .long 0x00000c0e ++#endif ++ b __xscale_setup ++ .long cpu_arch_name ++ .long cpu_elf_name ++ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_XSCALE ++ .long cpu_pxa210_info ++ .long xscale_processor_functions ++ .size __pxa210_proc_info, . - __pxa210_proc_info ++ ++ .type __pxa250_proc_info,#object ++__pxa250_proc_info: ++ .long 0x69052100 ++ .long 0xfffff7f0 ++#if CACHE_WRITE_THROUGH ++ .long 0x00000c0a ++#else ++ .long 0x00000c0e ++#endif ++ b __xscale_setup ++ .long cpu_arch_name ++ .long cpu_elf_name ++ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_XSCALE ++ .long cpu_pxa250_info ++ .long xscale_processor_functions ++ .size __pxa250_proc_info, . - __pxa250_proc_info ++ ++ .type __pxa255_proc_info,#object ++__pxa255_proc_info: ++ .long 0x69052d00 ++ .long 0xfffffff0 ++#if CACHE_WRITE_THROUGH ++ .long 0x00000c0a ++#else ++ .long 0x00000c0e ++#endif ++ b __xscale_setup ++ .long cpu_arch_name ++ .long cpu_elf_name ++ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_XSCALE ++ .long cpu_pxa255_info ++ .long xscale_processor_functions ++ .size __pxa255_proc_info, . - __pxa255_proc_info ++ +--- /dev/null ++++ linux-2.4.27/arch/arm/vmlinux-armv-xip.lds.in +@@ -0,0 +1,125 @@ ++/* ++ * ld script to make ARM Linux kernel ++ * ++ * (C) Copyright 2001 Lineo Japan, Inc. ++ * ++ * May be copied or modified under the terms of the GNU General Public ++ * License. See linux/COPYING for more information. ++ * ++ * Based on arch/arm/vmlinux-armv.lds.in ++ * ++ * taken from the i386 version by Russell King ++ * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz> ++ */ ++OUTPUT_ARCH(arm) ++ENTRY(stext) ++SECTIONS ++{ ++ . = TEXTADDR; ++ .init : { /* Init code and data */ ++ _stext = .; ++ __init_begin = .; ++ *(.text.init) ++ __proc_info_begin = .; ++ *(.proc.info) ++ __proc_info_end = .; ++ __arch_info_begin = .; ++ *(.arch.info) ++ __arch_info_end = .; ++ __tagtable_begin = .; ++ *(.taglist) ++ __tagtable_end = .; ++ . = ALIGN(16); ++ __setup_start = .; ++ *(.setup.init) ++ __setup_end = .; ++ __initcall_start = .; ++ *(.initcall.init) ++ __initcall_end = .; ++ . = ALIGN(4096); ++ __init_end = .; ++ } ++ ++ /DISCARD/ : { /* Exit code and data */ ++ *(.text.exit) ++ *(.data.exit) ++ *(.exitcall.exit) ++ } ++ ++ .text : { /* Real text segment */ ++ _text = .; /* Text and read-only data */ ++ *(.text) ++ *(.fixup) ++ *(.gnu.warning) ++ *(.text.lock) /* out-of-line lock text */ ++ *(.rodata) ++ *(.rodata.*) ++ *(.glue_7) ++ *(.glue_7t) ++ *(.kstrtab) ++ *(.got) /* Global offset table */ ++ *(.got.plt) ++ ++ _etext = .; /* End of text section */ ++ } ++ ++ . = ALIGN(16); ++ __ex_table : { /* Exception table */ ++ __start___ex_table = .; ++ *(__ex_table) ++ __stop___ex_table = .; ++ } ++ ++ __ksymtab : { /* Kernel symbol table */ ++ __start___ksymtab = .; ++ *(__ksymtab) ++ __stop___ksymtab = .; ++ } ++ ++ _endtext = .; ++ ++ . = DATAADDR; ++ ++ _sdata = .; ++ ++ . = ALIGN(8192); ++ ++ .data : { ++ /* ++ * first, the init task union, aligned ++ * to an 8192 byte boundary. ++ */ ++ *(.init.task) ++ ++ /* ++ * then the cacheline aligned data ++ */ ++ . = ALIGN(32); ++ *(.data.cacheline_aligned) ++ ++ /* ++ * and the usual data section ++ */ ++ *(.data) ++ CONSTRUCTORS ++ ++ *(.data.init) ++ ++ _edata = .; ++ } ++ ++ .bss : { ++ __bss_start = .; /* BSS */ ++ *(.bss) ++ *(COMMON) ++ _end = . ; ++ } ++ /* Stabs debugging sections. */ ++ .stab 0 : { *(.stab) } ++ .stabstr 0 : { *(.stabstr) } ++ .stab.excl 0 : { *(.stab.excl) } ++ .stab.exclstr 0 : { *(.stab.exclstr) } ++ .stab.index 0 : { *(.stab.index) } ++ .stab.indexstr 0 : { *(.stab.indexstr) } ++ .comment 0 : { *(.comment) } ++} +--- linux-2.4.27/drivers/Makefile~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/Makefile +@@ -25,6 +25,7 @@ + subdir-$(CONFIG_NUBUS) += nubus + subdir-$(CONFIG_TC) += tc + subdir-$(CONFIG_VT) += video ++subdir-$(CONFIG_MMC) += mmc + subdir-$(CONFIG_MAC) += macintosh + subdir-$(CONFIG_PPC32) += macintosh + subdir-$(CONFIG_USB) += usb +--- linux-2.4.27/drivers/char/Config.in~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/char/Config.in +@@ -253,6 +253,7 @@ + dep_tristate ' DC21285 watchdog' CONFIG_21285_WATCHDOG $CONFIG_FOOTBRIDGE + dep_tristate ' NetWinder WB83C977 watchdog' CONFIG_977_WATCHDOG $CONFIG_ARCH_NETWINDER + dep_tristate ' SA1100 watchdog' CONFIG_SA1100_WATCHDOG $CONFIG_ARCH_SA1100 ++ dep_tristate ' PXA250/210 watchdog' CONFIG_SA1100_WATCHDOG $CONFIG_ARCH_PXA + dep_tristate ' EPXA watchdog' CONFIG_EPXA_WATCHDOG $CONFIG_ARCH_CAMELOT + dep_tristate ' Omaha watchdog' CONFIG_OMAHA_WATCHDOG $CONFIG_ARCH_OMAHA + dep_tristate ' AT91RM9200 watchdog' CONFIG_AT91_WATCHDOG $CONFIG_ARCH_AT91RM9200 +@@ -334,6 +335,9 @@ + if [ "$CONFIG_ARCH_SA1100" = "y" ]; then + tristate 'SA1100 Real Time Clock' CONFIG_SA1100_RTC + fi ++if [ "$CONFIG_ARCH_PXA" = "y" ]; then ++ tristate 'PXA250/210 Real Time Clock' CONFIG_PXA_RTC ++fi + if [ "$CONFIG_ARCH_OMAHA" = "y" ]; then + tristate 'Omaha Real Time Clock' CONFIG_OMAHA_RTC + fi +@@ -416,4 +420,8 @@ + dep_tristate 'HP OB600 C/CT Pop-up mouse support' CONFIG_OBMOUSE $CONFIG_INPUT_MOUSEDEV + fi + ++if [ "$CONFIG_ARCH_TRIZEPS2" = "y" ]; then ++ tristate ' MT6N TTL I/O suport' CONFIG_TRIZEPS2_TTLIO ++fi ++ + endmenu +--- linux-2.4.27/drivers/char/Makefile~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/char/Makefile +@@ -281,6 +281,7 @@ + obj-$(CONFIG_MIPS_RTC) += mips_rtc.o + obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o + obj-$(CONFIG_SA1100_RTC) += sa1100-rtc.o ++obj-$(CONFIG_PXA_RTC) += sa1100-rtc.o + obj-$(CONFIG_OMAHA_RTC) += omaha-rtc.o + ifeq ($(CONFIG_PPC),) + obj-$(CONFIG_NVRAM) += nvram.o +--- /dev/null ++++ linux-2.4.27/drivers/char/mt6n_ttl.c +@@ -0,0 +1,316 @@ ++/* ++ * Trizeps-2 MT6N development board TTL-IO interface for Linux ++ * ++ * Copyright (C) 2003 Luc De Cock ++ * ++ * This driver allows use of the TTL-IO interface on the MT6N ++ * from user space. It exports the /dev/ttlio interface supporting ++ * some ioctl() and also the /proc/driver/ttlio pseudo-file ++ * for status information. ++ * ++ * The ioctls can be used to set individual TTL output lines. ++ * Only ioctls are supported. ++ * ++ * 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. ++ * ++ * Based on other minimal char device drivers, like Alan's ++ * watchdog, Ted's random, Paul's rtc, etc. etc. ++ * ++ * 1.00 Luc De Cock: initial version. ++ */ ++ ++#define TTLIO_VERSION "1.00" ++ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/types.h> ++#include <linux/miscdevice.h> ++#include <linux/fcntl.h> ++#include <linux/init.h> ++#include <linux/poll.h> ++#include <linux/proc_fs.h> ++ ++#include <asm/io.h> ++#include <asm/uaccess.h> ++#include <asm/system.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++ ++/* Writing to the register sets the output lines ++* Reading from the register returns the status of the input lines ++*/ ++static unsigned short *ttlio_base = (unsigned short *) TRIZEPS2_TTLIO_BASE; ++static unsigned short ttlio_shadow = 0; ++ ++/* interrupt stuff */ ++static struct fasync_struct *ttlio_async_queue; ++static DECLARE_WAIT_QUEUE_HEAD(ttlio_wait); ++static int ttlio_irq_arrived = 0; ++static spinlock_t ttlio_lock; ++static unsigned short ttlio_in = 0; ++static volatile unsigned long teller = 0; ++ ++ ++static int ttlio_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg); ++ ++static int ttlio_read_proc(char *page, char **start, off_t off, ++ int count, int *eof, void *data); ++ ++ ++static void ttlio_interrupt(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ ttlio_in = *ttlio_base; ++ ++ ttlio_irq_arrived = 1; ++ teller++; ++ ++ /* wake up the waiting process */ ++ wake_up_interruptible(&ttlio_wait); ++ kill_fasync(&ttlio_async_queue, SIGIO, POLL_IN); ++} ++ ++/* ++ * Now all the various file operations that we export. ++ */ ++ ++static int ttlio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ unsigned long ttlio_val; ++ ++ switch (cmd) { ++ case TTLIO_RESET: /* clear all lines */ ++ { ++ *ttlio_base = 0; ++ return 0; ++ } ++ case TTLIO_GET: /* get state of TTL input lines */ ++ { ++ ttlio_val = *ttlio_base; ++ return put_user(ttlio_val, (unsigned long *)arg); ++ } ++ case TTLIO_SET: /* set state of TTL output lines */ ++ { ++ unsigned long user_val; ++ if (copy_from_user(&user_val, arg, sizeof(unsigned long))) ++ return -EFAULT; ++ ttlio_shadow |= (unsigned short) user_val; ++ *ttlio_base = ttlio_shadow; ++ return 0; ++ } ++ case TTLIO_UNSET: /* unset (clear) state of TTL output lines */ ++ { ++ unsigned long user_val; ++ if (copy_from_user(&user_val, arg, sizeof(unsigned long))) ++ return -EFAULT; ++ ttlio_shadow &= ~((unsigned short) user_val); ++ *ttlio_base = ttlio_shadow; ++ return 0; ++ } ++ case 100: /* get counter */ ++ { ++ return put_user(teller, (unsigned long *)arg); ++ } ++ case 101: /* reset counter */ ++ { ++ teller = 0; ++ return 0; ++ } ++ default: ++ return -ENOTTY; ++ } ++ return 0; ++} ++ ++static ssize_t ttlio_read(struct file *file, char *buf, ++ size_t count, loff_t *ppos) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned short data; ++ ssize_t retval; ++ ++ if (count < sizeof(unsigned short)) ++ return -EINVAL; ++ ++ if (file->f_flags & O_NONBLOCK) { ++ spin_lock_irq(&ttlio_lock); ++ data = *ttlio_base; ++ spin_unlock_irq(&ttlio_lock); ++ retval = put_user(data, (unsigned short *) buf); ++ if (!retval) ++ retval = sizeof(unsigned short); ++ return retval; ++ } ++ /* blocking read: wait for interrupt */ ++ add_wait_queue(&ttlio_wait, &wait); ++ set_current_state(TASK_INTERRUPTIBLE); ++ for (;;) { ++ spin_lock_irq(&ttlio_lock); ++ data = *ttlio_base; ++ if (ttlio_irq_arrived) { ++ ttlio_irq_arrived = 0; ++ break; ++ } ++ spin_unlock_irq(&ttlio_lock); ++ ++ if (signal_pending(current)) { ++ retval = -ERESTARTSYS; ++ goto out; ++ } ++ schedule(); ++ } ++ ++ spin_unlock_irq(&ttlio_lock); ++ retval = put_user(data, (unsigned short *)buf); ++ if (!retval) ++ retval = sizeof(unsigned short); ++ ++out: ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&ttlio_wait, &wait); ++ return retval; ++} ++ ++static ssize_t ttlio_write(struct file *file, ++ const char *buf, size_t count, loff_t *ppos) ++{ ++ unsigned short content; ++ ++ if (count < sizeof(unsigned short)) ++ return -EINVAL; ++ ++ if (copy_from_user (&content, buf, sizeof(unsigned short))) ++ return -EFAULT; ++ ++ ttlio_shadow = content; ++ *ttlio_base = ttlio_shadow; ++ ++ *ppos += sizeof(unsigned short); ++ ++ return sizeof(unsigned short); ++} ++ ++static int ttlio_open(struct inode *inode, struct file *file) ++{ ++ ttlio_irq_arrived = 0; ++ return 0; ++} ++ ++static int ttlio_fasync(int fd, struct file *filp, int on) ++{ ++ return fasync_helper(fd, filp, on, &ttlio_async_queue); ++} ++ ++static unsigned int ttlio_poll(struct file *file, poll_table *wait) ++{ ++ poll_wait(file, &ttlio_wait, wait); ++ return ttlio_irq_arrived ? 0 : POLLIN | POLLRDNORM; ++} ++ ++static loff_t ttlio_llseek(struct file *file, loff_t offset, int origin) ++{ ++ return -ESPIPE; ++} ++ ++/* ++ * The various file operations we support. ++ */ ++ ++static struct file_operations ttlio_fops = { ++ owner: THIS_MODULE, ++ llseek: ttlio_llseek, ++ read: ttlio_read, ++ poll: ttlio_poll, ++ write: ttlio_write, ++ ioctl: ttlio_ioctl, ++ open: ttlio_open, ++ fasync: ttlio_fasync, ++}; ++ ++static struct miscdevice ttlio_dev = { ++ TTLIO_MINOR, ++ "ttlio", ++ &ttlio_fops ++}; ++ ++static int __init ttlio_init(void) ++{ ++ printk(KERN_INFO "MT6N TTL-I/O driver (release %s)\n", ++ TTLIO_VERSION); ++ ++ misc_register(&ttlio_dev); ++ create_proc_read_entry ("driver/ttlio", 0, 0, ttlio_read_proc, NULL); ++ ++ set_GPIO_IRQ_edge(GPIO_TTLIO_IRQ, GPIO_FALLING_EDGE); ++ if (request_irq(TTLIO_IRQ, ttlio_interrupt, SA_INTERRUPT, "ttlio irq", NULL)) { ++ printk(KERN_ERR "ttlio: irq %d already in use\n", TTLIO_IRQ); ++ return 1; ++ } ++ return 0; ++} ++ ++static void __exit ttlio_exit(void) ++{ ++ free_irq(TTLIO_IRQ, NULL); ++ remove_proc_entry ("driver/ttlio", NULL); ++ misc_deregister(&ttlio_dev); ++} ++ ++module_init(ttlio_init); ++module_exit(ttlio_exit); ++EXPORT_NO_SYMBOLS; ++ ++/* ++ * Info exported via "/proc/driver/ttlio". ++ */ ++ ++static int ttlio_proc_output(char *buf) ++{ ++ char *p; ++ unsigned short val; ++ int i; ++ ++ p = buf; ++ ++ p += sprintf(p, "input : "); ++ /* write the state of the input lines */ ++ val = *ttlio_base; ++ for (i = 0; i < 8*sizeof(unsigned short); i++) { ++ *p++ = (val & 1) ? '1' : '0'; ++ val >>= 1; ++ } ++ *p = 0; ++ p += sprintf(p, "\noutput: "); ++ /* write the state of the output lines */ ++ val = ttlio_shadow; ++ for (i = 0; i < 8*sizeof(unsigned short); i++) { ++ *p++ = (val & 1) ? '1' : '0'; ++ val >>= 1; ++ } ++ *p = 0; ++ p += sprintf(p, "\n"); ++ ++ return p - buf; ++} ++ ++static int ttlio_read_proc(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len = ttlio_proc_output (page); ++ if (len <= off+count) *eof = 1; ++ *start = page + off; ++ len -= off; ++ if (len > count) len = count; ++ if (len < 0) len = 0; ++ return len; ++} ++ ++MODULE_AUTHOR("Luc De Cock"); ++MODULE_DESCRIPTION("MT6N TTL-I/O driver"); ++MODULE_LICENSE("GPL"); +--- linux-2.4.27/drivers/char/sa1100-rtc.c~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/char/sa1100-rtc.c +@@ -1,5 +1,6 @@ + /* + * Real Time Clock interface for Linux on StrongARM SA1100 ++ * and XScale PXA250/210. + * + * Copyright (c) 2000 Nils Faerber + * +@@ -470,5 +471,5 @@ + module_exit(rtc_exit); + + MODULE_AUTHOR("Nils Faerber <nils@@kernelconcepts.de>"); +-MODULE_DESCRIPTION("SA1100 Realtime Clock Driver (RTC)"); ++MODULE_DESCRIPTION("SA1100/PXA Realtime Clock Driver (RTC)"); + EXPORT_NO_SYMBOLS; +--- linux-2.4.27/drivers/char/sa1100_wdt.c~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/char/sa1100_wdt.c +@@ -1,5 +1,5 @@ + /* +- * Watchdog driver for the SA11x0 ++ * Watchdog driver for the SA11x0/PXA + * + * (c) Copyright 2000 Oleg Drokin <green@crimea.edu> + * Based on SoftDog driver by Alan Cox <alan@redhat.com> +@@ -35,13 +35,20 @@ + + #define TIMER_MARGIN 60 /* (secs) Default is 1 minute */ + +-static int sa1100_margin = TIMER_MARGIN; /* in seconds */ ++static int timer_margin = TIMER_MARGIN; /* in seconds */ + static int sa1100wdt_users; + static int pre_margin; + #ifdef MODULE +-MODULE_PARM(sa1100_margin,"i"); ++MODULE_PARM(timer_margin,"i"); + #endif + ++static void sa1100dog_ping( void) ++{ ++ /* reload counter with (new) margin */ ++ pre_margin=3686400 * timer_margin; ++ OSMR3 = OSCR + pre_margin; ++} ++ + /* + * Allow only one person to hold it open + */ +@@ -51,9 +58,7 @@ + if(test_and_set_bit(1,&sa1100wdt_users)) + return -EBUSY; + MOD_INC_USE_COUNT; +- /* Activate SA1100 Watchdog timer */ +- pre_margin=3686400 * sa1100_margin; +- OSMR3 = OSCR + pre_margin; ++ sa1100dog_ping(); + OSSR = OSSR_M3; + OWER = OWER_WME; + OIER |= OIER_E3; +@@ -93,8 +98,11 @@ + unsigned int cmd, unsigned long arg) + { + static struct watchdog_info ident = { +- identity: "SA1100 Watchdog", ++ identity: "PXA/SA1100 Watchdog", ++ options: WDIOF_SETTIMEOUT, ++ firmware_version: 0, + }; ++ int new_margin; + + switch(cmd){ + default: +@@ -108,6 +116,16 @@ + case WDIOC_KEEPALIVE: + OSMR3 = OSCR + pre_margin; + return 0; ++ case WDIOC_SETTIMEOUT: ++ if (get_user(new_margin, (int *)arg)) ++ return -EFAULT; ++ if (new_margin < 1) ++ return -EINVAL; ++ timer_margin = new_margin; ++ sa1100dog_ping(); ++ /* Fall */ ++ case WDIOC_GETTIMEOUT: ++ return put_user(timer_margin, (int *)arg); + } + } + +@@ -123,7 +141,11 @@ + static struct miscdevice sa1100dog_miscdev= + { + WATCHDOG_MINOR, +- "SA1100 watchdog", ++#if defined(CONFIG_SA1100_WATCHDOG) ++ "SA1100_watchdog", ++#elif defined(CONFIG_PXA_WATCHDOG) ++ "PXA_watchdog", ++#endif + &sa1100dog_fops + }; + +@@ -136,7 +158,7 @@ + if (ret) + return ret; + +- printk("SA1100 Watchdog Timer: timer margin %d sec\n", sa1100_margin); ++ printk("SA1100/PXA Watchdog Timer: timer margin %d sec\n", timer_margin); + + return 0; + } +--- linux-2.4.27/drivers/char/serial.c~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/char/serial.c +@@ -133,6 +133,16 @@ + #endif + #endif + ++#ifdef CONFIG_ARCH_PXA ++#define pxa_port(x) ((x) == PORT_PXA) ++#define pxa_buggy_port(x) ({ \ ++ int cpu_ver; asm("mrc%? p15, 0, %0, c0, c0" : "=r" (cpu_ver)); \ ++ ((x) == PORT_PXA && (cpu_ver & ~1) == 0x69052100); }) ++#else ++#define pxa_port(x) (0) ++#define pxa_buggy_port(x) (0) ++#endif ++ + /* Set of debugging defines */ + + #undef SERIAL_DEBUG_INTR +@@ -311,6 +321,7 @@ + { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO | + UART_STARTECH }, + { "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO }, ++ { "PXA UART", 32, UART_CLEAR_FIFO | UART_USE_FIFO }, + { 0, 0} + }; + +@@ -424,6 +435,9 @@ + case SERIAL_IO_MEM: + return readb((unsigned long) info->iomem_base + + (offset<<info->iomem_reg_shift)); ++ case SERIAL_IO_MEM32: ++ return readl((unsigned long) info->iomem_base + ++ (offset<<info->iomem_reg_shift)); + default: + return inb(info->port + offset); + } +@@ -443,6 +457,10 @@ + writeb(value, (unsigned long) info->iomem_base + + (offset<<info->iomem_reg_shift)); + break; ++ case SERIAL_IO_MEM32: ++ writel(value, (unsigned long) info->iomem_base + ++ (offset<<info->iomem_reg_shift)); ++ break; + default: + outb(value, info->port+offset); + } +@@ -1306,6 +1324,16 @@ + } + #endif + ++#ifdef CONFIG_ARCH_PXA ++ if (state->type == PORT_PXA) { ++ switch ((long)state->iomem_base) { ++ case (long)&FFUART: CKEN |= CKEN6_FFUART; break; ++ case (long)&BTUART: CKEN |= CKEN7_BTUART; break; ++ case (long)&STUART: CKEN |= CKEN5_STUART; break; ++ } ++ } ++#endif ++ + /* + * Clear the FIFO buffers and disable them + * (they will be reenabled in change_speed()) +@@ -1403,6 +1431,8 @@ + { + if (state->irq != 0) + info->MCR |= UART_MCR_OUT2; ++ if (pxa_buggy_port(state->type) && state->irq != 0) ++ info->MCR ^= UART_MCR_OUT2; + } + info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */ + serial_outp(info, UART_MCR, info->MCR); +@@ -1411,6 +1441,8 @@ + * Finally, enable interrupts + */ + info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; ++ if (pxa_port(state->type)) ++ info->IER |= UART_IER_UUE | UART_IER_RTOIE; + serial_outp(info, UART_IER, info->IER); /* enable interrupts */ + + #ifdef CONFIG_SERIAL_MANY_PORTS +@@ -1542,6 +1574,8 @@ + } else + #endif + info->MCR &= ~UART_MCR_OUT2; ++ if (pxa_buggy_port(state->type)) ++ info->MCR ^= UART_MCR_OUT2; + info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */ + + /* disable break condition */ +@@ -1567,6 +1601,20 @@ + state->baud_base = SERIAL_RSA_BAUD_BASE_LO; + #endif + ++#ifdef CONFIG_ARCH_PXA ++ if (state->type == PORT_PXA ++#ifdef CONFIG_SERIAL_CONSOLE ++ && sercons.index != info->line ++#endif ++ ) { ++ switch ((long)state->iomem_base) { ++ case (long)&FFUART: CKEN &= ~CKEN6_FFUART; break; ++ case (long)&BTUART: CKEN &= ~CKEN7_BTUART; break; ++ case (long)&STUART: CKEN &= ~CKEN5_STUART; break; ++ } ++ } ++#endif ++ + + (void)serial_in(info, UART_RX); /* read data port to reset things */ + +@@ -1857,6 +1905,8 @@ + save_flags(flags); cli(); + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); ++ if (pxa_buggy_port(info->state->type)) ++ rs_interrupt_single(info->state->irq, NULL, NULL); + restore_flags(flags); + } + +@@ -1933,6 +1983,11 @@ + && !(info->IER & UART_IER_THRI)) { + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); ++ if (pxa_buggy_port(info->state->type)) { ++ save_flags(flags); cli(); ++ rs_interrupt_single(info->state->irq, NULL, NULL); ++ restore_flags(flags); ++ } + } + return ret; + } +@@ -1990,6 +2045,8 @@ + /* Make sure transmit interrupts are on */ + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); ++ if (pxa_buggy_port(info->state->type)) ++ rs_interrupt_single(info->state->irq, NULL, NULL); + } + } + +@@ -5517,7 +5574,6 @@ + for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { + state->magic = SSTATE_MAGIC; + state->line = i; +- state->type = PORT_UNKNOWN; + state->custom_divisor = 0; + state->close_delay = 5*HZ/10; + state->closing_wait = 30*HZ; +@@ -5531,14 +5587,18 @@ + state->irq = irq_cannonicalize(state->irq); + if (state->hub6) + state->io_type = SERIAL_IO_HUB6; +- if (state->port && check_region(state->port,8)) ++ if (state->port && check_region(state->port,8)) { ++ state->type = PORT_UNKNOWN; + continue; ++ } + #ifdef CONFIG_MCA + if ((state->flags & ASYNC_BOOT_ONLYMCA) && !MCA_bus) + continue; + #endif +- if (state->flags & ASYNC_BOOT_AUTOCONF) ++ if (state->flags & ASYNC_BOOT_AUTOCONF) { ++ state->type = PORT_UNKNOWN; + autoconfig(state); ++ } + } + for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { + if (state->type == PORT_UNKNOWN) +@@ -5858,6 +5918,8 @@ + */ + ier = serial_in(info, UART_IER); + serial_out(info, UART_IER, 0x00); ++ if (pxa_port(info->state->type)) ++ serial_out(info, UART_IER, UART_IER_UUE); + + /* + * Now, do each character +@@ -6009,6 +6071,8 @@ + serial_out(info, UART_DLM, quot >> 8); /* MS of divisor */ + serial_out(info, UART_LCR, cval); /* reset DLAB */ + serial_out(info, UART_IER, 0); ++ if (pxa_port(info->state->type)) ++ serial_out(info, UART_IER, UART_IER_UUE); + serial_out(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); + + /* +--- linux-2.4.27/drivers/i2c/Config.in~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/i2c/Config.in +@@ -54,6 +54,11 @@ + fi + fi + ++ if [ "$CONFIG_ARCH_PXA" = "y" ]; then ++ dep_tristate 'PXA I2C Algorithm' CONFIG_I2C_PXA_ALGO $CONFIG_I2C ++ dep_tristate 'PXA I2C Adapter' CONFIG_I2C_PXA_ADAP $CONFIG_I2C_PXA_ALGO ++ fi ++ + if [ "$CONFIG_ALL_PPC" = "y" ] ; then + dep_tristate 'Keywest I2C interface in Apple Core99 machines' CONFIG_I2C_KEYWEST $CONFIG_I2C + fi +--- linux-2.4.27/drivers/i2c/Makefile~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/i2c/Makefile +@@ -6,7 +6,7 @@ + + export-objs := i2c-core.o i2c-algo-bit.o i2c-algo-pcf.o \ + i2c-algo-ite.o i2c-algo-sibyte.o i2c-algo-sgi.o \ +- i2c-proc.o ++ i2c-proc.o i2c-algo-pxa.o + + # Init order: core, chardev, bit adapters, pcf adapters + +@@ -34,6 +34,10 @@ + obj-$(CONFIG_I2C_ALGO_SIBYTE) += i2c-algo-sibyte.o i2c-sibyte.o + obj-$(CONFIG_I2C_MAX1617) += i2c-max1617.o + obj-$(CONFIG_I2C_ALGO_SGI) += i2c-algo-sgi.o ++# PXA adapters ++obj-$(CONFIG_I2C_PXA_ALGO) += i2c-algo-pxa.o ++obj-$(CONFIG_I2C_PXA_ADAP) += i2c-adap-pxa.o ++ + + # This is needed for automatic patch generation: sensors code starts here + # This is needed for automatic patch generation: sensors code ends here +--- /dev/null ++++ linux-2.4.27/drivers/i2c/i2c-adap-pxa.c +@@ -0,0 +1,396 @@ ++/* ++ * i2c_adap_pxa.c ++ * ++ * I2C adapter for the PXA I2C bus access. ++ * ++ * Copyright (C) 2002 Intrinsyc Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * History: ++ * Apr 2002: Initial version [CS] ++ * Jun 2002: Properly seperated algo/adap [FB] ++ * Jan 2003: Fixed several bugs concerning interrupt handling [Kai-Uwe Bloem] ++ * Jan 2003: added limited signal handling [Kai-Uwe Bloem] ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++ ++#include <linux/i2c.h> ++#include <linux/i2c-id.h> ++#include <linux/init.h> ++#include <linux/time.h> ++#include <linux/sched.h> ++#include <linux/delay.h> ++#include <linux/errno.h> ++ ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/arch/irqs.h> /* for IRQ_I2C */ ++ ++#include "i2c-pxa.h" ++ ++/* ++ * Set this to zero to remove all debug statements via dead code elimination. ++ */ ++//#define DEBUG 1 ++ ++#if DEBUG ++static unsigned int i2c_debug = DEBUG; ++#else ++#define i2c_debug 0 ++#endif ++ ++static int irq = 0; ++static volatile int i2c_pending = 0; /* interrupt pending when 1 */ ++static volatile int bus_error = 0; ++static volatile int tx_finished = 0; ++static volatile int rx_finished = 0; ++ ++static wait_queue_head_t i2c_wait; ++static void i2c_pxa_transfer( int lastbyte, int receive, int midbyte); ++ ++/* place a byte in the transmit register */ ++static void i2c_pxa_write_byte(u8 value) ++{ ++ IDBR = value; ++} ++ ++/* read byte in the receive register */ ++static u8 i2c_pxa_read_byte(void) ++{ ++ return (u8) (0xff & IDBR); ++} ++ ++static void i2c_pxa_start(void) ++{ ++ unsigned long icr = ICR; ++ icr |= ICR_START; ++ icr &= ~(ICR_STOP | ICR_ALDIE | ICR_ACKNAK); ++ ICR = icr; ++ ++ bus_error=0; /* clear any bus_error from previous txfers */ ++ tx_finished=0; /* clear rx and tx interrupts from previous txfers */ ++ rx_finished=0; ++ i2c_pending = 0; ++} ++ ++static void i2c_pxa_repeat_start(void) ++{ ++ unsigned long icr = ICR; ++ icr |= ICR_START; ++ icr &= ~(ICR_STOP | ICR_ALDIE); ++ ICR = icr; ++ ++ bus_error=0; /* clear any bus_error from previous txfers */ ++ tx_finished=0; /* clear rx and tx interrupts from previous txfers */ ++ rx_finished=0; ++ i2c_pending = 0; ++} ++ ++static void i2c_pxa_stop(void) ++{ ++ unsigned long icr = ICR; ++ icr |= ICR_STOP; ++ icr &= ~(ICR_START); ++ ICR = icr; ++} ++ ++static void i2c_pxa_midbyte(void) ++{ ++ unsigned long icr = ICR; ++ icr &= ~(ICR_START | ICR_STOP); ++ ICR = icr; ++} ++ ++static void i2c_pxa_abort(void) ++{ ++ unsigned long timeout = jiffies + HZ/4; ++ ++#ifdef PXA_ABORT_MA ++ while ((long)(timeout - jiffies) > 0 && (ICR & ICR_TB)) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(1); ++ } ++ ++ ICR |= ICR_MA; ++ udelay(100); ++#else ++ while ((long)(timeout - jiffies) > 0 && (IBMR & 0x1) == 0) { ++ i2c_pxa_transfer( 1, I2C_RECEIVE, 1); ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(1); ++ } ++#endif ++ ICR &= ~(ICR_MA | ICR_START | ICR_STOP); ++} ++ ++static int i2c_pxa_wait_bus_not_busy( void) ++{ ++ int timeout = DEF_TIMEOUT; ++ ++ while (timeout-- && (ISR & ISR_IBB)) { ++ udelay(100); /* wait for 100 us */ ++ } ++ ++ return (timeout<=0); ++} ++ ++static void i2c_pxa_wait_for_ite(void){ ++ unsigned long flags; ++ if (irq > 0) { ++ save_flags_cli(flags); ++ if (i2c_pending == 0) { ++ interruptible_sleep_on_timeout(&i2c_wait, I2C_SLEEP_TIMEOUT ); ++ } ++ i2c_pending = 0; ++ restore_flags(flags); ++ } else { ++ udelay(100); ++ } ++} ++ ++static int i2c_pxa_wait_for_int( int wait_type) ++{ ++ int timeout = DEF_TIMEOUT; ++#ifdef DEBUG ++ if (bus_error) ++ printk(KERN_INFO"i2c_pxa_wait_for_int: Bus error on enter\n"); ++ if (rx_finished) ++ printk(KERN_INFO"i2c_pxa_wait_for_int: Receive interrupt on enter\n"); ++ if (tx_finished) ++ printk(KERN_INFO"i2c_pxa_wait_for_int: Transmit interrupt on enter\n"); ++#endif ++ ++ if (wait_type == I2C_RECEIVE){ /* wait on receive */ ++ ++ do { ++ i2c_pxa_wait_for_ite(); ++ } while (!(rx_finished) && timeout-- && !signal_pending(current)); ++ ++#ifdef DEBUG ++ if (timeout<0){ ++ if (tx_finished) ++ printk("Error: i2c-algo-pxa.o: received a tx" ++ " interrupt while waiting on a rx in wait_for_int"); ++ } ++#endif ++ } else { /* wait on transmit */ ++ ++ do { ++ i2c_pxa_wait_for_ite(); ++ } while (!(tx_finished) && timeout-- && !signal_pending(current)); ++ ++#ifdef DEBUG ++ if (timeout<0){ ++ if (rx_finished) ++ printk("Error: i2c-algo-pxa.o: received a rx" ++ " interrupt while waiting on a tx in wait_for_int"); ++ } ++#endif ++ } ++ ++ udelay(ACK_DELAY); /* this is needed for the bus error */ ++ ++ tx_finished=0; ++ rx_finished=0; ++ ++ if (bus_error){ ++ bus_error=0; ++ if( i2c_debug > 2)printk("wait_for_int: error - no ack.\n"); ++ return BUS_ERROR; ++ } ++ ++ if (signal_pending(current)) { ++ return (-ERESTARTSYS); ++ } else if (timeout < 0) { ++ if( i2c_debug > 2)printk("wait_for_int: timeout.\n"); ++ return(-EIO); ++ } else ++ return(0); ++} ++ ++static void i2c_pxa_transfer( int lastbyte, int receive, int midbyte) ++{ ++ if( lastbyte) ++ { ++ if( receive==I2C_RECEIVE) ICR |= ICR_ACKNAK; ++ i2c_pxa_stop(); ++ } ++ else if( midbyte) ++ { ++ i2c_pxa_midbyte(); ++ } ++ ICR |= ICR_TB; ++} ++ ++static void i2c_pxa_reset( void) ++{ ++#ifdef DEBUG ++ printk("Resetting I2C Controller Unit\n"); ++#endif ++ ++ /* abort any transfer currently under way */ ++ i2c_pxa_abort(); ++ ++ /* reset according to 9.8 */ ++ ICR = ICR_UR; ++ ISR = I2C_ISR_INIT; ++ ICR &= ~ICR_UR; ++ ++ /* set the global I2C clock on */ ++ CKEN |= CKEN14_I2C; ++ ++ /* set our slave address */ ++ ISAR = I2C_PXA_SLAVE_ADDR; ++ ++ /* set control register values */ ++ ICR = I2C_ICR_INIT; ++ ++ /* clear any leftover states from prior transmissions */ ++ i2c_pending = rx_finished = tx_finished = bus_error = 0; ++ ++ /* enable unit */ ++ ICR |= ICR_IUE; ++ udelay(100); ++} ++ ++static void i2c_pxa_handler(int this_irq, void *dev_id, struct pt_regs *regs) ++{ ++ int status, wakeup = 0; ++ status = (ISR); ++ ++ if (status & ISR_BED){ ++ (ISR) |= ISR_BED; ++ bus_error=ISR_BED; ++ wakeup = 1; ++ } ++ if (status & ISR_ITE){ ++ (ISR) |= ISR_ITE; ++ tx_finished=ISR_ITE; ++ wakeup = 1; ++ } ++ if (status & ISR_IRF){ ++ (ISR) |= ISR_IRF; ++ rx_finished=ISR_IRF; ++ wakeup = 1; ++ } ++ if (wakeup) { ++ i2c_pending = 1; ++ wake_up_interruptible(&i2c_wait); ++ } ++} ++ ++static int i2c_pxa_resource_init( void) ++{ ++ init_waitqueue_head(&i2c_wait); ++ ++ if (request_irq(IRQ_I2C, &i2c_pxa_handler, SA_INTERRUPT, "I2C_PXA", 0) < 0) { ++ irq = 0; ++ if( i2c_debug) ++ printk(KERN_INFO "I2C: Failed to register I2C irq %i\n", IRQ_I2C); ++ return -ENODEV; ++ }else{ ++ irq = IRQ_I2C; ++ enable_irq(irq); ++ } ++ return 0; ++} ++ ++static void i2c_pxa_resource_release( void) ++{ ++ if( irq > 0) ++ { ++ disable_irq(irq); ++ free_irq(irq,0); ++ irq=0; ++ } ++} ++ ++static void i2c_pxa_inc_use(struct i2c_adapter *adap) ++{ ++#ifdef MODULE ++ MOD_INC_USE_COUNT; ++#endif ++} ++ ++static void i2c_pxa_dec_use(struct i2c_adapter *adap) ++{ ++#ifdef MODULE ++ MOD_DEC_USE_COUNT; ++#endif ++} ++ ++static int i2c_pxa_client_register(struct i2c_client *client) ++{ ++ return 0; ++} ++ ++static int i2c_pxa_client_unregister(struct i2c_client *client) ++{ ++ return 0; ++} ++ ++static struct i2c_algo_pxa_data i2c_pxa_data = { ++ write_byte: i2c_pxa_write_byte, ++ read_byte: i2c_pxa_read_byte, ++ ++ start: i2c_pxa_start, ++ repeat_start: i2c_pxa_repeat_start, ++ stop: i2c_pxa_stop, ++ abort: i2c_pxa_abort, ++ ++ wait_bus_not_busy: i2c_pxa_wait_bus_not_busy, ++ wait_for_interrupt: i2c_pxa_wait_for_int, ++ transfer: i2c_pxa_transfer, ++ reset: i2c_pxa_reset, ++ ++ udelay: 10, ++ timeout: DEF_TIMEOUT, ++}; ++ ++static struct i2c_adapter i2c_pxa_ops = { ++ name: "PXA-I2C-Adapter", ++ id: I2C_ALGO_PXA, ++ algo_data: &i2c_pxa_data, ++ inc_use: i2c_pxa_inc_use, ++ dec_use: i2c_pxa_dec_use, ++ client_register: i2c_pxa_client_register, ++ client_unregister: i2c_pxa_client_unregister, ++ retries: 2, ++}; ++ ++extern int i2c_pxa_add_bus(struct i2c_adapter *); ++extern int i2c_pxa_del_bus(struct i2c_adapter *); ++ ++static int __init i2c_adap_pxa_init(void) ++{ ++ if( i2c_pxa_resource_init() == 0) { ++ ++ if (i2c_pxa_add_bus(&i2c_pxa_ops) < 0) { ++ i2c_pxa_resource_release(); ++ printk(KERN_INFO "I2C: Failed to add bus\n"); ++ return -ENODEV; ++ } ++ } else { ++ return -ENODEV; ++ } ++ ++ printk(KERN_INFO "I2C: Successfully added bus\n"); ++ ++ return 0; ++} ++ ++static void i2c_adap_pxa_exit(void) ++{ ++ i2c_pxa_del_bus( &i2c_pxa_ops); ++ i2c_pxa_resource_release(); ++ ++ printk(KERN_INFO "I2C: Successfully removed bus\n"); ++} ++ ++module_init(i2c_adap_pxa_init); ++module_exit(i2c_adap_pxa_exit); +--- /dev/null ++++ linux-2.4.27/drivers/i2c/i2c-algo-pxa.c +@@ -0,0 +1,376 @@ ++/* ++ * i2c-algo-pxa.c ++ * ++ * I2C algorithm for the PXA I2C bus access. ++ * Byte driven algorithm similar to pcf. ++ * ++ * Copyright (C) 2002 Intrinsyc Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * History: ++ * Apr 2002: Initial version [CS] ++ * Jun 2002: Properly seperated algo/adap [FB] ++ * Jan 2003: added limited signal handling [Kai-Uwe Bloem] ++ * Jan 2003: allow SMBUS_QUICK as valid msg [FB] ++ * ++ */ ++#include <linux/kernel.h> ++#include <linux/module.h> ++ ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/errno.h> ++#include <linux/i2c.h> /* struct i2c_msg and others */ ++#include <linux/i2c-id.h> ++ ++#include "i2c-pxa.h" ++ ++/* ++ * Set this to zero to remove all the debug statements via dead code elimination. ++ */ ++//#define DEBUG 1 ++ ++#if DEBUG ++static unsigned int i2c_debug = DEBUG; ++#else ++#define i2c_debug 0 ++#endif ++ ++static int pxa_scan = 1; ++ ++static int i2c_pxa_valid_messages( struct i2c_msg msgs[], int num) ++{ ++ int i; ++ if (num < 1 || num > MAX_MESSAGES){ ++ if( i2c_debug) ++ printk(KERN_INFO "Invalid number of messages (max=%d, num=%d)\n", ++ MAX_MESSAGES, num); ++ return -EINVAL; ++ } ++ ++ /* check consistency of our messages */ ++ for (i=0;i<num;i++){ ++ if (&msgs[i]==NULL){ ++ if( i2c_debug) printk(KERN_INFO "Msgs is NULL\n"); ++ return -EINVAL; ++ } else { ++ if (msgs[i].len < 0 || msgs[i].buf == NULL){ ++ if( i2c_debug)printk(KERN_INFO "Length is less than zero"); ++ return -EINVAL; ++ } ++ } ++ } ++ ++ return 1; ++} ++ ++static int i2c_pxa_readbytes(struct i2c_adapter *i2c_adap, char *buf, ++ int count, int last) ++{ ++ ++ int i, timeout=0; ++ struct i2c_algo_pxa_data *adap = i2c_adap->algo_data; ++ ++ /* increment number of bytes to read by one -- read dummy byte */ ++ for (i = 0; i <= count; i++) { ++ if (i!=0){ ++ /* set ACK to NAK for last received byte ICR[ACKNAK] = 1 ++ only if not a repeated start */ ++ ++ if ((i == count) && last) { ++ adap->transfer( last, I2C_RECEIVE, 0); ++ }else{ ++ adap->transfer( 0, I2C_RECEIVE, 1); ++ } ++ ++ timeout = adap->wait_for_interrupt(I2C_RECEIVE); ++ ++#ifdef DEBUG ++ if (timeout==BUS_ERROR){ ++ printk(KERN_INFO "i2c_pxa_readbytes: bus error -> forcing reset\n"); ++ adap->reset(); ++ return I2C_RETRY; ++ } else ++#endif ++ if (timeout == -ERESTARTSYS) { ++ adap->abort(); ++ return timeout; ++ } else ++ if (timeout){ ++#ifdef DEBUG ++ printk(KERN_INFO "i2c_pxa_readbytes: timeout -> forcing reset\n"); ++#endif ++ adap->reset(); ++ return I2C_RETRY; ++ } ++ ++ } ++ ++ if (i) { ++ buf[i - 1] = adap->read_byte(); ++ } else { ++ adap->read_byte(); /* dummy read */ ++ } ++ } ++ return (i - 1); ++} ++ ++static int i2c_pxa_sendbytes(struct i2c_adapter *i2c_adap, const char *buf, ++ int count, int last) ++{ ++ ++ struct i2c_algo_pxa_data *adap = i2c_adap->algo_data; ++ int wrcount, timeout; ++ ++ for (wrcount=0; wrcount<count; ++wrcount) { ++ ++ adap->write_byte(buf[wrcount]); ++ if ((wrcount==(count-1)) && last) { ++ adap->transfer( last, I2C_TRANSMIT, 0); ++ }else{ ++ adap->transfer( 0, I2C_TRANSMIT, 1); ++ } ++ ++ timeout = adap->wait_for_interrupt(I2C_TRANSMIT); ++ ++#ifdef DEBUG ++ if (timeout==BUS_ERROR) { ++ printk(KERN_INFO "i2c_pxa_sendbytes: bus error -> forcing reset.\n"); ++ adap->reset(); ++ return I2C_RETRY; ++ } else ++#endif ++ if (timeout == -ERESTARTSYS) { ++ adap->abort(); ++ return timeout; ++ } else ++ if (timeout) { ++#ifdef DEBUG ++ printk(KERN_INFO "i2c_pxa_sendbytes: timeout -> forcing reset\n"); ++#endif ++ adap->reset(); ++ return I2C_RETRY; ++ } ++ } ++ return (wrcount); ++} ++ ++ ++static inline int i2c_pxa_set_ctrl_byte(struct i2c_algo_pxa_data * adap, struct i2c_msg *msg) ++{ ++ u16 flags = msg->flags; ++ u8 addr; ++ addr = (u8) ( (0x7f & msg->addr) << 1 ); ++ if (flags & I2C_M_RD ) ++ addr |= 1; ++ if (flags & I2C_M_REV_DIR_ADDR ) ++ addr ^= 1; ++ adap->write_byte(addr); ++ return 0; ++} ++ ++static int i2c_pxa_do_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) ++{ ++ struct i2c_algo_pxa_data * adap; ++ struct i2c_msg *pmsg=NULL; ++ int i; ++ int ret=0, timeout; ++ ++ adap = i2c_adap->algo_data; ++ ++ timeout = adap->wait_bus_not_busy(); ++ ++ if (timeout) { ++ return I2C_RETRY; ++ } ++ ++ for (i = 0;ret >= 0 && i < num; i++) { ++ int last = i + 1 == num; ++ pmsg = &msgs[i]; ++ ++ ret = i2c_pxa_set_ctrl_byte(adap,pmsg); ++ ++ /* Send START */ ++ if (i == 0) { ++ adap->start(); ++ }else{ ++ adap->repeat_start(); ++ } ++ ++ adap->transfer(0, I2C_TRANSMIT, 0); ++ ++ /* Wait for ITE (transmit empty) */ ++ timeout = adap->wait_for_interrupt(I2C_TRANSMIT); ++ ++#ifdef DEBUG ++ /* Check for ACK (bus error) */ ++ if (timeout==BUS_ERROR){ ++ printk(KERN_INFO "i2c_pxa_do_xfer: bus error -> forcing reset\n"); ++ adap->reset(); ++ return I2C_RETRY; ++ } else ++#endif ++ if (timeout == -ERESTARTSYS) { ++ adap->abort(); ++ return timeout; ++ } else ++ if (timeout) { ++#ifdef DEBUG ++ printk(KERN_INFO "i2c_pxa_do_xfer: timeout -> forcing reset\n"); ++#endif ++ adap->reset(); ++ return I2C_RETRY; ++ } ++/* FIXME: handle arbitration... */ ++#if 0 ++ /* Check for bus arbitration loss */ ++ if (adap->arbitration_loss()){ ++ printk("Arbitration loss detected \n"); ++ adap->reset(); ++ return I2C_RETRY; ++ } ++#endif ++ ++ /* Read */ ++ if (pmsg->flags & I2C_M_RD) { ++ /* read bytes into buffer*/ ++ ret = i2c_pxa_readbytes(i2c_adap, pmsg->buf, pmsg->len, last); ++#if DEBUG > 2 ++ if (ret != pmsg->len) { ++ printk(KERN_INFO"i2c_pxa_do_xfer: read %d/%d bytes.\n", ++ ret, pmsg->len); ++ } else { ++ printk(KERN_INFO"i2c_pxa_do_xfer: read %d bytes.\n",ret); ++ } ++#endif ++ } else { /* Write */ ++ ret = i2c_pxa_sendbytes(i2c_adap, pmsg->buf, pmsg->len, last); ++#if DEBUG > 2 ++ if (ret != pmsg->len) { ++ printk(KERN_INFO"i2c_pxa_do_xfer: wrote %d/%d bytes.\n", ++ ret, pmsg->len); ++ } else { ++ printk(KERN_INFO"i2c_pxa_do_xfer: wrote %d bytes.\n",ret); ++ } ++#endif ++ } ++ } ++ ++ if (ret<0){ ++ return ret; ++ }else{ ++ return i; ++ } ++} ++ ++static int i2c_pxa_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) ++{ ++ int retval = i2c_pxa_valid_messages( msgs, num); ++ if( retval > 0) ++ { ++ int i; ++ for (i=i2c_adap->retries; i>=0; i--){ ++ int retval = i2c_pxa_do_xfer(i2c_adap,msgs,num); ++ if (retval!=I2C_RETRY){ ++ return retval; ++ } ++ if( i2c_debug)printk(KERN_INFO"Retrying transmission \n"); ++ udelay(100); ++ } ++ if( i2c_debug)printk(KERN_INFO"Retried %i times\n",i2c_adap->retries); ++ return -EREMOTEIO; ++ ++ } ++ return retval; ++} ++ ++struct i2c_algorithm i2c_pxa_algorithm = { ++ name: "PXA-I2C-Algorithm", ++ id: I2C_ALGO_PXA, ++ master_xfer: i2c_pxa_xfer, ++ smbus_xfer: NULL, ++ slave_send: NULL, ++ slave_recv: NULL, ++ algo_control: NULL, ++}; ++ ++/* ++ * registering functions to load algorithms at runtime ++ */ ++int i2c_pxa_add_bus(struct i2c_adapter *i2c_adap) ++{ ++ struct i2c_algo_pxa_data *adap = i2c_adap->algo_data; ++ ++ printk(KERN_INFO"I2C: Adding %s.\n", i2c_adap->name); ++ ++ i2c_adap->algo = &i2c_pxa_algorithm; ++ ++ MOD_INC_USE_COUNT; ++ ++ /* register new adapter to i2c module... */ ++ i2c_add_adapter(i2c_adap); ++ ++ adap->reset(); ++ ++ /* scan bus */ ++ if (pxa_scan) { ++ int i; ++ printk(KERN_INFO "I2C: Scanning bus "); ++ for (i = 0x02; i < 0xff; i+=2) { ++ if( i==(I2C_PXA_SLAVE_ADDR<<1)) continue; ++ ++ if (adap->wait_bus_not_busy()) { ++ printk(KERN_INFO "I2C: scanning bus %s - TIMEOUTed.\n", ++ i2c_adap->name); ++ return -EIO; ++ } ++ adap->write_byte(i); ++ adap->start(); ++ adap->transfer(0, I2C_TRANSMIT, 0); ++ ++ if ((adap->wait_for_interrupt(I2C_TRANSMIT) != BUS_ERROR)) { ++ printk("(%02x)",i>>1); ++ adap->abort(); ++ } else { ++// printk("."); ++ adap->stop(); ++ } ++ udelay(adap->udelay); ++ } ++ printk("\n"); ++ } ++ return 0; ++} ++ ++int i2c_pxa_del_bus(struct i2c_adapter *i2c_adap) ++{ ++ int res; ++ if ((res = i2c_del_adapter(i2c_adap)) < 0) ++ return res; ++ ++ MOD_DEC_USE_COUNT; ++ ++ printk(KERN_INFO "I2C: Removing %s.\n", i2c_adap->name); ++ ++ return 0; ++} ++ ++static int __init i2c_algo_pxa_init (void) ++{ ++ printk(KERN_INFO "I2C: PXA algorithm module loaded.\n"); ++ return 0; ++} ++ ++EXPORT_SYMBOL(i2c_pxa_add_bus); ++EXPORT_SYMBOL(i2c_pxa_del_bus); ++ ++MODULE_PARM(pxa_scan, "i"); ++MODULE_PARM_DESC(pxa_scan, "Scan for active chips on the bus"); ++ ++MODULE_AUTHOR("Intrinsyc Software Inc."); ++MODULE_LICENSE("GPL"); ++ ++module_init(i2c_algo_pxa_init); +--- /dev/null ++++ linux-2.4.27/drivers/i2c/i2c-pxa.h +@@ -0,0 +1,76 @@ ++/* ++ * i2c_pxa.h ++ * ++ * Copyright (C) 2002 Intrinsyc Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++#ifndef _I2C_PXA_H_ ++#define _I2C_PXA_H_ ++ ++struct i2c_algo_pxa_data ++{ ++ void (*write_byte) (u8 value); ++ u8 (*read_byte) (void); ++ void (*start) (void); ++ void (*repeat_start) (void); ++ void (*stop) (void); ++ void (*abort) (void); ++ int (*wait_bus_not_busy) (void); ++ int (*wait_for_interrupt) (int wait_type); ++ void (*transfer) (int lastbyte, int receive, int midbyte); ++ void (*reset) (void); ++ ++ int udelay; ++ int timeout; ++}; ++ ++#define DEF_TIMEOUT 3 ++#define BUS_ERROR (-EREMOTEIO) ++#define ACK_DELAY 0 /* time to delay before checking bus error */ ++#define MAX_MESSAGES 65536 /* maximum number of messages to send */ ++ ++#define I2C_SLEEP_TIMEOUT 2 /* time to sleep for on i2c transactions */ ++#define I2C_RETRY (-2000) /* an error has occurred retry transmit */ ++#define I2C_TRANSMIT 1 ++#define I2C_RECEIVE 0 ++#define I2C_PXA_SLAVE_ADDR 0x1 /* slave pxa unit address */ ++#define I2C_ICR_INIT (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE) /* ICR initialization value */ ++/* ICR initialize bit values ++* ++* 15. FM 0 (100 Khz operation) ++* 14. UR 0 (No unit reset) ++* 13. SADIE 0 (Disables the unit from interrupting on slave addresses ++* matching its slave address) ++* 12. ALDIE 0 (Disables the unit from interrupt when it loses arbitration ++* in master mode) ++* 11. SSDIE 0 (Disables interrupts from a slave stop detected, in slave mode) ++* 10. BEIE 1 (Enable interrupts from detected bus errors, no ACK sent) ++* 9. IRFIE 1 (Enable interrupts from full buffer received) ++* 8. ITEIE 1 (Enables the I2C unit to interrupt when transmit buffer empty) ++* 7. GCD 1 (Disables i2c unit response to general call messages as a slave) ++* 6. IUE 0 (Disable unit until we change settings) ++* 5. SCLE 1 (Enables the i2c clock output for master mode (drives SCL) ++* 4. MA 0 (Only send stop with the ICR stop bit) ++* 3. TB 0 (We are not transmitting a byte initially) ++* 2. ACKNAK 0 (Send an ACK after the unit receives a byte) ++* 1. STOP 0 (Do not send a STOP) ++* 0. START 0 (Do not send a START) ++* ++*/ ++ ++#define I2C_ISR_INIT 0x7FF /* status register init */ ++/* I2C status register init values ++ * ++ * 10. BED 1 (Clear bus error detected) ++ * 9. SAD 1 (Clear slave address detected) ++ * 7. IRF 1 (Clear IDBR Receive Full) ++ * 6. ITE 1 (Clear IDBR Transmit Empty) ++ * 5. ALD 1 (Clear Arbitration Loss Detected) ++ * 4. SSD 1 (Clear Slave Stop Detected) ++ */ ++ ++#endif +--- linux-2.4.27/drivers/misc/Config.in~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/misc/Config.in +@@ -13,5 +13,6 @@ + dep_tristate 'Support for UCB1200 / UCB1300' CONFIG_MCP_UCB1200 $CONFIG_MCP + dep_tristate ' Audio / Telephony interface support' CONFIG_MCP_UCB1200_AUDIO $CONFIG_MCP_UCB1200 $CONFIG_SOUND + dep_tristate ' Touchscreen interface support' CONFIG_MCP_UCB1200_TS $CONFIG_MCP_UCB1200 ++dep_tristate ' UCB1400 Touchscreen support' CONFIG_MCP_UCB1400_TS $CONFIG_ARCH_PXA $CONFIG_SOUND + + endmenu +--- linux-2.4.27/drivers/misc/Makefile~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/misc/Makefile +@@ -11,13 +11,15 @@ + + O_TARGET := misc.o + +-export-objs := mcp-core.o mcp-sa1100.o ucb1x00-core.o ++export-objs := mcp-core.o mcp-sa1100.o mcp-pxa.o \ ++ ucb1x00-core.o + +-obj-$(CONFIG_MCP) += mcp-core.o +-obj-$(CONFIG_MCP_SA1100) += mcp-sa1100.o ++obj-$(CONFIG_MCP_SA1100) += mcp-core.o mcp-sa1100.o + obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o + obj-$(CONFIG_MCP_UCB1200_AUDIO) += ucb1x00-audio.o + obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o ++obj-$(CONFIG_MCP_UCB1400_TS) += mcp-pxa.o ucb1x00-core.o ucb1x00-ts.o ++obj-$(CONFIG_PXA_CERF_PDA) += cerf_ucb1400gpio.o + + include $(TOPDIR)/Rules.make + +--- /dev/null ++++ linux-2.4.27/drivers/misc/cerf_ucb1400gpio.c +@@ -0,0 +1,189 @@ ++/* ++ * cerf_ucb1400gpio.c ++ * ++ * UCB1400 GPIO control stuff for the cerf. ++ * ++ * Copyright (C) 2002 Intrinsyc Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * History: ++ * Mar 2002: Initial version [FB] ++ * Jun 2002: Removed ac97 dependency [FB] ++ * ++ */ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/ctype.h> ++#include <linux/mm.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++ ++#include <asm/system.h> ++#include <asm/hardware.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++ ++#include "ucb1x00.h" ++ ++/* ++ * Set this to zero to remove all the debug statements via ++ * dead code elimination. ++ */ ++#define DEBUGGING 0 ++ ++#if DEBUGGING ++static unsigned int ucb_debug = DEBUGGING; ++#else ++#define ucb_debug 0 ++#endif ++ ++#define UP 1 ++#define DOWN 0 ++ ++/* -- -- */ ++ ++void cerf_ucb1400gpio_lcd_enable( void) ++{ ++ struct ucb1x00 * ucb = ucb1x00_get(); ++ if( ucb_debug > 2) printk( KERN_INFO "Enabling LCD.\n"); ++ /* Enable [not] LCD_RESET to enable the LCD display */ ++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_LCD_RESET); ++ ucb1x00_io_write( ucb, UCB1400_GPIO_LCD_RESET, 0); ++ ++ /* Enable the Contrast circuit */ ++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_CONT_ENA); ++ ucb1x00_io_write( ucb, UCB1400_GPIO_CONT_ENA, 0); ++} ++ ++void cerf_ucb1400gpio_lcd_disable( void) ++{ ++ struct ucb1x00 * ucb = ucb1x00_get(); ++ if( ucb_debug > 2) printk( KERN_INFO "Disabling LCD.\n"); ++ /* Disable the Contrast circuit */ ++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_CONT_ENA); ++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_ENA); ++ ++ /* Disable [not] LCD_RESET to enable the LCD display */ ++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_LCD_RESET); ++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_LCD_RESET); ++} ++ ++void cerf_ucb1400gpio_lcd_contrast_step( int direction) ++{ ++ struct ucb1x00 * ucb = ucb1x00_get(); ++ // Assert the chip select and the up modifier ++ ucb1x00_io_set_dir( ucb, 0, ++ (UCB1400_GPIO_CONT_CS | ++ UCB1400_GPIO_CONT_DOWN | ++ UCB1400_GPIO_CONT_INC)); ++ ++ if( direction == DOWN) ++ { ++ if( ucb_debug > 3) ++ printk(KERN_INFO "cerf_ucb1400gpio_lcd_contrast_step: " ++ "stepping up\n"); ++ //goin' up ++ ucb1x00_io_write( ucb, UCB1400_GPIO_CONT_DOWN, 0); ++ } ++ else ++ { ++ if( ucb_debug > 3) ++ printk(KERN_INFO "cerf_ucb1400gpio_lcd_contrast_step: " ++ "stepping down\n"); ++ //goin' down ++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_DOWN); ++ } ++ ++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_CS); ++ ++ // Assert the line up, down then up again ++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_INC); ++ udelay(1); ++ ucb1x00_io_write( ucb, UCB1400_GPIO_CONT_INC, 0); ++ udelay(1); ++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_INC); ++ ++ // Deassert the chip select and the up modifier ++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_DOWN); ++ ucb1x00_io_write( ucb, UCB1400_GPIO_CONT_CS, 0); ++} ++ ++/* -- -- */ ++ ++void cerf_ucb1400gpio_irda_enable( void) ++{ ++ struct ucb1x00 * ucb = ucb1x00_get(); ++ printk( KERN_INFO "Enabling IRDA.\n"); ++ /* Enable IRDA (active low) */ ++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_IRDA_ENABLE); ++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_IRDA_ENABLE); ++} ++ ++void cerf_ucb1400gpio_irda_disable( void) ++{ ++ struct ucb1x00 * ucb = ucb1x00_get(); ++ printk( KERN_INFO "Disabling IRDA.\n"); ++ /* Disable IRDA (active low) */ ++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_IRDA_ENABLE); ++ ucb1x00_io_write( ucb, UCB1400_GPIO_IRDA_ENABLE, 0); ++} ++ ++/* -- -- */ ++ ++void cerf_ucb1400gpio_bt_enable( void) ++{ ++ struct ucb1x00 * ucb = ucb1x00_get(); ++ printk( KERN_INFO "Enabling Bluetooth.\n"); ++ /* Enable BT (active low) */ ++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_BT_ENABLE); ++ ucb1x00_io_write( ucb, 0, UCB1400_GPIO_BT_ENABLE); ++} ++ ++void cerf_ucb1400gpio_bt_disable( void) ++{ ++ struct ucb1x00 * ucb = ucb1x00_get(); ++ printk( KERN_INFO "Disabling Bluetooth.\n"); ++ /* Disable BT (active low) */ ++ ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_BT_ENABLE); ++ ucb1x00_io_write( ucb, UCB1400_GPIO_BT_ENABLE, 0); ++} ++ ++/* -- -- */ ++ ++/* -- Enable Bluetooth and IRDA automatically via pseudo module -- */ ++#if defined(CONFIG_BLUEZ) || defined(CONFIG_IRDA) ++static int __init cerf_ucb1400gpio_module_init (void) ++{ ++#ifdef CONFIG_BLUEZ ++ cerf_ucb1400gpio_bt_enable(); ++#endif ++ ++#ifdef CONFIG_IRDA ++ cerf_ucb1400gpio_irda_enable(); ++#endif ++ return 0; ++} ++ ++static void __exit cerf_ucb1400gpio_module_exit (void) ++{ ++#ifdef CONFIG_BLUEZ ++ cerf_ucb1400gpio_bt_disable(); ++#endif ++ ++#ifdef CONFIG_IRDA ++ cerf_ucb1400gpio_irda_disable(); ++#endif ++} ++ ++module_init(cerf_ucb1400gpio_module_init); ++module_exit(cerf_ucb1400gpio_module_exit); ++#endif ++ +--- /dev/null ++++ linux-2.4.27/drivers/misc/mcp-pxa.c +@@ -0,0 +1,57 @@ ++/* ++ * linux/drivers/misc/mcp-pxa.c ++ * ++ * 2002-01-10 Jeff Sutherland <jeffs@accelent.com> ++ * ++ * 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. ++ * ++ * NOTE: This is a quick hack to gain access to the aclink codec's ++ * touch screen facility. Its audio is handled by a separate ++ * (non-mcp) driver at the present time. ++ */ ++ ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/ac97_codec.h> ++ ++#include "mcp.h" ++ ++ ++extern int pxa_ac97_get(struct ac97_codec **codec); ++extern void pxa_ac97_put(void); ++ ++ ++struct mcp *mcp_get(void) ++{ ++ struct ac97_codec *codec; ++ if (pxa_ac97_get(&codec) < 0) ++ return NULL; ++ return (struct mcp *)codec; ++} ++ ++void mcp_reg_write(struct mcp *mcp, unsigned int reg, unsigned int val) ++{ ++ struct ac97_codec *codec = (struct ac97_codec *)mcp; ++ codec->codec_write(codec, reg, val); ++} ++ ++unsigned int mcp_reg_read(struct mcp *mcp, unsigned int reg) ++{ ++ struct ac97_codec *codec = (struct ac97_codec *)mcp; ++ return codec->codec_read(codec, reg); ++} ++ ++void mcp_enable(struct mcp *mcp) ++{ ++ /* ++ * Should we do something here to make sure the aclink ++ * codec is alive??? ++ * A: not for now --NP ++ */ ++} ++ ++void mcp_disable(struct mcp *mcp) ++{ ++} +--- linux-2.4.27/drivers/misc/mcp.h~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/misc/mcp.h +@@ -10,16 +10,22 @@ + #ifndef MCP_H + #define MCP_H + ++#ifdef CONFIG_ARCH_SA1100 ++#include <asm/dma.h> ++#endif ++ + struct mcp { + struct module *owner; + spinlock_t lock; + int use_count; + unsigned int sclk_rate; + unsigned int rw_timeout; ++#ifdef CONFIG_ARCH_SA1100 + dma_device_t dma_audio_rd; + dma_device_t dma_audio_wr; + dma_device_t dma_telco_rd; + dma_device_t dma_telco_wr; ++#endif + void (*set_telecom_divisor)(struct mcp *, unsigned int); + void (*set_audio_divisor)(struct mcp *, unsigned int); + void (*reg_write)(struct mcp *, unsigned int, unsigned int); +--- linux-2.4.27/drivers/misc/ucb1x00-core.c~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/misc/ucb1x00-core.c +@@ -23,12 +23,18 @@ + #include <linux/errno.h> + #include <linux/interrupt.h> + #include <linux/pm.h> ++#include <linux/tqueue.h> ++#include <linux/config.h> + +-#include <asm/dma.h> +-#include <asm/hardware.h> + #include <asm/irq.h> + #include <asm/mach-types.h> ++ ++#ifdef CONFIG_ARCH_SA1100 ++#include <asm/arch/assabet.h> + #include <asm/arch/shannon.h> ++#endif ++ ++#include <asm/hardware.h> + + #include "ucb1x00.h" + +@@ -155,6 +161,10 @@ + * + * If called for a synchronised ADC conversion, it may sleep + * with the ADC semaphore held. ++ * ++ * See ucb1x00.h for definition of the UCB_ADC_DAT macro. It ++ * addresses a bug in the ucb1200/1300 which, of course, Philips ++ * decided to finally fix in the ucb1400 ;-) -jws + */ + unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync) + { +@@ -218,22 +228,75 @@ + * Since we need to read an internal register, we must re-enable + * SIBCLK to talk to the chip. We leave the clock running until + * we have finished processing all interrupts from the chip. ++ * ++ * A restriction with interrupts exists when using the ucb1400, as ++ * the codec read/write routines may sleep while waiting for codec ++ * access completion and uses semaphores for access control to the ++ * AC97 bus. A complete codec read cycle could take anywhere from ++ * 60 to 100uSec so we *definitely* don't want to spin inside the ++ * interrupt handler waiting for codec access. So, we handle the ++ * interrupt by scheduling a RT kernel thread to run in process ++ * context instead of interrupt context. + */ +-static void ucb1x00_irq(int irqnr, void *devid, struct pt_regs *regs) ++ ++static int ucb1x00_thread(void *_ucb) + { +- struct ucb1x00 *ucb = devid; ++ struct task_struct *tsk = current; ++ DECLARE_WAITQUEUE(wait, tsk); ++ struct ucb1x00 *ucb = _ucb; + struct ucb1x00_irq *irq; + unsigned int isr, i; + +- ucb1x00_enable(ucb); +- isr = ucb1x00_reg_read(ucb, UCB_IE_STATUS); +- ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr); +- ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0); ++ ucb->rtask = tsk; + +- for (i = 0, irq = ucb->irq_handler; i < 16 && isr; i++, isr >>= 1, irq++) +- if (isr & 1 && irq->fn) +- irq->fn(i, irq->devid); +- ucb1x00_disable(ucb); ++ daemonize(); ++ reparent_to_init(); ++ tsk->tty = NULL; ++ tsk->policy = SCHED_FIFO; ++ tsk->rt_priority = 1; ++ strcpy(tsk->comm, "kUCB1x00d"); ++ ++ /* only want to receive SIGKILL */ ++ spin_lock_irq(&tsk->sigmask_lock); ++ siginitsetinv(&tsk->blocked, sigmask(SIGKILL)); ++ recalc_sigpending(tsk); ++ spin_unlock_irq(&tsk->sigmask_lock); ++ ++ add_wait_queue(&ucb->irq_wait, &wait); ++ set_task_state(tsk, TASK_INTERRUPTIBLE); ++ complete(&ucb->complete); ++ ++ for (;;) { ++ if (signal_pending(tsk)) ++ break; ++ enable_irq(ucb->irq); ++ schedule(); ++ ++ ucb1x00_enable(ucb); ++ isr = ucb1x00_reg_read(ucb, UCB_IE_STATUS); ++ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr); ++ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0); ++ ++ for (i = 0, irq = ucb->irq_handler; ++ i < 16 && isr; ++ i++, isr >>= 1, irq++) ++ if (isr & 1 && irq->fn) ++ irq->fn(i, irq->devid); ++ ucb1x00_disable(ucb); ++ ++ set_task_state(tsk, TASK_INTERRUPTIBLE); ++ } ++ ++ remove_wait_queue(&ucb->irq_wait, &wait); ++ ucb->rtask = NULL; ++ complete_and_exit(&ucb->complete, 0); ++} ++ ++static void ucb1x00_irq(int irqnr, void *devid, struct pt_regs *regs) ++{ ++ struct ucb1x00 *ucb = devid; ++ disable_irq(irqnr); ++ wake_up(&ucb->irq_wait); + } + + /** +@@ -291,6 +354,11 @@ + spin_lock_irqsave(&ucb->lock, flags); + + ucb1x00_enable(ucb); ++ ++ /* This prevents spurious interrupts on the UCB1400 */ ++ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 1 << idx); ++ ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0); ++ + if (edges & UCB_RISING) { + ucb->irq_ris_enbl |= 1 << idx; + ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl); +@@ -456,6 +524,7 @@ + unsigned int irq_gpio_pin = 0; + int irq, default_irq = NO_IRQ; + ++#ifdef CONFIG_ARCH_SA1100 + if (machine_is_adsbitsy()) + default_irq = IRQ_GPCIN4; + +@@ -514,12 +583,40 @@ + } + #endif + ++#endif /* CONFIG_ARCH_SA1100 */ ++ ++#ifdef CONFIG_ARCH_PXA_IDP ++ if (machine_is_pxa_idp()) { ++ default_irq = TOUCH_PANEL_IRQ; ++ irq_gpio_pin = IRQ_TO_GPIO_2_80(TOUCH_PANEL_IRQ); ++ GPDR(irq_gpio_pin) &= ~GPIO_bit(irq_gpio_pin); ++ } ++#endif ++ ++#ifdef CONFIG_ARCH_TRIZEPS2 ++ if (machine_is_trizeps2()) { ++ default_irq = TOUCH_PANEL_IRQ; ++ irq_gpio_pin = IRQ_TO_GPIO_2_80(TOUCH_PANEL_IRQ); ++ GPDR(irq_gpio_pin) &= ~GPIO_bit(irq_gpio_pin); ++ } ++#endif ++ ++ ++#ifdef CONFIG_PXA_CERF_PDA ++ if (machine_is_pxa_cerf()) { ++ irq_gpio_pin = CERF_GPIO_UCB1400_IRQ; ++ } ++#endif ++ + /* + * Eventually, this will disappear. + */ + if (irq_gpio_pin) ++#ifdef CONFIG_ARCH_PXA_IDP ++ set_GPIO_IRQ_edge(irq_gpio_pin, GPIO_FALLING_EDGE); ++#else + set_GPIO_IRQ_edge(irq_gpio_pin, GPIO_RISING_EDGE); +- ++#endif + irq = ucb1x00_detect_irq(ucb); + if (irq != NO_IRQ) { + if (default_irq != NO_IRQ && irq != default_irq) +@@ -541,21 +638,7 @@ + + struct ucb1x00 *my_ucb; + +-/** +- * ucb1x00_get - get the UCB1x00 structure describing a chip +- * @ucb: UCB1x00 structure describing chip +- * +- * Return the UCB1x00 structure describing a chip. +- * +- * FIXME: Currently very noddy indeed, which currently doesn't +- * matter since we only support one chip. +- */ +-struct ucb1x00 *ucb1x00_get(void) +-{ +- return my_ucb; +-} +- +-static int __init ucb1x00_init(void) ++static int ucb1x00_init_helper(void) + { + struct mcp *mcp; + unsigned int id; +@@ -568,23 +651,28 @@ + mcp_enable(mcp); + id = mcp_reg_read(mcp, UCB_ID); + +- if (id != UCB_ID_1200 && id != UCB_ID_1300) { ++ if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_1400) { + printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id); + goto out; + } + ++ /* distinguish between UCB1400 revs 1B and 2A */ ++ if (id == UCB_ID_1400 && mcp_reg_read(mcp, 0x00) == 0x002a) ++ id = UCB_ID_1400_BUGGY; ++ + my_ucb = kmalloc(sizeof(struct ucb1x00), GFP_KERNEL); + ret = -ENOMEM; + if (!my_ucb) + goto out; + ++#ifdef CONFIG_ARCH_SA1100 + if (machine_is_shannon()) { + /* reset the codec */ + GPDR |= SHANNON_GPIO_CODEC_RESET; + GPCR = SHANNON_GPIO_CODEC_RESET; + GPSR = SHANNON_GPIO_CODEC_RESET; +- + } ++#endif + + memset(my_ucb, 0, sizeof(struct ucb1x00)); + +@@ -599,13 +687,12 @@ + if (ret) + goto out; + ++ init_waitqueue_head(&my_ucb->irq_wait); + ret = request_irq(my_ucb->irq, ucb1x00_irq, 0, "UCB1x00", my_ucb); + if (ret) { + printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n", + my_ucb->irq, ret); +- kfree(my_ucb); +- my_ucb = NULL; +- goto out; ++ goto irq_err; + } + + #ifdef CONFIG_PM +@@ -616,16 +703,55 @@ + my_ucb->pmdev->data = my_ucb; + #endif + ++ init_completion(&my_ucb->complete); ++ ret = kernel_thread(ucb1x00_thread, my_ucb, CLONE_FS | CLONE_FILES); ++ if (ret >= 0) { ++ wait_for_completion(&my_ucb->complete); ++ ret = 0; ++ goto out; ++ } ++ ++ free_irq(my_ucb->irq, my_ucb); ++irq_err: ++ kfree(my_ucb); ++ my_ucb = NULL; + out: + mcp_disable(mcp); + no_mcp: + return ret; + } + ++/** ++ * ucb1x00_get - get the UCB1x00 structure describing a chip ++ * @ucb: UCB1x00 structure describing chip ++ * ++ * Return the UCB1x00 structure describing a chip. ++ * ++ * FIXME: Currently very noddy indeed, which currently doesn't ++ * matter since we only support one chip. ++ */ ++struct ucb1x00 *ucb1x00_get(void) ++{ ++ if( !my_ucb) ucb1x00_init_helper(); ++ ++ return my_ucb; ++} ++ ++static int __init ucb1x00_init(void) ++{ ++ /* check if driver is already initialized */ ++ if( my_ucb) return 0; ++ ++ return ucb1x00_init_helper(); ++} ++ + static void __exit ucb1x00_exit(void) + { ++ send_sig(SIGKILL, my_ucb->rtask, 1); ++ wait_for_completion(&my_ucb->complete); + free_irq(my_ucb->irq, my_ucb); + kfree(my_ucb); ++ my_ucb = 0; + } + + module_init(ucb1x00_init); +--- linux-2.4.27/drivers/misc/ucb1x00-ts.c~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/misc/ucb1x00-ts.c +@@ -35,7 +35,11 @@ + /* + * Define this if you want the UCB1x00 stuff to talk to the input layer + */ ++#ifdef CONFIG_INPUT ++#define USE_INPUT ++#else + #undef USE_INPUT ++#endif + + #ifndef USE_INPUT + +@@ -73,7 +77,7 @@ + struct pm_dev *pmdev; + #endif + +- wait_queue_head_t irq_wait; ++ struct semaphore irq_wait; + struct semaphore sem; + struct completion init_exit; + struct task_struct *rtask; +@@ -259,6 +263,11 @@ + input_report_abs(&ts->idev, ABS_PRESSURE, pressure); + } + ++static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts) ++{ ++ input_report_abs(&ts->idev, ABS_PRESSURE, 0); ++} ++ + static int ucb1x00_ts_open(struct input_dev *idev) + { + struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev; +@@ -304,10 +313,15 @@ + */ + static inline void ucb1x00_ts_mode_int(struct ucb1x00_ts *ts) + { +- ucb1x00_reg_write(ts->ucb, UCB_TS_CR, +- UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | +- UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | +- UCB_TS_CR_MODE_INT); ++ if (ts->ucb->id == UCB_ID_1400_BUGGY) ++ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, ++ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | ++ UCB_TS_CR_MODE_INT); ++ else ++ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, ++ UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | ++ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | ++ UCB_TS_CR_MODE_INT); + } + + /* +@@ -397,13 +411,13 @@ + /* + * This is a RT kernel thread that handles the ADC accesses + * (mainly so we can use semaphores in the UCB1200 core code +- * to serialise accesses to the ADC). ++ * to serialise accesses to the ADC). The UCB1400 access ++ * functions are expected to be able to sleep as well. + */ + static int ucb1x00_thread(void *_ts) + { + struct ucb1x00_ts *ts = _ts; + struct task_struct *tsk = current; +- DECLARE_WAITQUEUE(wait, tsk); + int valid; + + ts->rtask = tsk; +@@ -429,10 +443,8 @@ + + valid = 0; + +- add_wait_queue(&ts->irq_wait, &wait); + for (;;) { + unsigned int x, y, p, val; +- signed long timeout; + + ts->restart = 0; + +@@ -457,8 +469,6 @@ + val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR); + + if (val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW)) { +- set_task_state(tsk, TASK_INTERRUPTIBLE); +- + ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING); + ucb1x00_disable(ts->ucb); + +@@ -471,7 +481,15 @@ + valid = 0; + } + +- timeout = MAX_SCHEDULE_TIMEOUT; ++ /* ++ * Since ucb1x00_enable_irq() might sleep due ++ * to the way the UCB1400 regs are accessed, we ++ * can't use set_task_state() before that call, ++ * and not changing state before enabling the ++ * interrupt is racy. A semaphore solves all ++ * those issues quite nicely. ++ */ ++ down_interruptible(&ts->irq_wait); + } else { + ucb1x00_disable(ts->ucb); + +@@ -486,16 +504,13 @@ + } + + set_task_state(tsk, TASK_INTERRUPTIBLE); +- timeout = HZ / 100; ++ schedule_timeout(HZ / 100); + } + +- schedule_timeout(timeout); + if (signal_pending(tsk)) + break; + } + +- remove_wait_queue(&ts->irq_wait, &wait); +- + ts->rtask = NULL; + ucb1x00_ts_evt_clear(ts); + complete_and_exit(&ts->init_exit, 0); +@@ -509,7 +524,7 @@ + { + struct ucb1x00_ts *ts = id; + ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING); +- wake_up(&ts->irq_wait); ++ up(&ts->irq_wait); + } + + static int ucb1x00_ts_startup(struct ucb1x00_ts *ts) +@@ -525,7 +540,7 @@ + if (ts->rtask) + panic("ucb1x00: rtask running?"); + +- init_waitqueue_head(&ts->irq_wait); ++ sema_init(&ts->irq_wait, 0); + ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts); + if (ret < 0) + goto out; +@@ -585,7 +600,7 @@ + * after sleep. + */ + ts->restart = 1; +- wake_up(&ts->irq_wait); ++ up(&ts->irq_wait); + } + return 0; + } +--- linux-2.4.27/drivers/misc/ucb1x00.h~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/misc/ucb1x00.h +@@ -10,8 +10,47 @@ + #ifndef UCB1200_H + #define UCB1200_H + ++#ifdef CONFIG_ARCH_PXA ++ ++/* ucb1400 aclink register mappings: */ ++ ++#define UCB_IO_DATA 0x5a ++#define UCB_IO_DIR 0x5c ++#define UCB_IE_RIS 0x5e ++#define UCB_IE_FAL 0x60 ++#define UCB_IE_STATUS 0x62 ++#define UCB_IE_CLEAR 0x62 ++#define UCB_TS_CR 0x64 ++#define UCB_ADC_CR 0x66 ++#define UCB_ADC_DATA 0x68 ++#define UCB_ID 0x7e /* 7c is mfr id, 7e part id (from aclink spec) */ ++ ++#define UCB_ADC_DAT(x) ((x) & 0x3ff) ++ ++#else ++ ++/* ucb1x00 SIB register mappings: */ ++ + #define UCB_IO_DATA 0x00 + #define UCB_IO_DIR 0x01 ++#define UCB_IE_RIS 0x02 ++#define UCB_IE_FAL 0x03 ++#define UCB_IE_STATUS 0x04 ++#define UCB_IE_CLEAR 0x04 ++#define UCB_TC_A 0x05 ++#define UCB_TC_B 0x06 ++#define UCB_AC_A 0x07 ++#define UCB_AC_B 0x08 ++#define UCB_TS_CR 0x09 ++#define UCB_ADC_CR 0x0a ++#define UCB_ADC_DATA 0x0b ++#define UCB_ID 0x0c ++#define UCB_MODE 0x0d ++ ++#define UCB_ADC_DAT(x) (((x) & 0x7fe0) >> 5) ++ ++#endif ++ + + #define UCB_IO_0 (1 << 0) + #define UCB_IO_1 (1 << 1) +@@ -24,10 +63,6 @@ + #define UCB_IO_8 (1 << 8) + #define UCB_IO_9 (1 << 9) + +-#define UCB_IE_RIS 0x02 +-#define UCB_IE_FAL 0x03 +-#define UCB_IE_STATUS 0x04 +-#define UCB_IE_CLEAR 0x04 + #define UCB_IE_ADC (1 << 11) + #define UCB_IE_TSPX (1 << 12) + #define UCB_IE_TSMX (1 << 13) +@@ -36,11 +71,9 @@ + + #define UCB_IRQ_TSPX 12 + +-#define UCB_TC_A 0x05 + #define UCB_TC_A_LOOP (1 << 7) /* UCB1200 */ + #define UCB_TC_A_AMPL (1 << 7) /* UCB1300 */ + +-#define UCB_TC_B 0x06 + #define UCB_TC_B_VOICE_ENA (1 << 3) + #define UCB_TC_B_CLIP (1 << 4) + #define UCB_TC_B_ATT (1 << 6) +@@ -49,14 +82,11 @@ + #define UCB_TC_B_IN_ENA (1 << 14) + #define UCB_TC_B_OUT_ENA (1 << 15) + +-#define UCB_AC_A 0x07 +-#define UCB_AC_B 0x08 + #define UCB_AC_B_LOOP (1 << 8) + #define UCB_AC_B_MUTE (1 << 13) + #define UCB_AC_B_IN_ENA (1 << 14) + #define UCB_AC_B_OUT_ENA (1 << 15) + +-#define UCB_TS_CR 0x09 + #define UCB_TS_CR_TSMX_POW (1 << 0) + #define UCB_TS_CR_TSPX_POW (1 << 1) + #define UCB_TS_CR_TSMY_POW (1 << 2) +@@ -72,7 +102,6 @@ + #define UCB_TS_CR_TSPX_LOW (1 << 12) + #define UCB_TS_CR_TSMX_LOW (1 << 13) + +-#define UCB_ADC_CR 0x0a + #define UCB_ADC_SYNC_ENA (1 << 0) + #define UCB_ADC_VREFBYP_CON (1 << 1) + #define UCB_ADC_INP_TSPX (0 << 2) +@@ -87,15 +116,13 @@ + #define UCB_ADC_START (1 << 7) + #define UCB_ADC_ENA (1 << 15) + +-#define UCB_ADC_DATA 0x0b + #define UCB_ADC_DAT_VAL (1 << 15) +-#define UCB_ADC_DAT(x) (((x) & 0x7fe0) >> 5) + +-#define UCB_ID 0x0c + #define UCB_ID_1200 0x1004 + #define UCB_ID_1300 0x1005 ++#define UCB_ID_1400 0x4304 ++#define UCB_ID_1400_BUGGY 0x4303 /* fake ID */ + +-#define UCB_MODE 0x0d + #define UCB_MODE_DYN_VFLAG_ENA (1 << 12) + #define UCB_MODE_AUD_OFF_CAN (1 << 13) + +@@ -115,6 +142,9 @@ + unsigned int irq; + struct semaphore adc_sem; + spinlock_t io_lock; ++ wait_queue_head_t irq_wait; ++ struct completion complete; ++ struct task_struct *rtask; + u16 id; + u16 io_dir; + u16 io_out; +--- /dev/null ++++ linux-2.4.27/drivers/mmc/Config.in +@@ -0,0 +1,12 @@ ++mainmenu_option next_comment ++comment 'MMC device drivers' ++tristate 'Multi Media Card support' CONFIG_MMC ++if [ "$CONFIG_MMC" = "y" -o "$CONFIG_MMC" = "m" ]; then ++ dep_tristate 'PXA250 MMC driver' CONFIG_MMC_PXA $CONFIG_MMC ++ dep_tristate 'MMC block driver' CONFIG_MMC_BLOCK $CONFIG_MMC ++ if [ "$CONFIG_MMC_BLOCK" = "y" -o "$CONFIG_MMC_BLOCK" = "m" ]; then ++ bool ' MMC partitioning support' CONFIG_MMC_PARTITIONS ++ fi ++fi ++endmenu ++ +--- /dev/null ++++ linux-2.4.27/drivers/mmc/Makefile +@@ -0,0 +1,14 @@ ++# ++# Makefile for MMC drivers ++# ++ ++export-objs := mmc_core.o ++ ++obj-$(CONFIG_MMC) += mmc_core.o # mmc_test.o ++obj-$(CONFIG_MMC_BLOCK) += mmc_block.o ++obj-$(CONFIG_MMC_PXA) += mmc_pxa.o ++# EXTRA_CFLAGS += -DCONFIG_MMC_DEBUG -DCONFIG_MMC_DEBUG_VERBOSE=2 ++ ++O_TARGET := mmcdrivers.o ++ ++include $(TOPDIR)/Rules.make +--- /dev/null ++++ linux-2.4.27/drivers/mmc/error.h +@@ -0,0 +1,70 @@ ++/* ++ * linux/include/linux/mmc/error.h ++ * ++ * Author: Vladimir Shebordaev ++ * Copyright: MontaVista Software Inc. ++ * ++ * $Id: error.h,v 0.2 2002/07/11 16:27:01 ted Exp ted $ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef __MMC_ERROR_H__ ++#define __MMC_ERROR_H__ ++ ++/* MMC protocol card error codes */ ++#define MMC_CARD_STATUS_OUT_OF_RANGE (1<<31) ++#define MMC_CARD_STATUS_ADDRESS_ERROR (1<<30) ++#define MMC_CARD_STATUS_BLOCK_LEN_ERROR (1<<29) ++#define MMC_CARD_STATUS_ERASE_SEQ_ERROR (1<<28) ++#define MMC_CARD_STATUS_ERASE_PARAM (1<<27) ++#define MMC_CARD_STATUS_WP_VIOLATION (1<<26) ++#define MMC_CARD_STATUS_CARD_IS_LOCKED (1<<25) ++#define MMC_CARD_STATUS_LOCK_UNLOCK_FAILED (1<<24) ++#define MMC_CARD_STATUS_COM_CRC_ERROR (1<<23) ++#define MMC_CARD_STATUS_ILLEGAL_COMMAND (1<<22) ++#define MMC_CARD_STATUS_CARD_ECC_FAILED (1<<21) ++#define MMC_CARD_STATUS_CC_ERROR (1<<20) ++#define MMC_CARD_STATUS_ERROR (1<<19) ++#define MMC_CARD_STATUS_UNDERRUN (1<<18) ++#define MMC_CARD_STATUS_OVERRUN (1<<17) ++#define MMC_CARD_STATUS_CID_CSD_OVERWRITE (1<<16) ++#define MMC_CARD_STATUS_ERASE_RESET (1<<13) ++ ++#define MMC_ERROR( fmt, args... ) printk( KERN_ERR "%s(): " fmt, __FUNCTION__, ##args ) ++ ++/* ++ * Error codes returned by MMC subsystem functions and ++ * error reporting function prototypes ++ */ ++enum _mmc_error { ++/* controller errors */ ++ MMC_ERROR_GENERIC = -10000, ++ MMC_ERROR_CRC_WRITE_ERROR = -10001, ++ MMC_ERROR_CRC_READ_ERROR = -10002, ++ MMC_ERROR_RES_CRC_ERROR = -10003, ++ MMC_ERROR_READ_TIME_OUT = -10004, ++ MMC_ERROR_TIME_OUT_RESPONSE = -10005, ++ MMC_ERROR_INVAL = -10006, ++/* protocol errors reported in card status (R1 response) */ ++ MMC_ERROR_OUT_OF_RANGE = -10007, ++ MMC_ERROR_ADDRESS_ERROR = -10008, ++ MMC_ERROR_BLOCK_LEN_ERROR = -10009, ++ MMC_ERROR_ERASE_SEQ_ERROR = -10010, ++ MMC_ERROR_ERASE_PARAM = -10011, ++ MMC_ERROR_WP_VIOLATION = -10012, ++ MMC_ERROR_CARD_IS_LOCKED = -10013, ++ MMC_ERROR_LOCK_UNLOCK_FAILED = -10014, ++ MMC_ERROR_COM_CRC_ERROR = -10015, ++ MMC_ERROR_ILLEGAL_COMMAND = -10016, ++ MMC_ERROR_CARD_ECC_FAILED = -10017, ++ MMC_ERROR_CC_ERROR = -10018, ++ MMC_ERROR_ERROR = -10019, ++ MMC_ERROR_UNDERRUN = -10020, ++ MMC_ERROR_OVERRUN = -10021, ++ MMC_ERROR_CID_CSD_OVERWRITE = -10022, ++ /* FIXME: incomplete */ ++ MMC_ERROR_ERASE_RESET = -10025 ++}; ++#endif /* __MMC_ERROR_H__ */ +--- /dev/null ++++ linux-2.4.27/drivers/mmc/mmc.h +@@ -0,0 +1,463 @@ ++/* ++ * linux/drivers/mmc/mmc.h ++ * ++ * Author: Vladimir Shebordaev ++ * Copyright: MontaVista Software Inc. ++ * ++ * $Id: mmc.h,v 0.3.1.8 2002/09/18 12:58:00 ted Exp ted $ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef __MMC_P_H__ ++#define __MMC_P_H__ ++ ++#ifdef __KERNEL__ ++ ++#include <linux/types.h> ++#include <linux/slab.h> ++ ++#include <linux/spinlock.h> ++ ++#ifdef CONFIG_PROC_FS ++#include <linux/proc_fs.h> ++#endif ++ ++#include <asm/semaphore.h> ++#include <mmc/types.h> ++#include <mmc/mmc.h> ++ ++#include "types.h" ++ ++#include "error.h" ++ ++#define MMC_CONTROLLERS_MAX (4) ++#define MMC_CARDS_MAX (16) ++ ++/* test device */ ++#define MMC_TEST_MAJOR (240) ++#define MMC_TEST_TRANSFER_MODE_DEFAULT MMC_TRANSFER_MODE_BLOCK_SINGLE ++ ++/* block device */ ++#define MMC_BLOCK_MAJOR (241) /* FIXME: MMC_MAJOR */ ++#define MMC_BLOCK_DEVICES_MAX (1<<MINORBITS) /* FIXME */ ++#define MMC_BLOCK_SECT_SIZE (512) /* FIXME */ ++#define MMC_BLOCK_PARTNBITS (3) ++ ++/* Device minor number encoding: ++ * [7:6] - host ++ * [5:3] - card slot number ++ * [2:0] - partition number ++ */ ++#define MMC_MINOR_HOST_SHIFT (6) ++#define MMC_MINOR_CARD_MASK (0x07) ++ ++/* ++ * MMC controller abstraction ++ */ ++enum _mmc_controller_state { ++ MMC_CONTROLLER_ABSENT = 0, ++ MMC_CONTROLLER_FOUND, ++ MMC_CONTROLLER_INITIALIZED, ++ MMC_CONTROLLER_UNPLUGGED ++}; ++ ++enum _mmc_dir { ++ MMC_READ = 1, ++ MMC_WRITE ++}; ++ ++enum _mmc_buftype { ++ MMC_USER = 1, ++ MMC_KERNEL ++}; ++ ++struct _mmc_data_transfer_req_rec { ++ mmc_dir_t cmd; /* read or write operation requested */ ++ mmc_transfer_mode_t mode; /* requested data transfer mode */ ++ mmc_buftype_t type; /* whether supplied buffer resides in user or kernel space */ ++ char *buf; /* poiner to the caller's buffer */ ++ ssize_t cnt; /* number of bytes to transfer */ ++ loff_t addr; /* card address */ ++ ssize_t blksz; /* block size as for CSD[READ_BL_LEN] or CSD[WRITE_BL_LEN] */ ++ ssize_t nob; /* number of blocks to transfer */ ++}; ++ ++struct _mmc_controller_tmpl_rec { ++ struct module *owner; /* driver module */ ++ char name[16]; ++ ++ const ssize_t block_size_max; /* max acceptable block size */ ++ const ssize_t nob_max; /* max blocks per one data transfer */ ++ ++ int (*probe)( mmc_controller_t ); /* hardware probe */ ++ int (*init)( mmc_controller_t ); /* initialize, e.g. request irq, DMA and allocate buffers */ ++ void (*remove)( mmc_controller_t ); /* free resources */ ++#if 0 /* CONFIG_HOTPLUG */ ++ void (*attach)( void ); /|* controller hotplug callbacks *|/ ++ void (*detach)( void ); ++#endif ++#ifdef CONFIG_PM ++ int (*suspend)( mmc_controller_t ); /* power management callbacks */ ++ void (*resume)( mmc_controller_t ); ++#endif ++ ++/* MMC protocol macros, v3.4, p.120 */ ++ int (*init_card_stack)( mmc_controller_t ); ++ int (*update_acq)( mmc_controller_t ); /* update card stack management data */ ++ int (*single_card_acq)( mmc_controller_t ); ++ int (*check_card_stack)( mmc_controller_t ); ++ int (*setup_card)( mmc_controller_t, mmc_card_t ); ++ int (*stream_read)( mmc_controller_t, mmc_data_transfer_req_t ); ++ int (*read_block)( mmc_controller_t, mmc_data_transfer_req_t ); ++ int (*read_mblock)( mmc_controller_t, mmc_data_transfer_req_t ); ++ int (*stream_write)( mmc_controller_t, mmc_data_transfer_req_t ); ++ int (*write_block)( mmc_controller_t, mmc_data_transfer_req_t ); ++ int (*write_mblock)( mmc_controller_t, mmc_data_transfer_req_t ); ++/* TODO: ++ int (*sg_io)( mmc_controller_t, sg_list_t ); ++*/ ++/* TODO: ++ * 1) erase group macros ++ * int (*erase_group)( mmc_controller_t, mmc_erase_group_info_t ); ++ * 2) write protection macros; ++ * int (*set_write_prot)( mmc_controller_t, mmc_write_protection_info_t ) ++ * 3) lock/password management macros; ++ */ ++}; ++ ++#ifndef MMC_CTRLR_BLKSZ_DEFAULT ++#define MMC_CTRLR_BLKSZ_DEFAULT (512) ++#endif ++ ++#ifndef MMC_CTRLR_NOB_DEFAULT ++#define MMC_CTRLR_NOB_DEFAULT (1) ++#endif ++ ++struct _mmc_card_rec { ++/* public card interface */ ++ struct _mmc_card_info_rec info; /* see <linux/mmc/mmc.h> */ ++ ++/* private kernel specific data */ ++ mmc_state_t state; /* card's state as per last operation */ ++ mmc_card_t next; /* link to the stack */ ++ mmc_controller_t ctrlr; /* back reference to the controller */ ++ int usage; /* reference count */ ++ int slot; /* card's number for device reference */ ++/* TODO: async I/O queue */ ++#ifdef CONFIG_PROC_FS ++ proc_dir_entry_t proc; ++ char proc_name[16]; ++#endif ++ unsigned long card_data[0] /* card specific data */ ++ __attribute__((aligned (sizeof(unsigned long)))); ++}; ++ ++struct _mmc_card_stack_rec { ++ mmc_card_t first; /* first card on the stack */ ++ mmc_card_t last; /* last card on the stack */ ++ mmc_card_t selected; /* currently selected card */ ++ int ncards; ++}; ++ ++struct _mmc_controller_rec { ++ mmc_controller_state_t state; /* found, initialized, unplugged... */ ++ int usage; /* reference count */ ++ int slot; /* host's number for device reference */ ++ semaphore_t io_sem; /* I/O serialization */ ++ rwsemaphore_t update_sem; /* card stack check/update serialization */ ++ ++ mmc_controller_tmpl_t tmpl; /* methods provided by the driver */ ++ mmc_card_stack_rec_t stack; /* card stack management data */ ++ ++ u32 rca_next; /* next RCA to assign */ ++ int slot_next; /* next slot number to assign */ ++#ifdef CONFIG_PROC_FS ++ char proc_name[16]; ++ proc_dir_entry_t proc; ++#endif ++ unsigned long host_data[0] /* driver can request some extra space */ ++ __attribute__((aligned (sizeof(unsigned long)))); ++}; ++ ++/* ++ * MMC core interface ++ */ ++enum _mmc_reg_type { ++ MMC_REG_TYPE_USER = 1, ++ MMC_REG_TYPE_HOST, ++ MMC_REG_TYPE_CARD ++}; ++ ++struct _mmc_notifier_rec { ++ struct _mmc_notifier_rec *next; ++ mmc_notifier_fn_t add; ++ mmc_notifier_fn_t remove; ++}; ++ ++enum _mmc_response { ++ MMC_NORESPONSE = 1, ++ MMC_R1, ++ MMC_R2, ++ MMC_R3, ++ MMC_R4, ++ MMC_R5 ++}; ++ ++#undef EXTERN ++#ifndef __MMC_CORE_IMPLEMENTATION__ ++#define EXTERN extern ++#else ++#define EXTERN /* empty */ ++#endif ++ ++EXTERN void *mmc_register( mmc_reg_type_t, void *, size_t ); ++EXTERN void mmc_unregister( mmc_reg_type_t, void * ); ++EXTERN int mmc_update_card_stack( int ); ++ ++EXTERN mmc_card_t mmc_get_card( int, int );/* get reference to the card */ ++EXTERN void mmc_put_card( mmc_card_t ); /* release card reference */ ++ ++EXTERN int mmc_notify_add( mmc_card_t ); /* user notification */ ++EXTERN int mmc_notify_remove( mmc_card_t ); ++ ++EXTERN ssize_t mmc_read( mmc_card_t, mmc_transfer_mode_t, char *, size_t, loff_t * ); /* generic read */ ++EXTERN ssize_t mmc_write( mmc_card_t, mmc_transfer_mode_t, const char *, size_t, loff_t * ); /* generic write */ ++EXTERN int mmc_ioctl( mmc_card_t, unsigned int, unsigned long ); /* generic ioctl */ ++/* ++ * TODO: [?m.b. ioctl()] to erase, lock and write protect ++ * 1) mmc_erase ++ * 2) mmc_write_prot ++ * 3) mmc_lock ++ */ ++#undef EXTERN ++ ++static inline mmc_card_t __mmc_card_alloc( size_t extra ) ++{ ++ mmc_card_t ret = kmalloc( sizeof( mmc_card_rec_t ) + extra, GFP_KERNEL ); ++ ++ if ( ret ) { ++ memset( ret, 0, sizeof( mmc_card_rec_t ) + extra ); ++ } ++ ++ return ret; ++} ++ ++static inline void __mmc_card_free( mmc_card_t card ) ++{ ++ if ( card ) { ++ kfree( card ); ++ } ++} ++ ++static inline mmc_card_stack_t __mmc_card_stack_init( mmc_card_stack_t stack ) ++{ ++ mmc_card_stack_t ret = NULL; ++ if ( stack ) { ++ memset( stack, 0, sizeof( mmc_card_stack_rec_t ) ); ++ ret = stack; ++ } ++ return ret; ++} ++ ++static inline mmc_card_stack_t __mmc_card_stack_add( mmc_card_stack_t stack, mmc_card_t card ) ++{ ++ mmc_card_stack_t ret = NULL; ++ ++ if ( stack && card ) { ++ card->next = NULL; ++ ++ if ( stack->first ) { ++ stack->last->next = card; ++ stack->last = card; ++ } else ++ stack->first = stack->last = card; ++ ++ ++stack->ncards; ++ ret = stack; ++ } ++ return ret; ++} ++ ++static inline mmc_card_stack_t __mmc_card_stack_remove( mmc_card_stack_t stack, mmc_card_t card ) ++{ ++ mmc_card_stack_t ret = NULL; ++ register mmc_card_t prev; ++ int found = FALSE; ++ ++ if ( !stack || !card ) ++ goto error; ++ ++ if ( stack->ncards > 0 ) { ++ if ( stack->first == card ) { ++ stack->first = stack->first->next; ++ if ( stack->last == card ) ++ stack->last = stack->last->next; ++ found = TRUE; ++ } else { ++ for ( prev = stack->first; prev; prev = prev->next ) ++ if ( prev->next == card ) { ++ found = TRUE; ++ break; ++ } ++ if ( found ) { ++ if ( prev->next == stack->last ) ++ stack->last = prev->next; ++ prev->next = prev->next->next; ++ } ++ } ++ if ( found ) { ++ --stack->ncards; ++ ret = stack; ++ } ++ } ++error: ++ return ret; ++} ++ ++static inline void __mmc_card_stack_free( mmc_card_stack_t stack ) ++{ ++ mmc_card_t card, next; ++ ++ if ( stack && (stack->ncards > 0) ) { ++ card = stack->first; ++ while ( card ) { ++ next = card->next; ++ kfree( card ); ++ card = next; ++ } ++ __mmc_card_stack_init( stack ); ++ } ++} ++ ++static inline int __mmc_card_stack_foreach( mmc_card_stack_t stack, mmc_notifier_fn_t fn, int unplugged_also ) ++{ ++ int ret = 0; ++ register mmc_card_t card = NULL; ++ ++ if ( stack && fn ) { ++ for ( card = stack->first; card; card = card->next ) ++ if ( (card->state != MMC_CARD_STATE_UNPLUGGED) ++ || unplugged_also ) ++ if ( fn( card ) ) { ++ ret = -card->slot; ++ break; ++ } ++ } ++ ++ return ret; ++} ++ ++/* ++ * Debugging macros ++ */ ++#ifdef CONFIG_MMC_DEBUG ++ ++#define MMC_DEBUG_LEVEL0 (0) /* major */ ++#define MMC_DEBUG_LEVEL1 (1) ++#define MMC_DEBUG_LEVEL2 (2) /* device */ ++#define MMC_DEBUG_LEVEL3 (3) /* protocol */ ++#define MMC_DEBUG_LEVEL4 (4) /* everything */ ++ ++#define MMC_DEBUG(n, args...) \ ++if (n <= CONFIG_MMC_DEBUG_VERBOSE) { \ ++ printk(KERN_INFO __FUNCTION__ "(): " args); \ ++} ++#define __ENTER0( ) MMC_DEBUG( MMC_DEBUG_LEVEL2, "entry\n" ); ++#define __LEAVE0( ) MMC_DEBUG( MMC_DEBUG_LEVEL2, "exit\n" ); ++#define __ENTER( format, args... ) MMC_DEBUG( MMC_DEBUG_LEVEL2, "entry: " format "\n", args ); ++#define __LEAVE( format, args... ) MMC_DEBUG( MMC_DEBUG_LEVEL2, "exit: " format "\n", args ); ++ ++#define MMC_DUMP_CSD( card ) MMC_DEBUG( MMC_DEBUG_LEVEL3, \ ++"CSD register:\n" \ ++" csd_structure=%u\n" \ ++" spec_vers=%u\n" \ ++" taac=%x\n" \ ++" nsac=%x\n" \ ++" tran_speed=%x\n" \ ++" ccc=%x\n" \ ++" read_bl_len=%u\n" \ ++" read_bl_partial=%u\n" \ ++" write_blk_misalign=%u\n" \ ++" read_blk_misalign=%u\n" \ ++" dsr_imp=%u\n" \ ++" c_size=%u\n" \ ++" vdd_r_curr_min=%u\n" \ ++" vdd_r_curr_max=%u\n" \ ++" vdd_w_curr_min=%u\n" \ ++" vdd_w_curr_max=%u\n" \ ++" c_size_mult=%u\n" \ ++" erase_grp_size=%u\n" \ ++" erase_grp_mult=%u\n" \ ++" wp_grp_size=%u\n" \ ++" wp_grp_enable=%u\n" \ ++" default_ecc=%u\n" \ ++" r2w_factor=%u\n" \ ++" write_bl_len=%u\n" \ ++" write_bl_partial=%u\n" \ ++" content_prot_app=%u\n" \ ++" file_format_grp=%u\n" \ ++" copy=%u\n" \ ++" perm_write_protect=%d\n" \ ++" tmp_write_protect=%d\n" \ ++" file_format=%d\n" \ ++" ecc=%d\n", \ ++card->info.csd.csd_structure, \ ++card->info.csd.spec_vers, \ ++card->info.csd.taac, \ ++card->info.csd.nsac, \ ++card->info.csd.tran_speed, \ ++card->info.csd.ccc, \ ++card->info.csd.read_bl_len, \ ++card->info.csd.read_bl_partial, \ ++card->info.csd.write_blk_misalign, \ ++card->info.csd.read_blk_misalign, \ ++card->info.csd.dsr_imp, \ ++card->info.csd.c_size, \ ++card->info.csd.vdd_r_curr_min, \ ++card->info.csd.vdd_r_curr_max, \ ++card->info.csd.vdd_w_curr_min, \ ++card->info.csd.vdd_w_curr_max, \ ++card->info.csd.c_size_mult, \ ++card->info.csd.erase_grp_size, \ ++card->info.csd.erase_grp_mult, \ ++card->info.csd.wp_grp_size, \ ++card->info.csd.wp_grp_enable, \ ++card->info.csd.default_ecc, \ ++card->info.csd.r2w_factor, \ ++card->info.csd.write_bl_len, \ ++card->info.csd.write_bl_partial, \ ++card->info.csd.content_prot_app, \ ++card->info.csd.file_format_grp, \ ++card->info.csd.copy, \ ++card->info.csd.perm_write_protect, \ ++card->info.csd.tmp_write_protect, \ ++card->info.csd.file_format, \ ++card->info.csd.ecc ); ++ ++#else /* CONFIG_MMC_DEBUG */ ++#define MMC_DEBUG(n, args...) /* empty */ ++#define __ENTER0( ) /* empty */ ++#define __LEAVE0( ) /* empty */ ++#define __ENTER( args... ) /* empty */ ++#define __LEAVE( args... ) /* empty */ ++#define MMC_DUMP_CSD( card ) /* empty */ ++#endif /* CONFIG_MMC_DEBUG */ ++ ++/* ++ * Miscellaneous defines ++ */ ++#ifndef MMC_DUMP_R1 ++#define MMC_DUMP_R1( ctrlr ) /* empty */ ++#endif ++#ifndef MMC_DUMP_R2 ++#define MMC_DUMP_R2( ctrlr ) /* empty */ ++#endif ++#ifndef MMC_DUMP_R3 ++#define MMC_DUMP_R3( ctrlr ) /* empty */ ++#endif ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* __MMC_P_H__ */ +--- /dev/null ++++ linux-2.4.27/drivers/mmc/mmc_block.c +@@ -0,0 +1,989 @@ ++/* ++ * linux/drivers/mmc/mmc_block.c ++ * driver for the block device on the MMC card ++ * ++ * Author: Vladimir Shebordaev ++ * Copyright: MontaVista Software Inc. ++ * ++ * $Id: mmc_block.c,v 0.3.1.16 2002/09/27 17:36:09 ted Exp ted $ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/version.h> ++#include <linux/config.h> ++#include <linux/types.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/devfs_fs_kernel.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/hdreg.h> ++#include <linux/blkpg.h> ++#include <asm/uaccess.h> ++ ++#include <mmc/types.h> ++#include <mmc/mmc.h> ++ ++#include "types.h" ++#include "mmc.h" ++#include "error.h" ++ ++#define MAJOR_NR MMC_BLOCK_MAJOR ++#define MAJOR_NAME "mmc" ++#define DEVICE_NAME "mmc_block" ++#define DEVICE_REQUEST mmc_block_request ++#define DEVICE_NR(device) (device) ++#define DEVICE_ON(device) ++#define DEVICE_OFF(device) ++#define DEVICE_NO_RANDOM ++#include <linux/blk.h> ++/* for old kernels... */ ++#ifndef QUEUE_EMPTY ++#define QUEUE_EMPTY (!CURRENT) ++#endif ++#if LINUX_VERSION_CODE < 0x20300 ++#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].plug_tq.sync) ++#else ++#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].request_queue.plugged) ++#endif ++ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14) ++#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT ++#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT ++#else ++#define BLK_INC_USE_COUNT do {} while(0) ++#define BLK_DEC_USE_COUNT do {} while(0) ++#endif ++ ++#define MMC_BLOCK_RAW_DEVICE( device ) ((device>>MMC_BLOCK_PARTNBITS)<<MMC_BLOCK_PARTNBITS) ++#define MMC_BLOCK_MKDEV( host, slot ) \ ++ MKDEV( MMC_BLOCK_MAJOR, \ ++ (host<<MMC_MINOR_HOST_SHIFT) \ ++ | (slot<<MMC_BLOCK_PARTNBITS) ) ++ ++typedef struct _mmc_block_device mmc_block_device_rec_t; ++typedef struct _mmc_block_device *mmc_block_device_t; ++ ++struct _mmc_block_device { ++ mmc_card_t card; ++ int host; ++ int slot; ++ kdev_t rdev; ++ int usage; ++ semaphore_t sem; ++}; ++ ++static int mmc_block_blk_sizes[1<<MINORBITS]; ++static int mmc_block_blk_blksizes[1<<MINORBITS]; ++static int mmc_block_hardsect_sizes[1<<MINORBITS]; ++static struct hd_struct mmc_block_partitions[1<<MINORBITS]; ++ ++/* Accessed under device table lock */ ++static gendisk_rec_t mmc_block_gendisk = { ++ major: MMC_BLOCK_MAJOR, ++ major_name: MAJOR_NAME, ++ minor_shift: MMC_BLOCK_PARTNBITS, ++ max_p: (1<<MMC_BLOCK_PARTNBITS), ++ sizes: mmc_block_blk_sizes, ++ part: mmc_block_partitions ++}; ++ ++static mmc_block_device_rec_t mmc_block_device[1<<MINORBITS]; ++static rwsemaphore_t mmc_block_device_sem; ++ ++static inline void __mmc_block_rdlock_devices( void ) ++{ ++ down_read( &mmc_block_device_sem ); ++} ++ ++static inline void __mmc_block_rdunlock_devices( void ) ++{ ++ up_read( &mmc_block_device_sem ); ++} ++ ++static inline void __mmc_block_wrlock_devices( void ) ++{ ++ down_write( &mmc_block_device_sem ); ++} ++ ++static inline void __mmc_block_wrunlock_devices( void ) ++{ ++ up_write( &mmc_block_device_sem ); ++} ++ ++static inline void __mmc_block_lock_device( kdev_t rdev ) ++{ ++ __mmc_block_rdlock_devices(); ++ down( &mmc_block_device[MINOR( rdev )].sem ); ++} ++ ++static inline void __mmc_block_unlock_device( kdev_t rdev ) ++{ ++ up( &mmc_block_device[MINOR( rdev )].sem ); ++ __mmc_block_rdunlock_devices(); ++} ++ ++static inline void __mmc_block_device_init( int minor ) ++{ ++ mmc_block_device_t dev = &mmc_block_device[minor]; ++ ++ dev->usage = 0; ++ dev->card = NULL; ++ dev->host = minor >> MMC_MINOR_HOST_SHIFT; ++ dev->slot = (minor & MMC_MINOR_CARD_MASK)>>MMC_BLOCK_PARTNBITS; ++ dev->rdev = MKDEV( MMC_BLOCK_MAJOR, minor ); ++} ++ ++static inline int __mmc_block_validate_device( kdev_t rdev ) ++{ ++ int ret = -1; ++ int minor = MINOR( rdev ); ++ ++ if ( mmc_block_device[minor].card ++ && (mmc_block_gendisk.part[minor].nr_sects > 0) ) ++ ret = 0; ++ ++ return ret; ++} ++ ++static inline int __mmc_block_invalidate_card( mmc_card_t card, int invalidate ) ++{ ++ int ret = 0; ++ kdev_t start; ++ int minor; ++ ++ __ENTER( "card = 0x%p", card ); ++ ++ if ( card && card->ctrlr ) { ++ register int i; ++ ++ start = MMC_BLOCK_MKDEV( card->ctrlr->slot, card->slot ); ++ minor = MINOR( start ); ++ ++ __mmc_block_wrlock_devices(); ++ for ( i = mmc_block_gendisk.max_p - 1; i >= 0; --i ) { ++ if ( invalidate ) ++ invalidate_device( start + i, 0 ); ++ ++ __mmc_block_device_init( minor + i ); ++ ++ mmc_block_gendisk.part[minor + i].nr_sects = 0; ++ mmc_block_gendisk.part[minor + i].start_sect = 0; ++ } ++ __mmc_block_wrunlock_devices(); ++ } ++ ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++static inline int mmc_block_invalidate_card( int host, int slot, int invalidate ) ++{ ++ int ret = 0; ++ kdev_t start; ++ int minor; ++ ++ __ENTER( "host=%d slot=%d", host, slot ); ++ ++ if ( (host >= 0) && (slot >= 0) ) { ++ register int i; ++ mmc_card_t card = NULL; ++ ++ start = MMC_BLOCK_MKDEV( host, slot ); ++ minor = MINOR( start ); ++ ++ __mmc_block_wrlock_devices(); ++ for ( i = mmc_block_gendisk.max_p - 1; i >= 0; --i ) { ++ if ( !card ) ++ card = mmc_block_device[minor + i].card; ++ ++ if ( invalidate ) ++ invalidate_device( start + i, 0 ); ++ ++ __mmc_block_device_init( minor + i ); ++ ++ mmc_block_gendisk.part[minor + i].nr_sects = 0; ++ mmc_block_gendisk.part[minor + i].start_sect = 0; ++ } ++ if ( card ) ++ mmc_put_card( card ); ++ __mmc_block_wrunlock_devices(); ++ } ++ ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++/* Get device reference locked for writing */ ++static inline mmc_block_device_t __mmc_block_get_device( kdev_t rdev ) ++{ ++ mmc_block_device_t ret = NULL; ++ u8 minor = MINOR( rdev ); ++ int host_no, card_no; ++ ++ __ENTER( "rdev=%x:%x", MAJOR( rdev ), MINOR( rdev ) ); ++ ++ host_no = minor >> MMC_MINOR_HOST_SHIFT; ++ if ( host_no >= MMC_CONTROLLERS_MAX ) ++ goto error; ++ ++ card_no = (minor & MMC_MINOR_CARD_MASK)>>MMC_BLOCK_PARTNBITS; ++ if ( card_no >= MMC_CARDS_MAX ) ++ goto error; ++ ++ __mmc_block_lock_device( rdev ); ++ if ( __mmc_block_validate_device( rdev ) ) { ++ __mmc_block_unlock_device( rdev ); ++ goto error; ++ } ++ ++ ret = &mmc_block_device[minor]; ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "(%x:%x) card=%p, dusage=%d\n", ++ MAJOR( ret->rdev ), MINOR( ret->rdev ), ++ ret->card, ret->usage ); ++error: ++ __LEAVE( "ret=0x%p", ret ); ++ return ret; ++} ++ ++/* Unlocks the device */ ++static inline void __mmc_block_put_device( mmc_block_device_t dev ) ++{ ++ __ENTER0(); ++ ++ if ( dev ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "(%x:%x) card=%p, dusage=%d\n", ++ MAJOR( dev->rdev ), MINOR( dev->rdev ), ++ dev->card, dev->usage ); ++ __mmc_block_unlock_device( dev->rdev ); ++ } ++ ++ __LEAVE0(); ++} ++ ++/* Atomically increases use count of the valid device */ ++static inline mmc_block_device_t mmc_block_get_device( kdev_t rdev ) ++{ ++ mmc_block_device_t ret = NULL; ++ ++ __ENTER0(); ++ ++ ret = __mmc_block_get_device( rdev ); ++ if ( !ret ) ++ goto error; ++ ++ ret->usage++; ++ __mmc_block_put_device( ret ); ++error: ++ __LEAVE( "ret=0x%p dusage=%d card=0x%p cusage=%d", ++ ret, ret ? ret->usage : -1, ++ ret ? ret->card : NULL, ++ ret ? (ret->card ? ret->card->usage : -1) : -1 ); ++ return ret; ++} ++ ++/* Check is there references to the card */ ++static inline int __mmc_block_check_card( kdev_t rdev ) ++{ ++ int ret = TRUE; ++ int start = MINOR( MMC_BLOCK_RAW_DEVICE( rdev ) ); ++ register int i; ++ ++ for ( i = 0; i < mmc_block_gendisk.max_p; i++ ) ++ if ( mmc_block_device[start + i].usage > 0 ) { ++ ret = FALSE; ++ break; ++ } ++ ++ return ret; ++} ++ ++/* Atomically decreases device use count */ ++static inline void mmc_block_put_device( mmc_block_device_t dev ) ++{ ++ __ENTER0(); ++ ++ if ( dev ) { ++ int invalidate = FALSE; ++ ++ __mmc_block_get_device( dev->rdev ); ++ if ( dev->usage > 0 ) ++ --dev->usage; ++ ++ if ( dev->usage ) { ++ __mmc_block_put_device( dev ); ++ goto out; ++ ++ } else { ++ int host, slot; ++ mmc_card_t card = NULL; ++ ++ invalidate = __mmc_block_check_card( dev->rdev ); ++ if ( invalidate ) { ++ host = dev->card->ctrlr->slot; ++ slot = dev->card->slot; ++ ++ if ( dev->card ) { ++ card = dev->card; ++ mmc_put_card( dev->card ); ++ dev->card = NULL; ++ } ++ } ++ __mmc_block_put_device( dev ); ++ ++ if ( invalidate ) ++ __mmc_block_invalidate_card( card, TRUE ); ++ } ++ ++ } ++out: ++ __LEAVE0(); ++} ++ ++static int mmc_block_open( struct inode *inode, struct file *file ) ++{ ++ int ret = -ENODEV; ++ mmc_block_device_t dev = NULL; ++ ++ __ENTER0(); ++ ++ if ( !inode || !file ) ++ goto error; ++ ++ BLK_INC_USE_COUNT; ++ ++ check_disk_change( inode->i_rdev ); ++ ++ dev = mmc_block_get_device( inode->i_rdev ); ++ if ( !dev ) ++ goto error; ++ ++ dev = __mmc_block_get_device( inode->i_rdev ); ++ if ( !dev ) ++ goto error; ++ ++ if ( file->f_mode & FMODE_WRITE ) { /* FIXME */ ++ if ( dev->usage > 1 ) { ++ ret = -EBUSY; ++ __mmc_block_put_device( dev ); ++ mmc_block_put_device( dev ); ++ goto error; ++ } ++ } ++ ++ __mmc_block_put_device( dev ); ++ ++ if ( file ) ++ file->private_data = dev; ++ ++ ret = 0; ++ goto out; ++error: ++ BLK_DEC_USE_COUNT; ++out: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++static int mmc_block_release( struct inode *inode, struct file *file ) ++{ ++ int ret = -EINVAL; ++ mmc_block_device_t dev = NULL; ++ ++ __ENTER( "inode=0x%p file=0x%p rdev=(%x:%x)", inode, file, ++ inode ? MAJOR( inode->i_rdev ) : 0xff, ++ inode ? MINOR( inode->i_rdev ) : 0xff ); ++ ++ if ( !file && !inode ) ++ goto error; ++ ++ if ( file ) ++ dev = file->private_data; ++ else ++ dev = __mmc_block_get_device( inode->i_rdev ); ++ ++ if ( !dev ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "invalid device\n" ); ++ goto error; ++ } ++ ++ if ( file ) { ++ mmc_block_put_device( dev ); ++ file->private_data = NULL; ++ ++ } else { ++ int invalidate = FALSE; ++ ++ if ( dev->usage > 0 ) ++ --dev->usage; ++ ++ if ( dev->usage ) { ++ __mmc_block_put_device( dev ); ++ goto out; ++ ++ } else { ++ int host, slot; ++ mmc_card_t card = NULL; ++ ++ invalidate = __mmc_block_check_card( dev->rdev ); ++ if ( invalidate ) { ++ host = dev->card->ctrlr->slot; ++ slot = dev->card->slot; ++ ++ if ( dev->card ) { ++ card = dev->card; ++ mmc_put_card( dev->card ); ++ dev->card = NULL; ++ } ++ } ++ __mmc_block_put_device( dev ); ++ ++ if ( invalidate ) ++ __mmc_block_invalidate_card( card, TRUE ); ++ ++ } ++ } ++ ++out: ++ BLK_DEC_USE_COUNT; ++ ret = 0; ++error: ++ __LEAVE0(); ++ return ret; ++} ++ ++static int mmc_block_check_disk_change( kdev_t rdev ) ++{ ++ int ret = 0; ++#if 0 ++ mmc_block_device_t dev = &mmc_block_device[MINOR( rdev )]; ++ ++ __mmc_block_lock_device( rdev ); ++ if ( !dev->card ) ++ ret = 1; ++ __mmc_block_unlock_device( rdev ); ++#else ++ ret = 1; ++#endif ++ return ret; ++} ++ ++static int mmc_block_revalidate( kdev_t rdev ) ++{ ++ int ret = 1; ++ mmc_card_t card; ++ mmc_block_device_t dev; ++ kdev_t start = MMC_BLOCK_RAW_DEVICE( rdev ); ++ int minor = MINOR( start ); ++ int host, slot; ++ int i; ++ ++ __ENTER0(); ++ ++ (void)mmc_update_card_stack( MINOR( start )>>MMC_MINOR_HOST_SHIFT ); ++ ++ __mmc_block_wrlock_devices(); ++ ++ dev = &mmc_block_device[minor]; ++ host = dev->host; ++ slot = dev->slot; ++ ++ if ( dev->card ) { /* card has not been changed actually */ ++ __mmc_block_wrunlock_devices(); ++ goto out; ++ ++ } else { ++ card = mmc_get_card( host, slot ); ++ if ( !card ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "failed to get card: " ++ "host=%d, slot=%d\n", host, slot ); ++ __mmc_block_wrunlock_devices(); ++ goto error; ++ } ++ dev->card = card; ++ } ++ __mmc_block_wrunlock_devices(); ++ /* FIXME */ ++ __mmc_block_rdlock_devices(); /* handle the request for sector 0 */ ++ grok_partitions( &mmc_block_gendisk, MINOR( start ), ++ mmc_block_gendisk.max_p, ++ card->info.capacity>>9 /* sectors */ ++ ); ++ __mmc_block_rdunlock_devices(); ++ /* FIXME */ ++ __mmc_block_wrlock_devices(); ++ for ( i = start + mmc_block_gendisk.max_p - 1; i >= 0; --i ) { ++ int minor = MINOR( i ); ++ ++ dev = &mmc_block_device[minor]; ++ if ( mmc_block_gendisk.part[minor].nr_sects > 0 ) ++ dev->card = card; ++ } ++ __mmc_block_wrunlock_devices(); ++out: ++error: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++static void mmc_block_handle_request( void ) ++{ ++ struct request *request; ++ mmc_block_device_t dev; ++ mmc_card_t card; ++ char *buf; ++ loff_t pos; ++ unsigned int result = 0; ++ ++ for (;;) { ++ int minor; ++ ++ INIT_REQUEST; ++ request = CURRENT; ++ spin_unlock_irq( &io_request_lock ); ++ ++ minor = MINOR( request->rq_dev ); ++ dev = __mmc_block_get_device( request->rq_dev ); ++ if ( !dev ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "invalid device (%x:%x)\n", ++ MAJOR( request->rq_dev ), minor ); ++ ++ goto end_req; ++ } ++ ++ card = dev->card; ++ (void)__mmc_block_put_device( dev ); ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, ++// printk( KERN_INFO __FUNCTION__"(): " ++ "request %p: cmd %i sec %li (nr. %li)\n", ++ CURRENT, CURRENT->cmd, CURRENT->sector, ++ CURRENT->current_nr_sectors ); ++ ++ if ( request->current_nr_sectors > ++ mmc_block_gendisk.part[minor].nr_sects ) ++ goto end_req; ++ ++ // Handle the request ++ // TODO: handle clusterred requests in multiple block transfer mode ++ buf = request->buffer; ++ pos = (mmc_block_gendisk.part[minor].start_sect + ++ request->sector) * MMC_BLOCK_SECT_SIZE; ++ ++ switch ( request->cmd ) ++ { ++ int i, ret; ++ ++ case READ: ++#if 0 ++ ret = mmc_read( card, ++ (request->current_nr_sectors > 1) ? ++ MMC_TRANSFER_MODE_BLOCK_MULTIPLE : ++ MMC_TRANSFER_MODE_BLOCK_SINGLE, ++ buf, ++ request->current_nr_sectors ++ * MMC_BLOCK_SECT_SIZE, /* FIXME */ ++ &pos ); ++ if ( ret < 0 ) ++ goto end_req; ++ ++#else ++ for ( i = 0; ++ i < request->current_nr_sectors; ++ i++ ) { ++ ret = mmc_read( card, ++ MMC_TRANSFER_MODE_BLOCK_SINGLE, ++ buf, ++ MMC_BLOCK_SECT_SIZE, /* FIXME */ ++ &pos ); ++ if ( ret < 0 ) ++ goto end_req; ++ else ++ buf += ret; ++ } ++#endif ++ result = 1; ++ break; ++ ++ case WRITE: ++ // TODO: Read only device ++#if 0 ++ ret = mmc_write( card, ++ (request->current_nr_sectors > 1) ? ++ MMC_TRANSFER_MODE_BLOCK_MULTIPLE : ++ MMC_TRANSFER_MODE_BLOCK_SINGLE, ++ buf, ++ request->current_nr_sectors ++ * MMC_BLOCK_SECT_SIZE, /* FIXME */ ++ &pos ); ++ if ( ret < 0 ) ++ goto end_req; ++ ++#else ++ for ( i = 0; ++ i < request->current_nr_sectors; ++ i++ ) { ++ ret = mmc_write( card, ++ MMC_TRANSFER_MODE_BLOCK_SINGLE, ++ buf, ++ MMC_BLOCK_SECT_SIZE, /* FIXME */ ++ &pos ); ++ if ( ret < 0 ) ++ goto end_req; ++ else ++ buf += ret; ++ } ++#endif ++ result = 1; ++ break; ++ } ++ ++end_req: ++ __LEAVE( "result=%d", result ); ++ spin_lock_irq( &io_request_lock ); ++ end_request( result ); ++ } ++} ++ ++static volatile int leaving = 0; ++static DECLARE_MUTEX_LOCKED( thread_sem ); ++static DECLARE_WAIT_QUEUE_HEAD( thr_wq ); ++static pid_t thr_id = -1; ++ ++int mmc_block_thread( void *arg ) ++{ ++ struct task_struct *task = current; ++ DECLARE_WAITQUEUE(wait, task); ++ ++ __ENTER0(); ++ ++ task->session = 1; ++ task->pgrp = 1; ++ task->flags |= PF_MEMALLOC; ++ strcpy( task->comm, "mmcblockd" ); ++ task->tty = NULL; ++ spin_lock_irq( &task->sigmask_lock ); ++ sigfillset( &task->blocked ); ++ recalc_sigpending( task ); ++ spin_unlock_irq( &task->sigmask_lock ); ++ exit_mm( task ); ++ exit_files( task ); ++ exit_sighand( task ); ++ exit_fs( task ); ++ ++ while ( !leaving ) { ++ add_wait_queue( &thr_wq, &wait); ++ set_current_state( TASK_INTERRUPTIBLE ); ++ spin_lock_irq( &io_request_lock ); ++ if ( QUEUE_EMPTY || QUEUE_PLUGGED ) { ++ spin_unlock_irq( &io_request_lock ); ++ schedule(); ++ remove_wait_queue( &thr_wq, &wait ); ++ } else { ++ remove_wait_queue( &thr_wq, &wait ); ++ set_current_state( TASK_RUNNING ); ++ mmc_block_handle_request(); /* handle the request */ ++ spin_unlock_irq( &io_request_lock ); ++ } ++ } ++ ++ up( &thread_sem ); ++ ++ __LEAVE0(); ++ return 0; ++} ++ ++#if LINUX_VERSION_CODE < 0x20300 ++#define RQFUNC_ARG void ++#else ++#define RQFUNC_ARG request_queue_t *q ++#endif ++ ++static void mmc_block_request( RQFUNC_ARG ) ++{ ++ wake_up( &thr_wq ); ++} ++ ++static int mmc_block_ioctl( struct inode * inode, struct file * file, ++ unsigned int cmd, unsigned long arg ) ++{ ++ int ret = -ENODEV; ++ mmc_block_device_t dev; ++ mmc_card_t card; ++ int minor; ++ __ENTER0(); ++ ++ if ( !inode || !file ) { ++ ret = -EINVAL; ++ goto error; ++ } ++ minor = MINOR( inode->i_rdev ); ++ ++ dev = __mmc_block_get_device( inode->i_rdev ); ++ if ( !dev ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "invalid device\n" ); ++ goto error; ++ } ++ ++ card = dev->card; ++ __mmc_block_put_device( dev ); ++ ++ switch ( cmd ) { ++ case BLKGETSIZE: /* Return device size */ ++ { ++ unsigned long value; ++ ++ __mmc_block_rdlock_devices(); ++ value = mmc_block_gendisk.part[minor].nr_sects; ++ __mmc_block_rdunlock_devices(); ++ ++ if ( put_user( value, (unsigned long *) arg) ) { ++ ret = -EFAULT; ++ goto error; ++ } ++ } ++ break; ++ ++#ifdef BLKGETSIZE64 ++ case BLKGETSIZE64: ++ { ++ unsigned long value; ++ ++ __mmc_block_rdlock_devices(); ++ value = mmc_block_gendisk.part[minor].nr_sects; ++ __mmc_block_rdunlock_devices(); ++ ++ if ( put_user( (u64)value, (u64 *) arg) ) { ++ ret = -EFAULT; ++ goto error; ++ } ++ } ++ break; ++#endif ++ ++ case HDIO_GETGEO: ++ { ++ struct hd_geometry geo; ++ ++ ret = !access_ok( VERIFY_WRITE, arg, sizeof( geo ) ); ++ if ( ret ) { ++ ret = -EFAULT; ++ goto error; ++ } ++ ++ geo.heads = 1; ++ geo.sectors = 1; ++ ++ __mmc_block_rdlock_devices(); ++ geo.cylinders = mmc_block_gendisk.part[minor].nr_sects; ++ geo.start = mmc_block_gendisk.part[minor].start_sect; ++ __mmc_block_rdunlock_devices(); ++ ++ if ( copy_to_user( (int *)arg, &geo, sizeof( geo ) ) ) { ++ ret = -EFAULT; ++ goto error; ++ } ++ } ++ break; ++ ++ case BLKRRPART: ++ if ( !capable( CAP_SYS_ADMIN ) ) { ++ ret = -EACCES; ++ goto error; ++ } ++ (void)mmc_block_revalidate( inode->i_rdev ); ++ break; ++ ++ default: ++ ret = blk_ioctl( inode->i_rdev, cmd, arg ); ++ goto out; ++ } ++ ++ ret = 0; ++error: ++out: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++#if LINUX_VERSION_CODE < 0x20326 ++static struct file_operations mmc_block_fops = ++{ ++ open: mmc_block_open, ++ ioctl: mmc_block_ioctl, ++ release: mmc_block_release, ++ check_media_change: mmc_block_check_disk_change, ++ revalidate: mmc_block_revalidate, ++ read: block_read, ++ write: block_write ++}; ++#else ++static struct block_device_operations mmc_block_fops = ++{ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14) ++ owner: THIS_MODULE, ++#endif ++ open: mmc_block_open, ++ release: mmc_block_release, ++ ioctl: mmc_block_ioctl, ++ check_media_change: mmc_block_check_disk_change, ++ revalidate: mmc_block_revalidate ++}; ++#endif ++ ++ ++static int mmc_block_notify_add( mmc_card_t card ) ++{ ++ int ret = -1; ++ mmc_block_device_t dev; ++ kdev_t start; ++ int minor; ++ ++ __ENTER0(); ++ ++ if ( !card || !card->ctrlr ) ++ goto error; ++ ++ start = MMC_BLOCK_MKDEV( card->ctrlr->slot, card->slot ); ++ dev = &mmc_block_device[MINOR( start )]; ++ ++ __mmc_block_wrlock_devices(); ++ if ( !dev->card ) { ++ dev->card = card; ++ ret = 0; ++ } ++ __mmc_block_wrunlock_devices(); ++ ++ if ( !ret ) { ++ int i; ++ ++ /* allow to read partition table */ ++ __mmc_block_rdlock_devices(); ++ grok_partitions( &mmc_block_gendisk, MINOR( start ), ++ mmc_block_gendisk.max_p, ++ card->info.capacity>>9 /* sectors */ ++ ); ++ __mmc_block_rdunlock_devices(); ++ ++ __mmc_block_wrlock_devices(); ++ for ( i = start + mmc_block_gendisk.max_p - 1; i >= 0; --i ) { ++ minor = MINOR( i ); ++ dev = &mmc_block_device[minor]; ++ if ( mmc_block_gendisk.part[minor].nr_sects > 0 ) ++ dev->card = card; ++ } ++ __mmc_block_wrunlock_devices(); ++ } ++error: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++ ++static int mmc_block_notify_remove( mmc_card_t card ) ++{ ++ int ret = -1; ++ ++ __ENTER( "card=0x%p", card ); ++ ++ if ( card && card->ctrlr ) ++ ret = __mmc_block_invalidate_card( card, FALSE ); ++ ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++static mmc_notifier_rec_t mmc_block_notifier = { ++ add: mmc_block_notify_add, ++ remove: mmc_block_notify_remove ++}; ++ ++static int __init mmc_block_module_init( void ) ++{ ++ int ret = -ENODEV; ++ int i; ++ ++ __ENTER0(); ++ ++ init_rwsem( &mmc_block_device_sem ); ++ ++ if ( devfs_register_blkdev( MAJOR_NR, MAJOR_NAME, &mmc_block_fops ) ) { ++ MMC_ERROR( "Can't allocate major number %d for MMC block devices.\n", MMC_BLOCK_MAJOR ); ++ ret = -EAGAIN; ++ goto error; ++ } ++ ++ for ( i = 0; i < (1<<MINORBITS); i++ ) { ++ __mmc_block_device_init( i ); ++ init_MUTEX( &mmc_block_device[i].sem ); ++ ++ /* We fill it in at open() time. */ ++ mmc_block_blk_sizes[i] = 0; ++ mmc_block_blk_blksizes[i] = BLOCK_SIZE; ++ mmc_block_hardsect_sizes[i] = 0; ++ } ++ ++ init_waitqueue_head( &thr_wq ); ++ /* Allow the block size to default to BLOCK_SIZE. */ ++ blksize_size[MAJOR_NR] = mmc_block_blk_blksizes; ++ hardsect_size[MAJOR_NR] = mmc_block_hardsect_sizes; ++ /* Gendisk stuff */ ++ memset( mmc_block_partitions, 0, sizeof( mmc_block_partitions ) ); ++ add_gendisk( &mmc_block_gendisk ); ++ ++/* FIXME: per controller request queue, I/O and card stack update threads */ ++ blk_init_queue( BLK_DEFAULT_QUEUE( MAJOR_NR ), &mmc_block_request ); ++ thr_id = kernel_thread( mmc_block_thread, NULL, ++ CLONE_FS|CLONE_FILES|CLONE_SIGHAND ); ++ ++ if ( !mmc_register( MMC_REG_TYPE_USER, &mmc_block_notifier, 0 ) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "failed to register with MMC core\n" ); ++ goto error; ++ } ++ ++ ret = 0; ++ goto out; ++error: ++ if ( thr_id != -1 ) { ++/* quit the thread */ ++ leaving = 1; ++ wake_up(&thr_wq); ++ ++ down(&thread_sem); ++ } ++ blksize_size[MAJOR_NR] = NULL; ++ blk_size[MAJOR_NR] = NULL; ++ hardsect_size[MAJOR_NR] = NULL; ++out: ++ __LEAVE0(); ++ return ret; ++} ++ ++static void __exit mmc_block_module_cleanup( void ) ++{ ++/* quit the thread */ ++ leaving = 1; ++ wake_up(&thr_wq); ++ ++ down(&thread_sem); ++ ++ mmc_unregister( MMC_REG_TYPE_USER, &mmc_block_notifier ); ++ del_gendisk( &mmc_block_gendisk ); ++ devfs_unregister_blkdev( MAJOR_NR, MAJOR_NAME ); ++ ++ blk_cleanup_queue( BLK_DEFAULT_QUEUE( MAJOR_NR ) ); ++ blksize_size[MAJOR_NR] = NULL; ++ blk_size[MAJOR_NR] = NULL; ++ hardsect_size[MAJOR_NR] = NULL; ++} ++ ++EXPORT_NO_SYMBOLS; ++ ++module_init( mmc_block_module_init ); ++module_exit( mmc_block_module_cleanup ); ++ ++ ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ linux-2.4.27/drivers/mmc/mmc_core.c +@@ -0,0 +1,1124 @@ ++/* ++ * linux/drivers/mmc/mmc_core.c ++ * MultiMediaCard subsystem core implementation ++ * ++ * Author: Vladimir Shebordaev ++ * Copyright: MontaVista Software Inc. ++ * ++ * $Id: mmc_core.c,v 0.3.1.14 2002/09/27 17:36:09 ted Exp ted $ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/version.h> ++#include <linux/config.h> ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/errno.h> ++ ++#include <linux/slab.h> ++#include <asm/uaccess.h> ++#include <asm/semaphore.h> ++ ++#ifdef CONFIG_PM ++#include <linux/pm.h> ++#endif ++ ++#include <mmc/types.h> ++#include <mmc/mmc.h> ++#include <mmc/ioctl.h> ++ ++#include "types.h" ++ ++#define __MMC_CORE_IMPLEMENTATION__ ++#include "mmc.h" ++ ++/* MMC controllers registered in the system */ ++static mmc_controller_t mmc_controller[MMC_CONTROLLERS_MAX]; ++static int mmc_ncontrollers = 0; ++static rwsemaphore_t mmc_controller_sem; /* controller table lock */ ++#ifdef CONFIG_PM ++static struct pm_dev *mmc_pm_dev = NULL; ++#endif ++ ++/* users' notification list */ ++static mmc_notifier_t mmc_notifier = NULL; ++static rwsemaphore_t mmc_notifier_sem; /* notifiers' list lock */ ++#ifdef CONFIG_PROC_FS ++static proc_dir_entry_t mmc_proc_dir = NULL; ++#endif ++ ++/************************************************ ++ * service function prototypes and declarations * ++ ************************************************/ ++static inline int mmc_acquire_io( mmc_controller_t ctrlr, mmc_card_t card ) ++{ ++ int ret = -EIO; ++ ++ __ENTER0(); ++ ++ if ( !card || !ctrlr ) { ++ ret = -EINVAL; ++ goto error; ++ } ++#ifdef CONFIG_HOTPLUG ++/* TODO: account for controller removal */ ++#endif ++ down( &ctrlr->io_sem ); ++#if 0 ++ down_read( &ctrlr->update_sem ); /* FIXME */ ++ if ( card->state != MMC_CARD_STATE_UNPLUGGED ) ++ ret = 0; ++ up_read( &ctrlr->update_sem ); ++ ++ if ( ret ) ++ up( &ctrlr->io_sem ); ++#else ++ ret = 0; ++#endif ++ ++error: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++static inline void mmc_release_io( mmc_controller_t ctrlr, mmc_card_t card ) ++{ ++ __ENTER0(); ++#ifdef CONFIG_HOTPLUG ++/* TODO: account for controller removal */ ++#endif ++ if ( !card && !ctrlr ) { /* FIXME */ ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "bad card reference\n" ); ++ goto error; ++ } ++ up( &ctrlr->io_sem ); ++error: ++ __LEAVE0(); ++} ++ ++/* TODO: there should be a separate context to be awaken ++ * by the card intertion interrupt; called under ctrlr->update_sem ++ * held down by now */ ++static int __mmc_update_card_stack( mmc_controller_t ctrlr ) ++{ ++ int ret = -1; ++ mmc_card_t card, prev; ++ ++ __ENTER0(); ++ ++ if ( !ctrlr || !ctrlr->tmpl ) ++ goto error; ++ ++ /* check unplugged cards first... */ ++ if ( (ret = ctrlr->tmpl->check_card_stack( ctrlr )) ) ++ goto error; ++ ++ /* unregister unplugged cards and free 'em immediately */ ++ if ( ctrlr->stack.ncards > 0 ) { ++ prev = ctrlr->stack.first; ++ /* process the stack tail first */ ++ if ( prev->next ) { ++ card = prev->next; ++ while ( card ) { ++ if ( card->state == MMC_CARD_STATE_UNPLUGGED ) { ++ if ( ctrlr->stack.selected == card ) ++ ctrlr->stack.selected = NULL; ++#ifdef CONFIG_PROC_FS ++ if ( card->proc ) { ++ remove_proc_entry( card->proc_name, ctrlr->proc ); ++ card->proc = NULL; ++ } ++#endif ++ ctrlr->slot_next = card->slot; /* FIXME */ ++ prev->next = card->next; ++ if ( ctrlr->stack.last == card ) ++ ctrlr->stack.last = prev; ++ /* FIXME: controller use count */ ++ mmc_notify_remove( card ); ++ --ctrlr->stack.ncards; ++ if ( (ctrlr->usage > 0) && ctrlr->tmpl->owner ) { ++ --ctrlr->usage; ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, ++ "'%s' use count " ++ "decreased (%d)\n", ++ ctrlr->tmpl->name, ++ ctrlr->usage ); ++ __MOD_DEC_USE_COUNT( ++ ctrlr->tmpl->owner ); ++ } ++ __mmc_card_free( card ); ++ ++ card = prev->next; ++ } ++ } ++ } ++ /* then the head */ ++ card = ctrlr->stack.first; ++ if ( card && (card->state == MMC_CARD_STATE_UNPLUGGED) ) { ++ if ( ctrlr->stack.selected == card ) ++ ctrlr->stack.selected = NULL; ++#ifdef CONFIG_PROC_FS ++ if ( card->proc ) { ++ remove_proc_entry( card->proc_name, ctrlr->proc ); ++ card->proc = NULL; ++ } ++#endif ++ ctrlr->slot_next = card->slot; /* FIXME */ ++ mmc_notify_remove( card ); /* FIXME: should unregister here */ ++ ctrlr->stack.first = card->next; ++ if ( ctrlr->stack.last == card ) ++ ctrlr->stack.last = NULL; ++ /* FIXME: controller use count */ ++ --ctrlr->stack.ncards; ++ if ( (ctrlr->usage > 0) && ctrlr->tmpl->owner ) { ++ --ctrlr->usage; ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "'%s' use count " ++ "decreased (%d)\n", ctrlr->tmpl->name, ++ ctrlr->usage ); ++ __MOD_DEC_USE_COUNT( ctrlr->tmpl->owner ); ++ } ++ __mmc_card_free( card ); ++ } ++ } ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "after stack check: ncards=%d" ++ " first=0x%x last=0x%x\n", ctrlr->stack.ncards, ++ ctrlr->stack.first, ctrlr->stack.last ); ++ /* ...then add newly inserted ones */ ++ if ( (ret = ctrlr->tmpl->update_acq( ctrlr )) ) ++ goto error; ++ /* ret = 0; */ ++error: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++/* ++ * 1) check error code returned by controller; it's up to ++ * controller to detect error conditions reported by the card ++ * and to abort data transfer requests properly (e.g. send ++ * CMD12(STOP_TRANSMISSION) to abort ADDRESS_ERROR multiple ++ * block transfers) ++ * 2) arrange for card stack update when necessary ++ * (all pending i/o requests must be held pending, ++ * update procedure must start immediately after ++ * error has been detected) ++ */ ++static inline int __mmc_check_error( mmc_card_t card, int err ) ++{ ++ int ret = -EIO; ++ mmc_controller_t ctrlr; ++ ++ __ENTER0(); ++ ++ if ( !card || !card->ctrlr ) ++ goto error; ++ ++ ctrlr = card->ctrlr; ++ ++ if ( err < 0 ) { ++ switch ( err ) { ++ /* bus error occurred */ ++ case MMC_ERROR_CRC_WRITE_ERROR: ++ case MMC_ERROR_CRC_READ_ERROR: ++ case MMC_ERROR_RES_CRC_ERROR: ++ case MMC_ERROR_READ_TIME_OUT: ++ case MMC_ERROR_TIME_OUT_RESPONSE: ++ down_write( &ctrlr->update_sem ); /* FIXME */ ++ if ( !__mmc_update_card_stack( ctrlr ) ) ++ ret = -ENXIO; ++ up_write( &ctrlr->update_sem ); ++ break; ++ } ++ } else ++ ret = err; ++error: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++static inline void __mmc_free_controller( mmc_controller_t ctrlr ) ++{ ++ if ( ctrlr ) { ++ if ( ctrlr->stack.ncards > 0 ) ++ __mmc_card_stack_free( &ctrlr->stack ); ++ kfree( ctrlr ); ++ } ++} ++ ++#ifdef CONFIG_PROC_FS ++static int mmc_proc_read_card_info( char *page, char **start, off_t off, int count, int *eof, void *data ) ++{ ++ int ret = -EINVAL; ++ mmc_card_t card = (mmc_card_t)data; ++ char *cp = page; ++ ++ if ( !card ) ++ goto error; ++ ++ down_read( &card->ctrlr->update_sem ); ++/* TODO: proc report ++ * Type: RO, RW or IO (by CCC) ++ * MID: 0x%02x card->info.cid.mid ++ * OID: 0x%04x card->info.cid.oid ++ * PNM: %s card->info.pnm ++ * PRV: %s card->info.prv ++ * PSN: 0x%08x card->info.cid.psn ++ * MDT: %s card->info.mdt ++ * Capacity: card->info.capacity (Bytes) ++ */ ++#if 1 ++ cp += sprintf( cp, "Capacity: %dKb.\n\n", (card->info.capacity>>10) ); ++#else /* TODO */ ++ cp += sprintf( cp, "Type : %s\n", card->info.type ); ++ cp += sprintf( cp, "MID : 0x%02x\n", card->info.cid.mid ); ++ cp += sprintf( cp, "OID : 0x%04x\n", card->info.cid.oid ); ++ cp += sprintf( cp, "PNM : %s\n", card->info.pnm ); ++ cp += sprintf( cp, "PRV : %s\n", card->info.prv ); ++ cp += sprintf( cp, "PSN : 0x%08x\n", card->info.cid.psn ); ++ cp += sprintf( cp, "MDT : %s\n", card->info.mdt ); ++ cp += sprintf( cp, "Capacity: %dKB\n", ++ (card->info.capacity>>10) ); ++#endif ++ up_read( &card->ctrlr->update_sem ); ++ ++ ret = cp - page; ++error: ++ return ret; ++} ++#endif ++ ++/************************************* ++ * MMC core interface implementation * ++ *************************************/ ++int mmc_notify_add( mmc_card_t card ) ++{ ++ int ret = 0; ++ mmc_notifier_t notifier; ++ ++ __ENTER0(); ++ if ( card ) { ++ for ( notifier = mmc_notifier; notifier; ++ notifier = notifier->next ) ++ if ( notifier->add ) ++ if ( (ret = notifier->add( card )) ) ++ break; ++ } ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++EXPORT_SYMBOL( mmc_notify_add ); ++ ++int mmc_notify_remove( mmc_card_t card ) ++{ ++ int ret = 0; ++ mmc_notifier_t notifier; ++ ++ __ENTER0(); ++ if ( card ) { ++ for ( notifier = mmc_notifier; notifier; ++ notifier = notifier->next ) ++ if ( notifier->remove ) ++ if ( (ret = notifier->remove( card )) ) ++ break; ++ } ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++EXPORT_SYMBOL( mmc_notify_remove ); ++ ++int mmc_update_card_stack( int host ) ++{ ++ int ret = -EINVAL; ++ mmc_controller_t ctrlr; ++ ++ __ENTER0(); ++ ++ if ( (host < 0) || (host >= MMC_CONTROLLERS_MAX) ) ++ goto error; ++ ++ down_read( &mmc_controller_sem ); ++ if ( (ctrlr = mmc_controller[host]) ) { ++ down_write( &ctrlr->update_sem ); ++ (void)__mmc_update_card_stack( ctrlr ); ++ up_write( &ctrlr->update_sem ); ++ } ++ up_read( &mmc_controller_sem ); ++ ret = 0; ++error: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++EXPORT_SYMBOL( mmc_update_card_stack ); ++ ++ssize_t mmc_read( mmc_card_t card, mmc_transfer_mode_t mode, char *buf, size_t size, loff_t *paddr ) ++{ ++ ssize_t ret = -EIO; ++ mmc_controller_t ctrlr; ++ mmc_data_transfer_req_rec_t transfer; ++ ++ if ( !paddr ) { ++ ret = -EINVAL; ++ goto error; ++ } ++ ++ if ( !card ) { ++ ret = -ENODEV; ++ goto error; ++ } ++ ++ __ENTER( "card=%p usage=%d mode=%d buf=%p size=%d addr=%x", ++ card, card->usage, mode, buf, size, *paddr ); ++ ++ ctrlr = card->ctrlr; ++ if ( (ret = mmc_acquire_io( ctrlr, card )) ) ++ goto error; ++ ++ memset( &transfer, 0, sizeof( mmc_data_transfer_req_rec_t ) ); ++ transfer.cmd = MMC_READ; ++ transfer.mode = mode; ++ transfer.type = MMC_USER; /* FIXME: buffer cache */ ++ transfer.buf = buf; ++ transfer.addr = *paddr; ++ transfer.cnt = size; ++ ++/* max block size defined by CSD[read_bl_len] */ ++ transfer.blksz = card->info.read_bl_len; ++ transfer.nob = size / transfer.blksz; ++ if ( (size - (transfer.nob * transfer.blksz)) > 0 ) ++ transfer.nob++; ++ ++/* TODO: controller may restrict maximum block size; set block size ++ * and number of blocks that their accumulated length fit to ++ * CSD[READ_BL_LEN] not to bother with block misalignment in multiple ++ * block transfers */ ++ ctrlr = card->ctrlr; ++ if ( transfer.blksz > ctrlr->tmpl->block_size_max ) { ++ ret = -EINVAL; /* FIXME */ ++ goto error; ++ } ++ ++ if ( ctrlr->stack.selected != card ) { ++ if ( (ret = ctrlr->tmpl->setup_card( ctrlr, card )) ) ++ goto err_mmc; ++ ctrlr->stack.selected = card; ++ } ++ ++ switch( mode ) { ++ case MMC_TRANSFER_MODE_STREAM: ++ if ( !ctrlr->tmpl->stream_read ) { ++ ret = -ENXIO; ++ goto err_down; ++ } ++/* TODO: The max clock frequency for stream read operation is given by ++ the following formula: ++ max speed = min ( TRAN_SPEED, 8*2^(READ_BL_LEN) - NSAC/TAAC ) ++ ++ If the card is not able to sustain data transfer it will set the ++ UNDERRUN error bit in the status register, abort the transmission ++ and wait in the Data state for a stop command ++ */ ++ ret = ctrlr->tmpl->stream_read( ctrlr, &transfer ); ++ break; ++ ++ case MMC_TRANSFER_MODE_BLOCK_SINGLE: ++ if ( !ctrlr->tmpl->read_block ) { ++ ret = -ENXIO; ++ goto err_down; ++ } ++/* TODO: buffer size and data alignment (v3.4, p.29): ++ if CSD[READ_BL_PARTIAL] is set, smaller blocks whose starting ++ and ending address are entirely contained within one physical ++ block (as defined by CSD[READ_BL_LEN]) may also be transmitted ++ */ ++ transfer.type = MMC_KERNEL; /* FIXME */ ++ ret = ctrlr->tmpl->read_block( ctrlr, &transfer ); ++ break; ++ ++ case MMC_TRANSFER_MODE_BLOCK_MULTIPLE: ++ if ( !ctrlr->tmpl->read_mblock ) { ++ ret = -ENXIO; ++ goto err_down; ++ } ++ ++ if ( transfer.nob > ctrlr->tmpl->nob_max ) { ++ ret = -EINVAL; ++ goto error; ++ } ++/* TODO: buffer size and data alignment (v3.4, p.29): ++ if the host uses patrial blocks whose accumulated length is ++ not block aligned and block misalignment is not allowed, the ++ card should detect a block misalignment error condition at the ++ beginning of the first misaligned block ++ */ ++ transfer.type = MMC_KERNEL; /* FIXME */ ++ ret = ctrlr->tmpl->read_mblock( card->ctrlr, &transfer ); ++ break; ++ ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "request for unknown transfer type\n" ); ++ ret = -EINVAL; ++ } ++err_mmc: ++ ret = __mmc_check_error( card, ret ); ++ if ( ret >= 0 ) { ++ ret = size - transfer.cnt; ++ *paddr += ret; ++ } ++err_down: ++ mmc_release_io( ctrlr, card ); ++error: ++ __LEAVE("ret=%d", ret); ++ return ret; ++} ++EXPORT_SYMBOL( mmc_read ); ++ ++ssize_t mmc_write( mmc_card_t card, mmc_transfer_mode_t mode, const char *buf, size_t size, loff_t *paddr ) ++{ ++ ssize_t ret = -ESPIPE; ++ mmc_controller_t ctrlr; ++ mmc_data_transfer_req_rec_t transfer; ++ ++ if ( !paddr ) { ++ ret = -EINVAL; ++ goto error; ++ } ++ ++ if ( !card ) { ++ ret = -ENODEV; ++ goto error; ++ } ++ ++ __ENTER( "card=%p usage=%d mode=%d buf=%p size=%d addr=%llx", ++ card, card->usage, mode, buf, size, *paddr ); ++ ++ ctrlr = card->ctrlr; ++ if ( (ret = mmc_acquire_io( ctrlr, card )) ) ++ goto error; ++ ++ memset( &transfer, 0, sizeof( mmc_data_transfer_req_rec_t ) ); ++ transfer.cmd = MMC_WRITE; ++ transfer.mode = mode; ++ transfer.type = MMC_USER; /* FIXME: buffer cache */ ++ transfer.buf = (char *)buf; ++ transfer.addr = *paddr; ++ transfer.cnt = size; ++ ++/* max block size defined by CSD[write_bl_len] */ ++ transfer.blksz = card->info.write_bl_len; ++ transfer.nob = size / transfer.blksz; ++ if ( (size - (transfer.nob * transfer.blksz)) > 0 ) ++ transfer.nob++; ++ ++/* TODO: controller may restrict maximum block size; set block size ++ * and number of blocks that their accumulated length fit to ++ * CSD[WRITE_BL_LEN] not to bother with block misalignment in multiple ++ * block transfers */ ++ ctrlr = card->ctrlr; ++ if ( transfer.blksz > ctrlr->tmpl->block_size_max ) { ++ ret = -EINVAL; /* FIXME */ ++ goto error; ++ } ++ ++ if ( ctrlr->stack.selected != card ) { ++ if ( (ret = ctrlr->tmpl->setup_card( ctrlr, card )) ) ++ goto err_mmc; ++ ctrlr->stack.selected = card; ++ } ++ ++ transfer.cmd = MMC_WRITE; ++ transfer.mode = mode; ++ transfer.type = MMC_USER; ++ switch( mode ) { ++ case MMC_TRANSFER_MODE_STREAM: ++ if ( !ctrlr->tmpl->stream_write ) { ++ ret = -ENXIO; ++ goto err_down; ++ } ++ ret = ctrlr->tmpl->stream_write( ctrlr, &transfer ); ++ break; ++ ++ case MMC_TRANSFER_MODE_BLOCK_SINGLE: ++ if ( !ctrlr->tmpl->write_block ) { ++ ret = -ENXIO; ++ goto err_down; ++ } ++ transfer.type = MMC_KERNEL; /* FIXME */ ++ ret = ctrlr->tmpl->write_block( ctrlr, &transfer ); ++ break; ++ ++ case MMC_TRANSFER_MODE_BLOCK_MULTIPLE: ++ if ( !ctrlr->tmpl->write_mblock ) { ++ ret = -ENXIO; ++ goto err_down; ++ } ++ transfer.type = MMC_KERNEL; /* FIXME */ ++ ret = ctrlr->tmpl->write_mblock( card->ctrlr, &transfer ); ++ break; ++ ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "request for unknown transfer type\n" ); ++ } ++ ++err_mmc: ++ ret = __mmc_check_error( card, ret ); /* FIXME */ ++ if ( ret >= 0 ) { ++ ret = size - transfer.cnt; ++ *paddr += ret; ++ } ++err_down: ++ mmc_release_io( ctrlr, card ); ++error: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++EXPORT_SYMBOL( mmc_write ); ++ ++int mmc_ioctl( mmc_card_t card, unsigned int cmd, unsigned long arg ) ++{ ++ int ret = -EINVAL; ++ mmc_controller_t ctrlr; ++ ++ if ( !card ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "bad card reference\n" ) ++ goto error; ++ } ++ ++ ctrlr = card->ctrlr; ++ if ( mmc_acquire_io( ctrlr, card ) ) { ++ ret = -ENXIO; ++ goto error; ++ } ++ ++ switch ( cmd ) { ++ case IOCMMCGCARDESC: ++ if ( copy_to_user( (void *)arg, &card->info, sizeof( mmc_card_info_rec_t ) ) ) ++ ret = -EFAULT; ++ break; ++/* ++ * 1. TODO: erase region ++ * 2. TODO: set/unset write protection, lock/password ++ */ ++ default: ++ ret = -ENOIOCTLCMD; ++ } ++ ++ mmc_release_io( ctrlr, card ); ++error: ++ return ret; ++} ++EXPORT_SYMBOL( mmc_ioctl ); ++ ++/* ++ * registry stuff ++ */ ++mmc_card_t mmc_get_card( int host, int slot ) ++{ ++ mmc_card_t ret = NULL; ++ mmc_controller_t ctrlr = NULL; ++ int found; ++ ++ __ENTER( "host=%d, card=%d", host, slot ); ++ ++ if ( ((host < 0) || (host >= MMC_CONTROLLERS_MAX)) ++ && ((slot < 0) || (slot >= MMC_CARDS_MAX)) ) ++ goto error; ++ ++ down_read( &mmc_controller_sem ); ++ ++ if ( (ctrlr = mmc_controller[host]) ) { ++ down_write( &ctrlr->update_sem ); ++ if ( ctrlr->stack.ncards > 0 ) { ++ ret = ctrlr->stack.first; ++ found = FALSE; ++ while ( ret ) { ++ if ( (ret->slot == slot) && (ret->state != ++ MMC_CARD_STATE_UNPLUGGED) ) { ++ found = TRUE; ++ break; ++ } ++ ret = ret->next; ++ } ++ ++ if ( found ) { ++ if ( ctrlr->tmpl->owner ) { ++ ++ctrlr->usage; ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, ++ "'%s' use count increased (%d)\n", ++ ctrlr->tmpl->name, ctrlr->usage ); ++ __MOD_INC_USE_COUNT( ctrlr->tmpl->owner ); ++ } ++ ++ret->usage; ++ } else ++ ret = NULL; ++ } ++ up_write( &ctrlr->update_sem ); ++ } ++ up_read( &mmc_controller_sem ); ++error: ++ __LEAVE("ret=0x%p usage=%d", ret, ret ? ret->usage : -1 ); ++ return ret; ++} ++EXPORT_SYMBOL( mmc_get_card ); ++ ++void mmc_put_card( mmc_card_t card ) ++{ ++ mmc_card_t tmp = NULL; ++ mmc_controller_t ctrlr; ++ int found; ++ ++ __ENTER( "card=0x%p", card ); ++ ++ if ( !card ) ++ goto error; ++ ++ ctrlr = card->ctrlr; ++ ++ down_read( &mmc_controller_sem ); ++ if ( !ctrlr || (ctrlr != mmc_controller[ctrlr->slot]) ) { ++ MMC_ERROR( "bad controller reference: ctrlr=0x%p\n", ctrlr ); ++ goto err_down; ++ } ++ ++ down_write( &ctrlr->update_sem ); ++ if ( ctrlr->stack.ncards > 0 ) { ++ tmp = ctrlr->stack.first; ++ found = FALSE; ++ while ( tmp ) { ++ if ( tmp == card ) { ++ found = TRUE; ++ break; ++ } ++ tmp = tmp->next; ++ } ++ ++ if ( found ) { ++ if ( tmp->usage > 0 ) { ++ --tmp->usage; ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "usage=%d" ++ "owner=0x%p\n", tmp->usage, ++ ctrlr->tmpl->owner ); ++ if ( !tmp->usage && (ctrlr->usage > 0) ++ && ctrlr->tmpl->owner ) { ++ --ctrlr->usage; ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, ++ "'%s' use count " ++ "decreased (%d)\n", ++ ctrlr->tmpl->name, ++ ctrlr->usage ); ++ __MOD_DEC_USE_COUNT( ++ ctrlr->tmpl->owner ); ++ } ++ } ++ } else ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "bad card reference\n" ); ++ ++ } ++ up_write( &ctrlr->update_sem ); ++err_down: ++ up_read( &mmc_controller_sem ); ++error: ++ __LEAVE( "found=%d", found ); ++ return; ++} ++EXPORT_SYMBOL( mmc_put_card ); ++ ++static inline void *mmc_register_user( mmc_notifier_t notifier ) ++{ ++ mmc_notifier_t ret = NULL, last = mmc_notifier; ++ ++ MOD_INC_USE_COUNT; ++ if ( notifier ) { ++ down_write( &mmc_notifier_sem ); ++ ++ notifier->next = NULL; ++ if ( !last ) { ++ mmc_notifier = notifier; ++ ret = notifier; ++ } else { ++ while ( last->next ) { ++ if ( last == notifier ) { ++ MOD_DEC_USE_COUNT; ++ break; ++ } ++ last = last->next; ++ } ++ if ( last != notifier ) { ++ last->next = notifier; ++ ret = notifier; ++ } ++ } ++ up_write( &mmc_notifier_sem ); ++ } ++/* notify new user about the cards present in the system */ ++ if ( ret && ret->add ) { ++ int i; ++ ++ down_read( &mmc_controller_sem ); ++ for ( i = 0; i < mmc_ncontrollers; i++ ) { ++ mmc_controller_t ctrlr = mmc_controller[i]; ++ ++ down_read( &ctrlr->update_sem ); /* FIXME */ ++ __mmc_card_stack_foreach( &ctrlr->stack, ++ ret->add, FALSE ); ++ up_read( &ctrlr->update_sem ); /* FIXME */ ++ } ++ up_read( &mmc_controller_sem ); ++ } ++/* error: */ ++ __LEAVE( "mmc_notifier=0x%p, mmc_notifier->next=0x%p", ++ mmc_notifier, mmc_notifier ? mmc_notifier->next : NULL ); ++ return ret; ++} ++ ++static inline mmc_controller_t mmc_register_controller( mmc_controller_tmpl_t tmpl, size_t extra ) ++{ ++ mmc_controller_t ret = NULL; ++ int found; ++ int i; ++ ++ MOD_INC_USE_COUNT; ++ ++ down_write( &mmc_controller_sem ); ++ ++ if ( mmc_ncontrollers >= MMC_CONTROLLERS_MAX ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "there're too many controllers\n" ); ++ goto error; ++ } ++ ++ found = FALSE; ++ for ( i = 0; i < MMC_CONTROLLERS_MAX; i++ ) ++ if ( !mmc_controller[i] ) { ++ found = TRUE; ++ break; ++ } ++ ++ if ( !found ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "there're no empty slots\n" ); ++ goto error; ++ } ++ ++ if ( !tmpl->init ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'init()'\n" ); ++ goto error; ++ } ++ ++ if ( !tmpl->probe ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'probe()'\n" ); ++ goto error; ++ } ++ ++ if ( !tmpl->init_card_stack ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'init_card_stack()'\n" ); ++ goto error; ++ } ++ ++ if ( !tmpl->update_acq ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'update_acq()'\n" ); ++ goto error; ++ } ++ ++ if ( !tmpl->check_card_stack ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'check_card_stack()'\n" ); ++ goto error; ++ } ++ ++ if ( !tmpl->setup_card ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'setup_card()'\n" ); ++ goto error; ++ } ++ ++ ret = kmalloc( sizeof( mmc_controller_rec_t ) + extra, GFP_ATOMIC ); /* FIXME: ISA + GFP_DMA */ ++ if ( !ret ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "out of memory\n" ); ++ goto error; ++ } ++ ++ memset( ret, 0, sizeof( mmc_controller_rec_t ) + extra ); ++ ++ if ( (tmpl->probe( ret ) != 1) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "controller probe failed\n" ); ++ goto err_free; ++ } ++ ++ if ( tmpl->init( ret ) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "controller initialization failure\n" ); ++ goto err_free; ++ } ++ ++ ret->state = MMC_CONTROLLER_FOUND; ++ ret->slot = i; ++ ret->tmpl = tmpl; ++ init_MUTEX( &ret->io_sem ); ++ init_rwsem( &ret->update_sem ); ++#ifdef CONFIG_PROC_FS ++ if ( mmc_proc_dir ) { ++ snprintf( ret->proc_name, sizeof( ret->proc_name ), ++ "host%d", ret->slot ); ++ ret->proc = proc_mkdir( ret->proc_name, mmc_proc_dir ); ++ } ++#endif ++ ++/* initialize card stack */ ++ if ( ret->tmpl->init_card_stack( ret ) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "card stack initialization failure\n" ); ++ if ( ret->tmpl->remove ) ++ ret->tmpl->remove( ret ); /* FIXME */ ++ goto err_free; ++ } ++ ++ mmc_controller[ret->slot] = ret; ++ ++mmc_ncontrollers; ++ ++/* notify users */ ++ if ( ret->stack.ncards > 0 ) { ++ down_read( &mmc_notifier_sem ); ++ if ( (i = __mmc_card_stack_foreach( &ret->stack, mmc_notify_add, FALSE ) ) < 0 ) ++ MMC_ERROR( "device add notification failed at slot %d\n", -i ); ++ up_read( &mmc_notifier_sem ); ++ } ++ goto out; ++ ++err_free: ++#ifdef CONFIG_PROC_FS ++ if ( ret->proc ) ++ remove_proc_entry( ret->proc_name, mmc_proc_dir ); ++#endif ++ kfree( ret ); ++error: ++ ret = NULL; ++ MOD_DEC_USE_COUNT; ++out: ++ up_write( &mmc_controller_sem ); ++ return ret; ++} ++ ++static inline mmc_card_t mmc_register_card( mmc_card_t card ) ++{ ++ mmc_card_t ret = NULL; ++ mmc_controller_t ctrlr; ++ ++ if ( !card || !card->ctrlr ) ++ goto error; ++ ++ ctrlr = card->ctrlr; ++#ifdef CONFIG_PROC_FS ++ if ( ctrlr->proc ) { ++ snprintf( card->proc_name, sizeof( card->proc_name ), ++ "card%d", card->slot ); ++ card->proc = create_proc_read_entry( card->proc_name, ++ 0444, ctrlr->proc, ++ mmc_proc_read_card_info, card ); ++ } ++#endif ++ mmc_notify_add( card ); ++error: ++ return ret; ++} ++ ++void *mmc_register( mmc_reg_type_t reg_type, void *tmpl, size_t extra ) ++{ ++ void *ret = NULL; ++ ++ switch ( reg_type ) { ++ case MMC_REG_TYPE_CARD: ++ ret = mmc_register_card( (mmc_card_t)tmpl ); ++ break; ++ ++ case MMC_REG_TYPE_USER: ++ ret = mmc_register_user( (mmc_notifier_t)tmpl ); ++ break; ++ ++ case MMC_REG_TYPE_HOST: ++ ret = mmc_register_controller( (mmc_controller_tmpl_t)tmpl, extra ); ++ break; ++ ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "register request for unknown type\n" ); ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL( mmc_register ); ++ ++static inline void mmc_unregister_user( mmc_notifier_t notifier ) ++{ ++ mmc_notifier_t prev = mmc_notifier; ++ int found = FALSE; ++ ++ if ( notifier ) { ++ down_write( &mmc_notifier_sem ); ++ ++ if ( mmc_notifier == notifier) { ++ mmc_notifier = prev->next; ++ found = TRUE; ++ ++ } else if ( mmc_notifier ) { ++ while( prev ) { ++ if ( prev->next == notifier ) { ++ found = TRUE; ++ prev->next = prev->next->next; ++ break; ++ } ++ prev = prev->next; ++ } ++ } ++ ++ if ( found ) { ++ if ( notifier->remove ) { ++ int i; ++ ++ down_read( &mmc_controller_sem ); ++ for ( i = 0; i < mmc_ncontrollers; i++ ) { ++ mmc_controller_t ctrlr = ++ mmc_controller[i]; ++ ++ down_read( &ctrlr->update_sem ); ++ __mmc_card_stack_foreach( &ctrlr->stack, notifier->remove, FALSE ); ++ up_read( &ctrlr->update_sem ); ++ } ++ up_read( &mmc_controller_sem ); ++ } ++ } ++ ++ up_write( &mmc_notifier_sem ); ++ } ++ ++ MOD_DEC_USE_COUNT; ++} ++ ++static inline void mmc_unregister_controller( mmc_controller_t ctrlr ) ++{ ++ if ( !ctrlr || (mmc_controller[ctrlr->slot] != ctrlr ) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "bad unregister request\n" ); ++ goto error; ++ } ++ ++ down_write( &mmc_controller_sem ); ++ ++/* notify users */ ++ if ( ctrlr->stack.ncards > 0 ) { ++ int slot; ++ ++ down_read( &mmc_notifier_sem ); ++ if ( (slot = __mmc_card_stack_foreach( &ctrlr->stack, mmc_notify_remove, FALSE ) ) ) ++ MMC_ERROR( "device remove notification failed at slot %d\n", -slot ); ++ up_read( &mmc_notifier_sem ); ++ } ++ ++#ifdef CONFIG_PROC_FS ++ if ( ctrlr->proc ) ++ remove_proc_entry( ctrlr->proc_name, mmc_proc_dir ); ++#endif ++ ++ if ( ctrlr->tmpl && ctrlr->tmpl->remove ) ++ ctrlr->tmpl->remove( ctrlr ); ++ ++ mmc_controller[ctrlr->slot] = NULL; ++ --mmc_ncontrollers; ++ ++ __mmc_free_controller( ctrlr ); ++ ++ up_write( &mmc_controller_sem ); ++ MOD_DEC_USE_COUNT; ++error: ++ return; ++} ++ ++void mmc_unregister( mmc_reg_type_t reg_type, void *tmpl ) ++{ ++ switch ( reg_type ) { ++ case MMC_REG_TYPE_USER: ++ mmc_unregister_user( (mmc_notifier_t)tmpl ); ++ break; ++ ++ case MMC_REG_TYPE_HOST: ++ mmc_unregister_controller( (mmc_controller_t)tmpl ); ++ break; ++ ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "unregister request for unknown type\n" ); ++ } ++} ++EXPORT_SYMBOL( mmc_unregister ); ++ ++#ifdef CONFIG_PM ++/* power management support */ ++static int mmc_pm_callback( struct pm_dev *pmdev, pm_request_t pmreq, void *pmdata ) ++{ ++ int ret = -EINVAL; ++ mmc_controller_t ctrlr; ++ int i; ++ ++ __ENTER( "pmreq=%d", pmreq ); ++ ++ down_read( &mmc_controller_sem ); ++ ++ switch ( pmreq ) { ++ case PM_SUSPEND: ++ for ( ret = 0, i = 0; !ret && (i < mmc_ncontrollers); i++ ) { ++ ctrlr = mmc_controller[i]; ++ if ( ctrlr->tmpl->suspend ) ++ ret = ctrlr->tmpl->suspend( ctrlr ); ++ } ++ if ( !ret ) ++ break; ++ ++ case PM_RESUME: ++ for ( i = mmc_ncontrollers - 1; i >= 0; i-- ) { ++ ctrlr = mmc_controller[i]; ++ if ( ctrlr->tmpl->resume ) ++ ctrlr->tmpl->resume( ctrlr ); ++ } ++ ret = 0; ++ break; ++ ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "unsupported PM request %d\n", ++ pmreq ); ++ } ++ ++ up_read( &mmc_controller_sem ); ++/* error: */ ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++#endif ++ ++/* kernel module stuff */ ++static int __init mmc_core_module_init( void ) ++{ ++ int ret = -ENODEV; ++ ++ memset( &mmc_controller, 0, sizeof( mmc_controller ) ); ++ ++ init_rwsem( &mmc_controller_sem ); ++ init_rwsem( &mmc_notifier_sem ); ++#ifdef CONFIG_PM ++ if ( !(mmc_pm_dev = pm_register( PM_UNKNOWN_DEV, 0, mmc_pm_callback )) ) MMC_DEBUG( MMC_DEBUG_LEVEL0, "failed to register PM callback\n" ); ++#endif ++#ifdef CONFIG_PROC_FS ++ mmc_proc_dir = proc_mkdir( "mmc", NULL ); ++#endif ++ ret = 0; ++/* error: */ ++ return ret; ++} ++ ++static void __exit mmc_core_module_cleanup( void ) ++{ ++#ifdef CONFIG_PROC_FS ++ if ( mmc_proc_dir ) ++ remove_proc_entry( "mmc", NULL ); ++#endif ++#ifdef CONFIG_PM ++ pm_unregister( mmc_pm_dev ); ++#endif ++} ++ ++module_init( mmc_core_module_init ); ++module_exit( mmc_core_module_cleanup ); ++ ++MODULE_LICENSE( "GPL" ); ++ +--- /dev/null ++++ linux-2.4.27/drivers/mmc/mmc_pxa.c +@@ -0,0 +1,1902 @@ ++/* ++ * linux/drivers/mmc/mmc_pxa.c ++ * driver for Cotulla MMC controller ++ * ++ * Authors: Vladimir Shebordaev, Igor Oblakov ++ * Copyright: MontaVista Software Inc. ++ * ++ * $Id: mmc_pxa.c,v 0.3.1.12 2002/09/25 19:25:48 ted Exp ted $ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/version.h> ++#include <linux/config.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/errno.h> ++ ++#include <linux/slab.h> ++#include <linux/sched.h> ++#include <linux/delay.h> ++ ++#include <asm/hardware.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/dma.h> ++ ++#include <asm/uaccess.h> ++#include <asm/semaphore.h> ++ ++#include <mmc/types.h> ++#include <mmc/mmc.h> ++#include <mmc/ioctl.h> ++ ++#include "types.h" ++#include "mmc.h" ++#include "mmc_pxa.h" ++ ++static mmc_controller_t host = NULL; ++ ++/* service routines */ ++static inline int pxa_mmc_check_state( mmc_controller_t ctrlr, pxa_mmc_state_t state ) ++{ ++ int ret = -1; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ ++ if ( hostdata->state != state ) { ++ //MMC_DEBUG( MMC_DEBUG_LEVEL3, "state (%s vs %s)\n", PXA_MMC_STATE_LABEL( hostdata->state ), PXA_MMC_STATE_LABEL( state ) ); ++ goto error; ++ } ++ ret = 0; ++error: ++ return ret; ++} ++ ++static inline void pxa_mmc_set_state( mmc_controller_t ctrlr, pxa_mmc_state_t state ) ++{ ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ ++ hostdata->state = state; ++} ++ ++static inline int pxa_mmc_init_completion( mmc_controller_t ctrlr, u32 mask ) ++{ ++ int ret = -1; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ ++ if ( xchg( &hostdata->busy, 1 ) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "another interrupt " ++ "is already been expected\n" ); ++ goto error; ++ } ++ ++#if CONFIG_MMC_DEBUG_IRQ ++ hostdata->irqcnt = 1000; ++#endif ++ init_completion( &hostdata->completion ); ++ ++ MMC_I_MASK = MMC_I_MASK_ALL & ~mask; ++ ret = 0; ++error: ++ return ret; ++} ++ ++#if CONFIG_MMC_DEBUG_IRQ ++static struct timer_list timer; ++static void wait_timeo( unsigned long arg ) { ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)arg; ++ hostdata->timeo = 1; ++ complete( &hostdata->completion ); ++ return; ++} ++#endif ++ ++static inline int pxa_mmc_wait_for_completion( mmc_controller_t ctrlr, u32 mask ) ++{ ++ int ret = -1; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ ++ if ( !xchg( &hostdata->busy, 1 ) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "there were no " ++ "interrupt awaited for\n" ); ++ goto error; ++ } ++ ++#if CONFIG_MMC_DEBUG_IRQ ++ hostdata->timeo = 0; ++ del_timer( &timer ); ++ timer.function = wait_timeo; ++ timer.expires = jiffies + 1UL*HZ; ++ timer.data = (unsigned long)hostdata; ++ add_timer( &timer ); ++#endif ++ wait_for_completion( &hostdata->completion ); ++#if CONFIG_MMC_DEBUG_IRQ ++ del_timer( &timer ); ++ if ( hostdata->timeo ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "irq timed out: " "mask=%x stat=%x\n", mask, MMC_STAT ); ++ goto error; ++ } ++#endif ++ /* verify interrupt */ ++ if ( (mask == ~0UL) || !( hostdata->mmc_i_reg & ~mask ) ) ++ ret = 0; ++ ++error: ++ xchg( &hostdata->busy, 0 ); ++ return ret; ++} ++ ++static inline int pxa_mmc_stop_bus_clock( mmc_controller_t ctrlr ) ++{ ++ int ret = -1; ++ ++ if ( !pxa_mmc_check_state( ctrlr, PXA_MMC_FSM_CLK_OFF ) ) ++ goto out; ++ ++ if ( !pxa_mmc_check_state( ctrlr, PXA_MMC_FSM_BUFFER_IN_TRANSIT ) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "BUFFER_IN_TRANSIT\n" ); ++ goto error; ++ } ++ ++ if ( pxa_mmc_init_completion( ctrlr, MMC_I_MASK_CLK_IS_OFF ) ) ++ goto error; ++ ++ MMC_STRPCL = MMC_STRPCL_STOP_CLK; ++ ++ if ( pxa_mmc_wait_for_completion( ctrlr, MMC_I_REG_CLK_IS_OFF ) ) ++ goto error; ++ ++ //MMC_DEBUG( MMC_DEBUG_LEVEL3, "clock is off\n" ); ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_CLK_OFF ); ++out: ++ ret = 0; ++error: ++ return ret; ++} ++ ++static inline int pxa_mmc_start_bus_clock( mmc_controller_t ctrlr ) ++{ ++ int ret = -1; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ ++ if ( (hostdata->state != PXA_MMC_FSM_CLK_OFF) ++ && (hostdata->state != PXA_MMC_FSM_END_IO) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "illegal state %s\n", PXA_MMC_STATE_LABEL( hostdata->state ) ); ++ goto error; ++ } ++ ++ MMC_STRPCL = MMC_STRPCL_START_CLK; ++ wmb(); ++ //MMC_DEBUG( MMC_DEBUG_LEVEL3, "clock is on\n" ); ++ ret = 0; ++error: ++ return ret; ++} ++ ++/* ++int pxa_mmc_complete_cmd( mmc_controller_t ctrlr, mmc_response_fmt_t response ) ++ ++Effects: initializes completion to wait for END_CMD_RES intr, ++ waits for intr to occur, checks controller and card status ++Requiers: controller is in CLK_OFF state ++Modifies: moves controller to the END_CMD state ++Returns: ++*/ ++static mmc_error_t pxa_mmc_complete_cmd( mmc_controller_t ctrlr, mmc_response_fmt_t format, int send_abort ) ++{ ++ mmc_error_t ret = MMC_ERROR_GENERIC; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ int mask, nwords; ++ u32 status; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD%d(0x%04x%04x)\n", MMC_CMD & 0x3f, MMC_ARGH, MMC_ARGL); ++ ++/* FIXME: check arguments */ ++ ++ if ( (hostdata->state != PXA_MMC_FSM_CLK_OFF) ++ && (hostdata->state != PXA_MMC_FSM_END_IO) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "illegal state %s\n", ++ PXA_MMC_STATE_LABEL( hostdata->state ) ); ++ goto error; ++ } ++ ++ mask = MMC_I_MASK_END_CMD_RES; ++ if ( pxa_mmc_init_completion( ctrlr, mask ) ) ++ goto error; ++ ++ MMC_PRTBUF = MMC_PRTBUF_BUF_FULL; ++/* start the clock */ ++ if ( pxa_mmc_start_bus_clock( ctrlr ) ) ++ goto error; ++ ++/* wait for END_CMD_RES intr */ ++ if ( pxa_mmc_wait_for_completion( ctrlr, MMC_I_REG_END_CMD_RES ) ) ++ goto error; ++ ++/* check status */ ++ if ( hostdata->mmc_stat & MMC_STAT_TIME_OUT_RESPONSE ) { ++ // MMC_DEBUG(MMC_DEBUG_LEVEL3, "response timeout\n"); ++ ret = MMC_ERROR_TIME_OUT_RESPONSE; ++ goto error; ++ ++ } else if ( hostdata->mmc_stat & MMC_STAT_READ_TIME_OUT ) { ++ // MMC_DEBUG(MMC_DEBUG_LEVEL3, "read timeout\n"); ++ ret = MMC_ERROR_READ_TIME_OUT; ++ goto error; ++ ++ } else if ( hostdata->mmc_stat & MMC_STAT_RES_CRC_ERROR ) { ++ // MMC_DEBUG(MMC_DEBUG_LEVEL3, "response crc err\n"); ++ ret = MMC_ERROR_RES_CRC_ERROR; ++ goto error; ++ ++ } else if ( hostdata->mmc_stat & MMC_STAT_CRC_READ_ERROR ) { ++ // MMC_DEBUG(MMC_DEBUG_LEVEL3, "read crc err\n"); ++ ret = MMC_ERROR_CRC_READ_ERROR; ++ goto error; ++ ++ } else if ( hostdata->mmc_stat & MMC_STAT_CRC_WRITE_ERROR ) { ++ // MMC_DEBUG(MMC_DEBUG_LEVEL3, "write crc err\n"); ++ ret = MMC_ERROR_CRC_WRITE_ERROR; ++ goto error; ++ } ++ ++ nwords = (format == MMC_NORESPONSE) ? 0 : ++ (format == MMC_R1) ? 3 : ++ (format == MMC_R2) ? 8 : ++ (format == MMC_R3) ? 3 : ++ -1; ++ ret = nwords; ++ if ( nwords > 0 ) { ++ register int i; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "nwords=%d\n", nwords ); ++ for ( i = nwords - 1; i >= 0 ; i-- ) { ++ u32 res = MMC_RES; ++ int ibase = i<<1; ++ ++ hostdata->mmc_res[ibase] = ((u8 *)&res)[0]; ++ hostdata->mmc_res[ibase + 1] = ((u8 *)&res)[1]; ++ --ret; ++ } ++#ifdef CONFIG_MMC_DEBUG ++ switch ( format ) { ++ case MMC_R1: ++ MMC_DUMP_R1( ctrlr ); ++ break; ++ case MMC_R2: ++ MMC_DUMP_R2( ctrlr ); ++ break; ++ case MMC_R3: ++ MMC_DUMP_R3( ctrlr ); ++ break; ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, ++ "unknown response format\n" ); ++ ret = MMC_ERROR_GENERIC; ++ goto error; ++ } ++#endif ++ ++/* check card status for R1(b) commands */ ++ if ( format == MMC_R1 ) { ++ u8 cmd; ++ ++ ((u8 *)&status)[0] = hostdata->mmc_res[1]; ++ ((u8 *)&status)[1] = hostdata->mmc_res[2]; ++ ((u8 *)&status)[2] = hostdata->mmc_res[3]; ++ ((u8 *)&status)[3] = hostdata->mmc_res[4]; ++ cmd = PXA_MMC_RESPONSE( ctrlr, 5 )&0x3f; ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, ++ //printk( KERN_INFO __FUNCTION__"(): " ++ "cmd=%u status: 0x%08x\n", ++ cmd, status ); ++ switch ( cmd ) { ++ case 11: ++ case 18: ++ case 20: ++ case 25: ++ if ( !(status & 0x00000100) ) /* FIXME */ ++ goto mmc_error; ++ default: ++ break; ++ } ++ if ( status & MMC_CARD_STATUS_OUT_OF_RANGE ) { ++ ret = MMC_ERROR_OUT_OF_RANGE; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_ADDRESS_ERROR ) { ++ ret = MMC_ERROR_ADDRESS_ERROR; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_BLOCK_LEN_ERROR ) { ++ ret = MMC_ERROR_ADDRESS_ERROR; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_ERASE_SEQ_ERROR ) { ++ ret = MMC_ERROR_ERASE_SEQ_ERROR; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_ERASE_PARAM ) { ++ ret = MMC_ERROR_ERASE_PARAM; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_WP_VIOLATION ) { ++ ret = MMC_ERROR_WP_VIOLATION; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_CARD_IS_LOCKED ) { ++ ret = MMC_ERROR_CARD_IS_LOCKED; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_LOCK_UNLOCK_FAILED ) { ++ ret = MMC_ERROR_LOCK_UNLOCK_FAILED; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_COM_CRC_ERROR ) { ++ ret = MMC_ERROR_COM_CRC_ERROR; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_ILLEGAL_COMMAND ) { ++ ret = MMC_ERROR_ILLEGAL_COMMAND; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_CARD_ECC_FAILED ) { ++ ret = MMC_ERROR_CARD_ECC_FAILED; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_CC_ERROR ) { ++ ret = MMC_ERROR_CC_ERROR; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_ERROR ) { ++ ret = MMC_ERROR_ERROR; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_UNDERRUN ) { ++ ret = MMC_ERROR_UNDERRUN; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_OVERRUN ) { ++ ret = MMC_ERROR_OVERRUN; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_CID_CSD_OVERWRITE ) { ++ ret = MMC_ERROR_CID_CSD_OVERWRITE; ++ goto mmc_error; ++ } else if ( status & MMC_CARD_STATUS_ERASE_RESET ) { ++ ret = MMC_ERROR_ERASE_RESET; ++ goto mmc_error; ++ } ++ } ++ } ++ ++ if ( ret >= 0 ) ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_CMD ); ++ goto out; ++mmc_error: ++#if 1 ++ if ( send_abort ) { ++ /* send CMD12 to abort failed transfer */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ MMC_CMD = CMD(12); /* STOP_TRANSMISSION */ ++ MMC_CMDAT = MMC_CMDAT_R1; ++ ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) ) ++ goto error; ++ ++ ret = -EIO; ++ goto error; ++ } ++#endif ++error: ++ /* move controller to the IDLE state */ ++ pxa_mmc_stop_bus_clock( ctrlr ); ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_IDLE ); ++out: ++ return ret; ++} ++ ++/* ++int pxa_mmc_complete_io( mmc_controller_t ctrlr, mmc_dir_t cmd, mmc_dir_t dir, mmc_transfer_mode_t mode ) ++ ++Effects: finilizes data transfer request ++Reqires: controller is in the END_BUFFER state ++Modifies: moves controller to the IDLE state ++Returns: zero upon success or error condition code otherwise ++ */ ++static mmc_error_t pxa_mmc_complete_io( mmc_controller_t ctrlr, mmc_dir_t dir, mmc_transfer_mode_t mode ) ++{ ++ int ret = MMC_ERROR_GENERIC; ++ ++ if ( pxa_mmc_check_state( ctrlr, PXA_MMC_FSM_END_IO ) ) ++ goto error; ++ ++ switch ( mode ) { ++ case MMC_TRANSFER_MODE_STREAM: /* FIXME */ ++ if ( dir == MMC_WRITE ) { ++ /* 1. wait for STOP_CMD intr */ ++ if ( (ret = pxa_mmc_init_completion( ctrlr, ++ MMC_I_MASK_STOP_CMD )) ) ++ goto error; ++ if ( (ret = pxa_mmc_wait_for_completion( ctrlr, ++ MMC_I_REG_STOP_CMD )) ) ++ goto error; ++ } ++ /* 2. send CMD12 */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ MMC_CMD = CMD(12); /* STOP_TRANSMISSION */ ++ MMC_CMDAT = MMC_CMDAT_R1; ++ if ( dir == MMC_WRITE ) ++ MMC_CMDAT |= MMC_CMDAT_BUSY; ++ ++ /* 3. wait for CMD12 to complete */ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "ready for CMD12\n" ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) ) ++ goto error; ++ ++ /* 4. wait for DATA_TRAN_DONE intr */ ++ if ( (ret = pxa_mmc_init_completion( ctrlr, ++ MMC_I_MASK_DATA_TRAN_DONE )) ) ++ goto error; ++ if ( (ret = pxa_mmc_wait_for_completion( ctrlr, ++ MMC_I_REG_DATA_TRAN_DONE )) ) ++ goto error; ++ ++ if ( dir == MMC_WRITE ) { ++ /* 5. wait for PRG_DONE intr */ ++ if ( (ret = pxa_mmc_init_completion( ctrlr, ++ MMC_I_MASK_PRG_DONE )) ) ++ goto error; ++ if ( (ret = pxa_mmc_wait_for_completion( ctrlr, ++ MMC_I_REG_PRG_DONE )) ) ++ goto error; ++ } ++ break; ++ case MMC_TRANSFER_MODE_BLOCK_MULTIPLE: ++ /* 1. wait for DATA_TRAN done intr */ ++ if ( (ret = pxa_mmc_init_completion( ctrlr, ++ MMC_I_MASK_DATA_TRAN_DONE )) ) ++ goto error; ++ if ( (ret = pxa_mmc_wait_for_completion( ctrlr, ++ MMC_I_REG_DATA_TRAN_DONE )) ) ++ goto error; ++ ++ /* 2. send CMD12 */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ MMC_CMD = CMD(12); /* STOP_TRANSMISSION */ ++ MMC_CMDAT = MMC_CMDAT_R1; ++ if ( dir == MMC_WRITE ) ++ MMC_CMDAT |= MMC_CMDAT_BUSY; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD12\n" ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) ) ++ goto error; ++ ++ if ( dir == MMC_WRITE ) { ++ /* 3. wait for PRG_DONE intr */ ++ if ( (ret = pxa_mmc_init_completion( ctrlr, ++ MMC_I_MASK_PRG_DONE )) ) ++ goto error; ++ if ( (ret = pxa_mmc_wait_for_completion( ctrlr, ++ MMC_I_REG_PRG_DONE )) ) ++ goto error; ++ } ++ break; ++ case MMC_TRANSFER_MODE_BLOCK_SINGLE: ++ /* 1. wait for DATA_TRAN_DONE intr */ ++ if ( (ret = pxa_mmc_init_completion( ctrlr, ++ MMC_I_MASK_DATA_TRAN_DONE )) ) ++ goto error; ++ if ( (ret = pxa_mmc_wait_for_completion( ctrlr, ++ MMC_I_REG_DATA_TRAN_DONE )) ) ++ goto error; ++ ++ if ( dir == MMC_WRITE ) { ++ /* 2. wait for PRG_DONE intr */ ++ if ( (ret = pxa_mmc_init_completion( ctrlr, ++ MMC_I_MASK_PRG_DONE )) ) ++ goto error; ++ if ( (ret = pxa_mmc_wait_for_completion( ctrlr, ++ MMC_I_REG_PRG_DONE )) ) ++ goto error; ++ } ++ break; ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "unknown transfer mode\n" ); ++ goto error; ++ } ++/* move the controller to the IDLE state */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_IDLE ); ++ ++ ret = 0; ++error: ++ return ret; ++} ++ ++static inline int pxa_mmc_update_acq( mmc_controller_t ctrlr ) ++{ ++ int ret = -EINVAL; ++ pxa_mmc_hostdata_t hostdata = NULL; ++ mmc_card_t card = NULL; ++ mmc_card_stack_rec_t fake; ++ mmc_card_stack_t stack = &fake; ++ u16 argl = 0U, argh = 0U; ++ int ncards = 0; ++ ++ if ( !ctrlr ) ++ goto error; ++ ++ hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ ++ __mmc_card_stack_init( stack ); ++ ++ /* max open-drain mode frequency is 400kHZ */ ++ MMC_CLKRT = MMC_CLKRT_0_3125MHZ; ++ MMC_RESTO = MMC_RES_TO_MAX; /* set response timeout */ ++ ++ /* discover and add cards to the stack */ ++ /* I. bus operation condition setup */ ++ /* 1) send CMD1 */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto err_free; ++ ++ argl = 0x0000; ++ argh = 0x0004; ++ ++ MMC_CMD = CMD(1); ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ ++ MMC_CMDAT = MMC_CMDAT_BUSY|MMC_CMDAT_R3; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD1(0x%04x%04x)\n", argh, argl ); ++ ret = pxa_mmc_complete_cmd( ctrlr, MMC_R3, FALSE ); ++ if ( !ret ) { ++ argh = (PXA_MMC_RESPONSE( ctrlr, 4 ) << 8) ++ | PXA_MMC_RESPONSE( ctrlr, 3 ); ++ argl = (PXA_MMC_RESPONSE( ctrlr, 2 ) << 8) ++ | PXA_MMC_RESPONSE( ctrlr, 1 ); ++ ++ } else if ( ret != MMC_ERROR_TIME_OUT_RESPONSE ) ++ goto err_free; ++ ++ if ( !argh && !argl ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, ++ "assuming full voltage range support\n" ); ++ argh = 0x00ff; ++ argl = 0xff00; ++ } ++ ++ /* 2) continuously send CMD1 'till there're busy cards */ ++ for(;;) { ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto err_free; ++ ++ MMC_CMD = CMD(1); ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ ++ MMC_CMDAT = MMC_CMDAT_BUSY|MMC_CMDAT_R3; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD1(0x%04x%04x)\n", argh, argl ); ++ ret = pxa_mmc_complete_cmd( ctrlr, MMC_R3, FALSE ); ++ if ( ret == MMC_ERROR_TIME_OUT_RESPONSE ) ++ break; ++ ++ else if ( !ret ) { ++ /* busy state reported by LOW signal level ++ * (MMC v3.2, p.58) ++ * ++ * Thanks to Alexander Samoutin :) ++ */ ++ if ( !(PXA_MMC_RESPONSE( ctrlr, 4 ) & 0x80) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "busy state reported\n"); ++ udelay( 20 ); ++ continue; ++ } else ++ break; ++ } else ++ goto err_free; ++ } ++ ++/* II. card identification: the cards in Ready state ++ * are the only expected to respond ++ */ ++ for (;;) { ++ argh = 0U; ++ argl = 0U; ++ ++ /* 1) send CMD2 */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto err_free; ++ ++ MMC_CMD = CMD(2); ++ MMC_ARGH = 0x0003; ++ MMC_ARGL = 0xf300; ++ MMC_CMDAT = MMC_CMDAT_R2; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD2(0x%04x%04x)\n", argh, argl ); ++ ret = pxa_mmc_complete_cmd( ctrlr, MMC_R2, FALSE ); ++ if ( ret == MMC_ERROR_TIME_OUT_RESPONSE ) ++ break; ++ ++ else if ( ret ) /* bus error */ ++ goto err_free; ++ ++ /* TODO: store CID for the card */ ++ ++ /* 2) assign RCA */ ++ if ( !++ctrlr->rca_next ) /* overflow */ ++ ++ctrlr->rca_next; ++ argh = ctrlr->rca_next; ++ ++ /* 3) send it to the card last responded (CMD3) */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto err_free; ++ ++ MMC_CMD = CMD(3); ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_CMDAT = MMC_CMDAT_R1; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD3(0x%04x%04x)\n", argh, argl ); ++ ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE ); ++ if ( ret ) /* CMD3 failed */ ++ goto err_free; ++ ++ card = __mmc_card_alloc( sizeof( pxa_mmc_card_data_rec_t ) ); ++ if ( !card ) { ++ MMC_ERROR( "out of memory\n" ); ++ goto err_free; ++ } ++ ++ card->info.rca = argh; ++ card->slot = ctrlr->slot_next++; /* FIXME: minor encoding */ ++ card->ctrlr = ctrlr; ++ ++ if ( !__mmc_card_stack_add( stack, card ) ) ++ goto err_free; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "added card: " ++ "slot %d, RCA=0x%04x\n", card->slot, argh ); ++ ++ncards; ++ } ++ ++ if ( ncards ) { ++/* III. read CSD registers of all cards; DSR support also reported there */ ++ for ( card = stack->first; card; card = card->next ) { ++ pxa_mmc_card_data_t card_data = ++ (pxa_mmc_card_data_t)card->card_data; ++ ++ /* 1) send CMD9 */ ++ argh = card->info.rca; ++ argl = 0U; ++ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto err_free; ++ ++ MMC_CMD = CMD(9); ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_CMDAT = MMC_CMDAT_R2; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, ++ "CMD9(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R2, FALSE )) ) ++ goto err_free; ++ ++ memcpy( &card->info.csd, hostdata->mmc_res, 15 ); ++ MMC_DUMP_CSD( card ); ++ ++ card->info.read_bl_len = (1<<card->info.csd.read_bl_len); ++ card->info.write_bl_len = (1<<card->info.csd.write_bl_len); ++ card->info.capacity = (card->info.csd.c_size + 1) ++ * (1<<(card->info.csd.c_size_mult + 2)) ++ * card->info.read_bl_len; ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "card capacity=%dMb\n", ++ card->info.capacity>>20 ); ++ card->info.tran_speed = 20*1024; /* FIXME */ ++ card->info.transfer_mode = MMC_TRANSFER_MODE_BLOCK_SINGLE; ++ /* 2) set bus operation freq */ ++ card_data->clkrt = pxa_mmc_clkrt( card->info.tran_speed ); ++ /* 3) register card with MMC core */ ++ mmc_register( MMC_REG_TYPE_CARD, card, 0 ); ++ } ++/* IV. set DSR registers of the cards */ ++#if 0 /* TODO */ ++ if ( card->info.csd.dsr_imp ) { ++ set_dsr = TRUE; ++ /* calculate DSR */ ++ } ++#endif ++ } ++#if 0 /* TODO */ ++ if ( set_dsr ) { ++ /* send CMD4 */ ++ } ++#endif ++/* merge list of the newly inserted cards into controller card stack */ ++ if ( !ctrlr->stack.ncards ) { ++ ctrlr->stack.first = stack->first; ++ ctrlr->stack.last = stack->last; ++ } else ++ ctrlr->stack.last->next = stack->first; ++ ++ ctrlr->stack.ncards += stack->ncards; ++ ++ ret = 0; ++ goto out; ++err_free: ++ __mmc_card_stack_free( stack ); ++error: ++out: ++ return ret; ++} ++ ++/* MMC protocol macros: v3.4, p.120 */ ++static int pxa_mmc_init_card_stack( mmc_controller_t ctrlr ) ++{ ++ int ret = -EIO; ++ u16 argl = 0U, argh = 0U; ++ ++ if ( !ctrlr || ctrlr->stack.ncards ) { ++ ret = -EINVAL; ++ goto error; ++ } ++ ++ /* initialize stack */ ++ /* 1) send CMD0 */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ /* max open-drain mode frequency is 400kHZ */ ++ MMC_CLKRT = MMC_CLKRT_0_3125MHZ; ++ MMC_RESTO = MMC_RES_TO_MAX; /* set response timeout */ ++ MMC_SPI = MMC_SPI_DISABLE; ++ ++ MMC_CMD = CMD(0); /* CMD0 with zero argument */ ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_CMDAT = MMC_CMDAT_INIT; ++ ++ //MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD0(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_NORESPONSE, FALSE )) ) ++ goto error; ++ ++ /* update card stack */ ++ if ( (ret = pxa_mmc_update_acq( ctrlr )) ) ++ goto err_free; ++ ++ /* move the controller to the IDLE state */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto err_free; ++ ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_IDLE ); ++ ++ ret = 0; ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "ncards=%d\n", ctrlr->stack.ncards ); ++ goto out; ++ ++err_free: ++ __mmc_card_stack_free( &ctrlr->stack ); ++error: ++out: ++ return ret; ++} ++ ++static int pxa_mmc_check_card_stack( mmc_controller_t ctrlr ) ++{ ++ int ret = -1; ++ mmc_card_t card; ++ ++ if ( !ctrlr ) ++ goto error; ++ ++ if ( ctrlr->stack.ncards > 0 ) { ++/* for each card in the stack: */ ++ for( card = ctrlr->stack.first; card; card = card->next ) { ++ u16 argh = card->info.rca; ++ u16 argl = 0UL; ++ ++/* 1) send CMD9( card->rca ) */ ++ if ( pxa_mmc_stop_bus_clock( ctrlr ) ) ++ goto error; ++ ++ /* SanDisk's cards do not respond to CMD9 */ ++ MMC_CMD = CMD(13); ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_CMDAT = MMC_CMDAT_R1; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD13(0x%04x%04x)\n", ++ argh, argl ); ++ ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE ); ++/* 2) if card responded, it is still there */ ++ if ( ret ) ++ card->state = MMC_CARD_STATE_UNPLUGGED; ++ } ++ } ++ ret = 0; ++error: ++ return ret; ++} ++ ++/* This procedure links the bus master with a single card ++ * 1) cross checks with the internal stack management data if a card still ++ * exists in the slot ++ * 2) send CMD7( card->public.rca ) ++ * 3) setup data path and controller options ++ */ ++static int pxa_mmc_setup_card( mmc_controller_t ctrlr, mmc_card_t card ) ++{ ++ int ret = -ENODEV; ++ pxa_mmc_hostdata_t hostdata; ++ pxa_mmc_card_data_t card_data; ++ u16 argh = 0U; ++#ifdef CONFIG_MMC_DEBUG ++ u16 argl = 0U; ++#endif ++ ++ if ( !ctrlr || !card ) { ++ ret = -EINVAL; ++ goto error; ++ } ++ ++ if ( card->ctrlr != ctrlr ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "card is on another bus\n" ); ++ goto error; ++ } ++ ++ hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ card_data = (pxa_mmc_card_data_t)card->card_data; ++ ++ argh = card->info.rca; ++ ++/* select requested card */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ MMC_CMD = CMD(7); ++ MMC_ARGH = argh; ++ MMC_CMDAT = MMC_CMDAT_R1; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD7(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) ) ++ goto error; ++ ++/* set controller options */ ++#ifndef CONFIG_MMC_DEBUG ++ MMC_CLKRT = card_data->clkrt; ++#endif ++/* move the controller to the IDLE state */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_IDLE ); ++ ++ ret = 0; ++error: ++ return ret; ++} ++ ++static inline int pxa_mmc_iobuf_init( mmc_controller_t ctrlr, ssize_t cnt ) ++{ ++#ifdef PIO ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++#endif ++#ifndef PIO ++/* TODO */ ++#else ++ hostdata->iobuf.buf.pos = hostdata->iobuf.iodata; ++ hostdata->iobuf.buf.cnt = cnt; ++#endif ++ return 0; ++} ++/* TODO: ssize_t pxa_mmc_read_buffer( mmc_controller_t ctrlr, ssize_t cnt ) ++effects: reads at most cnt bytes from the card to the controller I/O buffer; ++ takes care of partial data transfers ++requieres: ++modifies: ctrlr->iobuf ++returns: number of bytes actually transferred or negative error code if there were any errors ++ */ ++ssize_t pxa_mmc_read_buffer( mmc_controller_t ctrlr, ssize_t cnt ) ++{ ++ ssize_t ret = -EIO; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++#ifndef PIO ++ register int ndesc; ++ int chan = hostdata->iobuf.buf.chan; ++ pxa_dma_desc *desc; ++#endif ++ ++ if ( (hostdata->state != PXA_MMC_FSM_END_CMD) && (hostdata->state != PXA_MMC_FSM_END_BUFFER) ) { ++ goto error; ++ } ++ ++ if ( cnt > hostdata->iobuf.bufsz ) ++ cnt = hostdata->iobuf.bufsz; ++ ++ if ( (ret = pxa_mmc_iobuf_init( ctrlr, cnt )) ) ++ goto error; ++ ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_BUFFER_IN_TRANSIT ); ++#ifndef PIO ++ if ( pxa_mmc_init_completion( ctrlr, ~MMC_I_MASK_ALL ) ) /* FIXME */ ++ goto error; ++ ++ if ( (desc = hostdata->iobuf.buf.last_read_desc) ) { ++ desc->ddadr &= ~DDADR_STOP; ++ desc->dcmd &= ~(DCMD_ENDIRQEN|DCMD_LENGTH); ++ desc->dcmd |= (1<<5); ++ } ++/* 1) setup descriptors for DMA transfer from the device */ ++ ndesc = (cnt>>5) - 1; /* FIXME: partial read */ ++ desc = &hostdata->iobuf.buf.read_desc[ndesc]; ++ hostdata->iobuf.buf.last_read_desc = desc; ++ /* TODO: partial read */ ++ desc->ddadr |= DDADR_STOP; ++ desc->dcmd |= DCMD_ENDIRQEN; ++/* 2) start DMA channel */ ++ DDADR( chan ) = hostdata->iobuf.buf.read_desc_phys_addr; ++ DCSR( chan ) |= DCSR_RUN; ++#else ++ if ( pxa_mmc_init_completion( ctrlr, MMC_I_MASK_RXFIFO_RD_REQ ) ) ++ goto error; ++#endif ++ ++ if ( pxa_mmc_wait_for_completion( ctrlr, ~0UL ) ) ++ goto error; ++ ++ if ( pxa_mmc_check_state( ctrlr, PXA_MMC_FSM_END_BUFFER ) ) ++ goto error; ++ ++ if ( !(hostdata->mmc_stat & MMC_STAT_ERRORS) ) /* FIXME */ ++ ret = cnt; ++error: ++ return ret; ++} ++ ++ssize_t pxa_mmc_write_buffer( mmc_controller_t ctrlr, ssize_t cnt ) ++{ ++ ssize_t ret = -EIO; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++#ifndef PIO ++ register int ndesc; ++ int chan = hostdata->iobuf.buf.chan; ++ pxa_dma_desc *desc; ++#endif ++ ++ if ( (hostdata->state != PXA_MMC_FSM_END_CMD) ++ && (hostdata->state != PXA_MMC_FSM_END_BUFFER) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "unexpected state (%s)\n", ++ PXA_MMC_STATE_LABEL( hostdata->state ) ); ++ goto error; ++ } ++ ++ if ( cnt > hostdata->iobuf.bufsz ) ++ cnt = hostdata->iobuf.bufsz; ++ ++ if ( (ret = pxa_mmc_iobuf_init( ctrlr, cnt )) ) ++ goto error; ++ ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_BUFFER_IN_TRANSIT ); ++#ifndef PIO ++ if ( pxa_mmc_init_completion( ctrlr, ~MMC_I_MASK_ALL ) ) /* FIXME */ ++ goto error; ++ if ( (desc = hostdata->iobuf.buf.last_write_desc) ) { ++ desc->ddadr &= ~DDADR_STOP; ++ desc->dcmd &= ~(DCMD_ENDIRQEN|DCMD_LENGTH); ++ desc->dcmd |= (1<<5); ++ } ++/* 1) setup descriptors for DMA transfer to the device */ ++ ndesc = (cnt>>5) - 1; /* FIXME: partial write */ ++ desc = &hostdata->iobuf.buf.write_desc[ndesc]; ++ /* TODO: partial write */ ++ hostdata->iobuf.buf.last_write_desc = desc; ++ desc->ddadr |= DDADR_STOP; ++ desc->dcmd |= DCMD_ENDIRQEN; ++/* 2) start DMA channel */ ++ DDADR( chan ) = hostdata->iobuf.buf.write_desc_phys_addr; ++ DCSR( chan ) |= DCSR_RUN; ++#else ++ if ( pxa_mmc_init_completion( ctrlr, MMC_I_MASK_TXFIFO_WR_REQ ) ) ++ goto error; ++#endif ++ if ( pxa_mmc_wait_for_completion( ctrlr, ~0UL ) ) ++ goto error; ++ ++ if ( pxa_mmc_check_state( ctrlr, PXA_MMC_FSM_END_BUFFER ) ) ++ goto error; ++ ++ if ( !(hostdata->mmc_stat & MMC_STAT_ERRORS) ) /* FIXME */ ++ ret = cnt; ++error: ++ return ret; ++} ++ ++/* TODO: ssize_t pxa_mmc_copy_from_buffer( ctrlr, mmc_buftype_t to, char *buf, ssize_t cnt ) ++effects: copies at most cnt bytes from the controller I/O buffer to the user or kernel buffer ++ pointed by buf ++requiers: ++modifies: ++returns: number of bytes actually transferred or negative error code if there were any errors ++ */ ++ssize_t pxa_mmc_copy_from_buffer( mmc_controller_t ctrlr, mmc_buftype_t to, char *buf, ssize_t cnt ) ++{ ++ ssize_t ret = -EIO; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ ++#ifndef PIO ++/* TODO: check that DMA channel is not running */ ++#endif ++ switch ( to ) { ++ case MMC_USER: ++ if ( copy_to_user( buf, hostdata->iobuf.iodata, cnt ) ) { ++ ret = -EFAULT; ++ goto error; ++ } ++ break; ++ case MMC_KERNEL: ++ memcpy( buf, hostdata->iobuf.iodata, cnt ); ++ break; ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "unknown buffer type\n" ); ++ goto error; ++ } ++ ret = cnt; ++error: ++ return ret; ++} ++ ++ssize_t pxa_mmc_copy_to_buffer( mmc_controller_t ctrlr, mmc_buftype_t to, char *buf, ssize_t cnt ) ++{ ++ ssize_t ret = -EIO; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++#ifndef PIO ++/* check that DMA channel is not running */ ++#endif ++ switch ( to ) { ++ case MMC_USER: ++ if ( copy_from_user( hostdata->iobuf.iodata, buf, cnt ) ) { ++ ret = -EFAULT; ++ goto error; ++ } ++ break; ++ case MMC_KERNEL: ++ memcpy( hostdata->iobuf.iodata, buf, cnt ); ++ break; ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "unknown buffer type\n" ); ++ goto error; ++ } ++ ret = cnt; ++error: ++ return ret; ++} ++ ++/* This procedure sequentally passes the data from the user buffer to the card */ ++static int pxa_mmc_stream_read( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer ) ++{ ++ int ret = -EIO; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ u16 argh = 0UL, argl = 0UL; ++ ssize_t size = 0; ++ ++ while ( transfer->cnt > 0 ) { ++ size = (transfer->cnt < hostdata->iobuf.blksz) ? ++ transfer->cnt : hostdata->iobuf.blksz; ++ /* 1. send CMD11 */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ argh = transfer->addr >> 16; ++ argl = transfer->addr; ++ /* 2. setup controller registers to start stream data transfer */ ++ MMC_CMD = CMD(11); /* READ_DAT_UNTIL_STOP */ ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_NOB = 0xffff; ++ MMC_BLKLEN = size; ++ MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_READ|MMC_CMDAT_STREAM|MMC_CMDAT_DATA_EN; ++#ifndef PIO ++ MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN; ++#endif ++ /* 3. wait for cmd to complete */ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD11(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, TRUE )) ) ++ goto error; ++ ++ /* 4. transfer the data to the caller supplied buffer */ ++ if ( (ret = pxa_mmc_read_buffer( ctrlr, size )) < 0 ) ++ goto error; ++ ++ if ( (ret = pxa_mmc_copy_from_buffer( ctrlr, transfer->type, transfer->buf, ret )) < 0 ) ++ goto error; ++ ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO ); ++ ++ if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) ) ++ goto error; ++ ++ transfer->buf += ret; ++ transfer->addr += ret; ++ transfer->cnt -= ret; ++ } ++ ret = 0; ++error: ++ return ret; ++} ++ ++/* This procedure reads a data block from a card at a given kernel address */ ++static int pxa_mmc_read_block( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer ) ++{ ++ int ret = -ENODEV; ++ u16 argh = 0UL, argl = 0UL; ++ ++/* send CMD16 (SET_BLOCK_LEN) when requested block size is not the default ++ * for the current card */ ++ if ( transfer->blksz != ctrlr->stack.selected->info.read_bl_len ) { ++ argh = transfer->blksz >> 16; ++ argl = transfer->blksz; ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ MMC_CMD = CMD(16); /* SET_BLOCK_LEN */ ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_CMDAT = MMC_CMDAT_R1; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, ++ "CMD16(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) ) ++ goto error; ++ } ++ ++/* CMD17 (READ_SINGLE_BLOCK) */ ++ argh = transfer->addr >> 16; ++ argl = transfer->addr; ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ MMC_CMD = CMD(17); /* READ_SINGLE_BLOCK */ ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_READ|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN; ++ MMC_NOB = 1; ++ MMC_BLKLEN = transfer->blksz; ++#ifndef PIO ++ MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN; ++#endif ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD17(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) ) ++ goto error; ++ ++/* transfer the data to the caller supplied buffer */ ++ if ( (ret = pxa_mmc_read_buffer( ctrlr, transfer->blksz )) < 0 ) ++ goto error; ++ ++ if ( (ret = pxa_mmc_copy_from_buffer( ctrlr, transfer->type, transfer->buf, ret )) < 0 ) ++ goto error; ++ ++ transfer->buf += ret; ++ transfer->cnt -= ret; ++ transfer->nob -= 1; ++ ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO ); ++ ++ if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) ) ++ goto error; ++ ++ ret = 0; ++error: ++ return ret; ++} ++ ++/* This procedure sequentally reads data blocks from ++ * a card to the user buffer. Controller options and block size ++ * are already set by setup_card(). Data alignment and partial ++ * data accessibility assumed to be checked by mmc_core */ ++static int pxa_mmc_read_mblock( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer ) ++{ ++ int ret = -EIO; ++ u16 argh = 0UL, argl = 0UL; ++ ++/* send CMD16 (SET_BLOCK_LEN) when requested block size is not the default ++ * for the current card */ ++ if ( transfer->blksz != ctrlr->stack.selected->info.read_bl_len ) { ++ argh = transfer->blksz >> 16; ++ argl = transfer->blksz; ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ MMC_CMD = CMD(16); /* SET_BLOCK_LEN */ ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_CMDAT = MMC_CMDAT_R1; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD16(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) ) ++ goto error; ++ } ++ ++ argh = transfer->addr >> 16; ++ argl = transfer->addr; ++/* 1. stop bus clock */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++/* 2. setup controller registers to start multiple block transfer */ ++ MMC_CMD = CMD(18); /* READ_MULTIPLE_BLOCK */ ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_NOB = transfer->nob; ++ MMC_BLKLEN = transfer->blksz; ++ MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_READ|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN; ++#ifndef PIO ++ MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN; ++#endif ++ ++/* 3. start clock */ ++ if ( (ret = pxa_mmc_start_bus_clock( ctrlr )) ) ++ goto error; ++ ++/* 4. wait for cmd to complete */ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD18(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, TRUE )) ) ++ goto error; ++ ++/* 6. transfer the data to the caller supplied buffer */ ++ while ( transfer->cnt > 0 ) { ++ if ( (ret = pxa_mmc_read_buffer( ctrlr, transfer->cnt )) < 0 ) ++ goto error; ++ ++ if ( (ret = pxa_mmc_copy_from_buffer( ctrlr, transfer->type, transfer->buf, ret )) < 0 ) ++ goto error; ++ ++ transfer->buf += ret; ++ transfer->cnt -= ret; ++ } ++ ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO ); ++ ++ if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) ) ++ goto error; ++ ++ ret = 0; ++error: ++ return ret; ++} ++ ++/* Sequentally writes the data from a user buffer to the card */ ++static int pxa_mmc_stream_write( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer ) ++{ ++ int ret = -EIO; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ u16 argh = 0UL, argl = 0UL; ++ ssize_t size = 0; ++ ++ __ENTER( "transfer: cmd=%d mode=%d type=%d blksz=%d " ++ "nob=%d buf=%p cnt=%d addr=%Lx", transfer->cmd, ++ transfer->mode, transfer->type, transfer->blksz, ++ transfer->nob, transfer->buf, transfer->cnt, transfer->addr ); ++ ++ argh = transfer->addr >> 16; ++ argl = transfer->addr; ++/* 1. stop bus clock */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++/* 2. setup controller registers to start stream data transfer */ ++ MMC_CMD = CMD(20); /* WRITE_DAT_UNTIL_STOP */ ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_NOB = 0xffff; ++ MMC_BLKLEN = hostdata->iobuf.blksz; ++ MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_WRITE|MMC_CMDAT_STREAM|MMC_CMDAT_DATA_EN; ++#ifndef PIO ++ MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN; ++#endif ++ ++/* 3. wait for cmd to complete */ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD20(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, TRUE )) ) ++ goto error; ++ ++/* 4. transfer the data to the caller supplied buffer */ ++ while ( transfer->cnt > 0 ) { ++ size = (transfer->cnt < hostdata->iobuf.blksz) ? ++ transfer->cnt : hostdata->iobuf.blksz; ++ if ( (ret = pxa_mmc_copy_to_buffer( ctrlr, ++ transfer->type, transfer->buf, size )) < 0 ) ++ goto error; ++ ++ if ( (ret = pxa_mmc_write_buffer( ctrlr, ret )) < 0 ) ++ goto error; ++ ++ transfer->buf += ret; ++ transfer->cnt -= ret; ++ } ++ ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO ); ++ ++ if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) ) ++ goto error; ++ ++ ret = 0; ++error: ++ return ret; ++} ++ ++/* This procedure writes a data block to a card at a given address */ ++static int pxa_mmc_write_block( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer ) ++{ ++ int ret = -ENODEV; ++ u16 argh = 0UL, argl = 0UL; ++ ++/* send CMD16 (SET_BLOCK_LEN) when requested block size is not the default ++ * for the current card */ ++ if ( transfer->blksz != ctrlr->stack.selected->info.read_bl_len ) { ++ argh = transfer->blksz >> 16; ++ argl = transfer->blksz; ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ MMC_CMD = CMD(16); /* SET_BLOCK_LEN */ ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_CMDAT = MMC_CMDAT_R1; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD16(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) ) ++ goto error; ++ } ++ ++/* CMD17 (READ_SINGLE_BLOCK) */ ++ argh = transfer->addr >> 16; ++ argl = transfer->addr; ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ MMC_CMD = CMD(24); /* WRITE_BLOCK */ ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_WRITE|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN; ++#ifndef PIO ++ MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN; ++#endif ++ MMC_NOB = 1; ++ MMC_BLKLEN = transfer->blksz; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD24(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) ) ++ goto error; ++ ++/* transfer the data to the caller supplied buffer */ ++ if ( (ret = pxa_mmc_copy_to_buffer( ctrlr, transfer->type, transfer->buf, transfer->cnt )) < 0 ) ++ goto error; ++ ++ if ( (ret = pxa_mmc_write_buffer( ctrlr, ret )) < 0 ) ++ goto error; ++ ++ transfer->buf += ret; ++ transfer->cnt -= ret; ++ transfer->nob -= 1; ++ ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO ); ++ ++ if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) ) ++ goto error; ++ ++ ret = 0; ++error: ++ return ret; ++} ++ ++/* This procedure sequentally writes data blocks to a card at a given address */ ++static ssize_t pxa_mmc_write_mblock( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer ) ++{ ++ int ret = -EIO; ++ u16 argh = 0UL, argl = 0UL; ++ ++/* send CMD16 (SET_BLOCK_LEN) when requested block size is not the default ++ * for the current card */ ++ if ( transfer->blksz != ctrlr->stack.selected->info.write_bl_len ) { ++ argh = transfer->blksz >> 16; ++ argl = transfer->blksz; ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ MMC_CMD = CMD(16); /* SET_BLOCK_LEN */ ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_CMDAT = MMC_CMDAT_R1; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD16(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) ) ++ goto error; ++ } ++ ++ argh = transfer->addr >> 16; ++ argl = transfer->addr; ++/* 1. stop bus clock */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++/* 2. setup controller registers to start multiple block transfer */ ++ MMC_CMD = CMD(25); /* WRITE_MULTIPLE_BLOCK */ ++ MMC_ARGH = argh; ++ MMC_ARGL = argl; ++ MMC_NOB = transfer->nob; ++ MMC_BLKLEN = transfer->blksz; ++ MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_WRITE|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN; ++#ifndef PIO ++ MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN; ++#endif ++ ++/* 3. start clock */ ++ if ( (ret = pxa_mmc_start_bus_clock( ctrlr )) ) ++ goto error; ++ ++/* 4. wait for cmd to complete */ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD25(0x%04x%04x)\n", argh, argl ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, TRUE )) ) ++ goto error; ++ ++/* 6. transfer the data to the caller supplied buffer */ ++ while ( transfer->cnt > 0 ) { ++ if ( (ret = pxa_mmc_copy_to_buffer( ctrlr, transfer->type, ++ transfer->buf, transfer->cnt )) < 0 ) ++ goto error; ++ ++ if ( (ret = pxa_mmc_write_buffer( ctrlr, ret )) < 0 ) ++ goto error; ++ ++ transfer->buf += ret; ++ transfer->cnt -= ret; ++ } ++ ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO ); ++ ++ if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) ) ++ goto error; ++ ++ ret = 0; ++error: ++ return ret; ++} ++ ++static void pxa_mmc_irq( int irq, void *dev_id, struct pt_regs *regs ) ++{ ++ mmc_controller_t ctrlr = (mmc_controller_t)dev_id; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++#ifdef PIO ++ register int i, cnt; ++ register char *buf; ++#endif ++ ++ hostdata->mmc_i_reg = MMC_I_REG; ++ hostdata->mmc_stat = MMC_STAT; ++ hostdata->mmc_cmdat = MMC_CMDAT; ++#if 0 ++ if (hostdata->mmc_i_reg != 0x0010) { ++ printk("IREG %08x", hostdata->mmc_i_reg); ++ if (hostdata->mmc_i_reg & 0x0001) printk(" DATA_TRAN_DONE"); ++ if (hostdata->mmc_i_reg & 0x0002) printk(" PRG_DONE"); ++ if (hostdata->mmc_i_reg & 0x0004) printk(" END_CMD"); ++ if (hostdata->mmc_i_reg & 0x0008) printk(" STOP_CMD"); ++ if (hostdata->mmc_i_reg & 0x0010) printk(" CLK_OFF"); ++ if (hostdata->mmc_i_reg & 0x0020) printk(" RX_FIFO"); ++ if (hostdata->mmc_i_reg & 0x0040) printk(" TX_FIFO"); ++ printk("\nSTAT %08x", hostdata->mmc_stat); ++ if (hostdata->mmc_stat & 0x0001) printk(" READ_TO"); ++ if (hostdata->mmc_stat & 0x0002) printk(" RESP_TO"); ++ if (hostdata->mmc_stat & 0x0004) printk(" WR_CRC"); ++ if (hostdata->mmc_stat & 0x0008) printk(" READ_CRC"); ++ if (hostdata->mmc_stat & 0x0010) printk(" SPI_RD_TKN"); ++ if (hostdata->mmc_stat & 0x0020) printk(" RESP_CRC"); ++ if (hostdata->mmc_stat & 0x0040) printk(" TX_FIFO"); ++ if (hostdata->mmc_stat & 0x0080) printk(" RX_FIFO"); ++ if (hostdata->mmc_stat & 0x0100) printk(" CLK"); ++ if (hostdata->mmc_stat & 0x0800) printk(" DATA_TRAN_DONE"); ++ if (hostdata->mmc_stat & 0x1000) printk(" PRG_DONE"); ++ if (hostdata->mmc_stat & 0x2000) printk(" END_CMD"); ++ printk("\n"); ++ } ++#endif ++ ++#if CONFIG_MMC_DEBUG_IRQ ++ if ( --hostdata->irqcnt <= 0 ) { ++ printk( KERN_INFO __FUNCTION__"(): irqcnt exceeded\n" ); ++ goto complete; ++ } ++#endif ++ switch ( hostdata->state ) { ++ case PXA_MMC_FSM_IDLE: ++ case PXA_MMC_FSM_CLK_OFF: ++ case PXA_MMC_FSM_END_IO: ++ case PXA_MMC_FSM_END_BUFFER: ++ case PXA_MMC_FSM_END_CMD: ++ goto complete; ++#ifdef PIO ++ case PXA_MMC_FSM_BUFFER_IN_TRANSIT: ++ if ( hostdata->mmc_stat & MMC_STAT_ERRORS ) ++ goto complete; ++ ++ buf = hostdata->iobuf.buf.pos; ++ cnt = (hostdata->iobuf.buf.cnt < 32) ? ++ hostdata->iobuf.buf.cnt : 32; ++ if ( hostdata->mmc_cmdat & MMC_CMDAT_WRITE ) { ++ if ( !(hostdata->mmc_stat & MMC_STAT_XMIT_FIFO_EMPTY) ) ++ break; ++ for ( i = 0; i < cnt; i++ ) ++ MMC_TXFIFO = *buf++; ++ if ( cnt < 32 ) ++ MMC_PRTBUF = MMC_PRTBUF_BUF_PART_FULL; ++ } else { /* i.e. MMC_CMDAT_READ */ ++ if( !(hostdata->mmc_stat & MMC_STAT_RECV_FIFO_FULL) ) ++ break; ++ for( i = 0; i < cnt; i++ ) ++ *buf++ = MMC_RXFIFO; ++ } ++ ++ hostdata->iobuf.buf.pos = buf; ++ hostdata->iobuf.buf.cnt -= i; ++ if ( hostdata->iobuf.buf.cnt <= 0 ) { ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_BUFFER ); ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "buffer transferred\n" ); ++ goto complete; ++ } ++ break; ++#endif /* PIO */ ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "unexpected state %d\n", ++ hostdata->state ); ++ goto complete; ++ } ++ return; ++complete: ++ MMC_I_MASK = MMC_I_MASK_ALL; ++ complete( &hostdata->completion ); ++ return; ++} ++ ++#ifndef PIO ++static void pxa_mmc_dma_irq( int irq, void *dev_id, struct pt_regs *regs ) ++{ ++ mmc_controller_t ctrlr = (mmc_controller_t)dev_id; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ u32 dcsr; ++ u32 ddadr; ++ int chan = hostdata->iobuf.buf.chan; ++ ++ ddadr = DDADR( chan ); ++ dcsr = DCSR( chan ); ++ DCSR( chan ) = dcsr & ~DCSR_STOPIRQEN; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, ++ "MMC DMA interrupt: chan=%d ddadr=0x%08x " ++ "dcmd=0x%08x dcsr=0x%08x\n", ++ chan, ddadr, DCMD( chan ), dcsr ); ++/* bus error */ ++ if ( dcsr & DCSR_BUSERR ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "bus error on DMA channel %d\n", ++ chan ); ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_ERROR ); ++ goto complete; ++ } ++/* data transfer completed */ ++ if ( dcsr & DCSR_ENDINTR ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "buffer transferred\n" ); ++ pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_BUFFER ); ++ goto complete; ++ } ++ return; ++complete: ++ complete( &hostdata->completion ); ++ return; ++} ++#endif ++ ++ ++static int pxa_mmc_init( mmc_controller_t ctrlr ) ++{ ++ int ret = -ENODEV; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++#ifndef PIO ++ register int i; ++ register pxa_dma_desc *desc; ++#endif ++ ++/* hardware initialization */ ++/* I. prepare to transfer data */ ++/* 1. allocate buffer */ ++#ifndef PIO ++ hostdata->iobuf.buf.read_desc = consistent_alloc( GFP_KERNEL, ++ (PXA_MMC_IODATA_SIZE>>5) ++ * sizeof( pxa_dma_desc ), ++ &hostdata->iobuf.buf.read_desc_phys_addr, 0 ); ++ if ( !hostdata->iobuf.buf.read_desc ) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ hostdata->iobuf.buf.write_desc = consistent_alloc( GFP_KERNEL, ++ (PXA_MMC_IODATA_SIZE>>5) ++ * sizeof( pxa_dma_desc ), ++ &hostdata->iobuf.buf.write_desc_phys_addr, 0 ); ++ if ( !hostdata->iobuf.buf.write_desc ) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ hostdata->iobuf.iodata = consistent_alloc( GFP_ATOMIC, ++ PXA_MMC_IODATA_SIZE, ++ &hostdata->iobuf.buf.phys_addr, 0 ); ++#else ++ hostdata->iobuf.iodata = kmalloc( PXA_MMC_IODATA_SIZE, GFP_ATOMIC ); ++#endif ++ if ( !hostdata->iobuf.iodata ) { ++ ret = -ENOMEM; ++ goto error; ++ } ++/* 2. initialize iobuf */ ++ hostdata->iobuf.blksz = PXA_MMC_BLKSZ_MAX; ++ hostdata->iobuf.bufsz = PXA_MMC_IODATA_SIZE; ++ hostdata->iobuf.nob = PXA_MMC_BLOCKS_PER_BUFFER; ++#ifndef PIO ++ /* request DMA channel */ ++ if ( (hostdata->iobuf.buf.chan = pxa_request_dma( "MMC", DMA_PRIO_LOW, ++ pxa_mmc_dma_irq, ctrlr )) < 0 ) { ++ MMC_ERROR( "failed to request DMA channel\n" ); ++ goto error; ++ } ++ ++ DRCMRRXMMC = hostdata->iobuf.buf.chan | DRCMR_MAPVLD; ++ DRCMRTXMMC = hostdata->iobuf.buf.chan | DRCMR_MAPVLD; ++ ++ for ( i = 0; i < ((PXA_MMC_IODATA_SIZE>>5) - 1); i++ ) { ++ desc = &hostdata->iobuf.buf.read_desc[i]; ++ desc->ddadr = hostdata->iobuf.buf.read_desc_phys_addr ++ + ((i + 1) * sizeof( pxa_dma_desc )); ++ desc->dsadr = MMC_RXFIFO_PHYS_ADDR; ++ desc->dtadr = hostdata->iobuf.buf.phys_addr + (i<<5); ++ desc->dcmd = DCMD_FLOWSRC|DCMD_INCTRGADDR ++ |DCMD_WIDTH1|DCMD_BURST32|(1<<5); ++ ++ desc = &hostdata->iobuf.buf.write_desc[i]; ++ desc->ddadr = hostdata->iobuf.buf.write_desc_phys_addr ++ + ((i + 1) * sizeof( pxa_dma_desc )); ++ desc->dsadr = hostdata->iobuf.buf.phys_addr + (i<<5); ++ desc->dtadr = MMC_TXFIFO_PHYS_ADDR; ++ desc->dcmd = DCMD_FLOWTRG|DCMD_INCSRCADDR ++ |DCMD_WIDTH1|DCMD_BURST32|(1<<5); ++ } ++ desc = &hostdata->iobuf.buf.read_desc[i]; ++ desc->ddadr = (hostdata->iobuf.buf.read_desc_phys_addr + ++ (i + 1) * sizeof( pxa_dma_desc))|DDADR_STOP; ++ desc->dsadr = MMC_RXFIFO_PHYS_ADDR; ++ desc->dtadr = hostdata->iobuf.buf.phys_addr + (i<<5); ++ desc->dcmd = DCMD_FLOWSRC|DCMD_INCTRGADDR ++ |DCMD_WIDTH1|DCMD_BURST32|(1<<5); ++ ++ desc = &hostdata->iobuf.buf.write_desc[i]; ++ desc->ddadr = (hostdata->iobuf.buf.write_desc_phys_addr + ++ (i + 1) * sizeof( pxa_dma_desc))|DDADR_STOP; ++ desc->dsadr = hostdata->iobuf.buf.phys_addr + (i<<5); ++ desc->dtadr = MMC_TXFIFO_PHYS_ADDR; ++ desc->dcmd = DCMD_FLOWTRG|DCMD_INCSRCADDR ++ |DCMD_WIDTH1|DCMD_BURST32|(1<<5); ++#endif ++/* II. MMC */ ++/* 1) request irq */ ++ if ( request_irq( IRQ_MMC, pxa_mmc_irq, 0, "MMC", ctrlr ) ) { ++ MMC_ERROR( "failed to request IRQ_MMC\n" ); ++ goto error; ++ } ++ ++/* 2) initialize h/w and ctrlr */ ++ set_GPIO_mode( GPIO6_MMCCLK_MD ); ++ CKEN |= CKEN12_MMC; /* enable MMC unit clock */ ++ ++ ret = 0; ++ goto out; ++error: ++#ifndef PIO ++/* free DMA resources */ ++ if ( hostdata->iobuf.buf.chan >= 0 ) { ++ DRCMRRXMMC = 0; ++ DRCMRTXMMC = 0; ++ pxa_free_dma( hostdata->iobuf.buf.chan ); ++ } ++ if ( hostdata->iobuf.iodata ) ++ consistent_free( hostdata->iobuf.iodata, ++ PXA_MMC_IODATA_SIZE, ++ hostdata->iobuf.buf.phys_addr ); ++ if ( hostdata->iobuf.buf.read_desc ) ++ consistent_free( hostdata->iobuf.buf.read_desc, ++ (PXA_MMC_IODATA_SIZE>>5) ++ * sizeof( pxa_dma_desc ), ++ hostdata->iobuf.buf.read_desc_phys_addr ); ++ if ( hostdata->iobuf.buf.write_desc ) ++ consistent_free( hostdata->iobuf.buf.write_desc, ++ (PXA_MMC_IODATA_SIZE>>5) ++ * sizeof( pxa_dma_desc ), ++ hostdata->iobuf.buf.write_desc_phys_addr ); ++#else ++ kfree( hostdata->iobuf.iodata ); ++#endif ++out: ++ return ret; ++} ++ ++static void pxa_mmc_remove( mmc_controller_t ctrlr ) ++{ ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ ++/* 1) free buffer(s) */ ++#ifndef PIO ++ consistent_free( hostdata->iobuf.iodata, PXA_MMC_IODATA_SIZE, ++ hostdata->iobuf.buf.phys_addr ); ++ consistent_free( hostdata->iobuf.buf.read_desc, ++ (PXA_MMC_IODATA_SIZE>>5) ++ * sizeof( pxa_dma_desc ), ++ hostdata->iobuf.buf.read_desc_phys_addr ); ++ consistent_free( hostdata->iobuf.buf.write_desc, ++ (PXA_MMC_IODATA_SIZE>>5) ++ * sizeof( pxa_dma_desc ), ++ hostdata->iobuf.buf.write_desc_phys_addr ); ++/* 2) release DMA channel */ ++ if ( hostdata->iobuf.buf.chan >= 0 ) { ++ DRCMRRXMMC = 0; ++ DRCMRTXMMC = 0; ++ pxa_free_dma( hostdata->iobuf.buf.chan ); ++ } ++#else ++ kfree( hostdata->iobuf.iodata ); ++#endif ++/* II. MMC */ ++/* 1) release irq */ ++ free_irq( IRQ_MMC, ctrlr ); ++ CKEN &= ~CKEN12_MMC; /* disable MMC unit clock */ ++} ++ ++static int pxa_mmc_probe( mmc_controller_t ctrlr ) ++{ ++ return 1; ++} ++ ++#ifdef CONFIG_PM ++static int pxa_mmc_suspend( mmc_controller_t ctrlr ) ++{ ++ int ret = -EBUSY; ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL2, "state=%s\n", ++ PXA_MMC_STATE_LABEL( hostdata->state ) ); ++ ++ if ( hostdata->state == PXA_MMC_FSM_IDLE ) { ++ /* save registers */ ++ SAVED_MMC_CLKRT = MMC_CLKRT; ++ SAVED_MMC_RESTO = MMC_RESTO; ++ SAVED_MMC_SPI = MMC_SPI; ++ SAVED_DRCMRRXMMC = DRCMRRXMMC; ++ SAVED_DRCMRTXMMC = DRCMRTXMMC; ++ ++#if 0 /* FIXME */ ++ /* send CMD0 */ ++ if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) ++ goto error; ++ ++ MMC_CMD = CMD(0); /* CMD0 with zero argument */ ++ MMC_ARGH = 0UL; ++ MMC_ARGL = 0UL; ++ MMC_CMDAT = 0UL; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD0(0x%04x%04x)\n", 0UL, 0UL ); ++ if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_NORESPONSE, ++ FALSE )) ) ++ { ++ ret = -EIO; ++ goto error; ++ } ++#endif ++ ++ set_GPIO_mode( GPIO6_MMCCLK ); ++ CKEN &= ~CKEN12_MMC; /* disable MMC unit clock */ ++ ++ hostdata->suspended = TRUE; ++ ret = 0; ++ } ++error: ++ return ret; ++} ++ ++static void pxa_mmc_resume( mmc_controller_t ctrlr ) ++{ ++ pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data; ++ ++ if ( hostdata->suspended == TRUE ) { ++ set_GPIO_mode( GPIO6_MMCCLK_MD ); ++ CKEN |= CKEN12_MMC; /* enable MMC unit clock */ ++ ++ /* restore registers */ ++ MMC_CLKRT = SAVED_MMC_CLKRT; ++ MMC_RESTO = SAVED_MMC_RESTO; ++ MMC_SPI = SAVED_MMC_SPI; ++ DRCMRRXMMC = SAVED_DRCMRRXMMC; ++ DRCMRTXMMC = SAVED_DRCMRTXMMC; ++ ++ hostdata->suspended = FALSE; ++ ++ mmc_update_card_stack( ctrlr->slot ); /* FIXME */ ++ } ++ ++ return; ++} ++#endif ++ ++static mmc_controller_tmpl_rec_t pxa_mmc_controller_tmpl_rec = { ++ owner: THIS_MODULE, ++ name: "PXA250", ++ block_size_max: PXA_MMC_BLKSZ_MAX, ++ nob_max: PXA_MMC_NOB_MAX, ++ probe: pxa_mmc_probe, ++ init: pxa_mmc_init, ++ remove: __devexit_p( pxa_mmc_remove ), ++#ifdef CONFIG_PM ++ suspend: pxa_mmc_suspend, ++ resume: pxa_mmc_resume, ++#endif /* CONFIG_PM */ ++ update_acq: pxa_mmc_update_acq, ++// single_card_acq: pxa_mmc_single_card_acq, ++ init_card_stack: pxa_mmc_init_card_stack, ++ check_card_stack: pxa_mmc_check_card_stack, ++ setup_card: pxa_mmc_setup_card, ++ stream_read: pxa_mmc_stream_read, ++ read_block: pxa_mmc_read_block, ++ read_mblock: pxa_mmc_read_mblock, ++ stream_write: pxa_mmc_stream_write, ++ write_block: pxa_mmc_write_block, ++ write_mblock: pxa_mmc_write_mblock ++ /* TODO ++ sg_io: pxa_mmc_sg_io ++ */ ++ /* TODO: ++ * erase, ++ * write protection, ++ * lock/password management methods ++ */ ++}; ++ ++static int __devinit mmc_pxa_module_init( void ) ++{ ++ int ret = -ENODEV; ++#ifdef CONFIG_ARCH_RAMSES ++ RAMSES_MMC_ON(); ++ udelay(1000); ++#endif ++ ++ host = mmc_register( MMC_REG_TYPE_HOST, &pxa_mmc_controller_tmpl_rec, ++ sizeof( pxa_mmc_hostdata_rec_t ) ); ++ if ( !host ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, ++ "failed to register with MMC core\n" ); ++ goto error; ++ } ++ ++ ret = 0; ++error: ++ return ret; ++} ++ ++static void __devexit mmc_pxa_module_cleanup( void ) ++{ ++ mmc_unregister( MMC_REG_TYPE_HOST, host ); ++#ifdef CONFIG_ARCH_RAMSES ++ RAMSES_MMC_OFF(); ++#endif ++} ++ ++EXPORT_NO_SYMBOLS; ++ ++MODULE_LICENSE( "GPL" ); ++ ++module_init( mmc_pxa_module_init ); ++module_exit( mmc_pxa_module_cleanup ); +--- /dev/null ++++ linux-2.4.27/drivers/mmc/mmc_pxa.h +@@ -0,0 +1,278 @@ ++/* ++ * linux/drivers/mmc/mmc_pxa.h ++ * ++ * Author: Vladimir Shebordaev, Igor Oblakov ++ * Copyright: MontaVista Software Inc. ++ * ++ * $Id: mmc_pxa.h,v 0.3.1.6 2002/09/25 19:25:48 ted Exp ted $ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef __MMC_PXA_P_H__ ++#define __MMC_PXA_P_H__ ++ ++#include <linux/completion.h> ++ ++#define PIO ++ ++/* PXA-250 MMC controller registers */ ++ ++/* MMC_STRPCL */ ++#define MMC_STRPCL_STOP_CLK (0x0001UL) ++#define MMC_STRPCL_START_CLK (0x0002UL) ++ ++/* MMC_STAT */ ++#define MMC_STAT_END_CMD_RES (0x0001UL << 13) ++#define MMC_STAT_PRG_DONE (0x0001UL << 12) ++#define MMC_STAT_DATA_TRAN_DONE (0x0001UL << 11) ++#define MMC_STAT_CLK_EN (0x0001UL << 8) ++#define MMC_STAT_RECV_FIFO_FULL (0x0001UL << 7) ++#define MMC_STAT_XMIT_FIFO_EMPTY (0x0001UL << 6) ++#define MMC_STAT_RES_CRC_ERROR (0x0001UL << 5) ++#define MMC_STAT_SPI_READ_ERROR_TOKEN (0x0001UL << 4) ++#define MMC_STAT_CRC_READ_ERROR (0x0001UL << 3) ++#define MMC_STAT_CRC_WRITE_ERROR (0x0001UL << 2) ++#define MMC_STAT_TIME_OUT_RESPONSE (0x0001UL << 1) ++#define MMC_STAT_READ_TIME_OUT (0x0001UL) ++ ++#define MMC_STAT_ERRORS (MMC_STAT_RES_CRC_ERROR|MMC_STAT_SPI_READ_ERROR_TOKEN\ ++ |MMC_STAT_CRC_READ_ERROR|MMC_STAT_TIME_OUT_RESPONSE\ ++ |MMC_STAT_READ_TIME_OUT) ++ ++/* MMC_CLKRT */ ++#define MMC_CLKRT_20MHZ (0x0000UL) ++#define MMC_CLKRT_10MHZ (0x0001UL) ++#define MMC_CLKRT_5MHZ (0x0002UL) ++#define MMC_CLKRT_2_5MHZ (0x0003UL) ++#define MMC_CLKRT_1_25MHZ (0x0004UL) ++#define MMC_CLKRT_0_625MHZ (0x0005UL) ++#define MMC_CLKRT_0_3125MHZ (0x0006UL) ++ ++/* MMC_SPI */ ++#define MMC_SPI_DISABLE (0x00UL) ++#define MMC_SPI_EN (0x01UL) ++#define MMC_SPI_CS_EN (0x01UL << 2) ++#define MMC_SPI_CS_ADDRESS (0x01UL << 3) ++#define MMC_SPI_CRC_ON (0x01UL << 1) ++ ++/* MMC_CMDAT */ ++#define MMC_CMDAT_MMC_DMA_EN (0x0001UL << 7) ++#define MMC_CMDAT_INIT (0x0001UL << 6) ++#define MMC_CMDAT_BUSY (0x0001UL << 5) ++#define MMC_CMDAT_STREAM (0x0001UL << 4) ++#define MMC_CMDAT_BLOCK (0x0000UL << 4) ++#define MMC_CMDAT_WRITE (0x0001UL << 3) ++#define MMC_CMDAT_READ (0x0000UL << 3) ++#define MMC_CMDAT_DATA_EN (0x0001UL << 2) ++#define MMC_CMDAT_R1 (0x0001UL) ++#define MMC_CMDAT_R2 (0x0002UL) ++#define MMC_CMDAT_R3 (0x0003UL) ++ ++/* MMC_RESTO */ ++#define MMC_RES_TO_MAX (0x007fUL) /* [6:0] */ ++ ++/* MMC_RDTO */ ++#define MMC_READ_TO_MAX (0x0ffffUL) /* [15:0] */ ++ ++/* MMC_BLKLEN */ ++#define MMC_BLK_LEN_MAX (0x03ffUL) /* [9:0] */ ++ ++/* MMC_PRTBUF */ ++#define MMC_PRTBUF_BUF_PART_FULL (0x01UL) ++#define MMC_PRTBUF_BUF_FULL (0x00UL ) ++ ++/* MMC_I_MASK */ ++#define MMC_I_MASK_TXFIFO_WR_REQ (0x01UL << 6) ++#define MMC_I_MASK_RXFIFO_RD_REQ (0x01UL << 5) ++#define MMC_I_MASK_CLK_IS_OFF (0x01UL << 4) ++#define MMC_I_MASK_STOP_CMD (0x01UL << 3) ++#define MMC_I_MASK_END_CMD_RES (0x01UL << 2) ++#define MMC_I_MASK_PRG_DONE (0x01UL << 1) ++#define MMC_I_MASK_DATA_TRAN_DONE (0x01UL) ++#define MMC_I_MASK_ALL (0x07fUL) ++ ++ ++/* MMC_I_REG */ ++#define MMC_I_REG_TXFIFO_WR_REQ (0x01UL << 6) ++#define MMC_I_REG_RXFIFO_RD_REQ (0x01UL << 5) ++#define MMC_I_REG_CLK_IS_OFF (0x01UL << 4) ++#define MMC_I_REG_STOP_CMD (0x01UL << 3) ++#define MMC_I_REG_END_CMD_RES (0x01UL << 2) ++#define MMC_I_REG_PRG_DONE (0x01UL << 1) ++#define MMC_I_REG_DATA_TRAN_DONE (0x01UL) ++#define MMC_I_REG_ALL (0x007fUL) ++ ++/* MMC_CMD */ ++#define MMC_CMD_INDEX_MAX (0x006fUL) /* [5:0] */ ++#define CMD(x) (x) ++ ++/* MMC_ARGH */ ++/* MMC_ARGL */ ++/* MMC_RES */ ++/* MMC_RXFIFO */ ++#define MMC_RXFIFO_PHYS_ADDR 0x41100040 //MMC_RXFIFO physical address ++/* MMC_TXFIFO */ ++#define MMC_TXFIFO_PHYS_ADDR 0x41100044 //MMC_TXFIFO physical address ++ ++/* implementation specific declarations */ ++#define PXA_MMC_BLKSZ_MAX (1<<9) /* actually 1023 */ ++#define PXA_MMC_NOB_MAX ((1<<16)-2) ++#define PXA_MMC_BLOCKS_PER_BUFFER (2) ++ ++#define PXA_MMC_IODATA_SIZE (PXA_MMC_BLOCKS_PER_BUFFER*PXA_MMC_BLKSZ_MAX) /* 1K */ ++ ++typedef enum _pxa_mmc_fsm { /* command processing FSM */ ++ PXA_MMC_FSM_IDLE = 1, ++ PXA_MMC_FSM_CLK_OFF, ++ PXA_MMC_FSM_END_CMD, ++ PXA_MMC_FSM_BUFFER_IN_TRANSIT, ++ PXA_MMC_FSM_END_BUFFER, ++ PXA_MMC_FSM_END_IO, ++ PXA_MMC_FSM_END_PRG, ++ PXA_MMC_FSM_ERROR ++} pxa_mmc_state_t; ++ ++#define PXA_MMC_STATE_LABEL( state ) (\ ++ (state == PXA_MMC_FSM_IDLE) ? "IDLE" :\ ++ (state == PXA_MMC_FSM_CLK_OFF) ? "CLK_OFF" :\ ++ (state == PXA_MMC_FSM_END_CMD) ? "END_CMD" :\ ++ (state == PXA_MMC_FSM_BUFFER_IN_TRANSIT) ? "IN_TRANSIT" :\ ++ (state == PXA_MMC_FSM_END_BUFFER) ? "END_BUFFER" :\ ++ (state == PXA_MMC_FSM_END_IO) ? "END_IO" :\ ++ (state == PXA_MMC_FSM_END_PRG) ? "END_PRG" : "UNKNOWN" ) ++ ++typedef enum _pxa_mmc_result { ++ PXA_MMC_NORMAL = 0, ++ PXA_MMC_INVALID_STATE = -1, ++ PXA_MMC_TIMEOUT = -2, ++ PXA_MMC_ERROR = -3 ++} pxa_mmc_result_t; ++ ++typedef u32 pxa_mmc_clkrt_t; ++ ++typedef char *pxa_mmc_iodata_t; ++#ifdef PIO ++typedef struct _pxa_mmc_piobuf_rec { ++ char *pos; /* current buffer position */ ++ int cnt; /* byte counter */ ++} pxa_mmc_piobuf_rec_t, *pxa_mmc_piobuf_t; ++#else /* i.e. DMA */ ++typedef struct _pxa_mmc_dmabuf_rec { /* TODO: buffer ring, DMA irq completion */ ++ int chan; /* dma channel no */ ++ dma_addr_t phys_addr; /* iodata physical address */ ++ pxa_dma_desc *read_desc; /* input descriptor array virtual address */ ++ pxa_dma_desc *write_desc; /* output descriptor array virtual address */ ++ dma_addr_t read_desc_phys_addr; /* descriptor array physical address */ ++ dma_addr_t write_desc_phys_addr; /* descriptor array physical address */ ++ pxa_dma_desc *last_read_desc; /* last input descriptor ++ * used by the previous transfer ++ */ ++ pxa_dma_desc *last_write_desc; /* last output descriptor ++ * used by the previous transfer ++ */ ++} pxa_mmc_dmabuf_rec_t, *pxa_mmc_dmabuf_t; ++#endif ++ ++typedef struct _pxa_mmc_iobuf_rec { ++ ssize_t blksz; /* current block size in bytes */ ++ ssize_t bufsz; /* buffer size for each transfer */ ++ ssize_t nob; /* number of blocks pers buffer */ ++#ifndef PIO ++ pxa_mmc_dmabuf_rec_t buf; /* i.e. DMA buffer ring on the iodata */ ++#else /* i.e. DMA */ ++ pxa_mmc_piobuf_rec_t buf; /* PIO buffer accounting */ ++#endif ++ pxa_mmc_iodata_t iodata; /* I/O data buffer */ ++} pxa_mmc_iobuf_rec_t, *pxa_mmc_iobuf_t; ++ ++typedef struct _pxa_mmc_hostdata_rec { ++ pxa_mmc_state_t state; /* FSM */ ++#ifdef CONFIG_PM ++ int suspended; ++#endif ++ pxa_mmc_iobuf_rec_t iobuf; /* data transfer state */ ++ ++ int busy; /* atomic busy flag */ ++ struct completion completion; /* completion */ ++#if CONFIG_MMC_DEBUG_IRQ ++ int irqcnt; ++ int timeo; ++#endif ++ ++/* cached controller state */ ++ u32 mmc_i_reg; /* interrupt last requested */ ++ u32 mmc_i_mask; /* mask to be set by intr handler */ ++ u32 mmc_stat; /* status register at the last intr */ ++ u32 mmc_cmdat; /* MMC_CMDAT at the last inr */ ++ u8 mmc_res[16]; /* response to the last command in host order */ ++ u32 saved_mmc_clkrt; ++ u32 saved_mmc_resto; ++ u32 saved_mmc_spi; ++ u32 saved_drcmrrxmmc; ++ u32 saved_drcmrtxmmc; ++ ++/* controller options */ ++ pxa_mmc_clkrt_t clkrt; /* current bus clock rate */ ++} pxa_mmc_hostdata_rec_t, *pxa_mmc_hostdata_t; ++ ++#define PXA_MMC_STATUS( ctrlr ) (((pxa_mmc_hostdata_t)ctrlr->host_data)->mmc_stat) ++#define PXA_MMC_RESPONSE( ctrlr, idx ) ((((pxa_mmc_hostdata_t)ctrlr->host_data)->mmc_res)[idx]) ++#define PXA_MMC_CLKRT( ctrlr ) (((pxa_mmc_hostdata_t)ctrlr->host_data)->clkrt) ++ ++#define SAVED_MMC_CLKRT (hostdata->saved_mmc_clkrt) ++#define SAVED_MMC_RESTO (hostdata->saved_mmc_resto) ++#define SAVED_MMC_SPI (hostdata->saved_mmc_spi) ++#define SAVED_DRCMRRXMMC (hostdata->saved_drcmrrxmmc ) ++#define SAVED_DRCMRTXMMC (hostdata->saved_drcmrtxmmc ) ++ ++static inline int pxa_mmc_clkrt( int speed ) ++{ ++ return MMC_CLKRT_20MHZ; /* TODO */ ++} ++ ++/* PXA MMC controller specific card data */ ++typedef struct _pxa_mmc_card_data_rec { ++ pxa_mmc_clkrt_t clkrt; /* clock rate to be set for the card */ ++} pxa_mmc_card_data_rec_t, *pxa_mmc_card_data_t; ++ ++#ifdef CONFIG_MMC_DEBUG ++#undef MMC_DUMP_R1 ++#undef MMC_DUMP_R2 ++#undef MMC_DUMP_R3 ++#define MMC_DUMP_R2( ctrlr ) MMC_DEBUG( MMC_DEBUG_LEVEL3, \ ++"R2 response: %02x %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", \ ++PXA_MMC_RESPONSE( ctrlr, 15 ), \ ++PXA_MMC_RESPONSE( ctrlr, 14 ), \ ++PXA_MMC_RESPONSE( ctrlr, 13 ), \ ++PXA_MMC_RESPONSE( ctrlr, 12 ), \ ++PXA_MMC_RESPONSE( ctrlr, 11 ), \ ++PXA_MMC_RESPONSE( ctrlr, 10 ), \ ++PXA_MMC_RESPONSE( ctrlr, 9 ), \ ++PXA_MMC_RESPONSE( ctrlr, 8 ), \ ++PXA_MMC_RESPONSE( ctrlr, 7 ), \ ++PXA_MMC_RESPONSE( ctrlr, 6 ), \ ++PXA_MMC_RESPONSE( ctrlr, 5 ), \ ++PXA_MMC_RESPONSE( ctrlr, 4 ), \ ++PXA_MMC_RESPONSE( ctrlr, 3 ), \ ++PXA_MMC_RESPONSE( ctrlr, 2 ), \ ++PXA_MMC_RESPONSE( ctrlr, 1 ), \ ++PXA_MMC_RESPONSE( ctrlr, 0 ) ); ++#define MMC_DUMP_R1( ctrlr ) MMC_DEBUG( MMC_DEBUG_LEVEL3, \ ++"R1(b) response: %02x %02x%02x%02x%02x\n", \ ++PXA_MMC_RESPONSE( ctrlr, 5 ), \ ++PXA_MMC_RESPONSE( ctrlr, 4 ), \ ++PXA_MMC_RESPONSE( ctrlr, 3 ), \ ++PXA_MMC_RESPONSE( ctrlr, 2 ), \ ++PXA_MMC_RESPONSE( ctrlr, 1 ) ); ++#define MMC_DUMP_R3( ctrlr ) MMC_DEBUG( MMC_DEBUG_LEVEL3, \ ++"R3 response: %02x %02x%02x%02x%02x\n", \ ++PXA_MMC_RESPONSE( ctrlr, 5 ), \ ++PXA_MMC_RESPONSE( ctrlr, 4 ), \ ++PXA_MMC_RESPONSE( ctrlr, 3 ), \ ++PXA_MMC_RESPONSE( ctrlr, 2 ), \ ++PXA_MMC_RESPONSE( ctrlr, 1 ) ); ++ ++#endif ++#endif /* __MMC_PXA_P_H__ */ +--- /dev/null ++++ linux-2.4.27/drivers/mmc/mmc_test.c +@@ -0,0 +1,538 @@ ++/* ++ * linux/drivers/mmc/mmc_test.c ++ * ++ * Author: Vladimir Shebordaev ++ * Copyright: MontaVista Software Inc. ++ * ++ * $Id: mmc_test.c,v 0.4 2002/08/01 12:26:40 ted Exp ted $ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/version.h> ++#include <linux/config.h> ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/errno.h> ++ ++#include <linux/fs.h> ++#ifdef CONFIG_DEVFS_FS ++#include <linux/devfs_fs_kernel.h> ++#endif ++ ++#include <asm/uaccess.h> ++ ++#include <mmc/types.h> ++#include <mmc/mmc.h> ++#include <mmc/ioctl.h> ++ ++#include "types.h" ++#include "mmc.h" ++ ++typedef struct _mmc_test_device_rec mmc_test_device_rec_t; ++typedef struct _mmc_test_device_rec *mmc_test_device_t; ++ ++struct _mmc_test_device_rec { ++ mmc_card_t card; ++ mmc_transfer_mode_t transfer_mode; ++ int usage; ++#ifdef CONFIG_DEVFS_FS ++ devfs_handle_t devfs_handle; ++#endif ++}; ++ ++/* MMC device table */ ++static mmc_test_device_rec_t mmc_test_device[MMC_CONTROLLERS_MAX][MMC_CARDS_MAX]; ++static DECLARE_MUTEX(mmc_test_device_mutex); ++ ++static inline mmc_test_device_t __mmc_test_get_device( kdev_t rdev ) ++{ ++ mmc_test_device_t ret = NULL; ++ u8 minor = MINOR( rdev ); ++ int host_no, card_no; ++ ++ host_no = minor >> MMC_MINOR_HOST_SHIFT; ++ if ( host_no >= MMC_CONTROLLERS_MAX ) ++ goto error; ++ ++ card_no = minor & MMC_MINOR_CARD_MASK; ++ if ( card_no >= MMC_CARDS_MAX ) ++ goto error; ++ ++ ret = &mmc_test_device[host_no][card_no]; ++ if ( !ret->card ) { ++ ret->card = mmc_get_card( host_no, card_no ); ++ if ( !ret->card ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "failed to get card: host=%d, card=%d\n", host_no, card_no ); ++ ret = NULL; ++ goto error; ++ } ++ ++ } ++ ++ret->usage; ++ ++error: ++ return ret; ++} ++ ++static inline void __mmc_test_put_device( mmc_test_device_t dev ) ++{ ++ mmc_put_card( dev->card ); ++ --dev->usage; ++} ++ ++static inline mmc_test_device_t mmc_test_get_device( kdev_t kdev ) ++{ ++ mmc_test_device_t ret = NULL; ++ ++ down( &mmc_test_device_mutex ); ++ ret = __mmc_test_get_device( kdev ); ++ up( &mmc_test_device_mutex ); ++ ++ return ret; ++} ++ ++static inline void mmc_test_put_device( mmc_test_device_t dev ) ++{ ++ if ( dev ) { ++ down( &mmc_test_device_mutex ); ++ __mmc_test_put_device( dev ); ++ if ( !dev->usage ) { ++ if ( dev->card ) { ++ if ( dev->card->usage ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, ++ "broken card reference\n" ); ++ } ++ memset( dev, 0, sizeof( mmc_test_device_rec_t ) ); ++ } ++ } ++ up( &mmc_test_device_mutex ); ++ } ++} ++ ++static inline int mmc_test_set_transfer_mode( mmc_test_device_t dev, mmc_transfer_mode_t mode ) ++{ ++ int ret = -1; ++ ++ if ( dev ) { ++ down( &mmc_test_device_mutex ); ++ dev->transfer_mode = mode; ++ ret = 0; ++ up( &mmc_test_device_mutex ); ++ } ++ return ret; ++} ++ ++static inline mmc_transfer_mode_t mmc_test_get_transfer_mode( mmc_test_device_t dev ) ++{ ++ mmc_transfer_mode_t ret = MMC_TRANSFER_MODE_UNDEFINED; ++ ++ if ( dev ) { ++ down( &mmc_test_device_mutex ); ++ ret = dev->transfer_mode; ++ up( &mmc_test_device_mutex ); ++ } ++ return ret; ++} ++ ++static int mmc_test_open( struct inode *inode, struct file *file ) ++{ ++ int ret = -ENODEV; ++ mmc_test_device_t dev = NULL; ++ ++ MOD_INC_USE_COUNT; ++ ++ __ENTER0( ); ++ dev = mmc_test_get_device( inode->i_rdev ); ++ if ( !dev || !dev->card ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "failed to acquire device\n" ); ++ goto error; ++ } ++ ++ if ( dev->card->usage > 1 ) { ++ ret = -EBUSY; ++ goto error; ++ } ++ ++ dev->transfer_mode = MMC_TEST_TRANSFER_MODE_DEFAULT; /* FIXME: should check card CCC */ ++ file->private_data = dev; ++ ++ __LEAVE0( ); ++ return 0; ++error: ++ MOD_DEC_USE_COUNT; ++ mmc_test_put_device( dev ); ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++static int mmc_test_release( struct inode *inode, struct file *file ) ++{ ++ int ret = -ENODEV; ++ mmc_test_device_t dev = (mmc_test_device_t)file->private_data; ++ ++ if ( !dev ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "file->private_data == NULL\n" ); ++ goto error; ++ } ++ ++ __ENTER( "host=%d, card=%d", dev->card->ctrlr->slot, dev->card->slot ); ++ ++ file->private_data = NULL; ++ ++ mmc_test_put_device( dev ); ++ MOD_DEC_USE_COUNT; ++ ++ ret = 0; ++error: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++static ssize_t mmc_test_read( struct file *file, char *buf, size_t size, loff_t *ppos ) ++{ ++ ssize_t ret = -ENODEV; ++ ssize_t retsize = 0; ++ mmc_test_device_t dev = (mmc_test_device_t)file->private_data; ++ ++ __ENTER( "host=%d, card=%d, size=%d", dev->card->ctrlr->slot, dev->card->slot, size ); ++ ++ if ( !dev ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "file->private_data == NULL\n" ); ++ goto error; ++ } ++ ++ switch ( dev->transfer_mode ) { ++ char *mbuf; ++ ++ case MMC_TRANSFER_MODE_BLOCK_SINGLE: ++ mbuf = kmalloc( 512, GFP_ATOMIC ); /* FIXME: actual read_bl_len or ctrlr->block_size_max whichever is less ), GFP_KERNEL */ ++ if ( !mbuf ) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ while( size > 0 ) { ++ int lsize = (size > 512) ? 512 : size; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL4, ++ "before mmc_read mbuf=0x%x " ++ "lsize=%d ppos=0x%x *ppos=%d\n", ++ mbuf, lsize, ppos, *ppos ); ++ ret = mmc_read( dev->card, ++ MMC_TRANSFER_MODE_BLOCK_SINGLE, ++ mbuf, lsize, ppos ); ++ if ( ret <= 0 ) ++ break; ++ ++ /* Copy to user */ ++ if ( copy_to_user( buf, mbuf, ret ) ) { ++ ret = -EFAULT; ++ break; ++ } ++ retsize += ret; ++ buf += ret; ++ size -= ret; ++ } ++ ++ if ( retsize > 0 ) ++ ret = retsize; ++ kfree(mbuf); ++ break; ++ ++ case MMC_TRANSFER_MODE_BLOCK_MULTIPLE: ++ mbuf = kmalloc( 1024, GFP_ATOMIC ); /* FIXME */ ++ if ( !mbuf ) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ while( size > 0 ) { ++ int lsize = (size > 1024) ? 1024 : size; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL4, ++ "before mmc_read mbuf=0x%x " ++ "lsize=%d ppos=0x%x *ppos=%d\n", ++ mbuf, lsize, ppos, *ppos ); ++ ret = mmc_read( dev->card, ++ MMC_TRANSFER_MODE_BLOCK_MULTIPLE, ++ mbuf, lsize, ppos ); ++ if ( ret <= 0 ) ++ break; ++ ++ /* Copy to user */ ++ if ( copy_to_user( buf, mbuf, ret ) ) { ++ ret = -EFAULT; ++ break; ++ } ++ retsize += ret; ++ buf += ret; ++ size -= ret; ++ } ++ ++ if ( retsize > 0 ) ++ ret = retsize; ++ kfree(mbuf); ++ break; ++ ++ case MMC_TRANSFER_MODE_STREAM: ++ ret = mmc_read( dev->card, dev->transfer_mode, ++ buf, size, ppos ); ++ break; ++ ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "invalid transfer mode\n" ); ++ } ++error: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++static ssize_t mmc_test_write( struct file *file, const char *buf, size_t size, loff_t *ppos ) ++{ ++ ssize_t ret = -ENODEV; ++ mmc_test_device_t dev = (mmc_test_device_t)file->private_data; ++ int retsize=0; ++ ++ __ENTER( "host=%d, card=%d, size=%d", dev->card->ctrlr->slot, dev->card->slot, size ); ++ ++ if ( !dev ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "file->private_data == NULL\n" ); ++ goto error; ++ } ++ ++ switch ( dev->transfer_mode ) { ++ char *mbuf; ++ ++ case MMC_TRANSFER_MODE_BLOCK_SINGLE: ++ mbuf = kmalloc( 512, GFP_ATOMIC ); /* FIXME: actual write_bl_len or ctrlr->block_size_max whichever is less, GFP_KERNEL */ ++ if ( !mbuf ) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ while ( size > 0 ) { ++ int lsize = ( size > 512 ) ? 512 : size; ++ ++ /* Copy from user */ ++ if ( copy_from_user( mbuf, buf, lsize ) ) { ++ ret = -EFAULT; ++ break; ++ } ++ ++ ret = mmc_write( dev->card, ++ MMC_TRANSFER_MODE_BLOCK_SINGLE, ++ mbuf, lsize, ppos ); ++ if( ret <= 0 ) ++ break; ++ ++ retsize += ret; ++ buf += ret; ++ size -= ret; ++ } ++ ++ if ( retsize > 0 ) ++ ret = retsize; ++ ++ kfree( mbuf ); ++ break; ++ ++ case MMC_TRANSFER_MODE_BLOCK_MULTIPLE: ++ mbuf = kmalloc( 1024, GFP_ATOMIC ); /* FIXME */ ++ if ( !mbuf ) { ++ ret = -ENOMEM; ++ goto error; ++ } ++ ++ while( size > 0 ) { ++ int lsize = (size > 1024) ? 1024 : size; ++ ++ MMC_DEBUG( MMC_DEBUG_LEVEL4, ++ "before mmc_read mbuf=0x%x " ++ "lsize=%d ppos=0x%x *ppos=%d\n", ++ mbuf, lsize, ppos, *ppos ); ++ ret = mmc_write( dev->card, ++ MMC_TRANSFER_MODE_BLOCK_MULTIPLE, ++ mbuf, lsize, ppos ); ++ if ( ret <= 0 ) ++ break; ++ ++ /* Copy to user */ ++ if ( copy_to_user( (char *)buf, mbuf, ret ) ) { ++ ret = -EFAULT; ++ break; ++ } ++ retsize += ret; ++ buf += ret; ++ size -= ret; ++ } ++ ++ if ( retsize > 0 ) ++ ret = retsize; ++ kfree(mbuf); ++ break; ++ case MMC_TRANSFER_MODE_STREAM: ++ ret = mmc_write( dev->card, dev->transfer_mode, ++ buf, size, ppos ); ++ break; ++ ++ default: ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "invalid transfer mode\n" ); ++ } ++error: ++ __LEAVE( "ret=%d", ret ); ++ return ret; ++} ++ ++static loff_t mmc_test_llseek( struct file *file, loff_t offset, int origin ) ++{ ++ loff_t ret = -ESPIPE; ++ mmc_test_device_t dev = (mmc_test_device_t)file->private_data; ++ mmc_card_t card; ++ ++ if ( !dev ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "file->private_data == NULL\n" ); ++ ret = -ENODEV; ++ goto error; ++ } ++ ++ __ENTER( "host=%d, card=%d, off=%ld, orig=%d", dev->card->ctrlr->slot, dev->card->slot, (long)offset, origin ); ++ ++ card = dev->card; ++ ++ switch ( origin ) { ++ case SEEK_CUR: ++ file->f_pos += offset; ++ break; ++ ++ case SEEK_END: ++ file->f_pos = card->info.capacity + offset; ++ break; ++ ++ case SEEK_SET: ++ file->f_pos = offset; ++ break; ++ ++ default: ++ ret = -EINVAL; ++ goto error; ++ } ++ ++ ret = file->f_pos; ++error: ++ __LEAVE( "ret=%ld", (long)ret ); ++ return ret; ++} ++ ++static int mmc_test_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg ) ++{ ++ int ret = -ENODEV; ++ mmc_test_device_t dev = (mmc_test_device_t)file->private_data; ++ ++ if ( !dev ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "file->private_data == NULL\n" ); ++ goto error; ++ } ++ ++ switch ( cmd ) { ++ case IOCMMCSTRNSMODE: ++ if ( get_user( ret, (int *)arg ) ) { ++ ret = -EFAULT; ++ goto error; ++ } ++ ret = mmc_test_set_transfer_mode( dev, ret ); ++ break; ++ ++ case IOCMMCGTRNSMODE: ++ ret = mmc_test_get_transfer_mode( dev ); ++ if ( put_user( ret, (int *)arg ) ) ++ ret = -EFAULT; ++ break; ++ ++ default: ++ ret = mmc_ioctl( dev->card, cmd, arg ); ++ } ++ ++error: ++ return ret; ++} ++ ++struct file_operations mmc_test_fops = { ++ owner: THIS_MODULE, ++ open: mmc_test_open, ++ release: mmc_test_release, ++ read: mmc_test_read, ++ write: mmc_test_write, ++ ioctl: mmc_test_ioctl, ++ llseek: mmc_test_llseek ++}; ++ ++#ifdef CONFIG_DEVFS_FS ++static int mmc_test_add_card( mmc_card_t card ) /* TODO */ ++{ ++ int ret = -1; ++ __ENTER( "host=%d, card=%d", card->ctrlr->slot, card->slot ); ++/* TODO: make kdev; register with devfs */ ++ __LEAVE0( ); ++ return ret; ++} ++ ++static int mmc_test_remove_card( mmc_card_t card ) /* TODO */ ++{ ++ int ret = -1; ++ __ENTER( "host=%d, card=%d", card->ctrlr->slot, card->slot ); ++/* TODO: make kdev; unregister with devfs */ ++ __LEAVE0( ); ++ return ret; ++} ++ ++static mmc_notifier_rec_t mmc_test_notifier = { ++ add: mmc_test_add_card, ++ remove: mmc_test_remove_card ++}; ++#endif /* CONFIG_DEVFS_FS */ ++ ++static int __init mmc_test_module_init( void ) ++{ ++ int ret = -ENODEV; ++ ++#ifdef CONFIG_DEVFS_FS ++ if ( !mmc_register( MMC_REG_TYPE_USER, &mmc_test_notifier, 0 ) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, "failed to register with MMC core\n" ); ++ goto error; ++ } ++#else ++ mmc_register( MMC_REG_TYPE_USER, NULL, 0 ); ++ if ( register_chrdev( MMC_TEST_MAJOR, "mmc_test", &mmc_test_fops ) ) { ++ MMC_DEBUG( MMC_DEBUG_LEVEL0, ++ "failed to request device major number\n" ); ++ mmc_unregister( MMC_REG_TYPE_USER, NULL ); ++ goto error; ++ } ++#endif ++ ++ memset( mmc_test_device, 0, sizeof( mmc_test_device ) ); ++ ++ ret = 0; ++error: ++ return ret; ++} ++ ++static void __exit mmc_test_module_cleanup( void ) ++{ ++#ifdef CONFIG_DEVFS_FS ++ mmc_unregister( MMC_REG_TYPE_USER, &mmc_test_notifier ); ++#else ++ mmc_unregister( MMC_REG_TYPE_USER, NULL ); ++ unregister_chrdev( MMC_TEST_MAJOR, "mmc_test" ); ++#endif ++} ++ ++EXPORT_NO_SYMBOLS; ++ ++module_init( mmc_test_module_init ); ++module_exit( mmc_test_module_cleanup ); ++ ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ linux-2.4.27/drivers/mmc/pm_test.c +@@ -0,0 +1,29 @@ ++/* Power Managment Test Module. RTSoft Co. 2002 */ ++ ++/* The necessary header files */ ++ ++/* Standard in kernel modules */ ++#include <linux/kernel.h> /* We're doing kernel work */ ++#include <linux/module.h> /* Specifically, a module */ ++#define CONFIG_PM ++#include <linux/pm.h> ++ ++ ++static int pmdata = -1; ++ ++/* Initialize the module - register the proc file */ ++ ++int init_module() ++{ ++ pm_send_all(PM_SUSPEND,&pmdata); ++ return(0); ++} ++ ++ ++/* Cleanup - unregister our file from /proc */ ++void cleanup_module() ++{ ++ pm_send_all(PM_RESUME,NULL); ++} ++ ++MODULE_LICENSE( "GPL" ); +--- /dev/null ++++ linux-2.4.27/drivers/mmc/types.h +@@ -0,0 +1,59 @@ ++/* ++ * linux/drivers/mmc/types.h ++ * ++ * Author: Vladimir Shebordaev ++ * Copyright: MontaVista Software Inc. ++ * ++ * $Id: types.h,v 0.5 2002/08/13 17:34:02 ted Exp ted $ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef __MMC_TYPES_P_H__ ++#define __MMC_TYPES_P_H__ ++ ++#ifdef __KERNEL__ ++#include <linux/kdev_t.h> ++ ++typedef enum _mmc_reg_type mmc_reg_type_t; ++typedef enum _mmc_response mmc_response_fmt_t; ++ ++/* MMC card private description */ ++typedef struct _mmc_card_rec mmc_card_rec_t; ++typedef struct _mmc_card_rec *mmc_card_t; ++typedef enum _mmc_dir mmc_dir_t; ++typedef enum _mmc_buftype mmc_buftype_t; ++ ++/* notifier declarations */ ++typedef struct _mmc_notifier_rec mmc_notifier_rec_t; ++typedef struct _mmc_notifier_rec *mmc_notifier_t; ++ ++typedef int (*mmc_notifier_fn_t) ( mmc_card_t ); ++ ++/* MMC card stack */ ++typedef struct _mmc_card_stack_rec mmc_card_stack_rec_t; ++typedef struct _mmc_card_stack_rec *mmc_card_stack_t; ++ ++typedef struct _mmc_data_transfer_req_rec mmc_data_transfer_req_rec_t; ++typedef struct _mmc_data_transfer_req_rec *mmc_data_transfer_req_t; ++ ++/* MMC controller */ ++typedef struct _mmc_controller_tmpl_rec mmc_controller_tmpl_rec_t; ++typedef struct _mmc_controller_tmpl_rec *mmc_controller_tmpl_t; ++ ++typedef enum _mmc_controller_state mmc_controller_state_t; ++typedef struct _mmc_controller_rec mmc_controller_rec_t; ++typedef struct _mmc_controller_rec *mmc_controller_t; ++ ++/* various kernel types */ ++typedef struct semaphore semaphore_t; ++typedef struct rw_semaphore rwsemaphore_t; ++typedef struct proc_dir_entry proc_dir_entry_rec_t; ++typedef struct proc_dir_entry *proc_dir_entry_t; ++typedef struct gendisk gendisk_rec_t; ++typedef struct gendisk *gendisk_t; ++#endif /* __KERNEL__ */ ++ ++#endif /* __MMC_TYPES_P_H__ */ ++ +--- linux-2.4.27/drivers/mtd/maps/Config.in~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/mtd/maps/Config.in +@@ -75,6 +75,7 @@ + fi + + if [ "$CONFIG_ARM" = "y" ]; then ++ dep_tristate ' CFI Flash device mapped on Lubbock board' CONFIG_MTD_LUBBOCK $CONFIG_MTD_CFI $CONFIG_ARCH_LUBBOCK $CONFIG_MTD_PARTITIONS + dep_tristate ' CFI Flash device mapped on Nora' CONFIG_MTD_NORA $CONFIG_MTD_CFI + dep_tristate ' CFI Flash device mapped on ARM Integrator/P720T' CONFIG_MTD_ARM_INTEGRATOR $CONFIG_MTD_CFI + dep_tristate ' Cirrus CDB89712 evaluation board mappings' CONFIG_MTD_CDB89712 $CONFIG_MTD_CFI $CONFIG_ARCH_CDB89712 +--- linux-2.4.27/drivers/mtd/maps/Makefile~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/mtd/maps/Makefile +@@ -15,6 +15,9 @@ + obj-$(CONFIG_MTD_ELAN_104NC) += elan-104nc.o + obj-$(CONFIG_MTD_EPXA) += epxa-flash.o + obj-$(CONFIG_MTD_IQ80310) += iq80310.o ++obj-$(CONFIG_MTD_LUBBOCK) += lubbock.o ++obj-$(CONFIG_MTD_PXA_CERF) += pxa_cerf.o ++obj-$(CONFIG_MTD_TRIZEPS2) += trizeps2.o + obj-$(CONFIG_MTD_L440GX) += l440gx.o + obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o + obj-$(CONFIG_MTD_ICH2ROM) += ich2rom.o +--- /dev/null ++++ linux-2.4.27/drivers/mtd/maps/lubbock.c +@@ -0,0 +1,168 @@ ++/* ++ * $Id: ++ * ++ * Map driver for the Lubbock developer platform. ++ * ++ * Author: Nicolas Pitre ++ * Copyright: (C) 2001 MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <asm/io.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/map.h> ++#include <linux/mtd/partitions.h> ++ ++ ++#define WINDOW_ADDR 0 ++//#define WINDOW_ADDR 0x04000000 ++#define WINDOW_SIZE 64*1024*1024 ++ ++static __u8 lubbock_read8(struct map_info *map, unsigned long ofs) ++{ ++ return *(__u8 *)(map->map_priv_1 + ofs); ++} ++ ++static __u16 lubbock_read16(struct map_info *map, unsigned long ofs) ++{ ++ return *(__u16 *)(map->map_priv_1 + ofs); ++} ++ ++static __u32 lubbock_read32(struct map_info *map, unsigned long ofs) ++{ ++ return *(__u32 *)(map->map_priv_1 + ofs); ++} ++ ++static void lubbock_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) ++{ ++ memcpy(to, (void *)(map->map_priv_1 + from), len); ++} ++ ++static void lubbock_write8(struct map_info *map, __u8 d, unsigned long adr) ++{ ++ *(__u8 *)(map->map_priv_1 + adr) = d; ++} ++ ++static void lubbock_write16(struct map_info *map, __u16 d, unsigned long adr) ++{ ++ *(__u16 *)(map->map_priv_1 + adr) = d; ++} ++ ++static void lubbock_write32(struct map_info *map, __u32 d, unsigned long adr) ++{ ++ *(__u32 *)(map->map_priv_1 + adr) = d; ++} ++ ++static void lubbock_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) ++{ ++ memcpy((void *)(map->map_priv_1 + to), from, len); ++} ++ ++static struct map_info lubbock_map = { ++ name: "Lubbock flash", ++ size: WINDOW_SIZE, ++ read8: lubbock_read8, ++ read16: lubbock_read16, ++ read32: lubbock_read32, ++ copy_from: lubbock_copy_from, ++ write8: lubbock_write8, ++ write16: lubbock_write16, ++ write32: lubbock_write32, ++ copy_to: lubbock_copy_to ++}; ++ ++static struct mtd_partition lubbock_partitions[] = { ++ { ++ name: "Bootloader", ++ size: 0x00040000, ++ offset: 0, ++ mask_flags: MTD_WRITEABLE /* force read-only */ ++ },{ ++ name: "Kernel", ++ size: 0x00100000, ++ offset: 0x00040000, ++ },{ ++ name: "Filesystem", ++ size: MTDPART_SIZ_FULL, ++ offset: 0x00140000 ++ } ++}; ++ ++#define NB_OF(x) (sizeof(x)/sizeof(x[0])) ++ ++static struct mtd_info *mymtd; ++static struct mtd_partition *parsed_parts; ++ ++extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); ++ ++static int __init init_lubbock(void) ++{ ++ struct mtd_partition *parts; ++ int nb_parts = 0; ++ int parsed_nr_parts = 0; ++ char *part_type = "static"; ++ ++ lubbock_map.buswidth = (BOOT_DEF & 1) ? 2 : 4; ++ printk( "Probing Lubbock flash at physical address 0x%08x (%d-bit buswidth)\n", ++ WINDOW_ADDR, lubbock_map.buswidth * 8 ); ++ lubbock_map.map_priv_1 = (unsigned long)__ioremap(WINDOW_ADDR, WINDOW_SIZE, 0); ++ if (!lubbock_map.map_priv_1) { ++ printk("Failed to ioremap\n"); ++ return -EIO; ++ } ++ mymtd = do_map_probe("cfi_probe", &lubbock_map); ++ if (!mymtd) { ++ iounmap((void *)lubbock_map.map_priv_1); ++ return -ENXIO; ++ } ++ mymtd->module = THIS_MODULE; ++ ++#ifdef CONFIG_MTD_REDBOOT_PARTS ++ if (parsed_nr_parts == 0) { ++ int ret = parse_redboot_partitions(mymtd, &parsed_parts); ++ ++ if (ret > 0) { ++ part_type = "RedBoot"; ++ parsed_nr_parts = ret; ++ } ++ } ++#endif ++ ++ if (parsed_nr_parts > 0) { ++ parts = parsed_parts; ++ nb_parts = parsed_nr_parts; ++ } else { ++ parts = lubbock_partitions; ++ nb_parts = NB_OF(lubbock_partitions); ++ } ++ if (nb_parts) { ++ printk(KERN_NOTICE "Using %s partition definition\n", part_type); ++ add_mtd_partitions(mymtd, parts, nb_parts); ++ } else { ++ add_mtd_device(mymtd); ++ } ++ return 0; ++} ++ ++static void __exit cleanup_lubbock(void) ++{ ++ if (mymtd) { ++ del_mtd_partitions(mymtd); ++ map_destroy(mymtd); ++ if (parsed_parts) ++ kfree(parsed_parts); ++ } ++ if (lubbock_map.map_priv_1) ++ iounmap((void *)lubbock_map.map_priv_1); ++ return 0; ++} ++ ++module_init(init_lubbock); ++module_exit(cleanup_lubbock); ++ +--- /dev/null ++++ linux-2.4.27/drivers/mtd/maps/pxa_cerf.c +@@ -0,0 +1,172 @@ ++/* ++ * Map driver for the PXA Cerf. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <asm/io.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/map.h> ++#include <linux/mtd/partitions.h> ++ ++ ++#define WINDOW_ADDR 0 ++#if defined (CONFIG_PXA_CERF_FLASH_64MB) ++#define WINDOW_SIZE 64*1024*1024 ++#elif defined (CONFIG_PXA_CERF_FLASH_32MB) ++#define WINDOW_SIZE 32*1024*1024 ++#elif defined (CONFIG_PXA_CERF_FLASH_16MB) ++#define WINDOW_SIZE 16*1024*1024 ++#endif ++#define BUSWIDTH 4 ++ ++static __u8 pxa_cerf_read8(struct map_info *map, unsigned long ofs) ++{ ++ return *(__u8 *)(map->map_priv_1 + ofs); ++} ++ ++static __u16 pxa_cerf_read16(struct map_info *map, unsigned long ofs) ++{ ++ return *(__u16 *)(map->map_priv_1 + ofs); ++} ++ ++static __u32 pxa_cerf_read32(struct map_info *map, unsigned long ofs) ++{ ++ return *(__u32 *)(map->map_priv_1 + ofs); ++} ++ ++static void pxa_cerf_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) ++{ ++ memcpy(to, (void *)(map->map_priv_1 + from), len); ++} ++ ++static void pxa_cerf_write8(struct map_info *map, __u8 d, unsigned long adr) ++{ ++ *(__u8 *)(map->map_priv_1 + adr) = d; ++} ++ ++static void pxa_cerf_write16(struct map_info *map, __u16 d, unsigned long adr) ++{ ++ *(__u16 *)(map->map_priv_1 + adr) = d; ++} ++ ++static void pxa_cerf_write32(struct map_info *map, __u32 d, unsigned long adr) ++{ ++ *(__u32 *)(map->map_priv_1 + adr) = d; ++} ++ ++static void pxa_cerf_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) ++{ ++ memcpy((void *)(map->map_priv_1 + to), from, len); ++} ++ ++static struct map_info pxa_cerf_map = { ++ name: "PXA Cerf Flash", ++ size: WINDOW_SIZE, ++ buswidth: BUSWIDTH, ++ read8: pxa_cerf_read8, ++ read16: pxa_cerf_read16, ++ read32: pxa_cerf_read32, ++ copy_from: pxa_cerf_copy_from, ++ write8: pxa_cerf_write8, ++ write16: pxa_cerf_write16, ++ write32: pxa_cerf_write32, ++ copy_to: pxa_cerf_copy_to ++}; ++ ++static struct mtd_partition pxa_cerf_partitions[] = { ++ { ++ name: "Bootloader", ++ size: 0x00040000, ++ offset: 0, ++ mask_flags: MTD_WRITEABLE /* force read-only */ ++ },{ ++ name: "Partition Tables", ++ size: 0x00080000, ++ offset: 0x00040000, ++ },{ ++ name: "Kernel", ++ size: 0x00100000, ++ offset: 0x000C0000, ++ },{ ++ name: "Filesystem", ++ size: WINDOW_SIZE-0x001C0000, //MTDPART_SIZ_FULL, ++ offset: 0x001C0000 ++ } ++}; ++ ++#define NB_OF(x) (sizeof(x)/sizeof(x[0])) ++ ++static struct mtd_info *mymtd; ++static struct mtd_partition *parsed_parts; ++ ++extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); ++ ++static int __init init_pxa_cerf(void) ++{ ++ struct mtd_partition *parts; ++ int nb_parts = 0; ++ int parsed_nr_parts = 0; ++ char *part_type = "static"; ++ ++ printk("Probing PXA Cerf flash at physical address 0x%08x\n", WINDOW_ADDR); ++ pxa_cerf_map.map_priv_1 = (unsigned long)__ioremap(WINDOW_ADDR, WINDOW_SIZE, 0); ++ if (!pxa_cerf_map.map_priv_1) { ++ printk("Failed to ioremap\n"); ++ return -EIO; ++ } ++ mymtd = do_map_probe("cfi_probe", &pxa_cerf_map); ++ if (!mymtd) { ++ iounmap((void *)pxa_cerf_map.map_priv_1); ++ return -ENXIO; ++ } ++ mymtd->module = THIS_MODULE; ++ ++#ifdef CONFIG_MTD_REDBOOT_PARTS ++ if (parsed_nr_parts == 0) { ++ int ret = parse_redboot_partitions(mymtd, &parsed_parts); ++ ++ if (ret > 0) { ++ part_type = "RedBoot"; ++ parsed_nr_parts = ret; ++ } ++ } ++#endif ++ ++ if (parsed_nr_parts > 0) { ++ parts = parsed_parts; ++ nb_parts = parsed_nr_parts; ++ } else { ++ parts = pxa_cerf_partitions; ++ nb_parts = NB_OF(pxa_cerf_partitions); ++ } ++ if (nb_parts) { ++ printk(KERN_NOTICE "Using %s partition definition\n", part_type); ++ add_mtd_partitions(mymtd, parts, nb_parts); ++ } else { ++ add_mtd_device(mymtd); ++ } ++ return 0; ++} ++ ++static void __exit cleanup_pxa_cerf(void) ++{ ++ if (mymtd) { ++ del_mtd_partitions(mymtd); ++ map_destroy(mymtd); ++ if (parsed_parts) ++ kfree(parsed_parts); ++ } ++ if (pxa_cerf_map.map_priv_1) ++ iounmap((void *)pxa_cerf_map.map_priv_1); ++ return; ++} ++ ++module_init(init_pxa_cerf); ++module_exit(cleanup_pxa_cerf); ++ +--- /dev/null ++++ linux-2.4.27/drivers/mtd/maps/trizeps2.c +@@ -0,0 +1,172 @@ ++/* ++ * $Id: ++ * ++ * Map driver for the Trizeps-2 module. ++ * ++ * Author: Luc De Cock ++ * Copyright: (C) 2003 Teradyne DS, Ltd. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <asm/io.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/map.h> ++#include <linux/mtd/partitions.h> ++ ++ ++#define WINDOW_ADDR 0 ++#define WINDOW_SIZE 16*1024*1024 ++ ++static __u8 trizeps2_read8(struct map_info *map, unsigned long ofs) ++{ ++ return *(__u8 *)(map->map_priv_1 + ofs); ++} ++ ++static __u16 trizeps2_read16(struct map_info *map, unsigned long ofs) ++{ ++ return *(__u16 *)(map->map_priv_1 + ofs); ++} ++ ++static __u32 trizeps2_read32(struct map_info *map, unsigned long ofs) ++{ ++ return *(__u32 *)(map->map_priv_1 + ofs); ++} ++ ++static void trizeps2_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) ++{ ++ memcpy(to, (void *)(map->map_priv_1 + from), len); ++} ++ ++static void trizeps2_write8(struct map_info *map, __u8 d, unsigned long adr) ++{ ++ *(__u8 *)(map->map_priv_1 + adr) = d; ++} ++ ++static void trizeps2_write16(struct map_info *map, __u16 d, unsigned long adr) ++{ ++ *(__u16 *)(map->map_priv_1 + adr) = d; ++} ++ ++static void trizeps2_write32(struct map_info *map, __u32 d, unsigned long adr) ++{ ++ *(__u32 *)(map->map_priv_1 + adr) = d; ++} ++ ++static void trizeps2_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) ++{ ++ memcpy((void *)(map->map_priv_1 + to), from, len); ++} ++ ++static struct map_info trizeps2_map = { ++ name: "Trizeps-2 flash", ++ size: WINDOW_SIZE, ++ read8: trizeps2_read8, ++ read16: trizeps2_read16, ++ read32: trizeps2_read32, ++ copy_from: trizeps2_copy_from, ++ write8: trizeps2_write8, ++ write16: trizeps2_write16, ++ write32: trizeps2_write32, ++ copy_to: trizeps2_copy_to ++}; ++ ++static struct mtd_partition trizeps2_partitions[] = { ++ { ++ name: "Bootloader", ++ size: 0x00040000, ++ offset: 0, ++ mask_flags: MTD_WRITEABLE /* force read-only */ ++ },{ ++ name: "Bootloader (backup)", ++ size: 0x00040000, ++ offset: 0x00040000, ++ mask_flags: MTD_WRITEABLE /* force read-only */ ++ },{ ++ name: "Kernel", ++ size: 0x000C0000, ++ offset: 0x00080000, ++ },{ ++ name: "Filesystem", ++ size: MTDPART_SIZ_FULL, ++ offset: 0x00140000 ++ } ++}; ++ ++#define NB_OF(x) (sizeof(x)/sizeof(x[0])) ++ ++static struct mtd_info *mymtd; ++static struct mtd_partition *parsed_parts; ++ ++extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); ++ ++static int __init init_trizeps2(void) ++{ ++ struct mtd_partition *parts; ++ int nb_parts = 0; ++ int parsed_nr_parts = 0; ++ char *part_type = "static"; ++ ++ trizeps2_map.buswidth = (BOOT_DEF & 1) ? 2 : 4; ++ printk( "Probing Trizeps-2 flash at physical address 0x%08x (%d-bit buswidth)\n", ++ WINDOW_ADDR, trizeps2_map.buswidth * 8 ); ++ trizeps2_map.map_priv_1 = (unsigned long)__ioremap(WINDOW_ADDR, WINDOW_SIZE, 0); ++ if (!trizeps2_map.map_priv_1) { ++ printk("Failed to ioremap\n"); ++ return -EIO; ++ } ++ mymtd = do_map_probe("cfi_probe", &trizeps2_map); ++ if (!mymtd) { ++ iounmap((void *)trizeps2_map.map_priv_1); ++ return -ENXIO; ++ } ++ mymtd->module = THIS_MODULE; ++ ++#ifdef CONFIG_MTD_REDBOOT_PARTS ++ if (parsed_nr_parts == 0) { ++ int ret = parse_redboot_partitions(mymtd, &parsed_parts); ++ ++ if (ret > 0) { ++ part_type = "RedBoot"; ++ parsed_nr_parts = ret; ++ } ++ } ++#endif ++ ++ if (parsed_nr_parts > 0) { ++ parts = parsed_parts; ++ nb_parts = parsed_nr_parts; ++ } else { ++ parts = trizeps2_partitions; ++ nb_parts = NB_OF(trizeps2_partitions); ++ } ++ if (nb_parts) { ++ printk(KERN_NOTICE "Using %s partition definition\n", part_type); ++ add_mtd_partitions(mymtd, parts, nb_parts); ++ } else { ++ add_mtd_device(mymtd); ++ } ++ return 0; ++} ++ ++static void __exit cleanup_trizeps2(void) ++{ ++ if (mymtd) { ++ del_mtd_partitions(mymtd); ++ map_destroy(mymtd); ++ if (parsed_parts) ++ kfree(parsed_parts); ++ } ++ if (trizeps2_map.map_priv_1) ++ iounmap((void *)trizeps2_map.map_priv_1); ++ return 0; ++} ++ ++module_init(init_trizeps2); ++module_exit(cleanup_trizeps2); ++ +--- linux-2.4.27/drivers/net/Config.in~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/net/Config.in +@@ -125,6 +125,7 @@ + dep_tristate ' SMC Ultra support' CONFIG_ULTRA $CONFIG_ISA + dep_tristate ' SMC Ultra32 EISA support' CONFIG_ULTRA32 $CONFIG_EISA + dep_tristate ' SMC 9194 support' CONFIG_SMC9194 $CONFIG_ISA ++ tristate ' SMC 91C9x/91C1xx support' CONFIG_SMC91X + fi + bool ' Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL + if [ "$CONFIG_NET_VENDOR_RACAL" = "y" ]; then +--- linux-2.4.27/drivers/net/Makefile~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/net/Makefile +@@ -137,6 +137,7 @@ + obj-$(CONFIG_SK_G16) += sk_g16.o + obj-$(CONFIG_HP100) += hp100.o + obj-$(CONFIG_SMC9194) += smc9194.o ++obj-$(CONFIG_SMC91X) += smc91x.o + obj-$(CONFIG_ARM_AM79C961A) += am79c961a.o + obj-$(CONFIG_ARM_ETHERH) += 8390.o + obj-$(CONFIG_WD80x3) += wd.o 8390.o +--- linux-2.4.27/drivers/net/cirrus.c~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/net/cirrus.c +@@ -67,6 +67,9 @@ + #elif CONFIG_ARCH_CDB89712 + # define CIRRUS_DEFAULT_IO ETHER_BASE + 0x300 + # define CIRRUS_DEFAULT_IRQ IRQ_EINT3 ++#elif CONFIG_ARCH_CSB226 ++# define CIRRUS_DEFAULT_IO 0xF8000000 ++# define CIRRUS_DEFAULT_IRQ IRQ_GPIO(14) + #else + # define CIRRUS_DEFAULT_IO 0 + # define CIRRUS_DEFAULT_IRQ 0 +--- linux-2.4.27/drivers/net/irda/Config.in~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/net/irda/Config.in +@@ -42,5 +42,7 @@ + if [ "$CONFIG_ARCH_SA1100" = "y" ]; then + dep_tristate 'SA1100 Internal IR' CONFIG_SA1100_FIR $CONFIG_IRDA $CONFIG_EXPERIMENTAL + fi +- ++if [ "$CONFIG_ARCH_PXA" = "y" ]; then ++ dep_tristate 'Intel PXA2xx Internal IR' CONFIG_PXA_FIR $CONFIG_IRDA $CONFIG_EXPERIMENTAL ++fi + endmenu +--- linux-2.4.27/drivers/net/irda/Makefile~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/net/irda/Makefile +@@ -16,6 +16,7 @@ + obj-$(CONFIG_USB_IRDA) += irda-usb.o + obj-$(CONFIG_NSC_FIR) += nsc-ircc.o + obj-$(CONFIG_WINBOND_FIR) += w83977af_ir.o ++obj-$(CONFIG_PXA_FIR) += pxa_ir.o + obj-$(CONFIG_SA1100_FIR) += sa1100_ir.o + obj-$(CONFIG_TOSHIBA_OLD) += toshoboe.o + obj-$(CONFIG_TOSHIBA_FIR) += donauboe.o +--- /dev/null ++++ linux-2.4.27/drivers/net/irda/pxa_ir.c +@@ -0,0 +1,1545 @@ ++/* ++ * linux/drivers/net/irda/pxa_ir.c ++ * ++ * Author: ++ * Alexey Lugovskoy RTSoft. ++ * lugovskoy@rtsoft.msk.ru ++ * ++ * Dmitrij Frasenyak RTSoft. ++ * sed@mipt.sw.ru ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Infra-red SIR and FIR driver for the PXA 210/250 embedded microprocessors ++ * Based on linux/drivers/net/irda/sa1100_ir.c ++ * ++ */ ++ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/init.h> ++#include <linux/errno.h> ++#include <linux/netdevice.h> ++#include <linux/slab.h> ++#include <linux/rtnetlink.h> ++#include <linux/interrupt.h> ++#include <linux/delay.h> ++#include <linux/ioport.h> ++#include <linux/delay.h> ++ ++#include <linux/pm.h> ++ ++#include <net/irda/irda.h> ++#include <net/irda/irmod.h> ++#include <net/irda/wrapper.h> ++#include <net/irda/irda_device.h> ++ ++#include <asm/irq.h> ++#include <asm/dma.h> ++#include <asm/hardware.h> ++#include <asm/mach-types.h> ++#include <asm/arch/lubbock.h> ++ ++ ++static int rx_count = 0; ++static int tx_count = 0; ++ ++/* ++ * Our netdevice. There is only ever one of these. ++ */ ++ ++static struct net_device *netdev; ++ ++struct pxa250_irda { ++ ++ unsigned char open; ++ ++ int speed; ++ int newspeed; ++ ++ struct sk_buff *txskb; ++ struct sk_buff *rxskb; ++ ++ ++ /* => FIR */ ++ unsigned int fir_irq; ++ int txdma_ch; ++ int rxdma_ch; ++ dma_addr_t txbuf_dma; ++ dma_addr_t rxbuf_dma; ++ void* txbuf_dma_virt; ++ void* rxbuf_dma_virt; ++ /* <= FIR*/ ++ struct net_device_stats stats; ++ struct irlap_cb *irlap; ++ struct pm_dev *pmdev; ++ struct qos_info qos; ++ ++ /* => SIR */ ++ iobuff_t tx_buff; ++ iobuff_t rx_buff; ++ /* <= SIR */ ++}; ++ ++#define IS_FIR(si) ((si)->speed >= 4000000) ++ ++#define HPSIR_MAX_RXLEN 2050 ++#define HPSIR_MAX_TXLEN 2050 ++#define TXBUFF_MAX_SIZE HPSIR_MAX_TXLEN ++#define SET_SIR_MODE STISR = STISR_RCVEIR | STISR_XMITIR | STISR_XMODE ++ ++/* ++ * If you want to disable debug information ++ * please uncomment line bellow ++ */ ++ ++#define PXA_FIR_DUMP_ENABLE ++#undef PXA_FIR_DUMP_ENABLE ++ ++ ++#define PXA_FIR_DEBUG_ENABLE ++#undef PXA_FIR_DEBUG_ENABLE ++ ++#define PXA_FIR_IRQ_DEBUG_ENABLE ++#undef PXA_FIR_IRQ_DEBUG_ENABLE ++ ++#ifdef PXA_FIR_DEBUG_ENABLE ++#define __ECHO_IN printk(KERN_ERR "%s: enter\n",__FUNCTION__); ++#define __ECHO_OUT printk(KERN_ERR "%s: exit\n",__FUNCTION__); ++#define DBG(args...) printk(KERN_ERR __FUNCTION__"():"args); ++#else ++#define __ECHO_IN ++#define __ECHO_OUT ++#define DBG(args...) ++#endif ++ ++#ifdef PXA_FIR_IRQ_DEBUG_ENABLE ++#define DBG_IRQ(args...) printk(KERN_ERR __FUNCTION__"():"args); ++#else ++#define DBG_IRQ(args...) ++#endif ++ ++ ++static int pxa250_irda_set_speed(struct net_device *dev,int speed); ++static void pxa250_start_rx_dma(struct net_device *dev); ++ ++ ++ ++/************************************************************************** ++ * Misc FIR/SIR functions * ++ **************************************************************************/ ++/* ++ * Allocate the receive buffer, unless it is already allocated. ++ */ ++ ++static int pxa250_irda_rx_alloc(struct pxa250_irda *si) ++{ ++ __ECHO_IN; ++ ++ if (si->rxskb) ++ return 0; ++ ++ si->rxskb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC); ++ ++ if (!si->rxskb) { ++ printk(KERN_ERR "pxa250_ir: out of memory for RX SKB\n"); ++ return -ENOMEM; ++ } ++ ++ /* ++ * Align any IP headers that may be contained ++ * within the frame. ++ */ ++ skb_reserve(si->rxskb, 1); ++ ++ __ECHO_OUT; ++ ++ return 0; ++} ++ ++ ++ ++/************************************************************************** ++ * FIR * ++ **************************************************************************/ ++ ++ ++ ++ ++static inline void pxa250_dma_stop(int ch) ++{ ++ __ECHO_IN; ++ ++ DCSR(ch) &= ~DCSR_RUN; ++ ++ __ECHO_OUT; ++ ++} ++ ++ ++static void pxa250_ficp_rx_start(void) ++{ ++ ICCR0 = 0; ++ ICCR2 = 1 << 2 | 0 << 3 ; ++ ICCR0 = ICCR0_ITR ; ++ ICCR0 |= ICCR0_RIE | ICCR0_RXE ; ++} ++ ++/* ++ * Change Alternative Function encoding ++ * Enable ICP unit ++ * Disabe STUART unit ++ * Enable IRQ unit clock; ++ * Configure direction of GPIO used by ICP ++ */ ++ ++ ++static void pxa250_do_fir_GPIO_config(void) ++{ ++ /* ++ * Modify GPIO 46 and 47 Alternate Function ++ */ ++ ++ __ECHO_IN; ++ ++ /*Switch AF*/ ++ set_GPIO_mode (GPIO46_ICPRXD_MD); ++ set_GPIO_mode (GPIO47_ICPTXD_MD); ++ ++ if (machine_is_lubbock()) ++ LUB_MISC_WR |= 1 << 4; ++ ++ /*init clock*/ ++ CKEN |= CKEN13_FICP; ++ ++ __ECHO_OUT; ++} ++ ++/* ++ * Low level hardware configuration and startup. ++ */ ++ ++static int pxa250_fir_irda_startup(struct pxa250_irda *si) ++{ ++ ++ __ECHO_IN; ++ ++ /* ++ * Disable STUART ++ */ ++ ++ STIER &= ~IER_UUE; ++ ++ /*Disable STUART FIFO */ ++ STFCR = 0; ++ ++ /* ++ * Do low level configuration for HW AF and clock ++ */ ++ pxa250_do_fir_GPIO_config(); ++ ++ __ECHO_OUT; ++ return 0; ++} ++ ++ ++/* ++ * Aieeeeee .. we should never get here :( ++ */ ++static void pxa250_irda_rxdma_irq(int ch,void *id, struct pt_regs *regs) ++{ ++ struct net_device *dev=id; ++ struct pxa250_irda *si=dev->priv; ++ u_int dcsr; ++ ++ ++ __ECHO_IN; ++ ++ /* ++ * Make sure that irq is our. ++ */ ++ ++ if ( ch != si->rxdma_ch ) ++ /*just*/ return; ++ ++ /* ++ * Check status ++ */ ++ dcsr = DCSR(ch); ++ ++ DBG("DCSR=%x\n",dcsr); ++ ++ if (dcsr & DCSR_STOPSTATE ) ++ { ++ DBG_IRQ("Chanel %d in stop state\n",ch); ++ } ++ ++ if (dcsr & DCSR_BUSERR ) ++ { ++ /* ++ * BUS Error we must restart reception ++ */ ++ ++ DBG("PXA IrDA: bus error interrupt on channel %d\n", ch); ++ DCSR(ch) |= DCSR_BUSERR; ++ } ++ ++ if (dcsr & DCSR_ENDINTR ) ++ { ++ DBG("PXA IrDA: Normal end of dma channel %d - packet to big\n", ch); ++ DCSR(ch) |= DCSR_ENDINTR; ++ } ++ ++ /* no mater what restart rx*/ ++ pxa250_start_rx_dma(dev); ++ ++ return ; ++ ++} ++ ++ ++static void pxa250_irda_txdma_irq(int ch, void *id , struct pt_regs *regs) ++{ ++ struct net_device *dev=id; ++ struct pxa250_irda *si=dev->priv; ++ struct sk_buff *skb = si->txskb; ++ u_int dcsr; ++ ++ ++ __ECHO_IN; ++ DBG_IRQ("transmit\n"); ++ ++ ++ /* ++ * Make sure that irq is our. ++ */ ++ ++ if ( ch != si->txdma_ch ) ++ /*just*/ return; ++ ++ ++ /* ++ * Check status ++ */ ++ dcsr = DCSR(ch); ++ ++ DBG("DCSR=%x",dcsr); ++ ++ if (dcsr & DCSR_STOPSTATE ) ++ { ++ DBG("Chanel %d in stop state\n",ch); ++ } ++ ++ if (dcsr & DCSR_BUSERR ) ++ { ++ DBG("PXA IrDA: bus error interrupt on channel %d\n", ch); ++ DCSR(ch) |= DCSR_BUSERR; ++ si->txskb = NULL; ++ } ++ ++ if (dcsr & DCSR_ENDINTR ) ++ { ++ DBG("PXA IrDA: Normal end of dma channel %d\n", ch); ++ DCSR(ch) |= DCSR_ENDINTR; ++ si->txskb = NULL; ++ } ++ ++ /* ++ * Account and free the packet. ++ */ ++ if (skb) ++ { ++ si->stats.tx_packets ++; ++ si->stats.tx_bytes += skb->len; ++ dev_kfree_skb_irq(skb); ++ } ++ ++ /*Disable transceiver and enable receiver*/ ++ ++ if (si->newspeed) { ++ pxa250_irda_set_speed(dev, si->newspeed); ++ si->newspeed = 0; ++ } ++ ++ while (ICSR1 & ICSR1_TBY) ++ udelay(1); ++ ++ ICCR0 &= ~ICCR0_TXE; ++ ++ ++ enable_irq(si->fir_irq); ++ ++ ICCR0 |= ICCR0_RXE; ++ ++ /* ++ * Make sure that the TX queue is available for sending ++ * (for retries). TX has priority over RX at all times. ++ */ ++ netif_wake_queue(dev); ++ ++ __ECHO_OUT; ++} ++ ++ ++static void pxa250_start_rx_dma(struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ int ch=si->rxdma_ch; ++ ++ if (!si->rxskb) { ++ DBG("rx buffer went missing\n"); ++/* return; */ ++ } ++ ++ DCSR(ch)=0; ++ DCSR(ch)=DCSR_NODESC; ++ DSADR(ch) = __PREG(ICDR); ++ DTADR(ch) = si->rxbuf_dma; /* phisical address */; ++ ++ /* We should never do END_IRQ. !!!*/ ++ DCMD(ch) = DCMD_ENDIRQEN| DCMD_INCTRGADDR | DCMD_FLOWSRC | DCMD_BURST8 | DCMD_WIDTH1 | HPSIR_MAX_RXLEN; ++ ++ /* ++ * All right information will be available as soon as we set RXE flag ++ */ ++ ++ DCSR(ch) = DCSR_ENDINTR | DCSR_BUSERR; ++ DCSR(ch) = DCSR_RUN | DCSR_NODESC ; ++ ++} ++ ++ ++ ++ ++static int pxa250_get_rx_len(struct pxa250_irda *si) ++{ ++ /* ++ * DMA have to be stoped here ++ */ ++ ++ if ( ! (DCSR(si->rxdma_ch) & DCSR_STOPSTATE) ) ++ printk("warning dma have to be stoped befor counting len\n"); ++ ++ return ( HPSIR_MAX_RXLEN - ( DCMD(si->rxdma_ch) & DCMD_LENGTH ) ); ++ ++} ++ ++static void pxa250_irda_fir_error(struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ struct sk_buff *skb = si->rxskb; ++ int len; ++ int stat,data; ++ ++ __ECHO_IN; ++ ++ if (!skb) ++ { ++ printk("pxa250 fir_error: SKB is NULL!\n"); ++ return; ++ } ++ ++ /* ++ * Get the current data position. ++ */ ++ ++ len=pxa250_get_rx_len(si); ++ DBG("RXLEN=%d\n",len); ++ memcpy(skb->data, si->rxbuf_dma_virt, len); ++ ++ do { ++ /* ++ * Read Status, and then Data. ++ */ ++ stat = ICSR1; ++ rmb(); ++ data = ICDR; ++ if (stat & (ICSR1_CRE | ICSR1_ROR)) { ++ si->stats.rx_errors++; ++ if (stat & ICSR1_CRE) ++ si->stats.rx_crc_errors++; ++ if (stat & ICSR1_ROR) ++ si->stats.rx_frame_errors++; ++ } else ++ skb->data[len++] = data; ++ ++ /* ++ * If we hit the end of frame, there's ++ * no point in continuing. ++ */ ++ if (stat & ICSR1_EOF) ++ break; ++ } while (ICSR0 & ICSR0_EIF); ++ ++ if (stat & ICSR1_EOF) { ++ si->rxskb = NULL; ++ ++ skb_put(skb, len); ++ skb->dev = dev; ++ skb->mac.raw = skb->data; ++ skb->protocol = htons(ETH_P_IRDA); ++ si->stats.rx_packets++; ++ si->stats.rx_bytes += len; ++ ++ /* ++ * Before we pass the buffer up, allocate a new one. ++ */ ++ ++ si->rxskb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC); ++ ++ if (!si->rxskb) { ++ printk(KERN_ERR "pxa250_ir: out of memory for RX SKB\n"); ++ return; ++ } ++ ++ /* ++ * Align any IP headers that may be contained ++ * within the frame. ++ */ ++ skb_reserve(si->rxskb, 1); ++ ++ netif_rx(skb); ++ } ++} ++ ++/* ++ * FIR format interrupt service routine. We only have to ++ * handle RX events; transmit events go via the TX DMA irq handler. ++ * ++ * No matter what, we disable RX, process, and then restart RX. ++ */ ++ ++static void pxa250_irda_fir_irq(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ struct net_device *dev = dev_id; ++ struct pxa250_irda *si = dev->priv; ++ int status; ++ ++ /* ++ * Stop RX ++ */ ++ ++ __ECHO_IN; ++ ++ pxa250_dma_stop(si->rxdma_ch); ++ ++ ++ /* ++ * Framing error - we throw away the packet completely. ++ * Clearing RXE flushes the error conditions and data ++ * from the fifo. ++ */ ++ status=ICSR0; ++ ++ if (status & (ICSR0_FRE | ICSR0_RAB)) { ++ DBG_IRQ("Framing error or RAB\n"); ++ ++ si->stats.rx_errors++; ++ ++ if (ICSR0 & ICSR0_FRE) ++ si->stats.rx_frame_errors++; ++ ++ /* Clear RX fifo ++ * DMA will be cleared when we restart RX ++ * Should we check RNE after that? ++ */ ++ ++ ICCR0 &= ~ICCR0_RXE; ++ ++ /* ++ * Clear selected status bits now, so we ++ * don't miss them next time around. ++ */ ++ ICSR0 = status & (ICSR0_FRE | ICSR0_RAB); ++ } ++ ++ ++ /* ++ * Deal with any receive errors. The any of the lowest ++ * 8 bytes in the FIFO may contain an error. We must read ++ * them one by one. The "error" could even be the end of ++ * packet! ++ */ ++ if (ICSR0 & ICSR0_EIF) ++ pxa250_irda_fir_error(dev); ++ ++ /* ++ * No matter what happens, we must restart reception. ++ */ ++ ++ ICCR0 = 0; ++ pxa250_start_rx_dma(dev); ++ pxa250_ficp_rx_start(); ++ __ECHO_OUT; ++} ++ ++ ++ ++ ++ ++/************************************************************************** ++ * SIR * ++ **************************************************************************/ ++/* ++ * HP-SIR format interrupt service routines. ++ */ ++static void pxa250_sir_transmit(struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ ++ if (si->tx_buff.len) ++ { ++ /* Disable receiver and enable transmiter*/ ++ ++ ++ ++ STISR &= ~STISR_RCVEIR; ++// STISR |= STISR_XMITIR; ++ ++ ++ ++ disable_irq(dev->irq); ++ ++ do ++ { ++ ++ if (STLSR & LSR_TDRQ) ++ { ++ STTHR = *si->tx_buff.data++; ++ si->tx_buff.len -= 1; ++ ++ tx_count++; ++ } ++ ++ ++ } while (si->tx_buff.len); ++ ++ ++ if (si->tx_buff.len == 0) ++ { ++ ++ ++ si->stats.tx_packets++; ++ si->stats.tx_bytes += si->tx_buff.data - ++ si->tx_buff.head; ++ ++ /* ++ * We need to ensure that the transmitter has ++ * finished. ++ */ ++ ++ do ++ { ++ udelay(1); ++ ++ } ++ while ( ! (STLSR & LSR_TEMT) ); ++ ++ ++ /* ++ ++ * Ok, we've finished transmitting. Now enable ++ * the receiver. Sometimes we get a receive IRQ ++ * immediately after a transmit... ++ */ ++ ++ if (si->newspeed) ++ { ++ pxa250_irda_set_speed(dev, si->newspeed); ++ si->newspeed = 0; ++ } ++ ++ /* I'm hungry! */ ++ netif_wake_queue(dev); ++ } ++ ++ enable_irq (dev->irq); ++ STIER = (IER_RAVIE | IER_UUE | IER_RTIOE); ++ ++ STISR |= STISR_RCVEIR; ++// STISR &= ~STISR_XMITIR; ++ } ++} ++ ++static void pxa250_irda_hpsir_irq(struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ ++ /* ++ * Deal with any receive errors first. The bytes in error may be ++ * the only bytes in the receive FIFO, so we do this first. ++ */ ++ __ECHO_IN; ++ ++ while (STLSR & LSR_FIFOE) ++ { ++ int stat, data; ++ ++ stat = STLSR; ++ data = STRBR; ++ ++ ++ if (stat & (LSR_FE | LSR_OE | LSR_PE)) ++ ++ { ++ si->stats.rx_errors++; ++ if (stat & LSR_FE) ++ si->stats.rx_frame_errors++; ++ if (stat & LSR_OE) ++ si->stats.rx_fifo_errors++; ++ ++ } else ++ { ++ rx_count++; ++ async_unwrap_char(dev, &si->stats, &si->rx_buff, data); ++ } ++ ++ } ++ ++ /* ++ * We must clear certain bits. ++ */ ++ ++ if (STLSR & (LSR_DR)) ++ { ++ /* ++ * Fifo contains at least 1 character. ++ */ ++ do ++ { ++ int data; ++ ++ data = STRBR; ++ ++ async_unwrap_char(dev, &si->stats, &si->rx_buff, ++ data); /* was Ser2UTDR); Clo */ ++ rx_count++; ++ ++ } while (STLSR & LSR_DR); ++ ++ dev->last_rx = jiffies; ++ } ++ ++ __ECHO_OUT; ++} ++ ++static void pxa250_sir_irda_shutdown(struct pxa250_irda *si) ++{ ++ ++ STIER = 0; ++ STFCR = 0; ++ STISR = 0; ++ CKEN &= ~CKEN5_STUART; ++} ++ ++ ++/************************************************************************************/ ++ ++/*Low level init/uninstall function PM control and IrDA protocol stack registration */ ++ ++/* ++ * Set the IrDA communications speed. ++ * Interrupt have to be disabled here. ++ */ ++ ++static int pxa250_irda_startup(struct net_device *dev) ++{ ++ ++ ++ __ECHO_IN; ++ ++ /* ++ * Ensure that the ports for this device are setup correctly. ++ */ ++ ++ ++ set_GPIO_mode (GPIO46_STRXD_MD); ++ set_GPIO_mode (GPIO47_STTXD_MD); ++ ++ STMCR = MCR_OUT2; ++ STLCR = LCR_WLS1 | LCR_WLS0; ++ ++ SET_SIR_MODE; ++ CKEN |= CKEN5_STUART; ++ /* enable irq from stuart */ ++ ICMR |= ( 1 << 20 ); ++ ++ /*reset FIFO*/ ++ ++/* STFCR = FCR_TRFIFOE | FCR_RESETTF | FCR_RESETRF;// | FCR_ITL_16; ++ ++ STIER = IER_UUE | IER_RAVIE | IER_RTOIE; ++*/ ++ __ECHO_OUT; ++ ++ return 0; ++ ++} ++ ++ ++#ifdef CONFIG_PM ++/* ++ * Suspend the IrDA interface. ++ */ ++ ++static int pxa250_irda_shutdown(struct pxa250_irda *si) ++{ ++ ++ pxa250_sir_irda_shutdown(si); ++ return 0; ++ ++} ++ ++ ++static int pxa250_irda_suspend(struct net_device *dev, int state) ++{ ++ struct pxa250_irda *si = dev->priv; ++ ++ if (si && si->open) { ++ /* ++ * Stop the transmit queue ++ */ ++ if (IS_FIR(si)) ++ return -1; ++ ++ netif_stop_queue(dev); ++ disable_irq(dev->irq); ++ disable_irq(si->fir_irq); ++ pxa250_sir_irda_shutdown(si); ++ } ++ ++ return 0; ++} ++ ++/* ++ * Resume the IrDA interface. ++ */ ++ ++static int pxa250_irda_resume(struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ ++ __ECHO_IN; ++ ++ if (si && si->open) { ++ /* ++ * If we missed a speed change, initialise at the new speed ++ * directly. It is debatable whether this is actually ++ * required, but in the interests of continuing from where ++ * we left off it is desireable. The converse argument is ++ * that we should re-negotiate at 9600 baud again. ++ */ ++ if (si->newspeed) { ++ si->speed = si->newspeed; ++ si->newspeed = 0; ++ } ++ ++ pxa250_irda_startup(dev); ++ enable_irq(dev->irq); ++ ++ /* ++ * This automatically wakes up the queue ++ */ ++ netif_wake_queue(dev); ++ pxa250_irda_set_speed(dev,si->speed = 9600); ++ ++ } ++ ++ __ECHO_OUT; ++ return 0; ++} ++ ++static int pxa250_irda_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data) ++{ ++ int ret; ++ ++ ++ if (!dev->data) ++ return -EINVAL; ++ ++ ++ switch (rqst) { ++ case PM_SUSPEND: ++ ret = pxa250_irda_suspend((struct net_device *)dev->data, ++ (int)data); ++ break; ++ ++ case PM_RESUME: ++ ret = pxa250_irda_resume((struct net_device *)dev->data); ++ break; ++ ++ default: ++ ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++#endif ++ ++ ++ ++ ++static void pxa250_irda_irq(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ struct net_device *dev = dev_id; ++ ++ pxa250_irda_hpsir_irq(dev); ++ ++} ++ ++ ++static int pxa250_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ int speed = irda_get_next_speed(skb); ++ int mtt; ++ ++ __ECHO_IN; ++ ++ /* ++ * Does this packet contain a request to change the interface ++ * speed? If so, remember it until we complete the transmission ++ * of this frame. ++ */ ++ if (speed != si->speed && speed != -1) ++ si->newspeed = speed; ++ ++ /* ++ * If this is an empty frame, we can bypass a lot. ++ */ ++ if (skb->len == 0) { ++ if (si->newspeed) { ++ si->newspeed = 0; ++ pxa250_irda_set_speed(dev, speed); ++ } ++ dev_kfree_skb(skb); ++ return 0; ++ } ++ ++ ++ DBG("stop queue\n"); ++ netif_stop_queue(dev); ++ ++ if(!IS_FIR(si)) ++ { ++ ++ si->tx_buff.data = si->tx_buff.head; ++ si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, ++ si->tx_buff.truesize); ++ ++ ++ pxa250_sir_transmit(dev); ++ ++ ++ ++ dev_kfree_skb(skb); ++ ++ dev->trans_start = jiffies; ++ ++ return 0; ++ } ++ else /* FIR */ ++ { ++ DBG("Enter FIR transmit\n"); ++ /* ++ * We must not be transmitting... ++ */ ++ if (si->txskb) ++ BUG(); ++ ++ disable_irq(si->fir_irq); ++ ++ netif_stop_queue(dev); ++ DBG("queue stoped\n"); ++ si->txskb = skb; ++ ++ /* we could not just map so we'll need some triks */ ++ /* skb->data may be not DMA capable -Sed- */ ++ ++ ++ if (skb->len > TXBUFF_MAX_SIZE) ++ { ++ printk (KERN_ERR "skb data too large\n"); ++ printk (KERN_ERR "len=%d",skb->len); ++ BUG(); ++ } ++ ++ ++ DBG("gonna copy %d bytes to txbuf\n",skb->len); ++ ++ memcpy (si->txbuf_dma_virt, skb->data , skb->len); ++ ++ /* Actual sending ;must not be receiving !!! */ ++ /* Write data and source address */ ++ ++ DBG("ICSR1 & RNE =%d\n",(ICSR1 & ICSR1_RNE) ? 1 : 0 ); ++ ++ /*Disable receiver and enable transifer */ ++ ICCR0 &= ~ICCR0_RXE; ++ ++ if (ICSR1 & ICSR1_TBY) ++ BUG(); ++ ++ ICCR0 |= ICCR0_TXE; ++ ++ DBG("FICP status %x\n",ICSR0); ++ ++ if (0){ ++ int i; ++ ++ DBG("sending packet\n"); ++ for (i=0;i<skb->len;i++) ++ (i % 64) ? printk ("%2x ",skb->data[i]) : printk ("%2x \n",skb->data[i]) ; ++ DBG(" done\n"); ++ ++ } ++ /* ++ * If we have a mean turn-around time, impose the specified ++ * specified delay. We could shorten this by timing from ++ * the point we received the packet. ++ */ ++ ++ mtt = irda_get_mtt(skb); ++ if(mtt) ++ udelay(mtt); ++ ++ DCSR(si->txdma_ch)=0; ++ DCSR(si->txdma_ch)=DCSR_NODESC; ++ DSADR(si->txdma_ch) = si->txbuf_dma; /* phisic address */ ++ DTADR(si->txdma_ch) = __PREG(ICDR); ++ ++ DCMD(si->txdma_ch) = DCMD_ENDIRQEN| DCMD_INCSRCADDR | DCMD_FLOWTRG | DCMD_BURST8 | DCMD_WIDTH1 | skb->len; ++ ++ DCSR(si->txdma_ch) = DCSR_ENDINTR | DCSR_BUSERR; ++ DCSR(si->txdma_ch) = DCSR_RUN | DCSR_NODESC ; ++ ++ DBG("FICP status %x\n",ICSR0); ++ ++ return 0; ++ } ++ ++} ++ ++static int ++pxa250_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) ++{ ++ struct if_irda_req *rq = (struct if_irda_req *)ifreq; ++ struct pxa250_irda *si = dev->priv; ++ int ret = -EOPNOTSUPP; ++ ++ __ECHO_IN; ++ ++ switch (cmd) { ++ case SIOCSBANDWIDTH: ++ if (capable(CAP_NET_ADMIN)) { ++ /* ++ * We are unable to set the speed if the ++ * device is not running. ++ */ ++ if (si->open) { ++ ret = pxa250_irda_set_speed(dev, ++ rq->ifr_baudrate); ++ } else { ++ printk("pxa250_irda_ioctl: SIOCSBANDWIDTH: !netif_running\n"); ++ ret = 0; ++ } ++ } ++ break; ++ ++ case SIOCSMEDIABUSY: ++ ret = -EPERM; ++ if (capable(CAP_NET_ADMIN)) { ++ irda_device_set_media_busy(dev, TRUE); ++ ret = 0; ++ } ++ break; ++ ++ case SIOCGRECEIVING: ++ rq->ifr_receiving = IS_FIR(si) ? 0 ++ : si->rx_buff.state != OUTSIDE_FRAME; ++ break; ++ ++ default: ++ break; ++ } ++ ++ __ECHO_OUT; ++ ++ return ret; ++} ++ ++static struct net_device_stats *pxa250_irda_stats(struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ return &si->stats; ++} ++ ++static int pxa250_irda_start(struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ int err; ++ unsigned int flags; ++ ++ ++ MOD_INC_USE_COUNT; ++ ++ __ECHO_IN; ++ si->speed = 9600; ++ ++ local_irq_save(flags); ++ ++ err = request_irq(si->fir_irq, pxa250_irda_fir_irq, 0, dev->name, dev); ++ if (err) ++ goto err_fir_irq; ++ ++ err = request_irq(dev->irq, pxa250_irda_irq, 0, dev->name, dev); ++ if (err) ++ goto err_irq; ++ ++ /* ++ * The interrupt must remain disabled for now. ++ */ ++ ++ disable_irq(dev->irq); ++ disable_irq(si->fir_irq); ++ ++ local_irq_restore(flags); ++ ++ ++ /* Allocate DMA channel for receiver (not used) */ ++ err = pxa_request_dma("IrDA receive", DMA_PRIO_LOW, pxa250_irda_rxdma_irq, dev); ++ if (err < 0 ) ++ goto err_rx_dma; ++ si->rxdma_ch=err; ++ ++ DRCMRRXICDR = DRCMR_MAPVLD | si->rxdma_ch; ++ ++ ++ /* Allocate DMA channel for transmit */ ++ err = pxa_request_dma("IrDA transmit", DMA_PRIO_LOW, pxa250_irda_txdma_irq , dev); ++ if (err < 0 ) ++ goto err_tx_dma; ++ ++ si->txdma_ch=err; ++ ++ /* ++ * Make sure that ICP will be able ++ * to assert the transmit dma request bit ++ * through the peripherals request bus (PREQ) ++ */ ++ ++ DRCMRTXICDR = DRCMR_MAPVLD | si->txdma_ch; ++ ++ DBG("rx(not used) channel=%d tx channel=%d\n",si->rxdma_ch,si->txdma_ch); ++ ++ /* allocate consistent buffers for dma access ++ * buffers have to be aligned and situated in dma capable memory region; ++ */ ++ si->rxbuf_dma_virt = consistent_alloc(GFP_KERNEL | GFP_DMA ,HPSIR_MAX_RXLEN , &si->rxbuf_dma); ++ if (! si->rxbuf_dma_virt ) ++ goto err_rxbuf_dma; ++ ++ si->txbuf_dma_virt = consistent_alloc(GFP_KERNEL | GFP_DMA, HPSIR_MAX_TXLEN, &si->txbuf_dma); ++ if (! si->txbuf_dma_virt ) ++ goto err_txbuf_dma; ++ ++ /* Alocate skb for receiver */ ++ err=pxa250_irda_rx_alloc(si); ++ if (err) ++ goto err_rx_alloc; ++ ++ /* ++ * Setup the serial port for the specified config. ++ */ ++ err = pxa250_irda_startup(dev); ++ if (err) ++ goto err_startup; ++ ++ pxa250_irda_set_speed(dev,si->speed = 9600); ++ ++ ++ /* ++ * Open a new IrLAP layer instance. ++ */ ++ si->irlap = irlap_open(dev, &si->qos, "pxa250"); ++ err = -ENOMEM; ++ if (!si->irlap) ++ goto err_irlap; ++ ++ /* ++ * Now enable the interrupt and start the queue ++ */ ++ si->open = 1; ++ enable_irq(dev->irq); ++ netif_start_queue(dev); ++ return 0; ++ ++err_irlap: ++ si->open = 0; ++ pxa250_sir_irda_shutdown(si); ++err_startup: ++ dev_kfree_skb(si->rxskb); ++err_rx_alloc: ++ consistent_free (si->txbuf_dma_virt,HPSIR_MAX_TXLEN,si->txbuf_dma); ++err_txbuf_dma: ++ consistent_free (si->rxbuf_dma_virt,HPSIR_MAX_RXLEN,si->rxbuf_dma); ++err_rxbuf_dma: ++ pxa_free_dma(si->txdma_ch); ++err_tx_dma: ++ pxa_free_dma(si->rxdma_ch); ++err_rx_dma: ++ free_irq(dev->irq, dev); ++err_irq: ++ free_irq(si->fir_irq, dev); ++err_fir_irq: ++ MOD_DEC_USE_COUNT; ++ return err; ++} ++ ++static int pxa250_irda_stop(struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ ++ printk(KERN_ERR "Irda stop... RX = %d TX = %d\n",rx_count,tx_count); ++ ++ disable_irq(dev->irq); ++ disable_irq(si->fir_irq); ++/* pxa250_irda_shutdown(si); */ ++ ++ /* ++ * If we have been doing DMA receive, make sure we ++ * tidy that up cleanly. ++ */ ++ if (si->rxskb) { ++ dev_kfree_skb(si->rxskb); ++ si->rxskb = NULL; ++ } ++ ++ /* Stop IrLAP */ ++ if (si->irlap) { ++ irlap_close(si->irlap); ++ si->irlap = NULL; ++ } ++ ++ consistent_free (si->txbuf_dma_virt,HPSIR_MAX_TXLEN,si->txbuf_dma); ++ consistent_free (si->rxbuf_dma_virt,HPSIR_MAX_RXLEN,si->rxbuf_dma); ++ pxa_free_dma(si->txdma_ch); ++ pxa_free_dma(si->rxdma_ch); ++ ++ netif_stop_queue(dev); ++ si->open = 0; ++ ++ /* ++ * Free resources ++ */ ++ free_irq(dev->irq, dev); ++ free_irq(si->fir_irq, dev); ++ ++ ++ MOD_DEC_USE_COUNT; ++ ++ return 0; ++} ++ ++static int pxa250_irda_init_iobuf(iobuff_t *io, int size) ++{ ++ io->head = kmalloc(size, GFP_KERNEL | GFP_DMA); ++ if (io->head != NULL) { ++ io->truesize = size; ++ io->in_frame = FALSE; ++ io->state = OUTSIDE_FRAME; ++ io->data = io->head; ++ } ++ return io->head ? 0 : -ENOMEM; ++} ++ ++ ++ ++ ++static int pxa250_stop_fir(struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ unsigned int flag; ++ ++ save_flags(flag); ++ cli(); ++ ++ pxa250_dma_stop(si->txdma_ch); ++ pxa250_dma_stop(si->rxdma_ch); ++ ++ if (si->txskb) ++ dev_kfree_skb_irq(si->txskb); ++ ++ ICCR0 &= ~(ICCR0_RXE | ICCR0_TXE ); ++ disable_irq(si->fir_irq); ++ CKEN &= ~CKEN13_FICP; ++ ++ restore_flags(flag); ++ ++ return 0; ++} ++ ++ ++ ++static int pxa250_irda_set_speed(struct net_device *dev, int speed) ++{ ++ struct pxa250_irda *si = dev->priv; ++ int brd, ret = -EINVAL; ++ static int last_fir_speed=0; ++ ++ __ECHO_IN; ++ ++ ++ ++ switch (speed) { ++ case 9600: case 19200: case 38400: ++ case 57600: case 115200: ++ ++ /* Baud rate fixed - Clo */ ++ ++ /* ++ * FIXME ++ */ ++ if (last_fir_speed) ++ { ++ ++ pxa250_stop_fir(dev); ++ set_GPIO_mode (GPIO46_STRXD_MD); ++ set_GPIO_mode (GPIO47_STTXD_MD); ++ ++ enable_irq(dev->irq); ++ netif_wake_queue(dev); ++ last_fir_speed=0; ++ } ++ ++ ++ LUB_MISC_WR &= ~(1 << 4); ++ ++ brd = 14745600 / (16 * speed); ++ ++ STLCR |= LCR_DLAB; ++ ++ STDLH = brd >> 8; /* Clo: set Divisor Latch High */ ++ STDLL = brd & 0xFF; /* Clo: set Devisor Latch Low */ ++ ++ STLCR &= ~LCR_DLAB; /* Clo: clear DLAB bit */ ++ ++ STMCR = MCR_OUT2; ++ ++ CKEN |= CKEN5_STUART; ++ ++ ICMR |= ( 1 << 20 ); ++ ++ STLCR = LCR_WLS1 | LCR_WLS0; ++ ++ SET_SIR_MODE; ++ ++ STFCR = FCR_TRFIFOE | FCR_RESETTF | FCR_RESETRF | FCR_ITL_1 ;// | FCR_ITL_16; ++ ++ STIER = IER_UUE | IER_RAVIE | IER_RTIOE; ++ ++ si->speed = speed; ++ ++ ret = 0; ++ break; ++ ++ case 4000000: ++ ++ if (last_fir_speed) ++ goto speed_out; ++ ++ disable_irq(dev->irq); ++ ++ pxa250_sir_irda_shutdown(si); ++ pxa250_fir_irda_startup(si); ++ pxa250_irda_rx_alloc(si); ++ ICCR0=0; ++ pxa250_start_rx_dma(dev); ++ pxa250_ficp_rx_start(); ++ ++ enable_irq(si->fir_irq); ++ DBG("enable FIR \n"); ++ si->speed = speed; ++ ++ netif_wake_queue(dev); ++ last_fir_speed=1; ++speed_out: ++ ++ ret=0; ++ ++ break; ++ ++ default: ++ break; ++ } ++ __ECHO_OUT; ++ ++ return ret; ++} ++ ++ ++static int pxa250_irda_net_init(struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ unsigned int baudrate_mask; ++ int err = -ENOMEM; ++ ++ si = kmalloc(sizeof(struct pxa250_irda), GFP_KERNEL); ++ if (!si) ++ goto out; ++ ++ memset(si, 0, sizeof(*si)); ++ ++ /* ++ * Initialise the HP-SIR buffers ++ */ ++ ++ err = pxa250_irda_init_iobuf(&si->rx_buff, 14384); ++ if (err) ++ goto out; ++ err = pxa250_irda_init_iobuf(&si->tx_buff, 4000); ++ if (err) ++ goto out_free_rx; ++ ++ si->fir_irq = IRQ_ICP; ++ dev->priv = si; ++ dev->hard_start_xmit = pxa250_irda_hard_xmit; ++ dev->open = pxa250_irda_start; ++ dev->stop = pxa250_irda_stop; ++ dev->do_ioctl = pxa250_irda_ioctl; ++ dev->get_stats = pxa250_irda_stats; ++ ++ irda_device_setup(dev); ++ irda_init_max_qos_capabilies(&si->qos); ++ ++ /* ++ * We support original IRDA up to 115k2. (we don't currently ++ * support 4Mbps). Min Turn Time set to 1ms or greater. ++ */ ++ baudrate_mask = IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; ++ baudrate_mask |= IR_4000000 << 8; ++ si->qos.baud_rate.bits &= baudrate_mask; ++ si->qos.min_turn_time.bits = 7; ++ ++ irda_qos_bits_to_value(&si->qos); ++ ++#ifdef CONFIG_PM ++ /* ++ * Power-Management is optional. ++ */ ++ si->pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, pxa250_irda_pmproc); ++ if (si->pmdev) ++ si->pmdev->data = dev; ++#endif ++ ++ return 0; ++ ++ kfree(si->tx_buff.head); ++out_free_rx: ++ kfree(si->rx_buff.head); ++out: ++ kfree(si); ++ ++ return err; ++} ++ ++/* ++ * Remove all traces of this driver module from the kernel, so we can't be ++ * called. Note that the device has already been stopped, so we don't have ++ * to worry about interrupts or dma. ++ */ ++static void pxa250_irda_net_uninit(struct net_device *dev) ++{ ++ struct pxa250_irda *si = dev->priv; ++ ++ dev->hard_start_xmit = NULL; ++ dev->open = NULL; ++ dev->stop = NULL; ++ dev->do_ioctl = NULL; ++ dev->get_stats = NULL; ++ dev->priv = NULL; ++ ++ pm_unregister(si->pmdev); ++ ++ kfree(si->tx_buff.head); ++ kfree(si->rx_buff.head); ++ kfree(si); ++} ++ ++static int __init pxa250_irda_init(void) ++{ ++ struct net_device *dev; ++ int err; ++ ++ /* STUART */ ++ err = request_mem_region(__PREG(STRBR), 0x24, "IrDA") ? 0 : -EBUSY; ++ if (err) ++ goto err_mem_1; ++ ++ /* FIR */ ++ err = request_mem_region(__PREG(ICCR0), 0x1c, "IrDA") ? 0 : -EBUSY; ++ if (err) ++ goto err_mem_2; ++ ++ ++ rtnl_lock(); ++ dev = dev_alloc("irda%d", &err); ++ if (dev) { ++ dev->irq = IRQ_STUART; ++ dev->init = pxa250_irda_net_init; ++ dev->uninit = pxa250_irda_net_uninit; ++ ++ err = register_netdevice(dev); ++ ++ if (err) ++ kfree(dev); ++ else ++ netdev = dev; ++ } ++ rtnl_unlock(); ++ ++ if (err) { ++ release_mem_region(__PREG(ICCR0), 0x1c); ++err_mem_2: ++ release_mem_region(__PREG(STRBR), 0x24); ++ } ++err_mem_1: ++ return err; ++} ++ ++static void __exit pxa250_irda_exit(void) ++{ ++ struct net_device *dev = netdev; ++ ++ netdev = NULL; ++ if (dev) { ++ rtnl_lock(); ++ unregister_netdevice(dev); ++ rtnl_unlock(); ++ } ++ ++ release_mem_region(__PREG(ICCR0), 0x1c); ++ ++ release_mem_region(__PREG(STRBR), 0x24); ++ ++ /* ++ * We now know that the netdevice is no longer in use, and all ++ * references to our driver have been removed. The only structure ++ * which may still be present is the netdevice, which will get ++ * cleaned up by net/core/dev.c ++ */ ++} ++ ++module_init(pxa250_irda_init); ++module_exit(pxa250_irda_exit); ++ ++MODULE_AUTHOR("Alexey Lugovskoy Frasenyak Dmitrij"); ++MODULE_DESCRIPTION("PXA250 SIR/FIR"); ++MODULE_LICENSE("GPL"); ++EXPORT_NO_SYMBOLS; +--- /dev/null ++++ linux-2.4.27/drivers/net/smc91x.c +@@ -0,0 +1,2123 @@ ++/*------------------------------------------------------------------------ ++ . smc91x.c ++ . This is a driver for SMSC's 91C9x/91C1xx single-chip Ethernet devices. ++ . ++ . Copyright (C) 1996 by Erik Stahlman ++ . Copyright (C) 2001 Standard Microsystems Corporation ++ . Developed by Simple Network Magic Corporation ++ . Copyright (C) 2003 Monta Vista Software, Inc. ++ . Unified SMC91x driver by Nicolas Pitre ++ . ++ . 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. ++ . ++ . This program is distributed in the hope that it will be useful, ++ . but WITHOUT ANY WARRANTY; without even the implied warranty of ++ . MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ . GNU General Public License for more details. ++ . ++ . You should have received a copy of the GNU General Public License ++ . along with this program; if not, write to the Free Software ++ . Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ . ++ . Arguments: ++ . io = for the base address ++ . irq = for the IRQ ++ . nowait = 0 for normal wait states, 1 eliminates additional wait states ++ . ++ . original author: ++ . Erik Stahlman <erik@vt.edu> ++ . ++ . hardware multicast code: ++ . Peter Cammaert <pc@denkart.be> ++ . ++ . contributors: ++ . Daris A Nevil <dnevil@snmc.com> ++ . Nicolas Pitre <nico@cam.org> ++ . ++ . History: ++ . 08/20/00 Arnaldo Melo fix kfree(skb) in smc_hardware_send_packet ++ . 12/15/00 Christian Jullien fix "Warning: kfree_skb on hard IRQ" ++ . 03/16/01 Daris A Nevil modified smc9194.c for use with LAN91C111 ++ . 08/22/01 Scott Anderson merge changes from smc9194 to smc91111 ++ . 08/21/01 Pramod B Bhardwaj added support for RevB of LAN91C111 ++ . 12/20/01 Jeff Sutherland initial port to Xscale PXA with DMA support ++ . 04/07/03 Nicolas Pitre unified SMC91x driver, killed irq races, ++ . more bus abstraction, big cleanup, etc. ++ ----------------------------------------------------------------------------*/ ++ ++static const char version[] = ++ "smc91x.c: v1.0, mar 07 2003 by Nicolas Pitre <nico@cam.org>\n"; ++ ++/* Debugging level */ ++#ifndef SMC_DEBUG ++#define SMC_DEBUG 0 ++#endif ++ ++ ++#include <linux/config.h> ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/delay.h> ++#include <linux/timer.h> ++#include <linux/errno.h> ++#include <linux/ioport.h> ++ ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/skbuff.h> ++#ifdef CONFIG_PM ++#include <linux/pm.h> ++#endif ++ ++#include <asm/io.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++ ++#include "smc91x.h" ++ ++ ++#ifdef CONFIG_ISA ++/* ++ . the LAN91C111 can be at any of the following port addresses. To change, ++ . for a slightly different card, you can add it to the array. Keep in ++ . mind that the array must end in zero. ++*/ ++static unsigned int smc_portlist[] __initdata = { ++ 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, ++ 0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0 ++}; ++#endif /* CONFIG_ISA */ ++ ++#ifndef SMC_IOADDR ++# define SMC_IOADDR -1 ++#endif ++static int io = SMC_IOADDR; ++ ++#ifndef SMC_IRQ ++# define SMC_IRQ -1 ++#endif ++static int irq = SMC_IRQ; ++ ++#ifndef SMC_NOWAIT ++# define SMC_NOWAIT 0 ++#endif ++static int nowait = SMC_NOWAIT; ++ ++MODULE_PARM(io, "i"); ++MODULE_PARM(irq, "i"); ++MODULE_PARM(nowait, "i"); ++MODULE_PARM_DESC(io, "I/O base address"); ++MODULE_PARM_DESC(irq, "IRQ number"); ++MODULE_PARM_DESC(nowait, "set to 1 for no wait state"); ++ ++ ++/*------------------------------------------------------------------------ ++ . ++ . The internal workings of the driver. If you are changing anything ++ . here with the SMC stuff, you should have the datasheet and know ++ . what you are doing. ++ . ++ -------------------------------------------------------------------------*/ ++#define CARDNAME "LAN91x" ++ ++// Use power-down feature of the chip ++#define POWER_DOWN 1 ++ ++/* ++ . Wait time for memory to be free. This probably shouldn't be ++ . tuned that much, as waiting for this means nothing else happens ++ . in the system ++*/ ++#define MEMORY_WAIT_TIME 16 ++ ++/* ++ . This selects whether TX packets are sent one by one to the SMC91x internal ++ . memory ans throttled until transmission completes. This may prevent ++ . RX overruns a litle by keeping much of the memory free for RX packets ++ . but to the expense of reduced TX throughput and increased IRQ overhead. ++ . Note this is not a cure for a too slow data bus or too high IRQ latency. ++ */ ++#define THROTTLE_TX_PKTS 0 ++ ++ ++/* store this information for the driver.. */ ++struct smc_local { ++ ++ // If I have to wait until memory is available to send ++ // a packet, I will store the skbuff here, until I get the ++ // desired memory. Then, I'll send it out and free it. ++ struct sk_buff *saved_skb; ++ ++ // these are things that the kernel wants me to keep, so users ++ // can find out semi-useless statistics of how well the card is ++ // performing ++ struct net_device_stats stats; ++ ++ // version/revision of the SMC91x chip ++ int version; ++ ++ // Set to true during the auto-negotiation sequence ++ int autoneg_active; ++ ++ // Address of our PHY port ++ int phyaddr; ++ ++ // Type of PHY ++ int phytype; ++ ++ // Last contents of PHY Register 18 ++ int lastPhy18; ++ ++ // Contains the current active transmission mode ++ int tcr_cur_mode; ++ ++ // Contains the current active receive mode ++ int rcr_cur_mode; ++ ++ // Contains the current active receive/phy mode ++ int rpc_cur_mode; ++ int ctl_autoneg; ++ int ctl_rfduplx; ++ int ctl_rspeed; ++ ++#ifdef CONFIG_PM ++ struct pm_dev* pm; ++#endif ++ ++}; ++ ++ ++#if SMC_DEBUG > 2 ++#define PRINTK3(args...) printk(args) ++#else ++#define PRINTK3(args...) do { } while(0) ++#endif ++ ++#if SMC_DEBUG > 1 ++#define PRINTK2(args...) printk(args) ++#else ++#define PRINTK2(args...) do { } while(0) ++#endif ++ ++#if SMC_DEBUG > 0 ++#define PRINTK1(args...) printk(args) ++#define PRINTK(args...) printk(args) ++#else ++#define PRINTK1(args...) do { } while(0) ++#define PRINTK(args...) printk(KERN_DEBUG args) ++#endif ++ ++#if SMC_DEBUG > 3 ++static void PRINT_PKT(u_char *buf, int length) ++{ ++ int i; ++ int remainder; ++ int lines; ++ ++ lines = length / 16; ++ remainder = length % 16; ++ ++ for (i = 0; i < lines ; i ++) { ++ int cur; ++ for (cur = 0; cur < 8; cur++) { ++ u_char a, b; ++ a = *buf++; ++ b = *buf++; ++ printk("%02x%02x ", a, b); ++ } ++ printk("\n"); ++ } ++ for (i = 0; i < remainder/2 ; i++) { ++ u_char a, b; ++ a = *buf++; ++ b = *buf++; ++ printk("%02x%02x ", a, b ); ++ } ++ printk("\n"); ++} ++#else ++#define PRINT_PKT(x...) do { } while(0) ++#endif ++ ++ ++/* this enables an interrupt in the interrupt mask register */ ++#define SMC_ENABLE_INT(x) do { \ ++ unsigned long flags; \ ++ unsigned char mask; \ ++ local_irq_save(flags); \ ++ mask = SMC_GET_INT_MASK(); \ ++ mask |= (x); \ ++ SMC_SET_INT_MASK(mask); \ ++ local_irq_restore(flags); \ ++} while (0) ++ ++/* this disables an interrupt from the interrupt mask register */ ++#define SMC_DISABLE_INT(x) do { \ ++ unsigned long flags; \ ++ unsigned char mask; \ ++ local_irq_save(flags); \ ++ mask = SMC_GET_INT_MASK(); \ ++ mask &= ~(x); \ ++ SMC_SET_INT_MASK(mask); \ ++ local_irq_restore(flags); \ ++} while (0) ++ ++/* wait while MMU is busy */ ++#define SMC_WAIT_MMU_BUSY() do { \ ++ if (unlikely(SMC_GET_MMU_CMD() & MC_BUSY)) { \ ++ unsigned long timeout = jiffies + 2; \ ++ while (SMC_GET_MMU_CMD() & MC_BUSY) { \ ++ if (time_after(jiffies, timeout)) { \ ++ printk("%s: timeout %s line %d\n", \ ++ dev->name, __FILE__, __LINE__); \ ++ break; \ ++ } \ ++ } \ ++ } \ ++} while (0) ++ ++ ++/* this does a soft reset on the device */ ++static void ++smc_reset(struct net_device *dev) ++{ ++ unsigned long ioaddr = dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ int phyaddr = lp->phyaddr; ++ int status; ++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__); ++ ++ /* This resets the registers mostly to defaults, but doesn't ++ affect EEPROM. That seems unnecessary */ ++ SMC_SELECT_BANK( 0 ); ++ SMC_SET_RCR( RCR_SOFTRST ); ++ ++ /* Setup the Configuration Register */ ++ /* This is necessary because the CONFIG_REG is not affected */ ++ /* by a soft reset */ ++ SMC_SELECT_BANK( 1 ); ++ SMC_SET_CONFIG( CONFIG_DEFAULT ); ++ ++ /* Setup for fast accesses if requested */ ++ /* If the card/system can't handle it then there will */ ++ /* be no recovery except for a hard reset or power cycle */ ++ if (nowait) ++ SMC_SET_CONFIG( SMC_GET_CONFIG() | CONFIG_NO_WAIT ); ++ ++#ifdef POWER_DOWN ++ /* Release from possible power-down state */ ++ /* Configuration register is not affected by Soft Reset */ ++ SMC_SELECT_BANK( 1 ); ++ SMC_SET_CONFIG( SMC_GET_CONFIG() | CONFIG_EPH_POWER_EN ); ++ status = smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG); ++ status &= ~PHY_CNTL_PDN; ++ smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG); ++#endif ++ ++ /* this should pause enough for the chip to be happy */ ++ udelay(1); ++ ++ /* Disable transmit and receive functionality */ ++ SMC_SELECT_BANK( 0 ); ++ SMC_SET_RCR( RCR_CLEAR ); ++ SMC_SET_TCR( TCR_CLEAR ); ++ ++ /* set the control register to automatically ++ release successfully transmitted packets, to make the best ++ use out of our limited memory */ ++ SMC_SELECT_BANK( 1 ); ++#if ! THROTTLE_TX_PKTS ++ SMC_SET_CTL( SMC_GET_CTL() | CTL_AUTO_RELEASE ); ++#else ++ SMC_SET_CTL( SMC_GET_CTL() & ~CTL_AUTO_RELEASE ); ++#endif ++ ++ /* Disable all interrupts */ ++ SMC_SELECT_BANK( 2 ); ++ SMC_SET_INT_MASK( 0 ); ++ ++ /* Reset the MMU */ ++ SMC_SET_MMU_CMD( MC_RESET ); ++ SMC_WAIT_MMU_BUSY(); ++} ++ ++/* Enable Interrupts, Receive, and Transmit */ ++static void ++smc_enable(struct net_device *dev) ++{ ++ unsigned long ioaddr = dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ int mask; ++ ++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__); ++ ++ /* see the header file for options in TCR/RCR DEFAULT*/ ++ SMC_SELECT_BANK( 0 ); ++ SMC_SET_TCR( lp->tcr_cur_mode ); ++ SMC_SET_RCR( lp->rcr_cur_mode ); ++ ++ /* now, enable interrupts */ ++ mask = IM_EPH_INT|IM_RX_OVRN_INT|IM_RCV_INT; ++ if (lp->version >= 0x70) ++ mask |= IM_MDINT; ++ SMC_SELECT_BANK( 2 ); ++ SMC_SET_INT_MASK( mask ); ++} ++ ++/* this puts the device in an inactive state */ ++static void ++smc_shutdown(struct net_device *dev) ++{ ++ int ioaddr = dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ int phyaddr = lp->phyaddr; ++ int status; ++ ++ PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__); ++ ++ /* no more interrupts for me */ ++ SMC_SELECT_BANK( 2 ); ++ SMC_SET_INT_MASK( 0 ); ++ ++ /* and tell the card to stay away from that nasty outside world */ ++ SMC_SELECT_BANK( 0 ); ++ SMC_SET_RCR( RCR_CLEAR ); ++ SMC_SET_TCR( TCR_CLEAR ); ++ ++#ifdef POWER_DOWN ++ status = smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG); ++ status |= PHY_CNTL_PDN; ++ smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG); ++ ++ /* finally, shut the chip down */ ++ SMC_SELECT_BANK( 1 ); ++ SMC_SET_CONFIG( SMC_GET_CONFIG() & ~CONFIG_EPH_POWER_EN ); ++#endif ++} ++ ++/* This is the procedure to handle the receipt of a packet. */ ++static inline void ++smc_rcv(struct net_device *dev) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ unsigned long ioaddr = dev->base_addr; ++ unsigned int packet_number, status, packet_len; ++ ++ PRINTK3("%s: %s\n", dev->name, __FUNCTION__); ++ ++ packet_number = SMC_GET_RXFIFO(); ++ if (unlikely(packet_number & RXFIFO_REMPTY)) { ++ PRINTK("%s: smc_rcv with nothing on FIFO.\n", dev->name); ++ return; ++ } ++ ++ /* read from start of packet */ ++ SMC_SET_PTR( PTR_READ | PTR_RCV | PTR_AUTOINC ); ++ ++ /* First two words are status and packet length */ ++ SMC_GET_PKT_HDR(status, packet_len); ++ packet_len &= 0x07ff; /* mask off top bits */ ++ PRINTK2("%s: RX PNR 0x%x STATUS 0x%04x LENGTH 0x%04x (%d)\n", ++ dev->name, packet_number, status, ++ packet_len, packet_len); ++ ++ if (unlikely(status & RS_ERRORS)) { ++ lp->stats.rx_errors++; ++ if (status & RS_ALGNERR) ++ lp->stats.rx_frame_errors++; ++ if (status & (RS_TOOSHORT | RS_TOOLONG)) ++ lp->stats.rx_length_errors++; ++ if (status & RS_BADCRC) ++ lp->stats.rx_crc_errors++; ++ } else { ++ struct sk_buff *skb; ++ unsigned char *data; ++ unsigned int data_len; ++ ++ /* set multicast stats */ ++ if (status & RS_MULTICAST) ++ lp->stats.multicast++; ++ ++ /* ++ * Actual payload is packet_len - 4 (or 3 if odd byte). ++ * We want skb_reserve(2) and the final ctrl word ++ * (2 bytes, possibly containing the payload odd byte). ++ * Ence packet_len - 4 + 2 + 2. ++ */ ++ skb = dev_alloc_skb(packet_len); ++ if (unlikely(skb == NULL)) { ++ printk(KERN_NOTICE "%s: Low memory, packet dropped.\n", ++ dev->name); ++ lp->stats.rx_dropped++; ++ goto done; ++ } ++ ++ /* Align IP header to 32 bits */ ++ skb_reserve(skb, 2); ++ ++ /* BUG: the LAN91C111 rev A never sets this bit. Force it. */ ++ if (lp->version == 0x90) ++ status |= RS_ODDFRAME; ++ ++ /* ++ * If odd length: packet_len - 3, ++ * otherwise packet_len - 4. ++ */ ++ data_len = packet_len - ((status & RS_ODDFRAME) ? 3 : 4); ++ data = skb_put(skb, data_len); ++ SMC_PULL_DATA(data, packet_len - 2); ++ ++ PRINT_PKT(data, packet_len - 2); ++ ++ dev->last_rx = jiffies; ++ skb->dev = dev; ++ skb->protocol = eth_type_trans(skb, dev); ++ netif_rx(skb); ++ lp->stats.rx_packets++; ++ lp->stats.rx_bytes += data_len; ++ } ++ ++done: ++ SMC_WAIT_MMU_BUSY(); ++ SMC_SET_MMU_CMD( MC_RELEASE ); ++} ++ ++/* ++ * This is called to actually send a packet to the chip. ++ * Returns non-zero when successful. ++ */ ++static void ++smc_hardware_send_packet(struct net_device *dev) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ unsigned long ioaddr = dev->base_addr; ++ struct sk_buff *skb = lp->saved_skb; ++ unsigned int packet_no, len; ++ unsigned char *buf; ++ ++ PRINTK3("%s: %s\n", dev->name, __FUNCTION__); ++ ++ if (unlikely(!skb)) { ++ printk ("%s: In XMIT with no packet to send\n", dev->name); ++ return; ++ } ++ ++ packet_no = SMC_GET_AR(); ++ if (unlikely(packet_no & AR_FAILED)) { ++ printk("%s: Memory allocation failed.\n", dev->name); ++ lp->saved_skb = NULL; ++ lp->stats.tx_errors++; ++ lp->stats.tx_fifo_errors++; ++ dev_kfree_skb_any(skb); ++ return; ++ } ++ ++ /* point to the beginning of the packet */ ++ SMC_SET_PN( packet_no ); ++ SMC_SET_PTR( PTR_AUTOINC ); ++ ++ buf = skb->data; ++ len = skb->len; ++ PRINTK2("%s: TX PNR 0x%x lENGTH 0x%04x (%d) BUF 9x%p\n", ++ dev->name, packet_no, len, len, buf); ++ PRINT_PKT(buf, len); ++ ++ /* ++ * Send the packet length ( +6 for status words, length, and ctl. ++ * The card will pad to 64 bytes with zeroes if packet is too small. ++ */ ++ SMC_PUT_PKT_HDR(0, len + 6); ++ ++ /* send the actual data */ ++ SMC_PUSH_DATA(buf, len & ~1); ++ ++ /* Send final ctl word with the last byte if there is one */ ++ SMC_outw( ((len & 1) ? (0x2000 | buf[len-1]) : 0), ioaddr, DATA_REG ); ++ ++ /* and let the chipset deal with it */ ++ SMC_SET_MMU_CMD( MC_ENQUEUE ); ++ SMC_ACK_INT( IM_TX_EMPTY_INT ); ++ ++ dev->trans_start = jiffies; ++ dev_kfree_skb_any(skb); ++ lp->saved_skb = NULL; ++ lp->stats.tx_packets++; ++ lp->stats.tx_bytes += len; ++} ++ ++/* ++ . Since I am not sure if I will have enough room in the chip's ram ++ . to store the packet, I call this routine which either sends it ++ . now, or set the card to generates an interrupt when ready ++ . for the packet. ++ */ ++static int ++smc_hard_start_xmit( struct sk_buff * skb, struct net_device * dev ) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ unsigned long ioaddr = dev->base_addr; ++ unsigned int numPages, poll_count, status, saved_bank; ++ ++ PRINTK3("%s: %s\n", dev->name, __FUNCTION__); ++ ++ if (unlikely(lp->saved_skb != NULL)) { ++ /* THIS SHOULD NEVER HAPPEN. */ ++ printk( KERN_CRIT ++ "%s: Bad Craziness - sent packet while busy.\n", ++ dev->name ); ++ lp->stats.tx_errors++; ++ lp->stats.tx_aborted_errors++; ++ return 1; ++ } ++ lp->saved_skb = skb; ++ ++ /* ++ ** The MMU wants the number of pages to be the number of 256 bytes ++ ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) ) ++ ** ++ ** The 91C111 ignores the size bits, but the code is left intact ++ ** for backwards and future compatibility. ++ ** ++ ** Pkt size for allocating is data length +6 (for additional status ++ ** words, length and ctl!) ++ ** ++ ** If odd size then last byte is included in ctl word. ++ */ ++ numPages = ((skb->len & ~1) + (6 - 1)) >> 8; ++ if (unlikely(numPages > 7)) { ++ printk("%s: Far too big packet error.\n", dev->name); ++ lp->saved_skb = NULL; ++ lp->stats.tx_errors++; ++ lp->stats.tx_dropped++; ++ dev_kfree_skb(skb); ++ return 0; ++ } ++ ++ /* now, try to allocate the memory */ ++ saved_bank = SMC_CURRENT_BANK(); ++ SMC_SELECT_BANK( 2 ); ++ SMC_SET_MMU_CMD( MC_ALLOC | numPages ); ++ ++ /* ++ * Poll the chip for a short amount of time in case the ++ * allocation succeeds quickly. ++ */ ++ poll_count = MEMORY_WAIT_TIME; ++ do { ++ status = SMC_GET_INT(); ++ if (status & IM_ALLOC_INT) { ++ SMC_ACK_INT( IM_ALLOC_INT ); ++ break; ++ } ++ } while (--poll_count); ++ ++ if (!poll_count) { ++ /* oh well, wait until the chip finds memory later */ ++ netif_stop_queue(dev); ++ PRINTK2("%s: TX memory allocation deferred.\n", dev->name); ++ SMC_ENABLE_INT( IM_ALLOC_INT ); ++ } else { ++ /* Send current packet immediately.. */ ++#if THROTTLE_TX_PKTS ++ netif_stop_queue(dev); ++#endif ++ smc_hardware_send_packet(dev); ++ SMC_ENABLE_INT( IM_TX_INT | IM_TX_EMPTY_INT ); ++ } ++ ++ SMC_SELECT_BANK( saved_bank ); ++ return 0; ++} ++ ++/* ++ . This handles a TX interrupt, which is only called when an error ++ . relating to a packet is sent or CTL_AUTO_RELEASE is not set. ++*/ ++static void ++smc_tx(struct net_device *dev) ++{ ++ unsigned long ioaddr = dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ unsigned int saved_packet, packet_no, tx_status, pkt_len; ++ ++ PRINTK3("%s: %s\n", dev->name, __FUNCTION__); ++ ++ /* If the TX FIFO is empty then nothing to do */ ++ packet_no = SMC_GET_TXFIFO(); ++ if (unlikely(packet_no & TXFIFO_TEMPTY)) { ++ PRINTK("%s: smc_tx with nothing on FIFO.\n", dev->name); ++ return; ++ } ++ ++ /* select packet to read from */ ++ saved_packet = SMC_GET_PN(); ++ SMC_SET_PN( packet_no ); ++ ++ /* read the first word (status word) from this packet */ ++ SMC_SET_PTR( PTR_AUTOINC | PTR_READ ); ++ SMC_GET_PKT_HDR(tx_status, pkt_len); ++ PRINTK2("%s: TX STATUS 0x%04x PNR 0x%02x\n", ++ dev->name, tx_status, packet_no); ++ ++ if (!(tx_status & TS_SUCCESS)) ++ lp->stats.tx_errors++; ++ if (tx_status & TS_LOSTCAR) ++ lp->stats.tx_carrier_errors++; ++ if (tx_status & TS_LATCOL) { ++ printk( KERN_DEBUG ++ "%s: Late collision occurred on last xmit.\n", ++ dev->name); ++ lp->stats.tx_window_errors++; ++ } ++ ++ /* kill the packet */ ++ SMC_WAIT_MMU_BUSY(); ++ SMC_SET_MMU_CMD( MC_FREEPKT ); ++ ++ /* Don't restore Packet Number Reg until busy bit is cleared */ ++ SMC_WAIT_MMU_BUSY(); ++ SMC_SET_PN( saved_packet ); ++ ++ /* re-enable transmit */ ++ SMC_SELECT_BANK( 0 ); ++ SMC_SET_TCR( lp->tcr_cur_mode ); ++ SMC_SELECT_BANK( 2 ); ++} ++ ++ ++//---PHY CONTROL AND CONFIGURATION----------------------------------------- ++ ++/*------------------------------------------------------------ ++ . Debugging function for viewing MII Management serial bitstream ++ .-------------------------------------------------------------*/ ++#if SMC_DEBUG > 3 ++static void ++PRINT_MII_STREAM(u_char *bits, int size) ++{ ++ int i; ++ ++ printk("BIT#:"); ++ for (i = 0; i < size; ++i) ++ printk("%d", i%10); ++ ++ printk("\nMDOE:"); ++ for (i = 0; i < size; ++i) { ++ if (bits[i] & MII_MDOE) ++ printk("1"); ++ else ++ printk("0"); ++ } ++ ++ printk("\nMDO :"); ++ for (i = 0; i < size; ++i) { ++ if (bits[i] & MII_MDO) ++ printk("1"); ++ else ++ printk("0"); ++ } ++ ++ printk("\nMDI :"); ++ for (i = 0; i < size; ++i) { ++ if (bits[i] & MII_MDI) ++ printk("1"); ++ else ++ printk("0"); ++ } ++ ++ printk("\n"); ++} ++#else ++#define PRINT_MII_STREAM(x...) ++#endif ++ ++/*------------------------------------------------------------ ++ . Reads a register from the MII Management serial interface ++ .-------------------------------------------------------------*/ ++static int ++smc_read_phy_register(unsigned long ioaddr, int phyaddr, int phyreg) ++{ ++ int oldBank; ++ int i, mask, mii_reg; ++ u_char bits[64]; ++ int input_idx, phydata; ++ int clk_idx = 0; ++ ++ // 32 consecutive ones on MDO to establish sync ++ for (i = 0; i < 32; ++i) ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ ++ // Start code <01> ++ bits[clk_idx++] = MII_MDOE; ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ ++ // Read command <10> ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ bits[clk_idx++] = MII_MDOE; ++ ++ // Output the PHY address, msb first ++ mask = 0x10; ++ for (i = 0; i < 5; ++i) { ++ if (phyaddr & mask) ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ else ++ bits[clk_idx++] = MII_MDOE; ++ ++ // Shift to next lowest bit ++ mask >>= 1; ++ } ++ ++ // Output the phy register number, msb first ++ mask = 0x10; ++ for (i = 0; i < 5; ++i) { ++ if (phyreg & mask) ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ else ++ bits[clk_idx++] = MII_MDOE; ++ ++ // Shift to next lowest bit ++ mask >>= 1; ++ } ++ ++ // Tristate and turnaround (2 bit times) ++ bits[clk_idx++] = 0; ++ //bits[clk_idx++] = 0; ++ ++ // Input starts at this bit time ++ input_idx = clk_idx; ++ ++ // Will input 16 bits ++ for (i = 0; i < 16; ++i) ++ bits[clk_idx++] = 0; ++ ++ // Final clock bit ++ bits[clk_idx++] = 0; ++ ++ // Save the current bank ++ oldBank = SMC_CURRENT_BANK(); ++ ++ // Select bank 3 ++ SMC_SELECT_BANK( 3 ); ++ ++ // Get the current MII register value ++ mii_reg = SMC_GET_MII(); ++ ++ // Turn off all MII Interface bits ++ mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO); ++ ++ // Clock all 64 cycles ++ for (i = 0; i < sizeof bits; ++i) { ++ // Clock Low - output data ++ SMC_SET_MII( mii_reg | bits[i] ); ++ udelay(50); ++ ++ // Clock Hi - input data ++ SMC_SET_MII( mii_reg | bits[i] | MII_MCLK ); ++ udelay(50); ++ bits[i] |= SMC_GET_MII() & MII_MDI; ++ } ++ ++ // Return to idle state ++ // Set clock to low, data to low, and output tristated ++ SMC_SET_MII( mii_reg ); ++ udelay(50); ++ ++ // Restore original bank select ++ SMC_SELECT_BANK( oldBank ); ++ ++ // Recover input data ++ phydata = 0; ++ for (i = 0; i < 16; ++i) { ++ phydata <<= 1; ++ ++ if (bits[input_idx++] & MII_MDI) ++ phydata |= 0x0001; ++ } ++ ++ PRINTK3("%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", ++ __FUNCTION__, phyaddr, phyreg, phydata); ++ PRINT_MII_STREAM(bits, sizeof(bits)); ++ ++ return phydata; ++} ++ ++/*------------------------------------------------------------ ++ . Writes a register to the MII Management serial interface ++ .-------------------------------------------------------------*/ ++static void ++smc_write_phy_register( unsigned long ioaddr, int phyaddr, ++ int phyreg, int phydata ) ++{ ++ int oldBank; ++ int i, mask, mii_reg; ++ u_char bits[65]; ++ int clk_idx = 0; ++ ++ // 32 consecutive ones on MDO to establish sync ++ for (i = 0; i < 32; ++i) ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ ++ // Start code <01> ++ bits[clk_idx++] = MII_MDOE; ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ ++ // Write command <01> ++ bits[clk_idx++] = MII_MDOE; ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ ++ // Output the PHY address, msb first ++ mask = 0x10; ++ for (i = 0; i < 5; ++i) { ++ if (phyaddr & mask) ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ else ++ bits[clk_idx++] = MII_MDOE; ++ ++ // Shift to next lowest bit ++ mask >>= 1; ++ } ++ ++ // Output the phy register number, msb first ++ mask = 0x10; ++ for (i = 0; i < 5; ++i) { ++ if (phyreg & mask) ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ else ++ bits[clk_idx++] = MII_MDOE; ++ ++ // Shift to next lowest bit ++ mask >>= 1; ++ } ++ ++ // Tristate and turnaround (2 bit times) ++ bits[clk_idx++] = 0; ++ bits[clk_idx++] = 0; ++ ++ // Write out 16 bits of data, msb first ++ mask = 0x8000; ++ for (i = 0; i < 16; ++i) { ++ if (phydata & mask) ++ bits[clk_idx++] = MII_MDOE | MII_MDO; ++ else ++ bits[clk_idx++] = MII_MDOE; ++ ++ // Shift to next lowest bit ++ mask >>= 1; ++ } ++ ++ // Final clock bit (tristate) ++ bits[clk_idx++] = 0; ++ ++ // Save the current bank ++ oldBank = SMC_CURRENT_BANK(); ++ ++ // Select bank 3 ++ SMC_SELECT_BANK( 3 ); ++ ++ // Get the current MII register value ++ mii_reg = SMC_GET_MII(); ++ ++ // Turn off all MII Interface bits ++ mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO); ++ ++ // Clock all cycles ++ for (i = 0; i < sizeof bits; ++i) { ++ // Clock Low - output data ++ SMC_SET_MII( mii_reg | bits[i] ); ++ udelay(50); ++ ++ // Clock Hi - input data ++ SMC_SET_MII( mii_reg | bits[i] | MII_MCLK ); ++ udelay(50); ++ bits[i] |= SMC_GET_MII() & MII_MDI; ++ } ++ ++ // Return to idle state ++ // Set clock to low, data to low, and output tristated ++ SMC_SET_MII( mii_reg ); ++ udelay(50); ++ ++ // Restore original bank select ++ SMC_SELECT_BANK( oldBank ); ++ ++ PRINTK3("%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n", ++ __FUNCTION__, phyaddr, phyreg, phydata); ++ PRINT_MII_STREAM(bits, sizeof(bits)); ++} ++ ++ ++/*------------------------------------------------------------ ++ . Finds and reports the PHY address ++ .-------------------------------------------------------------*/ ++static int smc_detect_phy(struct net_device* dev) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ unsigned long ioaddr = dev->base_addr; ++ int phy_id1, phy_id2; ++ int phyaddr; ++ int found = 0; ++ ++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__); ++ ++ // Scan all 32 PHY addresses if necessary ++ for (phyaddr = 0; phyaddr < 32; ++phyaddr) { ++ // Read the PHY identifiers ++ phy_id1 = smc_read_phy_register(ioaddr, phyaddr, PHY_ID1_REG); ++ phy_id2 = smc_read_phy_register(ioaddr, phyaddr, PHY_ID2_REG); ++ ++ PRINTK3("%s: phy_id1=0x%x, phy_id2=0x%x\n", ++ dev->name, phy_id1, phy_id2); ++ ++ // Make sure it is a valid identifier ++ if ((phy_id2 > 0x0000) && (phy_id2 < 0xffff) && ++ (phy_id1 > 0x0000) && (phy_id1 < 0xffff)) { ++ if ((phy_id1 != 0x8000) && (phy_id2 != 0x8000)) { ++ // Save the PHY's address ++ lp->phyaddr = phyaddr; ++ found = 1; ++ break; ++ } ++ } ++ } ++ ++ if (!found) { ++ PRINTK("%s: No PHY found\n", dev->name); ++ return(0); ++ } ++ ++ // Set the PHY type ++ if ( (phy_id1 == 0x0016) && ((phy_id2 & 0xFFF0) == 0xF840 ) ) { ++ lp->phytype = PHY_LAN83C183; ++ PRINTK("%s: PHY=LAN83C183 (LAN91C111 Internal)\n", dev->name); ++ } ++ ++ if ( (phy_id1 == 0x0282) && ((phy_id2 & 0xFFF0) == 0x1C50) ) { ++ lp->phytype = PHY_LAN83C180; ++ PRINTK("%s: PHY=LAN83C180\n", dev->name); ++ } ++ ++ return 1; ++} ++ ++/*------------------------------------------------------------ ++ . Waits the specified number of milliseconds - kernel friendly ++ .-------------------------------------------------------------*/ ++static void ++smc_wait_ms(unsigned int ms) ++{ ++ if (!in_interrupt()) { ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ schedule_timeout(1 + ms * HZ / 1000); ++ } else { ++ /* if this happens it must be fixed */ ++ printk( KERN_WARNING "%s: busy wait while in interrupt!\n", ++ __FUNCTION__); ++ mdelay(ms); ++ } ++} ++ ++/*------------------------------------------------------------ ++ . Sets the PHY to a configuration as determined by the user ++ .-------------------------------------------------------------*/ ++static int ++smc_phy_fixed(struct net_device *dev) ++{ ++ unsigned long ioaddr = dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ int phyaddr = lp->phyaddr; ++ int my_fixed_caps, cfg1; ++ ++ PRINTK3("%s: %s\n", dev->name, __FUNCTION__); ++ ++ // Enter Link Disable state ++ cfg1 = smc_read_phy_register(ioaddr, phyaddr, PHY_CFG1_REG); ++ cfg1 |= PHY_CFG1_LNKDIS; ++ smc_write_phy_register(ioaddr, phyaddr, PHY_CFG1_REG, cfg1); ++ ++ // Set our fixed capabilities ++ // Disable auto-negotiation ++ my_fixed_caps = 0; ++ ++ if (lp->ctl_rfduplx) ++ my_fixed_caps |= PHY_CNTL_DPLX; ++ ++ if (lp->ctl_rspeed == 100) ++ my_fixed_caps |= PHY_CNTL_SPEED; ++ ++ // Write our capabilities to the phy control register ++ smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, my_fixed_caps); ++ ++ // Re-Configure the Receive/Phy Control register ++ SMC_SET_RPC( lp->rpc_cur_mode ); ++ ++ // Success ++ return(1); ++} ++ ++/*------------------------------------------------------------ ++ . Configures the specified PHY through the MII management interface ++ . using Autonegotiation. ++ . Calls smc_phy_fixed() if the user has requested a certain config. ++ .-------------------------------------------------------------*/ ++static void ++smc_phy_configure(struct net_device* dev) ++{ ++ unsigned long ioaddr = dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ int timeout; ++ int phyaddr; ++ int my_phy_caps; // My PHY capabilities ++ int my_ad_caps; // My Advertised capabilities ++ int status; ++ ++ PRINTK3("%s:smc_program_phy()\n", dev->name); ++ ++ // Set the blocking flag ++ lp->autoneg_active = 1; ++ ++ // Find the address and type of our phy ++ if (!smc_detect_phy(dev)) ++ goto smc_phy_configure_exit; ++ ++ // Get the detected phy address ++ phyaddr = lp->phyaddr; ++ ++ // Reset the PHY, setting all other bits to zero ++ smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, PHY_CNTL_RST); ++ ++ // Wait for the reset to complete, or time out ++ timeout = 6; // Wait up to 3 seconds ++ while (timeout--) { ++ if (!(smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG) ++ & PHY_CNTL_RST)) ++ // reset complete ++ break; ++ smc_wait_ms(500); // wait 500 millisecs ++ if (signal_pending(current)) { // Exit anyway if signaled ++ PRINTK("%s: PHY reset interrupted by signal\n", ++ dev->name); ++ timeout = 0; ++ break; ++ } ++ } ++ ++ if (timeout < 1) { ++ printk("%s: PHY reset timed out\n", dev->name); ++ goto smc_phy_configure_exit; ++ } ++ ++ // Read PHY Register 18, Status Output ++ lp->lastPhy18 = smc_read_phy_register(ioaddr, phyaddr, PHY_INT_REG); ++ ++ // Enable PHY Interrupts (for register 18) ++ // Interrupts listed here are disabled ++ smc_write_phy_register(ioaddr, phyaddr, PHY_MASK_REG, ++ PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD | ++ PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB | ++ PHY_INT_SPDDET | PHY_INT_DPLXDET); ++ ++ /* Configure the Receive/Phy Control register */ ++ SMC_SELECT_BANK( 0 ); ++ SMC_SET_RPC( lp->rpc_cur_mode ); ++ ++ // Copy our capabilities from PHY_STAT_REG to PHY_AD_REG ++ my_phy_caps = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG); ++ ++ // If the user requested no auto neg, then go set his request ++ if (!(lp->ctl_autoneg)) { ++ smc_phy_fixed(dev); ++ goto smc_phy_configure_exit; ++ } ++ ++ if( !( my_phy_caps & PHY_STAT_CAP_ANEG)) ++ { ++ printk(KERN_INFO "Auto negotiation NOT supported\n"); ++ smc_phy_fixed(dev); ++ goto smc_phy_configure_exit; ++ } ++ ++ my_ad_caps = PHY_AD_CSMA; // I am CSMA capable ++ ++ if (my_phy_caps & PHY_STAT_CAP_T4) ++ my_ad_caps |= PHY_AD_T4; ++ ++ if (my_phy_caps & PHY_STAT_CAP_TXF) ++ my_ad_caps |= PHY_AD_TX_FDX; ++ ++ if (my_phy_caps & PHY_STAT_CAP_TXH) ++ my_ad_caps |= PHY_AD_TX_HDX; ++ ++ if (my_phy_caps & PHY_STAT_CAP_TF) ++ my_ad_caps |= PHY_AD_10_FDX; ++ ++ if (my_phy_caps & PHY_STAT_CAP_TH) ++ my_ad_caps |= PHY_AD_10_HDX; ++ ++ // Disable capabilities not selected by our user ++ if (lp->ctl_rspeed != 100) ++ my_ad_caps &= ~(PHY_AD_T4|PHY_AD_TX_FDX|PHY_AD_TX_HDX); ++ ++ if (!lp->ctl_rfduplx) ++ my_ad_caps &= ~(PHY_AD_TX_FDX|PHY_AD_10_FDX); ++ ++ // Update our Auto-Neg Advertisement Register ++ smc_write_phy_register(ioaddr, phyaddr, PHY_AD_REG, my_ad_caps); ++ ++ // Read the register back. Without this, it appears that when ++ // auto-negotiation is restarted, sometimes it isn't ready and ++ // the link does not come up. ++ status = smc_read_phy_register(ioaddr, phyaddr, PHY_AD_REG); ++ ++ PRINTK2("%s: phy caps=%x\n", dev->name, my_phy_caps); ++ PRINTK2("%s: phy advertised caps=%x\n", dev->name, my_ad_caps); ++ ++ // Restart auto-negotiation process in order to advertise my caps ++ smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG, ++ PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST ); ++ ++ // Wait for the auto-negotiation to complete. This may take from ++ // 2 to 3 seconds. ++ // Wait for the reset to complete, or time out ++ timeout = 20; // Wait up to 10 seconds ++ while (timeout--) { ++ status = smc_read_phy_register(ioaddr, phyaddr, PHY_RMT_REG); ++ if (status & PHY_AD_ACK) ++ // auto-negotiate complete ++ break; ++ ++ smc_wait_ms(500); // wait 500 millisecs ++ if (signal_pending(current)) { // Exit anyway if signaled ++ printk(KERN_DEBUG ++ "%s: PHY auto-negotiate interrupted by signal\n", ++ dev->name); ++ timeout = 0; ++ break; ++ } ++ } ++ status = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG); ++ ++ if (timeout < 1) { ++ PRINTK("%s: PHY auto-negotiate timed out\n", dev->name); ++ } ++ ++ // Fail if we detected an auto-negotiate remote fault ++ if (status & PHY_STAT_REM_FLT) { ++ PRINTK("%s: PHY remote fault detected\n", dev->name); ++ } ++ ++ // Wait for link. Once the link is up, phy18 should be up to date ++ timeout = 200; ++ do ++ { ++ udelay(100); ++ status = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG); ++ } while ( ((status & PHY_STAT_LINK)==0) && --timeout); ++ ++ if (status & PHY_STAT_LINK) ++ { ++ PRINTK("%s: Ethernet Link Detected\n", dev->name); ++ } ++ ++ // The smc_phy_interrupt() routine will be called to update lastPhy18 ++ ++ // Set our sysctl parameters to match auto-negotiation results ++ if ( lp->lastPhy18 & PHY_INT_SPDDET ) { ++ PRINTK("%s: PHY 100BaseT\n", dev->name); ++ lp->rpc_cur_mode |= RPC_SPEED; ++ } else { ++ PRINTK("%s: PHY 10BaseT\n", dev->name); ++ lp->rpc_cur_mode &= ~RPC_SPEED; ++ } ++ ++ if ( lp->lastPhy18 & PHY_INT_DPLXDET ) { ++ PRINTK("%s: PHY Full Duplex\n", dev->name); ++ lp->rpc_cur_mode |= RPC_DPLX; ++ lp->tcr_cur_mode |= TCR_SWFDUP; ++ } else { ++ PRINTK("%s: PHY Half Duplex\n", dev->name); ++ lp->rpc_cur_mode &= ~RPC_DPLX; ++ lp->tcr_cur_mode &= ~TCR_SWFDUP; ++ } ++ ++ // Re-Configure the Receive/Phy Control register and TCR ++ SMC_SET_RPC( lp->rpc_cur_mode ); ++ SMC_SET_TCR( lp->tcr_cur_mode ); ++ ++smc_phy_configure_exit: ++ // Exit auto-negotiation ++ lp->autoneg_active = 0; ++} ++ ++/************************************************************************* ++ . smc_phy_interrupt ++ . ++ . Purpose: Handle interrupts relating to PHY register 18. This is ++ . called from the "hard" interrupt handler. ++ . ++ ************************************************************************/ ++static void ++smc_phy_interrupt(struct net_device* dev) ++{ ++ unsigned long ioaddr = dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ int phyaddr = lp->phyaddr; ++ int phy18; ++ ++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__); ++ ++ for(;;) { ++ // Read PHY Register 18, Status Output ++ phy18 = smc_read_phy_register(ioaddr, phyaddr, PHY_INT_REG); ++ ++ // Exit if not more changes ++ if (phy18 == lp->lastPhy18) ++ break; ++ ++#if SMC_DEBUG > 1 ++ PRINTK2("%s: phy18=0x%04x\n", dev->name, phy18); ++ PRINTK2("%s: lastPhy18=0x%04x\n", dev->name, lp->lastPhy18); ++ ++ // Handle events ++ if ((phy18 & PHY_INT_LNKFAIL) != ++ (lp->lastPhy18 & PHY_INT_LNKFAIL)) ++ PRINTK2("%s: PHY Link Fail=%x\n", dev->name, ++ phy18 & PHY_INT_LNKFAIL); ++ ++ if ((phy18 & PHY_INT_LOSSSYNC) != ++ (lp->lastPhy18 & PHY_INT_LOSSSYNC)) ++ PRINTK2("%s: PHY LOSS SYNC=%x\n", dev->name, ++ phy18 & PHY_INT_LOSSSYNC); ++ ++ if ((phy18 & PHY_INT_CWRD) != (lp->lastPhy18 & PHY_INT_CWRD)) ++ PRINTK2("%s: PHY INVALID 4B5B code=%x\n", dev->name, ++ phy18 & PHY_INT_CWRD); ++ ++ if ((phy18 & PHY_INT_SSD) != (lp->lastPhy18 & PHY_INT_SSD)) ++ PRINTK2("%s: PHY No Start Of Stream=%x\n", dev->name, ++ phy18 & PHY_INT_SSD); ++ ++ if ((phy18 & PHY_INT_ESD) != (lp->lastPhy18 & PHY_INT_ESD)) ++ ++ PRINTK2("%s: PHY No End Of Stream=%x\n", dev->name, ++ phy18 & PHY_INT_ESD); ++ ++ if ((phy18 & PHY_INT_RPOL) != (lp->lastPhy18 & PHY_INT_RPOL)) ++ PRINTK2("%s: PHY Reverse Polarity Detected=%x\n", ++ dev->name, phy18 & PHY_INT_RPOL); ++ ++ if ((phy18 & PHY_INT_JAB) != (lp->lastPhy18 & PHY_INT_JAB)) ++ PRINTK2("%s: PHY Jabber Detected=%x\n", dev->name, ++ phy18 & PHY_INT_JAB); ++ ++ if ((phy18 & PHY_INT_SPDDET) != ++ (lp->lastPhy18 & PHY_INT_SPDDET)) ++ PRINTK2("%s: PHY Speed Detect=%x\n", dev->name, ++ phy18 & PHY_INT_SPDDET); ++ ++ if ((phy18 & PHY_INT_DPLXDET) != ++ (lp->lastPhy18 & PHY_INT_DPLXDET)) ++ PRINTK2("%s: PHY Duplex Detect=%x\n", dev->name, ++ phy18 & PHY_INT_DPLXDET); ++#endif ++ // Update the last phy 18 variable ++ lp->lastPhy18 = phy18; ++ } ++} ++ ++//--- END PHY CONTROL AND CONFIGURATION------------------------------------- ++ ++ ++/* ++ * This is the main routine of the driver, to handle the device when ++ * it needs some attention. ++ */ ++static void ++smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ struct net_device *dev = dev_id; ++ unsigned long ioaddr = dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ int status, mask, timeout, card_stats; ++ int saved_bank, saved_pointer; ++ ++ PRINTK3("%s: %s\n", dev->name, __FUNCTION__); ++ ++ saved_bank = SMC_CURRENT_BANK(); ++ SMC_SELECT_BANK(2); ++ saved_pointer = SMC_GET_PTR(); ++ mask = SMC_GET_INT_MASK(); ++ SMC_SET_INT_MASK( 0 ); ++ ++ /* set a timeout value, so I don't stay here forever */ ++ timeout = 8; ++ ++ do { ++ status = SMC_GET_INT(); ++ ++ PRINTK2("%s: IRQ 0x%02x MASK 0x%02x MEM 0x%04x FIFO 0x%04x\n", ++ dev->name, status, mask, ++ ({ int meminfo; SMC_SELECT_BANK(0); ++ meminfo = SMC_GET_MIR(); ++ SMC_SELECT_BANK(2); meminfo; }), ++ SMC_GET_FIFO()); ++ ++ status &= mask; ++ if (!status) ++ break; ++ ++ if (status & IM_RCV_INT) { ++ PRINTK3("%s: RX irq\n", dev->name); ++ smc_rcv(dev); ++ } else if (status & IM_TX_INT) { ++ PRINTK3("%s: TX int\n", dev->name); ++ smc_tx(dev); ++ SMC_ACK_INT( IM_TX_INT ); ++#if THROTTLE_TX_PKTS ++ netif_wake_queue(dev); ++#endif ++ } else if (status & IM_ALLOC_INT) { ++ PRINTK3("%s: Allocation irq\n", dev->name); ++ smc_hardware_send_packet(dev); ++ mask |= (IM_TX_INT | IM_TX_EMPTY_INT); ++ mask &= ~IM_ALLOC_INT; ++#if ! THROTTLE_TX_PKTS ++ netif_wake_queue(dev); ++#endif ++ } else if (status & IM_TX_EMPTY_INT) { ++ PRINTK3("%s: TX empty\n", dev->name); ++ mask &= ~IM_TX_EMPTY_INT; ++ ++ /* update stats */ ++ SMC_SELECT_BANK( 0 ); ++ card_stats = SMC_GET_COUNTER(); ++ SMC_SELECT_BANK( 2 ); ++ ++ /* single collisions */ ++ lp->stats.collisions += card_stats & 0xF; ++ card_stats >>= 4; ++ ++ /* multiple collisions */ ++ lp->stats.collisions += card_stats & 0xF; ++ } else if (status & IM_RX_OVRN_INT) { ++ PRINTK1( "%s: RX overrun\n", dev->name); ++ SMC_ACK_INT( IM_RX_OVRN_INT ); ++ lp->stats.rx_errors++; ++ lp->stats.rx_fifo_errors++; ++ } else if (status & IM_EPH_INT) { ++ PRINTK("%s: UNSUPPORTED: EPH INTERRUPT\n", dev->name); ++ } else if (status & IM_MDINT) { ++ SMC_ACK_INT( IM_MDINT ); ++ smc_phy_interrupt(dev); ++ } else if (status & IM_ERCV_INT ) { ++ SMC_ACK_INT( IM_ERCV_INT ); ++ PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT \n", dev->name); ++ } ++ } while (--timeout); ++ ++ /* restore register states */ ++ SMC_SET_INT_MASK( mask ); ++ SMC_SET_PTR( saved_pointer ); ++ SMC_SELECT_BANK( saved_bank ); ++ ++ PRINTK3("%s: Interrupt done\n", dev->name); ++} ++ ++/* Our watchdog timed out. Called by the networking layer */ ++static void ++smc_timeout(struct net_device *dev) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ ++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__); ++ ++ smc_reset(dev); ++ smc_enable(dev); ++ ++#if 0 ++ /* Reconfiguring the PHY doesn't seem like a bad idea here, but ++ * it introduced a problem. Now that this is a timeout routine, ++ * we are getting called from within an interrupt context. ++ * smc_phy_configure() calls smc_wait_ms() which calls ++ * schedule_timeout() which calls schedule(). When schedule() ++ * is called from an interrupt context, it prints out ++ * "Scheduling in interrupt" and then calls BUG(). This is ++ * obviously not desirable. This was worked around by removing ++ * the call to smc_phy_configure() here because it didn't seem ++ * absolutely necessary. Ultimately, if smc_wait_ms() is ++ * supposed to be usable from an interrupt context (which it ++ * looks like it thinks it should handle), it should be fixed. ++ */ ++ /* Reconfigure the PHY */ ++ smc_phy_configure(dev); ++#endif ++ ++ /* clear anything saved */ ++ if (lp->saved_skb != NULL) { ++ dev_kfree_skb (lp->saved_skb); ++ lp->saved_skb = NULL; ++ lp->stats.tx_errors++; ++ lp->stats.tx_aborted_errors++; ++ } ++ dev->trans_start = jiffies; ++ netif_wake_queue(dev); ++} ++ ++/* ++ * Finds the CRC32 of a set of bytes. ++ * (from Peter Cammaert's code) ++ */ ++static int ++crc32(char *s, int length) ++{ ++ /* indices */ ++ int perByte; ++ int perBit; ++ /* crc polynomial for Ethernet */ ++ const unsigned long poly = 0xedb88320; ++ /* crc value - preinitialized to all 1's */ ++ unsigned long crc_value = 0xffffffff; ++ ++ for ( perByte = 0; perByte < length; perByte ++ ) { ++ unsigned char c; ++ ++ c = *(s++); ++ for ( perBit = 0; perBit < 8; perBit++ ) { ++ crc_value = (crc_value>>1)^ ++ (((crc_value^c)&0x01)?poly:0); ++ c >>= 1; ++ } ++ } ++ return crc_value; ++} ++ ++/* ++ . This sets the internal hardware table to filter out unwanted multicast ++ . packets before they take up memory. ++ . ++ . The SMC chip uses a hash table where the high 6 bits of the CRC of ++ . address are the offset into the table. If that bit is 1, then the ++ . multicast packet is accepted. Otherwise, it's dropped silently. ++ . ++ . To use the 6 bits as an offset into the table, the high 3 bits are the ++ . number of the 8 bit register, while the low 3 bits are the bit within ++ . that register. ++ . ++ . This routine is based very heavily on the one provided by Peter Cammaert. ++*/ ++static void ++smc_setmulticast(unsigned long ioaddr, int count, struct dev_mc_list *addrs) ++{ ++ int i; ++ unsigned char multicast_table[ 8 ]; ++ struct dev_mc_list *cur_addr; ++ ++ /* table for flipping the order of 3 bits */ ++ static unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 }; ++ ++ /* start with a table of all zeros: reject all */ ++ memset( multicast_table, 0, sizeof( multicast_table ) ); ++ ++ cur_addr = addrs; ++ for ( i = 0; i < count ; i ++, cur_addr = cur_addr->next ) { ++ int position; ++ ++ /* do we have a pointer here? */ ++ if ( !cur_addr ) ++ break; ++ /* make sure this is a multicast address - shouldn't this ++ be a given if we have it here ? */ ++ if ( !( *cur_addr->dmi_addr & 1 ) ) ++ continue; ++ ++ /* only use the low order bits */ ++ position = crc32( cur_addr->dmi_addr, 6 ) & 0x3f; ++ ++ /* do some messy swapping to put the bit in the right spot */ ++ multicast_table[invert3[position&7]] |= ++ (1<<invert3[(position>>3)&7]); ++ ++ } ++ /* now, the table can be loaded into the chipset */ ++ SMC_SELECT_BANK( 3 ); ++ SMC_SET_MCAST( multicast_table ); ++} ++ ++/* ++ . This routine will, depending on the values passed to it, ++ . either make it accept multicast packets, go into ++ . promiscuous mode ( for TCPDUMP and cousins ) or accept ++ . a select set of multicast packets ++*/ ++static void smc_set_multicast_list(struct net_device *dev) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ unsigned long ioaddr = dev->base_addr; ++ ++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__); ++ ++ SMC_SELECT_BANK(0); ++ if ( dev->flags & IFF_PROMISC ) { ++ PRINTK2("%s: RCR_PRMS\n", dev->name); ++ lp->rcr_cur_mode |= RCR_PRMS; ++ SMC_SET_RCR( lp->rcr_cur_mode ); ++ } ++ ++/* BUG? I never disable promiscuous mode if multicasting was turned on. ++ Now, I turn off promiscuous mode, but I don't do anything to multicasting ++ when promiscuous mode is turned on. ++*/ ++ ++ /* Here, I am setting this to accept all multicast packets. ++ I don't need to zero the multicast table, because the flag is ++ checked before the table is ++ */ ++ else if (dev->flags & IFF_ALLMULTI) { ++ lp->rcr_cur_mode |= RCR_ALMUL; ++ SMC_SET_RCR( lp->rcr_cur_mode ); ++ PRINTK2("%s: RCR_ALMUL\n", dev->name); ++ } ++ ++ /* We just get all multicast packets even if we only want them ++ . from one source. This will be changed at some future ++ . point. */ ++ else if (dev->mc_count ) { ++ /* support hardware multicasting */ ++ ++ /* be sure I get rid of flags I might have set */ ++ lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL); ++ SMC_SET_RCR( lp->rcr_cur_mode ); ++ /* NOTE: this has to set the bank, so make sure it is the ++ last thing called. The bank is set to zero at the top */ ++ smc_setmulticast( ioaddr, dev->mc_count, dev->mc_list ); ++ } else { ++ PRINTK2("%s: ~(RCR_PRMS|RCR_ALMUL)\n", dev->name); ++ lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL); ++ SMC_SET_RCR( lp->rcr_cur_mode ); ++ ++ /* ++ since I'm disabling all multicast entirely, I need to ++ clear the multicast list ++ */ ++ SMC_SELECT_BANK( 3 ); ++ SMC_CLEAR_MCAST(); ++ } ++} ++ ++ ++/* ++ * Open and Initialize the board ++ * ++ * Set up everything, reset the card, etc .. ++ */ ++static int ++smc_open(struct net_device *dev) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ unsigned long ioaddr = dev->base_addr; ++ ++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__); ++ ++ /* clear out all the junk that was put here before... */ ++ memset(dev->priv, 0, sizeof(struct smc_local)); ++ ++ // Setup the default Register Modes ++ lp->tcr_cur_mode = TCR_DEFAULT; ++ lp->rcr_cur_mode = RCR_DEFAULT; ++ lp->rpc_cur_mode = RPC_DEFAULT; ++ ++ /* Set default parameters */ ++#ifdef CONFIG_ARCH_RAMSES ++ lp->ctl_autoneg = 0; ++ lp->ctl_rfduplx = 0; ++ lp->ctl_rspeed = 10; ++#else ++ lp->ctl_autoneg = 1; ++ lp->ctl_rfduplx = 1; ++ lp->ctl_rspeed = 100; ++#endif ++ ++ SMC_SELECT_BANK(3); ++ lp->version = SMC_GET_REV() & 0xff; ++ ++ /* reset the hardware */ ++ smc_reset(dev); ++ smc_enable(dev); ++ ++ SMC_SELECT_BANK( 1 ); ++ SMC_SET_MAC_ADDR(dev->dev_addr); ++ ++ /* Configure the PHY */ ++ if (lp->version >= 0x70) ++ smc_phy_configure(dev); ++ ++ netif_start_queue(dev); ++ return 0; ++} ++ ++/*---------------------------------------------------- ++ . smc_close ++ . ++ . this makes the board clean up everything that it can ++ . and not talk to the outside world. Caused by ++ . an 'ifconfig ethX down' ++ . ++ -----------------------------------------------------*/ ++static int ++smc_close(struct net_device *dev) ++{ ++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__); ++ ++ netif_stop_queue(dev); ++ ++ /* clear everything */ ++ smc_shutdown(dev); ++ ++ return 0; ++} ++ ++/*------------------------------------------------------------ ++ . Get the current statistics. ++ . This may be called with the card open or closed. ++ .-------------------------------------------------------------*/ ++static struct net_device_stats * ++smc_query_statistics(struct net_device *dev) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ ++ PRINTK2("%s: %s\n", dev->name, __FUNCTION__); ++ ++ return &lp->stats; ++} ++ ++/*---------------------------------------------------------------------- ++ . smc_findirq ++ . ++ . This routine has a simple purpose -- make the SMC chip generate an ++ . interrupt, so an auto-detect routine can detect it, and find the IRQ, ++ ------------------------------------------------------------------------ ++*/ ++int __init ++smc_findirq( unsigned long ioaddr ) ++{ ++ int timeout = 20; ++ unsigned long cookie; ++ ++ PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__); ++ ++ cookie = probe_irq_on(); ++ ++ /* ++ * What I try to do here is trigger an ALLOC_INT. This is done ++ * by allocating a small chunk of memory, which will give an interrupt ++ * when done. ++ */ ++ ++ /* enable ALLOCation interrupts ONLY */ ++ SMC_SELECT_BANK(2); ++ SMC_SET_INT_MASK( IM_ALLOC_INT ); ++ ++ /* ++ . Allocate 512 bytes of memory. Note that the chip was just ++ . reset so all the memory is available ++ */ ++ SMC_SET_MMU_CMD( MC_ALLOC | 1 ); ++ ++ /* ++ . Wait until positive that the interrupt has been generated ++ */ ++ do { ++ int int_status; ++ udelay(10); ++ int_status = SMC_GET_INT(); ++ if (int_status & IM_ALLOC_INT) ++ break; /* got the interrupt */ ++ } while (--timeout); ++ ++ /* there is really nothing that I can do here if timeout fails, ++ as autoirq_report will return a 0 anyway, which is what I ++ want in this case. Plus, the clean up is needed in both ++ cases. */ ++ ++ /* and disable all interrupts again */ ++ SMC_SET_INT_MASK( 0 ); ++ ++ /* and return what I found */ ++ return probe_irq_off(cookie); ++} ++ ++/*---------------------------------------------------------------------- ++ . Function: smc_probe( unsigned long ioaddr ) ++ . ++ . Purpose: ++ . Tests to see if a given ioaddr points to an SMC91x chip. ++ . Returns a 0 on success ++ . ++ . Algorithm: ++ . (1) see if the high byte of BANK_SELECT is 0x33 ++ . (2) compare the ioaddr with the base register's address ++ . (3) see if I recognize the chip ID in the appropriate register ++ . ++ .--------------------------------------------------------------------- ++ */ ++/*--------------------------------------------------------------- ++ . Here I do typical initialization tasks. ++ . ++ . o Initialize the structure if needed ++ . o print out my vanity message if not done so already ++ . o print out what type of hardware is detected ++ . o print out the ethernet address ++ . o find the IRQ ++ . o set up my private data ++ . o configure the dev structure with my subroutines ++ . o actually GRAB the irq. ++ . o GRAB the region ++ .----------------------------------------------------------------- ++*/ ++static int __init ++smc_probe(struct net_device *dev, unsigned long ioaddr) ++{ ++ struct smc_local *lp = (struct smc_local *)dev->priv; ++ static int version_printed = 0; ++ int i, retval; ++ unsigned int val, revision_register; ++ const char *version_string; ++ ++ PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__); ++ ++ /* Grab the region so that no one else tries to probe our ioports. */ ++ if (!request_region(ioaddr, SMC_IO_EXTENT, dev->name)) ++ return -EBUSY; ++ ++ /* First, see if the high byte is 0x33 */ ++ val = SMC_CURRENT_BANK(); ++ PRINTK2("%s: bank signature probe returned 0x%04x\n", CARDNAME, val); ++ if ( (val & 0xFF00) != 0x3300 ) { ++ if ( (val & 0xFF) == 0x33 ) { ++ printk( KERN_WARNING ++ "%s: Detected possible byte-swapped interface" ++ " at IOADDR 0x%lx\n", CARDNAME, ioaddr); ++ } ++ retval = -ENODEV; ++ goto err_out; ++ } ++ ++ /* The above MIGHT indicate a device, but I need to write to further ++ test this. */ ++ SMC_SELECT_BANK(0); ++ val = SMC_CURRENT_BANK(); ++ if ( (val & 0xFF00 ) != 0x3300 ) { ++ retval = -ENODEV; ++ goto err_out; ++ } ++ ++ /* well, we've already written once, so hopefully another time won't ++ hurt. This time, I need to switch the bank register to bank 1, ++ so I can access the base address register */ ++ SMC_SELECT_BANK(1); ++ val = SMC_GET_BASE(); ++ val = ((val & 0x1F00) >> 3) << SMC_IO_SHIFT; ++ if ( (ioaddr & ((PAGE_SIZE-1)<<SMC_IO_SHIFT)) != val ) { ++ printk( "%s: IOADDR %lx doesn't match configuration (%x).\n", ++ CARDNAME, ioaddr, val ); ++ } ++ ++ /* check if the revision register is something that I recognize. ++ These might need to be added to later, as future revisions ++ could be added. */ ++ SMC_SELECT_BANK(3); ++ revision_register = SMC_GET_REV(); ++ PRINTK2("%s: revision = 0x%04x\n", CARDNAME, revision_register); ++ version_string = chip_ids[ (revision_register >> 4) & 0xF]; ++ if (!version_string || (revision_register & 0xff00) != 0x3300) { ++ /* I don't recognize this chip, so... */ ++ printk( "%s: IO 0x%lx: Unrecognized revision register 0x%04x" ++ ", Contact author.\n", CARDNAME, ++ ioaddr, revision_register); ++ ++ retval = -ENODEV; ++ goto err_out; ++ } ++ ++ /* At this point I'll assume that the chip is an SMC91x. */ ++ if (version_printed++ == 0) ++ printk("%s", version); ++ ++ /* set the private data to zero by default */ ++ memset(lp, 0, sizeof(struct smc_local)); ++ ++ /* fill in some of the fields */ ++ dev->base_addr = ioaddr; ++ lp->version = revision_register & 0xff; ++ ++ /* Get the MAC address */ ++ SMC_SELECT_BANK( 1 ); ++ SMC_GET_MAC_ADDR(dev->dev_addr); ++ ++ /* now, reset the chip, and put it into a known state */ ++ smc_reset( dev ); ++ ++ /* ++ . If dev->irq is 0, then the device has to be banged on to see ++ . what the IRQ is. ++ . ++ . This banging doesn't always detect the IRQ, for unknown reasons. ++ . a workaround is to reset the chip and try again. ++ . ++ . Interestingly, the DOS packet driver *SETS* the IRQ on the card to ++ . be what is requested on the command line. I don't do that, mostly ++ . because the card that I have uses a non-standard method of accessing ++ . the IRQs, and because this _should_ work in most configurations. ++ . ++ . Specifying an IRQ is done with the assumption that the user knows ++ . what (s)he is doing. No checking is done!!!! ++ . ++ */ ++ if ( dev->irq < 1 ) { ++ int trials; ++ ++ trials = 3; ++ while ( trials-- ) { ++ dev->irq = smc_findirq( ioaddr ); ++ if ( dev->irq ) ++ break; ++ /* kick the card and try again */ ++ smc_reset( dev ); ++ } ++ } ++ if (dev->irq == 0 ) { ++ printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n", ++ dev->name); ++ retval = -ENODEV; ++ goto err_out; ++ } ++ dev->irq = irq_cannonicalize(dev->irq); ++ ++ /* now, print out the card info, in a short format.. */ ++ printk( "%s: %s (rev %d) at %#lx IRQ %d%s%s\n", ++ dev->name, version_string, revision_register & 0x0f, ++ ioaddr, dev->irq, nowait ? " [nowait]" : "", ++ THROTTLE_TX_PKTS ? " [throttle_tx]" : "" ); ++ ++ /* Print the Ethernet address */ ++ printk("%s: Ethernet addr: ", dev->name); ++ for (i = 0; i < 5; i++) ++ printk("%2.2x:", dev->dev_addr[i] ); ++ printk("%2.2x\n", dev->dev_addr[5] ); ++ ++ /* Fill in the fields of the device structure with ethernet values. */ ++ ether_setup(dev); ++ ++ /* Grab the IRQ */ ++ retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev); ++ if (retval) { ++ goto err_out; ++ } ++ ++ dev->open = smc_open; ++ dev->stop = smc_close; ++ dev->hard_start_xmit = smc_hard_start_xmit; ++ dev->tx_timeout = smc_timeout; ++ dev->watchdog_timeo = HZ/10; ++ dev->get_stats = smc_query_statistics; ++ dev->set_multicast_list = smc_set_multicast_list; ++ ++ return 0; ++ ++err_out: ++ release_region(ioaddr, SMC_IO_EXTENT); ++ return retval; ++} ++ ++/*------------------------------------------------------------------------- ++ | ++ | smc_init( void ) ++ | Input parameters: ++ | dev->base_addr == 0, try to find all possible locations ++ | dev->base_addr > 0x1ff, this is the address to check ++ | dev->base_addr == <anything else>, return failure code ++ | ++ | Output: ++ | 0 --> there is a device ++ | anything else, error ++ | ++ --------------------------------------------------------------------------- ++*/ ++static struct net_device *global_dev = NULL; /* needs to be fixed */ ++ ++#ifdef CONFIG_PM ++ ++static int smc_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) ++{ ++ unsigned long ioaddr = global_dev->base_addr; ++ struct smc_local *lp = (struct smc_local *)global_dev->priv; ++ ++ switch (rqst) { ++ case PM_SUSPEND: ++ smc_shutdown(global_dev); ++ break; ++ case PM_RESUME: ++ smc_reset(global_dev); ++ smc_enable(global_dev); ++ SMC_SELECT_BANK( 1 ); ++ SMC_SET_MAC_ADDR(global_dev->dev_addr); ++ if (lp->version >= 0x70) ++ smc_phy_configure(global_dev); ++ break; ++ } ++ return 0; ++} ++ ++#endif ++ ++static int __init ++smc_init(void) ++{ ++ int ret; ++ ++ PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__); ++ ++#ifdef MODULE ++ if (io == -1) ++ printk( KERN_WARNING ++ "%s: You shouldn't use auto-probing with insmod!\n", ++ CARDNAME ); ++#endif ++ ++ if (global_dev) { ++ printk("%s: already initialized.\n", CARDNAME); ++ return -EBUSY; ++ } ++ ++ global_dev = init_etherdev(0, sizeof(struct smc_local)); ++ if (!global_dev) { ++ printk("%s: could not allocate device.\n", CARDNAME); ++ return -ENOMEM; ++ } ++ SET_MODULE_OWNER(global_dev); ++ ++ /* copy the parameters from insmod into the device structure */ ++ if (io != -1) ++ global_dev->base_addr = io; ++ if (irq != -1) ++ global_dev->irq = irq; ++ ++#ifdef CONFIG_ISA ++ /* try a specific location */ ++ if (global_dev->base_addr > 0x1ff) ++ ret = smc_probe(global_dev, global_dev->base_addr); ++ else if (global_dev->base_addr != 0) ++ ret = -ENXIO; ++ else { ++ int i; ++ ++ /* check every ethernet address */ ++ for (i = 0; smc_portlist[i]; i++) { ++ ret = smc_probe(global_dev, smc_portlist[i]); ++ if (ret == 0) ++ break; ++ } ++ } ++#elif defined(CONFIG_ARCH_LUBBOCK) ++ { ++ int ioaddr = LUBBOCK_ETH_VIRT + (0x300 << 2); ++ volatile int *attaddr = (int *)(LUBBOCK_ETH_VIRT + 0x100000); ++ unsigned long flags; ++ ++ /* first reset, then enable the device. Sequence is critical */ ++ local_irq_save(flags); ++ attaddr[ECOR] |= ECOR_RESET; ++ udelay(100); ++ attaddr[ECOR] &= ~ECOR_RESET; ++ attaddr[ECOR] |= ECOR_ENABLE; ++ ++ /* force 16-bit mode */ ++ attaddr[ECSR] &= ~ECSR_IOIS8; ++ mdelay(1); ++ local_irq_restore(flags); ++ ++ global_dev->irq = LUBBOCK_ETH_IRQ; ++ ret = smc_probe(global_dev, ioaddr); ++ } ++#elif defined(CONFIG_ARCH_PXA_IDP) ++ { ++ int ioaddr = IDP_ETH_BASE + 0x300; ++ global_dev->irq = SMC_IRQ; ++ ret = smc_probe(global_dev, ioaddr); ++ } ++#elif defined(CONFIG_ARCH_RAMSES) ++ { ++ int ioaddr = RAMSES_ETH_BASE + 0x300; ++ global_dev->irq = SMC_IRQ; ++ ret = smc_probe(global_dev, ioaddr); ++ } ++#else ++ if (global_dev->base_addr == -1) { ++ printk(KERN_WARNING"%s: SMC91X_BASE_ADDR not set!\n", CARDNAME); ++ ret = -ENXIO; ++ } else { ++ void *ioaddr = ioremap(global_dev->base_addr, SMC_IO_EXTENT); ++ ret = smc_probe(global_dev, (unsigned long)ioaddr); ++ if (ret != 0) ++ iounmap(ioaddr); ++ } ++#endif ++ ++#ifdef SMC_USE_PXA_DMA ++ if (ret == 0) { ++ int dma = pxa_request_dma(global_dev->name, DMA_PRIO_LOW, ++ smc_pxa_dma_irq, NULL); ++ if (dma >= 0) { ++ global_dev->dma = dma; ++ PRINTK("%s: using DMA channel %d\n", global_dev->name, dma); ++ } else { ++ global_dev->dma = -1; ++ } ++ } ++#endif ++ ++#ifdef CONFIG_PM ++ if (ret == 0) { ++ struct smc_local *lp = (struct smc_local *)global_dev->priv; ++ lp->pm = pm_register(PM_SYS_UNKNOWN, 0x73393178, smc_pm_callback); ++ } ++#endif ++ ++ if (ret != 0) { ++ printk("%s: not found.\n", CARDNAME); ++ kfree(global_dev->priv); ++ unregister_netdev(global_dev); ++ kfree(global_dev); ++ } ++ ++ return ret; ++} ++ ++static void __exit ++smc_cleanup(void) ++{ ++ unregister_netdev(global_dev); ++#ifdef CONFIG_PM ++ { ++ struct smc_local *lp = (struct smc_local *)global_dev->priv; ++ pm_unregister(lp->pm); ++ } ++#endif ++ free_irq(global_dev->irq, global_dev); ++ release_region(global_dev->base_addr, SMC_IO_EXTENT); ++ ++#ifndef CONFIG_ISA ++ iounmap((void *)global_dev->base_addr); ++#endif ++ ++ kfree(global_dev); ++ global_dev = NULL; ++} ++ ++module_init(smc_init); ++module_exit(smc_cleanup); ++ +--- /dev/null ++++ linux-2.4.27/drivers/net/smc91x.h +@@ -0,0 +1,835 @@ ++/*------------------------------------------------------------------------ ++ . smc91x.h - macros for SMSC's 91C9x/91C1xx single-chip Ethernet device. ++ . ++ . Copyright (C) 1996 by Erik Stahlman ++ . Copyright (C) 2001 Standard Microsystems Corporation ++ . Developed by Simple Network Magic Corporation ++ . Copyright (C) 2003 Monta Vista Software, Inc. ++ . Unified SMC91x driver by Nicolas Pitre ++ . ++ . 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. ++ . ++ . This program is distributed in the hope that it will be useful, ++ . but WITHOUT ANY WARRANTY; without even the implied warranty of ++ . MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ . GNU General Public License for more details. ++ . ++ . You should have received a copy of the GNU General Public License ++ . along with this program; if not, write to the Free Software ++ . Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ . ++ . Information contained in this file was obtained from the LAN91C111 ++ . manual from SMC. To get a copy, if you really want one, you can find ++ . information under www.smsc.com. ++ . ++ . Authors ++ . Erik Stahlman <erik@vt.edu> ++ . Daris A Nevil <dnevil@snmc.com> ++ . Nicolas Pitre <nico@cam.org> ++ . ++ ---------------------------------------------------------------------------*/ ++#ifndef _SMC91X_H_ ++#define _SMC91X_H_ ++ ++ ++/* ++ * Define your architecture specific configuration parameters here. ++ */ ++ ++#if defined(CONFIG_SA1100_GRAPHICSCLIENT) || \ ++ defined(CONFIG_SA1100_PFS168) || \ ++ defined(CONFIG_SA1100_FLEXANET) || \ ++ defined(CONFIG_SA1100_GRAPHICSMASTER) || \ ++ defined(CONFIG_ARCH_LUBBOCK) ++ ++/* We can only do 16-bit reads and writes in the static memory space. */ ++#define SMC_CAN_USE_8BIT 0 ++#define SMC_CAN_USE_16BIT 1 ++#define SMC_CAN_USE_32BIT 0 ++#define SMC_NOWAIT 1 ++ ++/* The first two address lines aren't connected... */ ++#define SMC_IO_SHIFT 2 ++ ++#define SMC_inw(a, r) readw((a) + (r)) ++#define SMC_outw(v, a, r) writew(v, (a) + (r)) ++#define SMC_insw(a, r, p, l) insw((a) + (r), p, l) ++#define SMC_outsw(a, r, p, l) outsw((a) + (r), p, l) ++ ++#ifdef CONFIG_ARCH_LUBBOCK ++#define SMC_IOADDR LUBBOCK_ETH_PHYS ++#endif ++ ++#elif defined(CONFIG_ARCH_MAINSTONE) || defined(CONFIG_ARCH_PXA_IDP) || defined(CONFIG_ARCH_RAMSES) ++ ++#ifdef CONFIG_ARCH_MAINSTONE ++#include <asm/arch/mainstone.h> ++#define SMC_IOADDR (MST_ETH_PHYS + 0x300) ++#define SMC_IRQ MAINSTONE_IRQ(3) ++ ++#elif CONFIG_ARCH_PXA_IDP ++#include <asm/arch/idp.h> ++#define SMC_IOADDR (IDP_ETH_PHYS + 0x300) ++#define SMC_IRQ ETHERNET_IRQ ++ ++#elif CONFIG_ARCH_RAMSES ++#include <asm/arch/ramses.h> ++#define SMC_IOADDR (RAMSES_ETH_PHYS + 0x300) ++#define SMC_IRQ ETHERNET_IRQ ++#endif ++ ++#define SMC_CAN_USE_8BIT 1 ++#define SMC_CAN_USE_16BIT 1 ++#define SMC_CAN_USE_32BIT 1 ++#define SMC_IO_SHIFT 0 ++#define SMC_NOWAIT 1 ++#define SMC_USE_PXA_DMA 1 ++ ++#define SMC_inb(a, r) readb((a) + (r)) ++#define SMC_inw(a, r) readw((a) + (r)) ++#define SMC_inl(a, r) readl((a) + (r)) ++#define SMC_outb(v, a, r) writeb(v, (a) + (r)) ++#define SMC_outl(v, a, r) writel(v, (a) + (r)) ++#define SMC_insl(a, r, p, l) insl((a) + (r), p, l) ++#define SMC_outsl(a, r, p, l) outsl((a) + (r), p, l) ++ ++/* We actually can't write halfwords properly if not word aligned */ ++static inline void ++SMC_outw(u16 val, unsigned long ioaddr, int reg) ++{ ++ if (reg & 2) { ++ unsigned int v = val << 16; ++ v |= readl(ioaddr + (reg & ~2)) & 0xffff; ++ writel(v, ioaddr + (reg & ~2)); ++ } else { ++ writew(val, ioaddr + reg); ++ } ++} ++ ++#elif defined(CONFIG_ISA) ++ ++#define SMC_CAN_USE_8BIT 1 ++#define SMC_CAN_USE_16BIT 1 ++#define SMC_CAN_USE_32BIT 0 ++ ++#define SMC_inb(a, r) inb((a) + (r)) ++#define SMC_inw(a, r) inw((a) + (r)) ++#define SMC_outb(v, a, r) outb(v, (a) + (r)) ++#define SMC_outw(v, a, r) outw(v, (a) + (r)) ++#define SMC_insw(a, r, p, l) insw((a) + (r), p, l) ++#define SMC_outsw(a, r, p, l) outsw((a) + (r), p, l) ++ ++#endif ++ ++ ++#ifdef SMC_USE_PXA_DMA ++/* ++ * Let's use the DMA engine on the XScale PXA2xx for RX packets. This is ++ * always happening in irq context so no need to worry about races. TX is ++ * different and probably not worth it for that reason, and not as critical ++ * as RX which can overrun memory and lose packets. ++ */ ++#include <linux/pci.h> ++#include <asm/dma.h> ++ ++#ifdef SMC_insl ++#undef SMC_insl ++#define SMC_insl(a, r, p, l) smc_pxa_dma_insl(a, r, dev->dma, p, l) ++static inline void ++smc_pxa_dma_insl(u_long ioaddr, int reg, int dma, u_char *buf, int len) ++{ ++ dma_addr_t dmabuf; ++ ++ /* fallback if no DMA available */ ++ if (dma == -1) { ++ insl(ioaddr + reg, buf, len); ++ return; ++ } ++ ++ /* 64 bit alignment is required for memory to memory DMA */ ++ if ((long)buf & 4) { ++ *((u32 *)buf)++ = SMC_inl(ioaddr, reg); ++ len--; ++ } ++ ++ len *= 4; ++ dmabuf = pci_map_single(NULL, buf, len, PCI_DMA_FROMDEVICE); ++ DCSR(dma) = DCSR_NODESC; ++ DTADR(dma) = dmabuf; ++ DSADR(dma) = SMC_IOADDR + reg; ++ DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 | ++ DCMD_WIDTH4 | (DCMD_LENGTH & len)); ++ DCSR(dma) = DCSR_NODESC | DCSR_RUN; ++ while (!(DCSR(dma) & DCSR_STOPSTATE)); ++ DCSR(dma) = 0; ++ pci_unmap_single(NULL, dmabuf,len, PCI_DMA_FROMDEVICE); ++} ++#endif ++ ++#ifdef SMC_insw ++#undef SMC_insw ++#define SMC_insw(a, r, p, l) smc_pxa_dma_insw(a, r, dev->dma, p, l) ++static inline void ++smc_pxa_dma_insw(u_long ioaddr, int reg, int dma, u_char *buf, int len) ++{ ++ dma_addr_t dmabuf; ++ ++ /* fallback if no DMA available */ ++ if (dma == -1) { ++ insw(ioaddr + reg, buf, len); ++ return; ++ } ++ ++ /* 64 bit alignment is required for memory to memory DMA */ ++ while ((long)buf & 6) { ++ *((u16 *)buf)++ = SMC_inw(ioaddr, reg); ++ len--; ++ } ++ ++ len *= 2; ++ dmabuf = pci_map_single(NULL, buf, len, PCI_DMA_FROMDEVICE); ++ DCSR(dma) = DCSR_NODESC; ++ DTADR(dma) = dmabuf; ++ DSADR(dma) = SMC_IOADDR + reg; ++ DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 | ++ DCMD_WIDTH2 | (DCMD_LENGTH & len)); ++ DCSR(dma) = DCSR_NODESC | DCSR_RUN; ++ while (!(DCSR(dma) & DCSR_STOPSTATE)); ++ DCSR(dma) = 0; ++ pci_unmap_single(NULL, dmabuf,len, PCI_DMA_FROMDEVICE); ++} ++#endif ++ ++static void ++smc_pxa_dma_irq(int dma, void *dummy, struct pt_regs *regs) ++{ ++ DCSR(dma) = 0; ++} ++#endif /* SMC_USE_PXA_DMA */ ++ ++ ++/* Because of bank switching, the LAN91xxx uses only 16 I/O ports */ ++#ifndef SMC_IO_SHIFT ++#define SMC_IO_SHIFT 0 ++#endif ++#define SMC_IO_EXTENT (16 << SMC_IO_SHIFT) ++ ++ ++/* ++ . Bank Select Register: ++ . ++ . yyyy yyyy 0000 00xx ++ . xx = bank number ++ . yyyy yyyy = 0x33, for identification purposes. ++*/ ++#define BANK_SELECT (14 << SMC_IO_SHIFT) ++ ++ ++// Transmit Control Register ++/* BANK 0 */ ++#define TCR_REG SMC_REG(0x0000, 0) ++#define TCR_ENABLE 0x0001 // When 1 we can transmit ++#define TCR_LOOP 0x0002 // Controls output pin LBK ++#define TCR_FORCOL 0x0004 // When 1 will force a collision ++#define TCR_PAD_EN 0x0080 // When 1 will pad tx frames < 64 bytes w/0 ++#define TCR_NOCRC 0x0100 // When 1 will not append CRC to tx frames ++#define TCR_MON_CSN 0x0400 // When 1 tx monitors carrier ++#define TCR_FDUPLX 0x0800 // When 1 enables full duplex operation ++#define TCR_STP_SQET 0x1000 // When 1 stops tx if Signal Quality Error ++#define TCR_EPH_LOOP 0x2000 // When 1 enables EPH block loopback ++#define TCR_SWFDUP 0x8000 // When 1 enables Switched Full Duplex mode ++ ++#define TCR_CLEAR 0 /* do NOTHING */ ++/* the default settings for the TCR register : */ ++#define TCR_DEFAULT (TCR_ENABLE | TCR_PAD_EN) ++ ++ ++// EPH Status Register ++/* BANK 0 */ ++#define EPH_STATUS_REG SMC_REG(0x0002, 0) ++#define ES_TX_SUC 0x0001 // Last TX was successful ++#define ES_SNGL_COL 0x0002 // Single collision detected for last tx ++#define ES_MUL_COL 0x0004 // Multiple collisions detected for last tx ++#define ES_LTX_MULT 0x0008 // Last tx was a multicast ++#define ES_16COL 0x0010 // 16 Collisions Reached ++#define ES_SQET 0x0020 // Signal Quality Error Test ++#define ES_LTXBRD 0x0040 // Last tx was a broadcast ++#define ES_TXDEFR 0x0080 // Transmit Deferred ++#define ES_LATCOL 0x0200 // Late collision detected on last tx ++#define ES_LOSTCARR 0x0400 // Lost Carrier Sense ++#define ES_EXC_DEF 0x0800 // Excessive Deferral ++#define ES_CTR_ROL 0x1000 // Counter Roll Over indication ++#define ES_LINK_OK 0x4000 // Driven by inverted value of nLNK pin ++#define ES_TXUNRN 0x8000 // Tx Underrun ++ ++ ++// Receive Control Register ++/* BANK 0 */ ++#define RCR_REG SMC_REG(0x0004, 0) ++#define RCR_RX_ABORT 0x0001 // Set if a rx frame was aborted ++#define RCR_PRMS 0x0002 // Enable promiscuous mode ++#define RCR_ALMUL 0x0004 // When set accepts all multicast frames ++#define RCR_RXEN 0x0100 // IFF this is set, we can receive packets ++#define RCR_STRIP_CRC 0x0200 // When set strips CRC from rx packets ++#define RCR_ABORT_ENB 0x0200 // When set will abort rx on collision ++#define RCR_FILT_CAR 0x0400 // When set filters leading 12 bit s of carrier ++#define RCR_SOFTRST 0x8000 // resets the chip ++ ++/* the normal settings for the RCR register : */ ++#define RCR_DEFAULT (RCR_STRIP_CRC | RCR_RXEN) ++#define RCR_CLEAR 0x0 // set it to a base state ++ ++ ++// Counter Register ++/* BANK 0 */ ++#define COUNTER_REG SMC_REG(0x0006, 0) ++ ++ ++// Memory Information Register ++/* BANK 0 */ ++#define MIR_REG SMC_REG(0x0008, 0) ++ ++ ++// Receive/Phy Control Register ++/* BANK 0 */ ++#define RPC_REG SMC_REG(0x000A, 0) ++#define RPC_SPEED 0x2000 // When 1 PHY is in 100Mbps mode. ++#define RPC_DPLX 0x1000 // When 1 PHY is in Full-Duplex Mode ++#define RPC_ANEG 0x0800 // When 1 PHY is in Auto-Negotiate Mode ++#define RPC_LSXA_SHFT 5 // Bits to shift LS2A,LS1A,LS0A to lsb ++#define RPC_LSXB_SHFT 2 // Bits to get LS2B,LS1B,LS0B to lsb ++#define RPC_LED_100_10 (0x00) // LED = 100Mbps OR's with 10Mbps link detect ++#define RPC_LED_RES (0x01) // LED = Reserved ++#define RPC_LED_10 (0x02) // LED = 10Mbps link detect ++#define RPC_LED_FD (0x03) // LED = Full Duplex Mode ++#define RPC_LED_TX_RX (0x04) // LED = TX or RX packet occurred ++#define RPC_LED_100 (0x05) // LED = 100Mbps link dectect ++#define RPC_LED_TX (0x06) // LED = TX packet occurred ++#define RPC_LED_RX (0x07) // LED = RX packet occurred ++#define RPC_DEFAULT (RPC_ANEG | (RPC_LED_100 << RPC_LSXA_SHFT) | (RPC_LED_FD << RPC_LSXB_SHFT) | RPC_SPEED | RPC_DPLX) ++ ++ ++/* Bank 0 0x0C is reserved */ ++ ++// Bank Select Register ++/* All Banks */ ++#define BSR_REG 0x000E ++ ++ ++// Configuration Reg ++/* BANK 1 */ ++#define CONFIG_REG SMC_REG(0x0000, 1) ++#define CONFIG_EXT_PHY 0x0200 // 1=external MII, 0=internal Phy ++#define CONFIG_GPCNTRL 0x0400 // Inverse value drives pin nCNTRL ++#define CONFIG_NO_WAIT 0x1000 // When 1 no extra wait states on ISA bus ++#define CONFIG_EPH_POWER_EN 0x8000 // When 0 EPH is placed into low power mode. ++ ++// Default is powered-up, Internal Phy, Wait States, and pin nCNTRL=low ++#define CONFIG_DEFAULT (CONFIG_EPH_POWER_EN) ++ ++ ++// Base Address Register ++/* BANK 1 */ ++#define BASE_REG SMC_REG(0x0002, 1) ++ ++ ++// Individual Address Registers ++/* BANK 1 */ ++#define ADDR0_REG SMC_REG(0x0004, 1) ++#define ADDR1_REG SMC_REG(0x0006, 1) ++#define ADDR2_REG SMC_REG(0x0008, 1) ++ ++ ++// General Purpose Register ++/* BANK 1 */ ++#define GP_REG SMC_REG(0x000A, 1) ++ ++ ++// Control Register ++/* BANK 1 */ ++#define CTL_REG SMC_REG(0x000C, 1) ++#define CTL_RCV_BAD 0x4000 // When 1 bad CRC packets are received ++#define CTL_AUTO_RELEASE 0x0800 // When 1 tx pages are released automatically ++#define CTL_LE_ENABLE 0x0080 // When 1 enables Link Error interrupt ++#define CTL_CR_ENABLE 0x0040 // When 1 enables Counter Rollover interrupt ++#define CTL_TE_ENABLE 0x0020 // When 1 enables Transmit Error interrupt ++#define CTL_EEPROM_SELECT 0x0004 // Controls EEPROM reload & store ++#define CTL_RELOAD 0x0002 // When set reads EEPROM into registers ++#define CTL_STORE 0x0001 // When set stores registers into EEPROM ++ ++ ++// MMU Command Register ++/* BANK 2 */ ++#define MMU_CMD_REG SMC_REG(0x0000, 2) ++#define MC_BUSY 1 // When 1 the last release has not completed ++#define MC_NOP (0<<5) // No Op ++#define MC_ALLOC (1<<5) // OR with number of 256 byte packets ++#define MC_RESET (2<<5) // Reset MMU to initial state ++#define MC_REMOVE (3<<5) // Remove the current rx packet ++#define MC_RELEASE (4<<5) // Remove and release the current rx packet ++#define MC_FREEPKT (5<<5) // Release packet in PNR register ++#define MC_ENQUEUE (6<<5) // Enqueue the packet for transmit ++#define MC_RSTTXFIFO (7<<5) // Reset the TX FIFOs ++ ++ ++// Packet Number Register ++/* BANK 2 */ ++#define PN_REG SMC_REG(0x0002, 2) ++ ++ ++// Allocation Result Register ++/* BANK 2 */ ++#define AR_REG SMC_REG(0x0003, 2) ++#define AR_FAILED 0x80 // Alocation Failed ++ ++ ++// TX FIFO Ports Register ++/* BANK 2 */ ++#define TXFIFO_REG SMC_REG(0x0004, 2) ++#define TXFIFO_TEMPTY 0x80 // TX FIFO Empty ++ ++// RX FIFO Ports Register ++/* BANK 2 */ ++#define RXFIFO_REG SMC_REG(0x0005, 2) ++#define RXFIFO_REMPTY 0x80 // RX FIFO Empty ++ ++#define FIFO_REG SMC_REG(0x0004, 2) ++ ++// Pointer Register ++/* BANK 2 */ ++#define PTR_REG SMC_REG(0x0006, 2) ++#define PTR_RCV 0x8000 // 1=Receive area, 0=Transmit area ++#define PTR_AUTOINC 0x4000 // Auto increment the pointer on each access ++#define PTR_READ 0x2000 // When 1 the operation is a read ++ ++ ++// Data Register ++/* BANK 2 */ ++#define DATA_REG SMC_REG(0x0008, 2) ++ ++ ++// Interrupt Status/Acknowledge Register ++/* BANK 2 */ ++#define INT_REG SMC_REG(0x000C, 2) ++ ++ ++// Interrupt Mask Register ++/* BANK 2 */ ++#define IM_REG SMC_REG(0x000D, 2) ++#define IM_MDINT 0x80 // PHY MI Register 18 Interrupt ++#define IM_ERCV_INT 0x40 // Early Receive Interrupt ++#define IM_EPH_INT 0x20 // Set by Ethernet Protocol Handler section ++#define IM_RX_OVRN_INT 0x10 // Set by Receiver Overruns ++#define IM_ALLOC_INT 0x08 // Set when allocation request is completed ++#define IM_TX_EMPTY_INT 0x04 // Set if the TX FIFO goes empty ++#define IM_TX_INT 0x02 // Transmit Interrupt ++#define IM_RCV_INT 0x01 // Receive Interrupt ++ ++ ++// Multicast Table Registers ++/* BANK 3 */ ++#define MCAST_REG1 SMC_REG(0x0000, 3) ++#define MCAST_REG2 SMC_REG(0x0002, 3) ++#define MCAST_REG3 SMC_REG(0x0004, 3) ++#define MCAST_REG4 SMC_REG(0x0006, 3) ++ ++ ++// Management Interface Register (MII) ++/* BANK 3 */ ++#define MII_REG SMC_REG(0x0008, 3) ++#define MII_MSK_CRS100 0x4000 // Disables CRS100 detection during tx half dup ++#define MII_MDOE 0x0008 // MII Output Enable ++#define MII_MCLK 0x0004 // MII Clock, pin MDCLK ++#define MII_MDI 0x0002 // MII Input, pin MDI ++#define MII_MDO 0x0001 // MII Output, pin MDO ++ ++ ++// Revision Register ++/* BANK 3 */ ++/* ( hi: chip id low: rev # ) */ ++#define REV_REG SMC_REG(0x000A, 3) ++ ++ ++// Early RCV Register ++/* BANK 3 */ ++/* this is NOT on SMC9192 */ ++#define ERCV_REG SMC_REG(0x000C, 3) ++#define ERCV_RCV_DISCRD 0x0080 // When 1 discards a packet being received ++#define ERCV_THRESHOLD 0x001F // ERCV Threshold Mask ++ ++ ++// External Register ++/* BANK 7 */ ++#define EXT_REG SMC_REG(0x0000, 7) ++ ++ ++#define CHIP_9192 3 ++#define CHIP_9194 4 ++#define CHIP_9195 5 ++#define CHIP_9196 6 ++#define CHIP_91100 7 ++#define CHIP_91100FD 8 ++#define CHIP_91111FD 9 ++ ++static const char * chip_ids[ 16 ] = { ++ NULL, NULL, NULL, ++ /* 3 */ "SMC91C90/91C92", ++ /* 4 */ "SMC91C94", ++ /* 5 */ "SMC91C95", ++ /* 6 */ "SMC91C96", ++ /* 7 */ "SMC91C100", ++ /* 8 */ "SMC91C100FD", ++ /* 9 */ "SMC91C11xFD", ++ NULL, NULL, NULL, ++ NULL, NULL, NULL}; ++ ++ ++/* ++ . Transmit status bits ++*/ ++#define TS_SUCCESS 0x0001 ++#define TS_LOSTCAR 0x0400 ++#define TS_LATCOL 0x0200 ++#define TS_16COL 0x0010 ++ ++/* ++ . Receive status bits ++*/ ++#define RS_ALGNERR 0x8000 ++#define RS_BRODCAST 0x4000 ++#define RS_BADCRC 0x2000 ++#define RS_ODDFRAME 0x1000 ++#define RS_TOOLONG 0x0800 ++#define RS_TOOSHORT 0x0400 ++#define RS_MULTICAST 0x0001 ++#define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT) ++ ++ ++// PHY Types ++enum { ++ PHY_LAN83C183 = 1, // LAN91C111 Internal PHY ++ PHY_LAN83C180 ++}; ++ ++ ++// PHY Register Addresses (LAN91C111 Internal PHY) ++ ++// PHY Control Register ++#define PHY_CNTL_REG 0x00 ++#define PHY_CNTL_RST 0x8000 // 1=PHY Reset ++#define PHY_CNTL_LPBK 0x4000 // 1=PHY Loopback ++#define PHY_CNTL_SPEED 0x2000 // 1=100Mbps, 0=10Mpbs ++#define PHY_CNTL_ANEG_EN 0x1000 // 1=Enable Auto negotiation ++#define PHY_CNTL_PDN 0x0800 // 1=PHY Power Down mode ++#define PHY_CNTL_MII_DIS 0x0400 // 1=MII 4 bit interface disabled ++#define PHY_CNTL_ANEG_RST 0x0200 // 1=Reset Auto negotiate ++#define PHY_CNTL_DPLX 0x0100 // 1=Full Duplex, 0=Half Duplex ++#define PHY_CNTL_COLTST 0x0080 // 1= MII Colision Test ++ ++// PHY Status Register ++#define PHY_STAT_REG 0x01 ++#define PHY_STAT_CAP_T4 0x8000 // 1=100Base-T4 capable ++#define PHY_STAT_CAP_TXF 0x4000 // 1=100Base-X full duplex capable ++#define PHY_STAT_CAP_TXH 0x2000 // 1=100Base-X half duplex capable ++#define PHY_STAT_CAP_TF 0x1000 // 1=10Mbps full duplex capable ++#define PHY_STAT_CAP_TH 0x0800 // 1=10Mbps half duplex capable ++#define PHY_STAT_CAP_SUPR 0x0040 // 1=recv mgmt frames with not preamble ++#define PHY_STAT_ANEG_ACK 0x0020 // 1=ANEG has completed ++#define PHY_STAT_REM_FLT 0x0010 // 1=Remote Fault detected ++#define PHY_STAT_CAP_ANEG 0x0008 // 1=Auto negotiate capable ++#define PHY_STAT_LINK 0x0004 // 1=valid link ++#define PHY_STAT_JAB 0x0002 // 1=10Mbps jabber condition ++#define PHY_STAT_EXREG 0x0001 // 1=extended registers implemented ++ ++// PHY Identifier Registers ++#define PHY_ID1_REG 0x02 // PHY Identifier 1 ++#define PHY_ID2_REG 0x03 // PHY Identifier 2 ++ ++// PHY Auto-Negotiation Advertisement Register ++#define PHY_AD_REG 0x04 ++#define PHY_AD_NP 0x8000 // 1=PHY requests exchange of Next Page ++#define PHY_AD_ACK 0x4000 // 1=got link code word from remote ++#define PHY_AD_RF 0x2000 // 1=advertise remote fault ++#define PHY_AD_T4 0x0200 // 1=PHY is capable of 100Base-T4 ++#define PHY_AD_TX_FDX 0x0100 // 1=PHY is capable of 100Base-TX FDPLX ++#define PHY_AD_TX_HDX 0x0080 // 1=PHY is capable of 100Base-TX HDPLX ++#define PHY_AD_10_FDX 0x0040 // 1=PHY is capable of 10Base-T FDPLX ++#define PHY_AD_10_HDX 0x0020 // 1=PHY is capable of 10Base-T HDPLX ++#define PHY_AD_CSMA 0x0001 // 1=PHY is capable of 802.3 CMSA ++ ++// PHY Auto-negotiation Remote End Capability Register ++#define PHY_RMT_REG 0x05 ++// Uses same bit definitions as PHY_AD_REG ++ ++// PHY Configuration Register 1 ++#define PHY_CFG1_REG 0x10 ++#define PHY_CFG1_LNKDIS 0x8000 // 1=Rx Link Detect Function disabled ++#define PHY_CFG1_XMTDIS 0x4000 // 1=TP Transmitter Disabled ++#define PHY_CFG1_XMTPDN 0x2000 // 1=TP Transmitter Powered Down ++#define PHY_CFG1_BYPSCR 0x0400 // 1=Bypass scrambler/descrambler ++#define PHY_CFG1_UNSCDS 0x0200 // 1=Unscramble Idle Reception Disable ++#define PHY_CFG1_EQLZR 0x0100 // 1=Rx Equalizer Disabled ++#define PHY_CFG1_CABLE 0x0080 // 1=STP(150ohm), 0=UTP(100ohm) ++#define PHY_CFG1_RLVL0 0x0040 // 1=Rx Squelch level reduced by 4.5db ++#define PHY_CFG1_TLVL_SHIFT 2 // Transmit Output Level Adjust ++#define PHY_CFG1_TLVL_MASK 0x003C ++#define PHY_CFG1_TRF_MASK 0x0003 // Transmitter Rise/Fall time ++ ++ ++// PHY Configuration Register 2 ++#define PHY_CFG2_REG 0x11 ++#define PHY_CFG2_APOLDIS 0x0020 // 1=Auto Polarity Correction disabled ++#define PHY_CFG2_JABDIS 0x0010 // 1=Jabber disabled ++#define PHY_CFG2_MREG 0x0008 // 1=Multiple register access (MII mgt) ++#define PHY_CFG2_INTMDIO 0x0004 // 1=Interrupt signaled with MDIO pulseo ++ ++// PHY Status Output (and Interrupt status) Register ++#define PHY_INT_REG 0x12 // Status Output (Interrupt Status) ++#define PHY_INT_INT 0x8000 // 1=bits have changed since last read ++#define PHY_INT_LNKFAIL 0x4000 // 1=Link Not detected ++#define PHY_INT_LOSSSYNC 0x2000 // 1=Descrambler has lost sync ++#define PHY_INT_CWRD 0x1000 // 1=Invalid 4B5B code detected on rx ++#define PHY_INT_SSD 0x0800 // 1=No Start Of Stream detected on rx ++#define PHY_INT_ESD 0x0400 // 1=No End Of Stream detected on rx ++#define PHY_INT_RPOL 0x0200 // 1=Reverse Polarity detected ++#define PHY_INT_JAB 0x0100 // 1=Jabber detected ++#define PHY_INT_SPDDET 0x0080 // 1=100Base-TX mode, 0=10Base-T mode ++#define PHY_INT_DPLXDET 0x0040 // 1=Device in Full Duplex ++ ++// PHY Interrupt/Status Mask Register ++#define PHY_MASK_REG 0x13 // Interrupt Mask ++// Uses the same bit definitions as PHY_INT_REG ++ ++ ++/* ++ * SMC91C96 ethernet config and status registers. ++ * These are in the "attribute" space. ++ */ ++#define ECOR 0x8000 ++#define ECOR_RESET 0x80 ++#define ECOR_LEVEL_IRQ 0x40 ++#define ECOR_WR_ATTRIB 0x04 ++#define ECOR_ENABLE 0x01 ++ ++#define ECSR 0x8002 ++#define ECSR_IOIS8 0x20 ++#define ECSR_PWRDWN 0x04 ++#define ECSR_INT 0x02 ++ ++ ++/* ++ * Macros to abstract register access according to the data bus ++ * capabilities. Please try to use those and not the in/out primitives. ++ * Note: the following macros do *not* select the bank -- this must ++ * be done separately as needed in the main code. The SMC_REG() macro ++ * only uses the bank argument for debugging purposes. ++ */ ++ ++#if SMC_DEBUG > 0 ++#define SMC_REG(reg, bank) \ ++ ({ \ ++ int __b = SMC_CURRENT_BANK(); \ ++ if ((__b & ~0xf0) != (0x3300 | bank)) { \ ++ printk( "%s: bank reg screwed (0x%04x)\n", \ ++ CARDNAME, __b ); \ ++ BUG(); \ ++ } \ ++ reg<<SMC_IO_SHIFT; \ ++ }) ++#else ++#define SMC_REG(reg, bank) (reg<<SMC_IO_SHIFT) ++#endif ++ ++#if SMC_CAN_USE_8BIT ++#define SMC_GET_PN() SMC_inb( ioaddr, PN_REG ) ++#define SMC_SET_PN(x) SMC_outb( x, ioaddr, PN_REG ) ++#define SMC_GET_AR() SMC_inb( ioaddr, AR_REG ) ++#define SMC_GET_TXFIFO() SMC_inb( ioaddr, TXFIFO_REG ) ++#define SMC_GET_RXFIFO() SMC_inb( ioaddr, RXFIFO_REG ) ++#define SMC_GET_INT() SMC_inb( ioaddr, INT_REG ) ++#define SMC_ACK_INT(x) SMC_outb( x, ioaddr, INT_REG ) ++#define SMC_GET_INT_MASK() SMC_inb( ioaddr, IM_REG ) ++#define SMC_SET_INT_MASK(x) SMC_outb( x, ioaddr, IM_REG ) ++#else ++#define SMC_GET_PN() (SMC_inw( ioaddr, PN_REG ) & 0xFF) ++#define SMC_SET_PN(x) SMC_outw( x, ioaddr, PN_REG ) ++#define SMC_GET_AR() (SMC_inw( ioaddr, PN_REG ) >> 8) ++#define SMC_GET_TXFIFO() (SMC_inw( ioaddr, TXFIFO_REG ) & 0xFF) ++#define SMC_GET_RXFIFO() (SMC_inw( ioaddr, TXFIFO_REG ) >> 8) ++#define SMC_GET_INT() (SMC_inw( ioaddr, INT_REG ) & 0xFF) ++#define SMC_ACK_INT(x) \ ++ do { \ ++ unsigned long __flags; \ ++ int __mask; \ ++ local_irq_save(__flags); \ ++ __mask = SMC_inw( ioaddr, INT_REG ) & ~0xff; \ ++ SMC_outw( __mask | (x), ioaddr, INT_REG ); \ ++ local_irq_restore(__flags); \ ++ } while (0) ++#define SMC_GET_INT_MASK() (SMC_inw( ioaddr, INT_REG ) >> 8) ++#define SMC_SET_INT_MASK(x) SMC_outw( (x) << 8, ioaddr, INT_REG ) ++#endif ++ ++#define SMC_CURRENT_BANK() SMC_inw( ioaddr, BANK_SELECT ) ++#define SMC_SELECT_BANK(x) SMC_outw( x, ioaddr, BANK_SELECT ) ++#define SMC_GET_BASE() SMC_inw( ioaddr, BASE_REG ) ++#define SMC_SET_BASE(x) SMC_outw( x, ioaddr, BASE_REG ) ++#define SMC_GET_CONFIG() SMC_inw( ioaddr, CONFIG_REG ) ++#define SMC_SET_CONFIG(x) SMC_outw( x, ioaddr, CONFIG_REG ) ++#define SMC_GET_COUNTER() SMC_inw( ioaddr, COUNTER_REG ) ++#define SMC_GET_CTL() SMC_inw( ioaddr, CTL_REG ) ++#define SMC_SET_CTL(x) SMC_outw( x, ioaddr, CTL_REG ) ++#define SMC_GET_MII() SMC_inw( ioaddr, MII_REG ) ++#define SMC_SET_MII(x) SMC_outw( x, ioaddr, MII_REG ) ++#define SMC_GET_MIR() SMC_inw( ioaddr, MIR_REG ) ++#define SMC_SET_MIR(x) SMC_outw( x, ioaddr, MIR_REG ) ++#define SMC_GET_MMU_CMD() SMC_inw( ioaddr, MMU_CMD_REG ) ++#define SMC_SET_MMU_CMD(x) SMC_outw( x, ioaddr, MMU_CMD_REG ) ++#define SMC_GET_FIFO() SMC_inw( ioaddr, FIFO_REG ) ++#define SMC_GET_PTR() SMC_inw( ioaddr, PTR_REG ) ++#define SMC_SET_PTR(x) SMC_outw( x, ioaddr, PTR_REG ) ++#define SMC_GET_RCR() SMC_inw( ioaddr, RCR_REG ) ++#define SMC_SET_RCR(x) SMC_outw( x, ioaddr, RCR_REG ) ++#define SMC_GET_REV() SMC_inw( ioaddr, REV_REG ) ++#define SMC_GET_RPC() SMC_inw( ioaddr, RPC_REG ) ++#define SMC_SET_RPC(x) SMC_outw( x, ioaddr, RPC_REG ) ++#define SMC_GET_TCR() SMC_inw( ioaddr, TCR_REG ) ++#define SMC_SET_TCR(x) SMC_outw( x, ioaddr, TCR_REG ) ++ ++#ifndef SMC_GET_MAC_ADDR ++#define SMC_GET_MAC_ADDR(addr) \ ++ do { \ ++ unsigned int __v; \ ++ __v = SMC_inw( ioaddr, ADDR0_REG ); \ ++ addr[0] = __v; addr[1] = __v >> 8; \ ++ __v = SMC_inw( ioaddr, ADDR1_REG ); \ ++ addr[2] = __v; addr[3] = __v >> 8; \ ++ __v = SMC_inw( ioaddr, ADDR2_REG ); \ ++ addr[4] = __v; addr[5] = __v >> 8; \ ++ } while (0) ++#endif ++ ++#define SMC_SET_MAC_ADDR(addr) \ ++ do { \ ++ SMC_outw( addr[0]|(addr[1] << 8), ioaddr, ADDR0_REG ); \ ++ SMC_outw( addr[2]|(addr[3] << 8), ioaddr, ADDR1_REG ); \ ++ SMC_outw( addr[4]|(addr[5] << 8), ioaddr, ADDR2_REG ); \ ++ } while (0) ++ ++#define SMC_CLEAR_MCAST() \ ++ do { \ ++ SMC_outw( 0, ioaddr, MCAST_REG1 ); \ ++ SMC_outw( 0, ioaddr, MCAST_REG2 ); \ ++ SMC_outw( 0, ioaddr, MCAST_REG3 ); \ ++ SMC_outw( 0, ioaddr, MCAST_REG4 ); \ ++ } while (0) ++#define SMC_SET_MCAST(x) \ ++ do { \ ++ unsigned char *mt = (x); \ ++ SMC_outw( mt[0] | (mt[1] << 8), ioaddr, MCAST_REG1 ); \ ++ SMC_outw( mt[2] | (mt[3] << 8), ioaddr, MCAST_REG2 ); \ ++ SMC_outw( mt[4] | (mt[5] << 8), ioaddr, MCAST_REG3 ); \ ++ SMC_outw( mt[6] | (mt[7] << 8), ioaddr, MCAST_REG4 ); \ ++ } while (0) ++ ++#if SMC_CAN_USE_32BIT ++/* ++ * Some setups just can't write 8 or 16 bits reliably when not aligned ++ * to a 32 bit boundary. I tell you that exists! ++ * We do the ones that can have their low parts written to 0 here. ++ */ ++#undef SMC_SELECT_BANK ++#define SMC_SELECT_BANK(x) SMC_outl( (x)<<16, ioaddr, 12<<SMC_IO_SHIFT ) ++#undef SMC_SET_RPC ++#define SMC_SET_RPC(x) SMC_outl( (x)<<16, ioaddr, SMC_REG(8, 0) ) ++#undef SMC_SET_PN ++#define SMC_SET_PN(x) SMC_outl( (x)<<16, ioaddr, SMC_REG(0, 2) ) ++#undef SMC_SET_PTR ++#define SMC_SET_PTR(x) SMC_outl( (x)<<16, ioaddr, SMC_REG(4, 2) ) ++#endif ++ ++#if SMC_CAN_USE_32BIT ++#define SMC_PUT_PKT_HDR(status, length) \ ++ SMC_outl( (status) | (length) << 16, ioaddr, DATA_REG ) ++#define SMC_GET_PKT_HDR(status, length) \ ++ do { \ ++ unsigned int __val = SMC_inl( ioaddr, DATA_REG ); \ ++ (status) = __val & 0xffff; \ ++ (length) = __val >> 16; \ ++ } while (0) ++#else ++#define SMC_PUT_PKT_HDR(status, length) \ ++ do { \ ++ SMC_outw( status, ioaddr, DATA_REG ); \ ++ SMC_outw( length, ioaddr, DATA_REG ); \ ++ } while (0) ++#define SMC_GET_PKT_HDR(status, length) \ ++ do { \ ++ (status) = SMC_inw( ioaddr, DATA_REG ); \ ++ (length) = SMC_inw( ioaddr, DATA_REG ); \ ++ } while (0) ++#endif ++ ++#if SMC_CAN_USE_32BIT ++#define SMC_PUSH_DATA(p, l) \ ++ do { \ ++ char *__ptr = (p); \ ++ int __len = (l); \ ++ if (__len >= 2 && (long)__ptr & 2) { \ ++ __len -= 2; \ ++ SMC_outw( *((u16 *)__ptr)++, ioaddr, DATA_REG );\ ++ } \ ++ SMC_outsl( ioaddr, DATA_REG, __ptr, __len >> 2); \ ++ if (__len & 2) { \ ++ __ptr += (__len & ~3); \ ++ SMC_outw( *((u16 *)__ptr), ioaddr, DATA_REG ); \ ++ } \ ++ } while (0) ++#define SMC_PULL_DATA(p, l) \ ++ do { \ ++ char *__ptr = (p); \ ++ int __len = (l); \ ++ if ((long)__ptr & 2) { \ ++ /* \ ++ * We want 32bit alignment here. \ ++ * Since some buses perform a full 32bit \ ++ * fetch even for 16bit data we can't use \ ++ * SMC_inw() here. Back both source (on chip \ ++ * and destination) pointers of 2 bytes. \ ++ */ \ ++ (long)__ptr &= ~2; \ ++ __len += 2; \ ++ SMC_SET_PTR( 2|PTR_READ|PTR_RCV|PTR_AUTOINC ); \ ++ } \ ++ __len += 2; \ ++ SMC_insl( ioaddr, DATA_REG, __ptr, __len >> 2); \ ++ } while (0) ++#elif SMC_CAN_USE_16BIT ++#define SMC_PUSH_DATA(p, l) SMC_outsw( ioaddr, DATA_REG, p, (l) >> 1 ) ++#define SMC_PULL_DATA(p, l) SMC_insw ( ioaddr, DATA_REG, p, (l) >> 1 ) ++#elif SMC_CAN_USE_8BIT ++#define SMC_PUSH_DATA(p, l) SMC_outsb( ioaddr, DATA_REG, p, l ) ++#define SMC_PULL_DATA(p, l) SMC_insb ( ioaddr, DATA_REG, p, l ) ++#endif ++ ++#if ! SMC_CAN_USE_16BIT ++#define SMC_outw(x, ioaddr, reg) \ ++ do { \ ++ unsigned int __val16 = (x); \ ++ SMC_outb( __val16, ioaddr, reg ); \ ++ SMC_outb( __val16 >> 8, ioaddr, reg + 1 ); \ ++ } while (0) ++#define SMC_inw(ioaddr, reg) \ ++ ({ \ ++ unsigned int __val16; \ ++ __val16 = SMC_inb( ioaddr, reg ); \ ++ __val16 |= SMC_inb( ioaddr, reg + 1 ) << 8; \ ++ __val16; \ ++ }) ++#endif ++ ++ ++#endif /* _SMC91X_H_ */ +--- linux-2.4.27/drivers/pcmcia/Config.in~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/pcmcia/Config.in +@@ -45,6 +45,7 @@ + if [ "$CONFIG_ARM" = "y" ]; then + dep_tristate ' CLPS6700 support' CONFIG_PCMCIA_CLPS6700 $CONFIG_ARCH_CLPS711X $CONFIG_PCMCIA + dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA ++ dep_tristate ' PXA250/210 support' CONFIG_PCMCIA_PXA $CONFIG_ARCH_PXA $CONFIG_PCMCIA + fi + + endmenu +--- linux-2.4.27/drivers/pcmcia/Makefile~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/pcmcia/Makefile +@@ -94,6 +94,11 @@ + + obj-$(CONFIG_PCMCIA_VRC4173) += vrc4173_cardu.o + ++subdir-$(CONFIG_PCMCIA_PXA) += pxa ++ifeq ($(CONFIG_PCMCIA_PXA),y) ++ obj-y += pxa/pxa_cs.o ++endif ++ + include $(TOPDIR)/Rules.make + + pcmcia_core.o: $(pcmcia_core-objs) +--- /dev/null ++++ linux-2.4.27/drivers/pcmcia/pxa/Makefile +@@ -0,0 +1,18 @@ ++# ++# Makefile for the Intel PXA250/210 PCMCIA driver ++# ++# Note! Dependencies are done automagically by 'make dep', which also ++# removes any old dependencies. DON'T put your own dependencies here ++# unless it's something special (ie not a .c file). ++ ++O_TARGET := pxa_cs.o ++ ++obj-y := pxa.o ++obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o ++obj-$(CONFIG_ARCH_PXA_IDP) += pxa_idp.o ++obj-$(CONFIG_ARCH_TRIZEPS2) += trizeps2.o ++obj-$(CONFIG_ARCH_PXA_CERF) += ../sa1100_cerf.o ++ ++obj-m := $(O_TARGET) ++ ++include $(TOPDIR)/Rules.make +--- /dev/null ++++ linux-2.4.27/drivers/pcmcia/pxa/lubbock.c +@@ -0,0 +1,329 @@ ++/* ++ * linux/drivers/pcmcia/pxa/lubbock.c ++ * ++ * Author: George Davis ++ * Created: Jan 10, 2002 ++ * Copyright: MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Originally based upon linux/drivers/pcmcia/sa1100_neponset.c ++ * ++ * Lubbock PCMCIA specific routines. ++ * ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/sched.h> ++ ++#include <pcmcia/ss.h> ++ ++#include <asm/delay.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/arch/pcmcia.h> ++#include <asm/hardware/sa1111.h> ++ ++/* ++ * I'd really like to move the INTPOL stuff to arch/arm/mach-sa1100/sa1111.c ++ * ... and maybe even arch/arm/mach-pxa/sa1111.c now too! : ) ++ */ ++#define SA1111_IRQMASK_LO(x) (1 << (x - IRQ_SA1111_START)) ++#define SA1111_IRQMASK_HI(x) (1 << (x - IRQ_SA1111_START - 32)) ++ ++static int lubbock_pcmcia_init(struct pcmcia_init *init){ ++ int return_val=0; ++ ++ /* Set PCMCIA Socket 0 power to standby mode. ++ */ ++ PA_DWR &= ~(GPIO_bit(0) | GPIO_bit(1) | GPIO_bit(2) | GPIO_bit(3)); ++ ++ /* Set GPIO_A<3:0> to be outputs for PCMCIA (socket 0) power controller. ++ * Note that this is done only after first initializing GPIO_A<3:0> ++ * output state above to be certain that we drive signals to the same ++ * state as the pull-downs connected to these lines. The pull-downs are ++ * req'd to make sure PCMCIA power is OFF until we can get around to ++ * setting up the GPIO_A<3:0> state and direction. ++ */ ++ PA_DDR &= ~(GPIO_bit(0) | GPIO_bit(1) | GPIO_bit(2) | GPIO_bit(3)); ++ ++ /* Set CF Socket 1 power to standby mode. */ ++ LUB_MISC_WR &= ~(GPIO_bit(15) | GPIO_bit(14)); ++ ++ INTPOL1 |= SA1111_IRQMASK_HI(S0_READY_NINT) | ++ SA1111_IRQMASK_HI(S1_READY_NINT) | ++ SA1111_IRQMASK_HI(S0_CD_VALID) | ++ SA1111_IRQMASK_HI(S1_CD_VALID) | ++ SA1111_IRQMASK_HI(S0_BVD1_STSCHG) | ++ SA1111_IRQMASK_HI(S1_BVD1_STSCHG); ++ ++#warning what if a request_irq fails? ++ return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT, ++ "Lubbock PCMCIA (0) CD", NULL); ++ return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT, ++ "Lubbock CF (1) CD", NULL); ++ return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT, ++ "Lubbock PCMCIA (0) BVD1", NULL); ++ return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT, ++ "Lubbock CF (1) BVD1", NULL); ++ ++ return (return_val<0) ? -1 : 2; ++} ++ ++static int lubbock_pcmcia_shutdown(void){ ++ ++ free_irq(S0_CD_VALID, NULL); ++ free_irq(S1_CD_VALID, NULL); ++ free_irq(S0_BVD1_STSCHG, NULL); ++ free_irq(S1_BVD1_STSCHG, NULL); ++ ++ INTPOL1 &= ~(SA1111_IRQMASK_HI(S0_CD_VALID) | ++ SA1111_IRQMASK_HI(S1_CD_VALID) | ++ SA1111_IRQMASK_HI(S0_BVD1_STSCHG) | ++ SA1111_IRQMASK_HI(S1_BVD1_STSCHG)); ++ ++ return 0; ++} ++ ++static int lubbock_pcmcia_socket_state(struct pcmcia_state_array ++ *state_array){ ++ unsigned long status; ++ int return_val=1; ++ ++ if(state_array->size<2) return -1; ++ ++ memset(state_array->state, 0, ++ (state_array->size)*sizeof(struct pcmcia_state)); ++ ++ status=PCSR; ++ ++ state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0; ++ ++ state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1; ++ ++ state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1; ++ ++ state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1; ++ ++ state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1; ++ ++ state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0; ++ ++ state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0; ++ ++ state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0; ++ ++ state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1; ++ ++ state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1; ++ ++ state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1; ++ ++ state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1; ++ ++ state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0; ++ ++ state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0; ++ ++ return return_val; ++} ++ ++static int lubbock_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ ++ ++ switch(info->sock){ ++ case 0: ++ info->irq=S0_READY_NINT; ++ break; ++ ++ case 1: ++ info->irq=S1_READY_NINT; ++ break; ++ ++ default: ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int ++lubbock_pcmcia_configure_socket(unsigned int sock, socket_state_t *state) ++{ ++ unsigned long flags, pccr, gpio, misc_wr, status; ++ int ret=1; ++ ++ local_irq_save(flags); ++ ++ pccr=PCCR; ++ gpio=PA_DWR; ++ misc_wr = LUB_MISC_WR; ++ ++ /* Lubbock uses the Maxim MAX1602, with the following connections: ++ * ++ * Socket 0 (PCMCIA): ++ * MAX1602 Lubbock Register ++ * Pin Signal ++ * ----- ------- ---------------------- ++ * A0VPP S0_PWR0 SA-1111 GPIO A<0> ++ * A1VPP S0_PWR1 SA-1111 GPIO A<1> ++ * A0VCC S0_PWR2 SA-1111 GPIO A<2> ++ * A1VCC S0_PWR3 SA-1111 GPIO A<3> ++ * VX VCC ++ * VY +3.3V ++ * 12IN +12V ++ * CODE +3.3V Cirrus Code, CODE = High (VY) ++ * ++ * Socket 1 (CF): ++ * MAX1602 Lubbock Register ++ * Pin Signal ++ * ----- ------- ---------------------- ++ * A0VPP GND VPP is not connected ++ * A1VPP GND VPP is not connected ++ * A0VCC S1_PWR0 MISC_WR<14> ++ * A1VCC S1_PWR0 MISC_WR<15> ++ * VX VCC ++ * VY +3.3V ++ * 12IN GND VPP is not connected ++ * CODE +3.3V Cirrus Code, CODE = High (VY) ++ * ++ */ ++ ++again: ++ switch(sock){ ++ case 0: ++ ++ switch(state->Vcc){ ++ case 0: ++ pccr = (pccr & ~PCCR_S0_FLT); ++ gpio &= ~(GPIO_bit(2) | GPIO_bit(3)); ++ break; ++ ++ case 33: ++ pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN; ++ gpio = (gpio & ~(GPIO_bit(2) | GPIO_bit(3))) | GPIO_bit(3); ++ break; ++ ++ case 50: ++ pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN); ++ gpio = (gpio & ~(GPIO_bit(2) | GPIO_bit(3))) | GPIO_bit(2); ++ break; ++ ++ default: ++ printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, state->Vcc); ++ ret = -1; ++ break; ++ } ++ ++ switch(state->Vpp){ ++ case 0: ++ gpio &= ~(GPIO_bit(0) | GPIO_bit(1)); ++ break; ++ ++ case 120: ++ gpio = (gpio & ~(GPIO_bit(0) | GPIO_bit(1))) | GPIO_bit(1); ++ break; ++ ++ default: ++ /* REVISIT: I'm not sure about this? Is this correct? ++ Is it always safe or do we have potential problems ++ with bogus combinations of Vcc and Vpp settings? */ ++ if(state->Vpp == state->Vcc) ++ gpio = (gpio & ~(GPIO_bit(0) | GPIO_bit(1))) | GPIO_bit(0); ++ else { ++ printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__, state->Vpp); ++ ret = -1; ++ break; ++ } ++ } ++ ++ pccr = (state->flags&SS_RESET) ? (pccr|PCCR_S0_RST) : (pccr&~PCCR_S0_RST); ++ ++ break; ++ ++ case 1: ++ switch(state->Vcc){ ++ case 0: ++ pccr = (pccr & ~PCCR_S1_FLT); ++ misc_wr &= ~((1 << 15) | (1 << 14)); ++ break; ++ ++ case 33: ++ pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN; ++ misc_wr = (misc_wr & ~(1 << 15)) | (1 << 14); ++ gpio = (gpio & ~(GPIO_bit(2) | GPIO_bit(3))) | GPIO_bit(2); ++ break; ++ ++ case 50: ++ pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN); ++ misc_wr = (misc_wr & ~(1 << 15)) | (1 << 14); ++ break; ++ ++ default: ++ printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, state->Vcc); ++ ret = -1; ++ break; ++ } ++ ++ if(state->Vpp!=state->Vcc && state->Vpp!=0){ ++ printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__, state->Vpp); ++ ret = -1; ++ break; ++ } ++ ++ pccr = (state->flags&SS_RESET) ? (pccr|PCCR_S1_RST) : (pccr&~PCCR_S1_RST); ++ ++ break; ++ ++ default: ++ ret = -1; ++ } ++ ++ if (ret >= 0) { ++ PCCR = pccr; ++ LUB_MISC_WR = misc_wr; ++ PA_DWR = gpio; ++ } ++ ++ if (ret > 0) { ++ ret = 0; ++ /* ++ * HACK ALERT: ++ * We can't sense the voltage properly on Lubbock before actually ++ * applying some power to the socket (catch 22). ++ * Resense the socket Voltage Sense pins after applying socket power. ++ */ ++ if (sock == 0) ++ status = PCSR & (PCSR_S0_VS1 | PCSR_S0_VS2); ++ else ++ status = PCSR & (PCSR_S1_VS1 | PCSR_S1_VS2); ++ ++ if ((status == (PCSR_S0_VS1 | PCSR_S0_VS2)) && (state->Vcc == 33)) { ++ /* Switch to 5V, Configure socket 0 with 5V voltage */ ++ PA_DWR &= ~(GPIO_bit(0) | GPIO_bit(1) | GPIO_bit(2) | GPIO_bit(3)); ++ PA_DDR &= ~(GPIO_bit(0) | GPIO_bit(1) | GPIO_bit(2) | GPIO_bit(3)); ++ state->Vcc = 50; ++ state->Vpp = 50; ++ goto again; ++ } ++ if ((status == (PCSR_S1_VS1 | PCSR_S1_VS2)) && (state->Vcc == 33)) { ++ /* Switch to 5V, Configure socket 1 with 5V voltage */ ++ LUB_MISC_WR &= ~((1 << 15) | (1 << 14)); ++ state->Vcc = 50; ++ state->Vpp = 50; ++ goto again; ++ } ++ } ++ ++ local_irq_restore(flags); ++ return ret; ++} ++ ++struct pcmcia_low_level lubbock_pcmcia_ops = { ++ lubbock_pcmcia_init, ++ lubbock_pcmcia_shutdown, ++ lubbock_pcmcia_socket_state, ++ lubbock_pcmcia_get_irq_info, ++ lubbock_pcmcia_configure_socket ++}; +--- /dev/null ++++ linux-2.4.27/drivers/pcmcia/pxa/pxa.c +@@ -0,0 +1,1247 @@ ++/* ++ * linux/drivers/pcmcia/pxa/pxa.c ++ * ++ * Author: George Davis ++ * Created: Jan 10, 2002 ++ * Copyright: MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Originally based upon linux/drivers/pcmcia/sa1100_generic.c ++ * ++ */ ++ ++/*====================================================================== ++ ++ Device driver for the PCMCIA control functionality of Intel ++ PXA250/210 microprocessors. ++ ++ The contents of this file are subject to the Mozilla Public ++ License Version 1.1 (the "License"); you may not use this file ++ except in compliance with the License. You may obtain a copy of ++ the License at http://www.mozilla.org/MPL/ ++ ++ Software distributed under the License is distributed on an "AS ++ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++ implied. See the License for the specific language governing ++ rights and limitations under the License. ++ ++ The initial developer of the original code is John G. Dorsey ++ <john+@cs.cmu.edu>. Portions created by John G. Dorsey are ++ Copyright (C) 1999 John G. Dorsey. All Rights Reserved. ++ ++ Alternatively, the contents of this file may be used under the ++ terms of the GNU Public License version 2 (the "GPL"), in which ++ case the provisions of the GPL are applicable instead of the ++ above. If you wish to allow the use of your version of this file ++ only under the terms of the GPL and not to allow others to use ++ your version of this file under the MPL, indicate your decision ++ by deleting the provisions above and replace them with the notice ++ and other provisions required by the GPL. If you do not delete ++ the provisions above, a recipient may use your version of this ++ file under either the MPL or the GPL. ++ ++======================================================================*/ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/config.h> ++#include <linux/cpufreq.h> ++#include <linux/delay.h> ++#include <linux/ioport.h> ++#include <linux/kernel.h> ++#include <linux/tqueue.h> ++#include <linux/timer.h> ++#include <linux/mm.h> ++#include <linux/notifier.h> ++#include <linux/proc_fs.h> ++#include <linux/version.h> ++#include <linux/cpufreq.h> ++ ++#include <pcmcia/version.h> ++#include <pcmcia/cs_types.h> ++#include <pcmcia/cs.h> ++#include <pcmcia/ss.h> ++#include <pcmcia/bus_ops.h> ++ ++#include <asm/hardware.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/system.h> ++#include <asm/arch/lubbock.h> ++ ++#include "pxa.h" ++ ++#ifdef PCMCIA_DEBUG ++static int pc_debug; ++#endif ++ ++MODULE_AUTHOR("George Davis <davis_g@mvista.com>"); ++MODULE_DESCRIPTION("Linux PCMCIA Card Services: PXA250/210 Socket Controller"); ++ ++/* This structure maintains housekeeping state for each socket, such ++ * as the last known values of the card detect pins, or the Card Services ++ * callback value associated with the socket: ++ */ ++static struct pxa_pcmcia_socket ++pxa_pcmcia_socket[PXA_PCMCIA_MAX_SOCK]; ++ ++static int pxa_pcmcia_socket_count; ++ ++ ++/* Returned by the low-level PCMCIA interface: */ ++static struct pcmcia_low_level *pcmcia_low_level; ++ ++/* Event poll timer structure */ ++static struct timer_list poll_timer; ++ ++ ++/* Prototypes for routines which are used internally: */ ++ ++static int pxa_pcmcia_driver_init(void); ++static void pxa_pcmcia_driver_shutdown(void); ++static void pxa_pcmcia_task_handler(void *data); ++static void pxa_pcmcia_poll_event(unsigned long data); ++static void pxa_pcmcia_interrupt(int irq, void *dev, ++ struct pt_regs *regs); ++static struct tq_struct pxa_pcmcia_task; ++ ++#ifdef CONFIG_PROC_FS ++static int pxa_pcmcia_proc_status(char *buf, char **start, off_t pos, ++ int count, int *eof, void *data); ++#endif ++ ++ ++/* Prototypes for operations which are exported to the ++ * new-and-impr^H^H^H^H^H^H^H^H^H^H in-kernel PCMCIA core: ++ */ ++ ++static int pxa_pcmcia_init(unsigned int sock); ++static int pxa_pcmcia_suspend(unsigned int sock); ++static int pxa_pcmcia_register_callback(unsigned int sock, ++ void (*handler)(void *, ++ unsigned int), ++ void *info); ++static int pxa_pcmcia_inquire_socket(unsigned int sock, ++ socket_cap_t *cap); ++static int pxa_pcmcia_get_status(unsigned int sock, u_int *value); ++static int pxa_pcmcia_get_socket(unsigned int sock, ++ socket_state_t *state); ++static int pxa_pcmcia_set_socket(unsigned int sock, ++ socket_state_t *state); ++static int pxa_pcmcia_get_io_map(unsigned int sock, ++ struct pccard_io_map *io); ++static int pxa_pcmcia_set_io_map(unsigned int sock, ++ struct pccard_io_map *io); ++static int pxa_pcmcia_get_mem_map(unsigned int sock, ++ struct pccard_mem_map *mem); ++static int pxa_pcmcia_set_mem_map(unsigned int sock, ++ struct pccard_mem_map *mem); ++#ifdef CONFIG_PROC_FS ++static void pxa_pcmcia_proc_setup(unsigned int sock, ++ struct proc_dir_entry *base); ++#endif ++ ++static struct pccard_operations pxa_pcmcia_operations = { ++ pxa_pcmcia_init, ++ pxa_pcmcia_suspend, ++ pxa_pcmcia_register_callback, ++ pxa_pcmcia_inquire_socket, ++ pxa_pcmcia_get_status, ++ pxa_pcmcia_get_socket, ++ pxa_pcmcia_set_socket, ++ pxa_pcmcia_get_io_map, ++ pxa_pcmcia_set_io_map, ++ pxa_pcmcia_get_mem_map, ++ pxa_pcmcia_set_mem_map, ++#ifdef CONFIG_PROC_FS ++ pxa_pcmcia_proc_setup ++#endif ++}; ++ ++#ifdef CONFIG_CPU_FREQ ++/* forward declaration */ ++static struct notifier_block pxa_pcmcia_notifier_block; ++#endif ++ ++ ++/* pxa_pcmcia_driver_init() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * ++ * This routine performs a basic sanity check to ensure that this ++ * kernel has been built with the appropriate board-specific low-level ++ * PCMCIA support, performs low-level PCMCIA initialization, registers ++ * this socket driver with Card Services, and then spawns the daemon ++ * thread which is the real workhorse of the socket driver. ++ * ++ * Please see linux/Documentation/arm/SA1100/PCMCIA for more information ++ * on the low-level kernel interface. ++ * ++ * Returns: 0 on success, -1 on error ++ */ ++static int __init pxa_pcmcia_driver_init(void){ ++ servinfo_t info; ++ struct pcmcia_init pcmcia_init; ++ struct pcmcia_state state[PXA_PCMCIA_MAX_SOCK]; ++ struct pcmcia_state_array state_array; ++ unsigned int i, clock; ++ unsigned long mecr; ++ ++ printk(KERN_INFO "Intel PXA250/210 PCMCIA (CS release %s)\n", CS_RELEASE); ++ ++ CardServices(GetCardServicesInfo, &info); ++ ++ if(info.Revision!=CS_RELEASE_CODE){ ++ printk(KERN_ERR "Card Services release codes do not match\n"); ++ return -1; ++ } ++ ++ /* Setup GPIOs for PCMCIA/CF alternate function mode. ++ * ++ * It would be nice if set_GPIO_mode included support ++ * for driving GPIO outputs to default high/low state ++ * before programming GPIOs as outputs. Setting GPIO ++ * outputs to default high/low state via GPSR/GPCR ++ * before defining them as outputs should reduce ++ * the possibility of glitching outputs during GPIO ++ * setup. This of course assumes external terminators ++ * are present to hold GPIOs in a defined state. ++ * ++ * In the meantime, setup default state of GPIO ++ * outputs before we enable them as outputs. ++ */ ++ ++ GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) | ++ GPIO_bit(GPIO49_nPWE) | ++ GPIO_bit(GPIO50_nPIOR) | ++ GPIO_bit(GPIO51_nPIOW) | ++ GPIO_bit(GPIO52_nPCE_1) | ++ GPIO_bit(GPIO53_nPCE_2); ++ ++ set_GPIO_mode(GPIO48_nPOE_MD); ++ set_GPIO_mode(GPIO49_nPWE_MD); ++ set_GPIO_mode(GPIO50_nPIOR_MD); ++ set_GPIO_mode(GPIO51_nPIOW_MD); ++ set_GPIO_mode(GPIO52_nPCE_1_MD); ++ set_GPIO_mode(GPIO53_nPCE_2_MD); ++ set_GPIO_mode(GPIO54_pSKTSEL_MD); /* REVISIT: s/b dependent on num sockets */ ++ set_GPIO_mode(GPIO55_nPREG_MD); ++ set_GPIO_mode(GPIO56_nPWAIT_MD); ++ set_GPIO_mode(GPIO57_nIOIS16_MD); ++ ++ ++ if(machine_is_lubbock()){ ++#if defined(CONFIG_ARCH_LUBBOCK) || defined(CONFIG_ARCH_CSB226) ++ pcmcia_low_level=&lubbock_pcmcia_ops; ++#endif ++ } else if (machine_is_pxa_idp()) { ++ pcmcia_low_level=&pxa_idp_pcmcia_ops; ++ } else if( machine_is_pxa_cerf()){ ++ pcmcia_low_level=&cerf_pcmcia_ops; ++ } else if (machine_is_trizeps2()){ ++#ifdef CONFIG_ARCH_TRIZEPS2 ++ pcmcia_low_level=&trizeps2_pcmcia_ops; ++#endif ++ } ++ ++ if (!pcmcia_low_level) { ++ printk(KERN_ERR "This hardware is not supported by the PXA250/210 Card Service driver\n"); ++ return -ENODEV; ++ } ++ ++ pcmcia_init.handler=pxa_pcmcia_interrupt; ++ ++ if((pxa_pcmcia_socket_count=pcmcia_low_level->init(&pcmcia_init))<0){ ++ printk(KERN_ERR "Unable to initialize kernel PCMCIA service.\n"); ++ return -EIO; ++ } ++ ++ state_array.size=pxa_pcmcia_socket_count; ++ state_array.state=state; ++ ++ /* Configure MECR based on the number of sockets present. */ ++ if (pxa_pcmcia_socket_count == 2) { ++ MECR |= GPIO_bit(0); ++ } else { ++ MECR &= ~GPIO_bit(0); ++ } ++ ++ if(pcmcia_low_level->socket_state(&state_array)<0){ ++ printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n"); ++ return -EIO; ++ } ++ ++ /* Well, it looks good to go. So we can now enable the PCMCIA ++ * controller. ++ */ ++ MECR |= GPIO_bit(1); ++ ++ /* We need to initialize the MCXX registers to default values ++ * here because we're not guaranteed to see a SetIOMap operation ++ * at runtime. ++ */ ++ ++ clock = get_lclk_frequency_10khz(); ++ ++ for(i=0; i<pxa_pcmcia_socket_count; ++i){ ++ pxa_pcmcia_socket[i].k_state=state[i]; ++ ++ /* This is an interim fix. Apparently, SetSocket is no longer ++ * called to initialize each socket (prior to the first detect ++ * event). For now, we'll just manually set up the mask. ++ */ ++ pxa_pcmcia_socket[i].cs_state.csc_mask=SS_DETECT; ++ ++ pxa_pcmcia_socket[i].virt_io=(i==0)?PCMCIA_IO_0_BASE:PCMCIA_IO_1_BASE; ++ pxa_pcmcia_socket[i].phys_attr=_PCMCIAAttr(i); ++ pxa_pcmcia_socket[i].phys_mem=_PCMCIAMem(i); ++ ++ /* REVISIT: cleanup these macros */ ++ //MCIO_SET(i, PXA_PCMCIA_IO_ACCESS, clock); ++ //MCATTR_SET(i, PXA_PCMCIA_5V_MEM_ACCESS, clock); ++ //MCMEM_SET(i, PXA_PCMCIA_5V_MEM_ACCESS, clock); ++ ++ pxa_pcmcia_socket[i].speed_io=PXA_PCMCIA_IO_ACCESS; ++ pxa_pcmcia_socket[i].speed_attr=PXA_PCMCIA_ATTR_MEM_ACCESS; ++ pxa_pcmcia_socket[i].speed_mem=PXA_PCMCIA_5V_MEM_ACCESS; ++ } ++ ++/* REVISIT: cleanup these macros */ ++MCMEM0 = ((pxa_mcxx_setup(PXA_PCMCIA_5V_MEM_ACCESS, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(PXA_PCMCIA_5V_MEM_ACCESS, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(PXA_PCMCIA_5V_MEM_ACCESS, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++MCMEM1 = ((pxa_mcxx_setup(PXA_PCMCIA_5V_MEM_ACCESS, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(PXA_PCMCIA_5V_MEM_ACCESS, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(PXA_PCMCIA_5V_MEM_ACCESS, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++MCATT0 = ((pxa_mcxx_setup(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++MCATT1 = ((pxa_mcxx_setup(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++MCIO0 = ((pxa_mcxx_setup(PXA_PCMCIA_IO_ACCESS, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(PXA_PCMCIA_IO_ACCESS, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(PXA_PCMCIA_IO_ACCESS, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++MCIO1 = ((pxa_mcxx_setup(PXA_PCMCIA_IO_ACCESS, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(PXA_PCMCIA_IO_ACCESS, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(PXA_PCMCIA_IO_ACCESS, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++ ++#ifdef CONFIG_CPU_FREQ ++ if(cpufreq_register_notifier(&pxa_pcmcia_notifier_block) < 0){ ++ printk(KERN_ERR "Unable to register CPU frequency change notifier\n"); ++ return -ENXIO; ++ } ++#endif ++ ++ /* Only advertise as many sockets as we can detect: */ ++ if(register_ss_entry(pxa_pcmcia_socket_count, ++ &pxa_pcmcia_operations)<0){ ++ printk(KERN_ERR "Unable to register socket service routine\n"); ++ return -ENXIO; ++ } ++ ++ /* Start the event poll timer. It will reschedule by itself afterwards. */ ++ pxa_pcmcia_poll_event(0); ++ ++ DEBUG(1, "pxa_cs: initialization complete\n"); ++ ++ return 0; ++ ++} /* pxa_pcmcia_driver_init() */ ++ ++module_init(pxa_pcmcia_driver_init); ++ ++ ++/* pxa_pcmcia_driver_shutdown() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Invokes the low-level kernel service to free IRQs associated with this ++ * socket controller and reset GPIO edge detection. ++ */ ++static void __exit pxa_pcmcia_driver_shutdown(void){ ++ ++ del_timer_sync(&poll_timer); ++ unregister_ss_entry(&pxa_pcmcia_operations); ++#ifdef CONFIG_CPU_FREQ ++ cpufreq_unregister_notifier(&pxa_pcmcia_notifier_block); ++#endif ++ pcmcia_low_level->shutdown(); ++ flush_scheduled_tasks(); ++ ++ DEBUG(1, "pxa_cs: shutdown complete\n"); ++} ++ ++module_exit(pxa_pcmcia_driver_shutdown); ++ ++ ++/* pxa_pcmcia_init() ++ * ^^^^^^^^^^^^^^^^^^^^ ++ * We perform all of the interesting initialization tasks in ++ * pxa_pcmcia_driver_init(). ++ * ++ * Returns: 0 ++ */ ++static int pxa_pcmcia_init(unsigned int sock){ ++ ++ DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, sock); ++ ++ return 0; ++} ++ ++ ++/* pxa_pcmcia_suspend() ++ * ^^^^^^^^^^^^^^^^^^^^^^^ ++ * We don't currently perform any actions on a suspend. ++ * ++ * Returns: 0 ++ */ ++static int pxa_pcmcia_suspend(unsigned int sock) ++{ ++ socket_state_t st; ++ int ret; ++ ++ DEBUG(2, "%s(): suspending socket %u\n", __FUNCTION__, sock); ++ ++ st.Vcc = 0; ++ st.Vpp = 0; ++ st.flags = SS_RESET; ++ ++ ret = pcmcia_low_level->configure_socket(sock, &st); ++ ++ if (ret == 0) ++ pxa_pcmcia_socket[sock].cs_state = dead_socket; ++ ++ return ret; ++} ++ ++ ++/* pxa_pcmcia_events() ++ * ^^^^^^^^^^^^^^^^^^^^^^ ++ * Helper routine to generate a Card Services event mask based on ++ * state information obtained from the kernel low-level PCMCIA layer ++ * in a recent (and previous) sampling. Updates `prev_state'. ++ * ++ * Returns: an event mask for the given socket state. ++ */ ++static inline unsigned pxa_pcmcia_events(struct pcmcia_state *state, ++ struct pcmcia_state *prev_state, ++ unsigned int mask, ++ unsigned int flags){ ++ unsigned int events=0; ++ ++ if(state->detect!=prev_state->detect){ ++ ++ DEBUG(2, "%s(): card detect value %u\n", __FUNCTION__, state->detect); ++ ++ events|=mask&SS_DETECT; ++ } ++ ++ if(state->ready!=prev_state->ready){ ++ ++ DEBUG(2, "%s(): card ready value %u\n", __FUNCTION__, state->ready); ++ ++ events|=mask&((flags&SS_IOCARD)?0:SS_READY); ++ } ++ ++ if(state->bvd1!=prev_state->bvd1){ ++ ++ DEBUG(2, "%s(): card BVD1 value %u\n", __FUNCTION__, state->bvd1); ++ ++ events|=mask&(flags&SS_IOCARD)?SS_STSCHG:SS_BATDEAD; ++ } ++ ++ if(state->bvd2!=prev_state->bvd2){ ++ ++ DEBUG(2, "%s(): card BVD2 value %u\n", __FUNCTION__, state->bvd2); ++ ++ events|=mask&(flags&SS_IOCARD)?0:SS_BATWARN; ++ } ++ ++ DEBUG(2, "events: %s%s%s%s%s%s\n", ++ (events==0)?"<NONE>":"", ++ (events&SS_DETECT)?"DETECT ":"", ++ (events&SS_READY)?"READY ":"", ++ (events&SS_BATDEAD)?"BATDEAD ":"", ++ (events&SS_BATWARN)?"BATWARN ":"", ++ (events&SS_STSCHG)?"STSCHG ":""); ++ ++ *prev_state=*state; ++ ++ return events; ++ ++} /* pxa_pcmcia_events() */ ++ ++ ++/* pxa_pcmcia_task_handler() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Processes serviceable socket events using the "eventd" thread context. ++ * ++ * Event processing (specifically, the invocation of the Card Services event ++ * callback) occurs in this thread rather than in the actual interrupt ++ * handler due to the use of scheduling operations in the PCMCIA core. ++ */ ++static void pxa_pcmcia_task_handler(void *data) { ++ struct pcmcia_state state[PXA_PCMCIA_MAX_SOCK]; ++ struct pcmcia_state_array state_array; ++ int i, events, all_events, irq_status; ++ ++ DEBUG(2, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__); ++ ++ state_array.size=pxa_pcmcia_socket_count; ++ state_array.state=state; ++ ++ do { ++ ++ DEBUG(3, "%s(): interrogating low-level PCMCIA service\n", __FUNCTION__); ++ ++ if((irq_status=pcmcia_low_level->socket_state(&state_array))<0) ++ printk(KERN_ERR "Error in kernel low-level PCMCIA service.\n"); ++ ++ all_events=0; ++ ++ if(irq_status>0){ ++ ++ for(i=0; i<state_array.size; ++i, all_events|=events) ++ if((events= ++ pxa_pcmcia_events(&state[i], ++ &pxa_pcmcia_socket[i].k_state, ++ pxa_pcmcia_socket[i].cs_state.csc_mask, ++ pxa_pcmcia_socket[i].cs_state.flags))) ++ if(pxa_pcmcia_socket[i].handler!=NULL) ++ pxa_pcmcia_socket[i].handler(pxa_pcmcia_socket[i].handler_info, ++ events); ++ } ++ ++ } while(all_events); ++} /* pxa_pcmcia_task_handler() */ ++ ++static struct tq_struct pxa_pcmcia_task = { ++ routine: pxa_pcmcia_task_handler ++}; ++ ++ ++/* pxa_pcmcia_poll_event() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Let's poll for events in addition to IRQs since IRQ only is unreliable... ++ */ ++static void pxa_pcmcia_poll_event(unsigned long dummy) ++{ ++ DEBUG(3, "%s(): polling for events\n", __FUNCTION__); ++ poll_timer.function = pxa_pcmcia_poll_event; ++ poll_timer.expires = jiffies + PXA_PCMCIA_POLL_PERIOD; ++ add_timer(&poll_timer); ++ schedule_task(&pxa_pcmcia_task); ++} ++ ++ ++/* pxa_pcmcia_interrupt() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Service routine for socket driver interrupts (requested by the ++ * low-level PCMCIA init() operation via pxa_pcmcia_thread()). ++ * The actual interrupt-servicing work is performed by ++ * pxa_pcmcia_thread(), largely because the Card Services event- ++ * handling code performs scheduling operations which cannot be ++ * executed from within an interrupt context. ++ */ ++static void pxa_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs){ ++ DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq); ++ schedule_task(&pxa_pcmcia_task); ++} ++ ++ ++/* pxa_pcmcia_register_callback() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Implements the register_callback() operation for the in-kernel ++ * PCMCIA service (formerly SS_RegisterCallback in Card Services). If ++ * the function pointer `handler' is not NULL, remember the callback ++ * location in the state for `sock', and increment the usage counter ++ * for the driver module. (The callback is invoked from the interrupt ++ * service routine, pxa_pcmcia_interrupt(), to notify Card Services ++ * of interesting events.) Otherwise, clear the callback pointer in the ++ * socket state and decrement the module usage count. ++ * ++ * Returns: 0 ++ */ ++static int pxa_pcmcia_register_callback(unsigned int sock, ++ void (*handler)(void *, ++ unsigned int), ++ void *info){ ++ if(handler==NULL){ ++ pxa_pcmcia_socket[sock].handler=NULL; ++ MOD_DEC_USE_COUNT; ++ } else { ++ MOD_INC_USE_COUNT; ++ pxa_pcmcia_socket[sock].handler=handler; ++ pxa_pcmcia_socket[sock].handler_info=info; ++ } ++ ++ return 0; ++} ++ ++ ++/* pxa_pcmcia_inquire_socket() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Implements the inquire_socket() operation for the in-kernel PCMCIA ++ * service (formerly SS_InquireSocket in Card Services). Of note is ++ * the setting of the SS_CAP_PAGE_REGS bit in the `features' field of ++ * `cap' to "trick" Card Services into tolerating large "I/O memory" ++ * addresses. Also set is SS_CAP_STATIC_MAP, which disables the memory ++ * resource database check. (Mapped memory is set up within the socket ++ * driver itself.) ++ * ++ * In conjunction with the STATIC_MAP capability is a new field, ++ * `io_offset', recommended by David Hinds. Rather than go through ++ * the SetIOMap interface (which is not quite suited for communicating ++ * window locations up from the socket driver), we just pass up ++ * an offset which is applied to client-requested base I/O addresses ++ * in alloc_io_space(). ++ * ++ * Returns: 0 on success, -1 if no pin has been configured for `sock' ++ */ ++static int pxa_pcmcia_inquire_socket(unsigned int sock, ++ socket_cap_t *cap){ ++ struct pcmcia_irq_info irq_info; ++ ++ DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock); ++ ++ if(sock>=pxa_pcmcia_socket_count){ ++ printk(KERN_ERR "pxa_cs: socket %u not configured\n", sock); ++ return -1; ++ } ++ ++ /* SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the ++ * force_low argument to validate_mem() in rsrc_mgr.c -- since in ++ * general, the mapped * addresses of the PCMCIA memory regions ++ * will not be within 0xffff, setting force_low would be ++ * undesirable. ++ * ++ * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory ++ * resource database; we instead pass up physical address ranges ++ * and allow other parts of Card Services to deal with remapping. ++ * ++ * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but ++ * not 32-bit CardBus devices. ++ */ ++ cap->features=(SS_CAP_PAGE_REGS | SS_CAP_STATIC_MAP | SS_CAP_PCCARD); ++ ++ irq_info.sock=sock; ++ irq_info.irq=-1; ++ ++ if(pcmcia_low_level->get_irq_info(&irq_info)<0){ ++ printk(KERN_ERR "Error obtaining IRQ info from kernel for socket %u\n", ++ sock); ++ return -1; ++ } ++ ++ cap->irq_mask=0; ++ cap->map_size=PAGE_SIZE; ++ cap->pci_irq=irq_info.irq; ++ cap->io_offset=pxa_pcmcia_socket[sock].virt_io; ++ ++ return 0; ++ ++} /* pxa_pcmcia_inquire_socket() */ ++ ++ ++/* pxa_pcmcia_get_status() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Implements the get_status() operation for the in-kernel PCMCIA ++ * service (formerly SS_GetStatus in Card Services). Essentially just ++ * fills in bits in `status' according to internal driver state or ++ * the value of the voltage detect chipselect register. ++ * ++ * As a debugging note, during card startup, the PCMCIA core issues ++ * three set_socket() commands in a row the first with RESET deasserted, ++ * the second with RESET asserted, and the last with RESET deasserted ++ * again. Following the third set_socket(), a get_status() command will ++ * be issued. The kernel is looking for the SS_READY flag (see ++ * setup_socket(), reset_socket(), and unreset_socket() in cs.c). ++ * ++ * Returns: 0 ++ */ ++static int pxa_pcmcia_get_status(unsigned int sock, ++ unsigned int *status){ ++ struct pcmcia_state state[PXA_PCMCIA_MAX_SOCK]; ++ struct pcmcia_state_array state_array; ++ ++ DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock); ++ ++ state_array.size=pxa_pcmcia_socket_count; ++ state_array.state=state; ++ ++ if((pcmcia_low_level->socket_state(&state_array))<0){ ++ printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n"); ++ return -1; ++ } ++ ++ pxa_pcmcia_socket[sock].k_state=state[sock]; ++ ++ *status=state[sock].detect?SS_DETECT:0; ++ ++ *status|=state[sock].ready?SS_READY:0; ++ ++ /* The power status of individual sockets is not available ++ * explicitly from the hardware, so we just remember the state ++ * and regurgitate it upon request: ++ */ ++ *status|=pxa_pcmcia_socket[sock].cs_state.Vcc?SS_POWERON:0; ++ ++ if(pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD) ++ *status|=state[sock].bvd1?SS_STSCHG:0; ++ else { ++ if(state[sock].bvd1==0) ++ *status|=SS_BATDEAD; ++ else if(state[sock].bvd2==0) ++ *status|=SS_BATWARN; ++ } ++ ++ *status|=state[sock].vs_3v?SS_3VCARD:0; ++ ++ *status|=state[sock].vs_Xv?SS_XVCARD:0; ++ ++ DEBUG(3, "\tstatus: %s%s%s%s%s%s%s%s\n", ++ (*status&SS_DETECT)?"DETECT ":"", ++ (*status&SS_READY)?"READY ":"", ++ (*status&SS_BATDEAD)?"BATDEAD ":"", ++ (*status&SS_BATWARN)?"BATWARN ":"", ++ (*status&SS_POWERON)?"POWERON ":"", ++ (*status&SS_STSCHG)?"STSCHG ":"", ++ (*status&SS_3VCARD)?"3VCARD ":"", ++ (*status&SS_XVCARD)?"XVCARD ":""); ++ ++ return 0; ++ ++} /* pxa_pcmcia_get_status() */ ++ ++ ++/* pxa_pcmcia_get_socket() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Implements the get_socket() operation for the in-kernel PCMCIA ++ * service (formerly SS_GetSocket in Card Services). Not a very ++ * exciting routine. ++ * ++ * Returns: 0 ++ */ ++static int pxa_pcmcia_get_socket(unsigned int sock, ++ socket_state_t *state){ ++ ++ DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock); ++ ++ /* This information was given to us in an earlier call to set_socket(), ++ * so we're just regurgitating it here: ++ */ ++ *state=pxa_pcmcia_socket[sock].cs_state; ++ ++ return 0; ++} ++ ++ ++/* pxa_pcmcia_set_socket() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Implements the set_socket() operation for the in-kernel PCMCIA ++ * service (formerly SS_SetSocket in Card Services). We more or ++ * less punt all of this work and let the kernel handle the details ++ * of power configuration, reset, &c. We also record the value of ++ * `state' in order to regurgitate it to the PCMCIA core later. ++ * ++ * Returns: 0 ++ */ ++static int pxa_pcmcia_set_socket(unsigned int sock, ++ socket_state_t *state){ ++ ++ DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock); ++ ++ DEBUG(3, "\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n" ++ "\tVcc %d Vpp %d irq %d\n", ++ (state->csc_mask==0)?"<NONE>":"", ++ (state->csc_mask&SS_DETECT)?"DETECT ":"", ++ (state->csc_mask&SS_READY)?"READY ":"", ++ (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"", ++ (state->csc_mask&SS_BATWARN)?"BATWARN ":"", ++ (state->csc_mask&SS_STSCHG)?"STSCHG ":"", ++ (state->flags==0)?"<NONE>":"", ++ (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"", ++ (state->flags&SS_IOCARD)?"IOCARD ":"", ++ (state->flags&SS_RESET)?"RESET ":"", ++ (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"", ++ (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"", ++ state->Vcc, state->Vpp, state->io_irq); ++ ++ if(pcmcia_low_level->configure_socket(sock, state)<0){ ++ printk(KERN_ERR "Unable to configure socket %u\n", sock); ++ return -1; ++ } ++ ++ pxa_pcmcia_socket[sock].cs_state=*state; ++ ++ return 0; ++ ++} /* pxa_pcmcia_set_socket() */ ++ ++ ++/* pxa_pcmcia_get_io_map() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Implements the get_io_map() operation for the in-kernel PCMCIA ++ * service (formerly SS_GetIOMap in Card Services). Just returns an ++ * I/O map descriptor which was assigned earlier by a set_io_map(). ++ * ++ * Returns: 0 on success, -1 if the map index was out of range ++ */ ++static int pxa_pcmcia_get_io_map(unsigned int sock, ++ struct pccard_io_map *map){ ++ ++ DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); ++ ++ if(map->map>=MAX_IO_WIN){ ++ printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, ++ map->map); ++ return -1; ++ } ++ ++ *map=pxa_pcmcia_socket[sock].io_map[map->map]; ++ ++ return 0; ++} ++ ++ ++/* pxa_pcmcia_set_io_map() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Implements the set_io_map() operation for the in-kernel PCMCIA ++ * service (formerly SS_SetIOMap in Card Services). We configure ++ * the map speed as requested, but override the address ranges ++ * supplied by Card Services. ++ * ++ * Returns: 0 on success, -1 on error ++ */ ++static int pxa_pcmcia_set_io_map(unsigned int sock, ++ struct pccard_io_map *map){ ++ unsigned int clock, speed; ++ unsigned long mecr, start; ++ ++ DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); ++ ++ DEBUG(4, "\tmap %u speed %u\n\tstart 0x%08lx stop 0x%08lx\n" ++ "\tflags: %s%s%s%s%s%s%s%s\n", ++ map->map, map->speed, map->start, map->stop, ++ (map->flags==0)?"<NONE>":"", ++ (map->flags&MAP_ACTIVE)?"ACTIVE ":"", ++ (map->flags&MAP_16BIT)?"16BIT ":"", ++ (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", ++ (map->flags&MAP_0WS)?"0WS ":"", ++ (map->flags&MAP_WRPROT)?"WRPROT ":"", ++ (map->flags&MAP_USE_WAIT)?"USE_WAIT ":"", ++ (map->flags&MAP_PREFETCH)?"PREFETCH ":""); ++ ++ if(map->map>=MAX_IO_WIN){ ++ printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, ++ map->map); ++ return -1; ++ } ++ ++ if(map->flags&MAP_ACTIVE){ ++ ++ speed=(map->speed>0)?map->speed:PXA_PCMCIA_IO_ACCESS; ++ ++ clock = get_lclk_frequency_10khz(); ++ ++ pxa_pcmcia_socket[sock].speed_io=speed; ++ ++ if (sock == 0) { ++ MCIO0 = ((pxa_mcxx_setup(speed, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(speed, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(speed, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++ } else { ++ MCIO1 = ((pxa_mcxx_setup(speed, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(speed, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(speed, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++ } ++ ++ DEBUG(4, "%s(): FAST%u %lx BSM%u %lx BSA%u %lx BSIO%u %lx\n", ++ __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock, ++ MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), ++ sock, MECR_BSIO_GET(mecr, sock)); ++ ++ } ++ ++ start=map->start; ++ ++ if(map->stop==1) ++ map->stop=PAGE_SIZE-1; ++ ++ map->start=pxa_pcmcia_socket[sock].virt_io; ++ map->stop=map->start+(map->stop-start); ++ ++ pxa_pcmcia_socket[sock].io_map[map->map]=*map; ++ ++ return 0; ++ ++} /* pxa_pcmcia_set_io_map() */ ++ ++ ++/* pxa_pcmcia_get_mem_map() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Implements the get_mem_map() operation for the in-kernel PCMCIA ++ * service (formerly SS_GetMemMap in Card Services). Just returns a ++ * memory map descriptor which was assigned earlier by a ++ * set_mem_map() request. ++ * ++ * Returns: 0 on success, -1 if the map index was out of range ++ */ ++static int pxa_pcmcia_get_mem_map(unsigned int sock, ++ struct pccard_mem_map *map){ ++ ++ DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); ++ ++ if(map->map>=MAX_WIN){ ++ printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, ++ map->map); ++ return -1; ++ } ++ ++ *map=pxa_pcmcia_socket[sock].mem_map[map->map]; ++ ++ return 0; ++} ++ ++ ++/* pxa_pcmcia_set_mem_map() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Implements the set_mem_map() operation for the in-kernel PCMCIA ++ * service (formerly SS_SetMemMap in Card Services). We configure ++ * the map speed as requested, but override the address ranges ++ * supplied by Card Services. ++ * ++ * Returns: 0 on success, -1 on error ++ */ ++static int pxa_pcmcia_set_mem_map(unsigned int sock, ++ struct pccard_mem_map *map){ ++ unsigned int clock, speed; ++ unsigned long mecr, start; ++ ++ DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); ++ ++ DEBUG(4, "\tmap %u speed %u\n\tsys_start %#lx\n" ++ "\tsys_stop %#lx\n\tcard_start %#x\n" ++ "\tflags: %s%s%s%s%s%s%s%s\n", ++ map->map, map->speed, map->sys_start, map->sys_stop, ++ map->card_start, (map->flags==0)?"<NONE>":"", ++ (map->flags&MAP_ACTIVE)?"ACTIVE ":"", ++ (map->flags&MAP_16BIT)?"16BIT ":"", ++ (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", ++ (map->flags&MAP_0WS)?"0WS ":"", ++ (map->flags&MAP_WRPROT)?"WRPROT ":"", ++ (map->flags&MAP_ATTRIB)?"ATTRIB ":"", ++ (map->flags&MAP_USE_WAIT)?"USE_WAIT ":""); ++ ++ if(map->map>=MAX_WIN){ ++ printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, ++ map->map); ++ return -1; ++ } ++ ++ if(map->flags&MAP_ACTIVE){ ++ /* When clients issue RequestMap, the access speed is not always ++ * properly configured: ++ */ ++ if(map->speed > 0) ++ speed = map->speed; ++ else ++ switch(pxa_pcmcia_socket[sock].cs_state.Vcc){ ++ case 33: ++ speed = PXA_PCMCIA_3V_MEM_ACCESS; ++ break; ++ default: ++ speed = PXA_PCMCIA_5V_MEM_ACCESS; ++ } ++ ++ clock = get_lclk_frequency_10khz(); ++ ++ if(map->flags&MAP_ATTRIB){ ++ if (sock == 0) { ++ MCATT0 = ((pxa_mcxx_setup(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++ } else { ++ MCATT1 = ((pxa_mcxx_setup(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(PXA_PCMCIA_ATTR_MEM_ACCESS, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++ } ++ pxa_pcmcia_socket[sock].speed_attr=speed; ++ } else { ++ if (sock == 0) { ++ MCMEM0 = ((pxa_mcxx_setup(speed, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(speed, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(speed, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++ } else { ++ MCMEM1 = ((pxa_mcxx_setup(speed, clock) ++ & MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT) ++ | ((pxa_mcxx_asst(speed, clock) ++ & MCXX_ASST_MASK) << MCXX_ASST_SHIFT) ++ | ((pxa_mcxx_hold(speed, clock) ++ & MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT); ++ } ++ pxa_pcmcia_socket[sock].speed_mem=speed; ++ } ++ DEBUG(4, "%s(): FAST%u %lx BSM%u %lx BSA%u %lx BSIO%u %lx\n", ++ __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock, ++ MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), ++ sock, MECR_BSIO_GET(mecr, sock)); ++ } ++ ++ start=map->sys_start; ++ ++ if(map->sys_stop==0) ++ map->sys_stop=PAGE_SIZE-1; ++ ++ map->sys_start=(map->flags & MAP_ATTRIB)?\ ++ pxa_pcmcia_socket[sock].phys_attr:\ ++ pxa_pcmcia_socket[sock].phys_mem; ++ ++ map->sys_stop=map->sys_start+(map->sys_stop-start); ++ ++ pxa_pcmcia_socket[sock].mem_map[map->map]=*map; ++ ++ return 0; ++ ++} /* pxa_pcmcia_set_mem_map() */ ++ ++ ++#if defined(CONFIG_PROC_FS) ++ ++/* pxa_pcmcia_proc_setup() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Implements the proc_setup() operation for the in-kernel PCMCIA ++ * service (formerly SS_ProcSetup in Card Services). ++ * ++ * Returns: 0 on success, -1 on error ++ */ ++static void pxa_pcmcia_proc_setup(unsigned int sock, ++ struct proc_dir_entry *base){ ++ struct proc_dir_entry *entry; ++ ++ DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); ++ ++ if((entry=create_proc_entry("status", 0, base))==NULL){ ++ printk(KERN_ERR "Unable to install \"status\" procfs entry\n"); ++ return; ++ } ++ ++ entry->read_proc=pxa_pcmcia_proc_status; ++ entry->data=(void *)sock; ++} ++ ++ ++/* pxa_pcmcia_proc_status() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * Implements the /proc/bus/pccard/??/status file. ++ * ++ * Returns: the number of characters added to the buffer ++ */ ++static int pxa_pcmcia_proc_status(char *buf, char **start, off_t pos, ++ int count, int *eof, void *data){ ++ char *p=buf; ++ unsigned int sock=(unsigned int)data; ++ unsigned int clock = get_lclk_frequency_10khz(); ++ unsigned long mecr = MECR; ++ ++ p+=sprintf(p, "k_flags : %s%s%s%s%s%s%s\n", ++ pxa_pcmcia_socket[sock].k_state.detect?"detect ":"", ++ pxa_pcmcia_socket[sock].k_state.ready?"ready ":"", ++ pxa_pcmcia_socket[sock].k_state.bvd1?"bvd1 ":"", ++ pxa_pcmcia_socket[sock].k_state.bvd2?"bvd2 ":"", ++ pxa_pcmcia_socket[sock].k_state.wrprot?"wrprot ":"", ++ pxa_pcmcia_socket[sock].k_state.vs_3v?"vs_3v ":"", ++ pxa_pcmcia_socket[sock].k_state.vs_Xv?"vs_Xv ":""); ++ ++ p+=sprintf(p, "status : %s%s%s%s%s%s%s%s%s\n", ++ pxa_pcmcia_socket[sock].k_state.detect?"SS_DETECT ":"", ++ pxa_pcmcia_socket[sock].k_state.ready?"SS_READY ":"", ++ pxa_pcmcia_socket[sock].cs_state.Vcc?"SS_POWERON ":"", ++ pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\ ++ "SS_IOCARD ":"", ++ (pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD && ++ pxa_pcmcia_socket[sock].k_state.bvd1)?"SS_STSCHG ":"", ++ ((pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 && ++ (pxa_pcmcia_socket[sock].k_state.bvd1==0))?"SS_BATDEAD ":"", ++ ((pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 && ++ (pxa_pcmcia_socket[sock].k_state.bvd2==0))?"SS_BATWARN ":"", ++ pxa_pcmcia_socket[sock].k_state.vs_3v?"SS_3VCARD ":"", ++ pxa_pcmcia_socket[sock].k_state.vs_Xv?"SS_XVCARD ":""); ++ ++ p+=sprintf(p, "mask : %s%s%s%s%s\n", ++ pxa_pcmcia_socket[sock].cs_state.csc_mask&SS_DETECT?\ ++ "SS_DETECT ":"", ++ pxa_pcmcia_socket[sock].cs_state.csc_mask&SS_READY?\ ++ "SS_READY ":"", ++ pxa_pcmcia_socket[sock].cs_state.csc_mask&SS_BATDEAD?\ ++ "SS_BATDEAD ":"", ++ pxa_pcmcia_socket[sock].cs_state.csc_mask&SS_BATWARN?\ ++ "SS_BATWARN ":"", ++ pxa_pcmcia_socket[sock].cs_state.csc_mask&SS_STSCHG?\ ++ "SS_STSCHG ":""); ++ ++ p+=sprintf(p, "cs_flags : %s%s%s%s%s\n", ++ pxa_pcmcia_socket[sock].cs_state.flags&SS_PWR_AUTO?\ ++ "SS_PWR_AUTO ":"", ++ pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\ ++ "SS_IOCARD ":"", ++ pxa_pcmcia_socket[sock].cs_state.flags&SS_RESET?\ ++ "SS_RESET ":"", ++ pxa_pcmcia_socket[sock].cs_state.flags&SS_SPKR_ENA?\ ++ "SS_SPKR_ENA ":"", ++ pxa_pcmcia_socket[sock].cs_state.flags&SS_OUTPUT_ENA?\ ++ "SS_OUTPUT_ENA ":""); ++ ++ p+=sprintf(p, "Vcc : %d\n", pxa_pcmcia_socket[sock].cs_state.Vcc); ++ ++ p+=sprintf(p, "Vpp : %d\n", pxa_pcmcia_socket[sock].cs_state.Vpp); ++ ++ p+=sprintf(p, "irq : %d\n", pxa_pcmcia_socket[sock].cs_state.io_irq); ++ ++ p+=sprintf(p, "I/O : %u (%u)\n", pxa_pcmcia_socket[sock].speed_io, ++ sock ? ++ pxa_pcmcia_cmd_time(clock, ++ ((MCIO1 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK)) : ++ pxa_pcmcia_cmd_time(clock, ++ ((MCIO0 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK))); ++ ++ p+=sprintf(p, "attribute: %u (%u)\n", pxa_pcmcia_socket[sock].speed_attr, ++ sock ? ++ pxa_pcmcia_cmd_time(clock, ++ ((MCATT1 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK)) : ++ pxa_pcmcia_cmd_time(clock, ++ ((MCATT0 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK))); ++ ++ p+=sprintf(p, "common : %u (%u)\n", pxa_pcmcia_socket[sock].speed_mem, ++ sock ? ++ pxa_pcmcia_cmd_time(clock, ++ ((MCMEM1 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK)) : ++ pxa_pcmcia_cmd_time(clock, ++ ((MCMEM0 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK))); ++ ++ return p-buf; ++} ++ ++#endif /* defined(CONFIG_PROC_FS) */ ++ ++ ++#ifdef CONFIG_CPU_FREQ ++ ++/* pxa_pcmcia_update_mecr() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * When pxa_pcmcia_notifier() decides that a MECR adjustment (due ++ * to a core clock frequency change) is needed, this routine establishes ++ * new BS_xx values consistent with the clock speed `clock'. ++ */ ++static void pxa_pcmcia_update_mecr(unsigned int clock){ ++ unsigned int sock; ++ ++ for(sock = 0; sock < PXA_PCMCIA_MAX_SOCK; ++sock){ ++ ++ // REVISIT: MCXX macros needed here ++ // MECR_BSIO_SET(mecr, sock, ++// pxa_pcmcia_mecr_bs(pxa_pcmcia_socket[sock].speed_io, ++// clock)); ++ // MECR_BSA_SET(mecr, sock, ++// pxa_pcmcia_mecr_bs(pxa_pcmcia_socket[sock].speed_attr, ++// clock)); ++ // MECR_BSM_SET(mecr, sock, ++// pxa_pcmcia_mecr_bs(pxa_pcmcia_socket[sock].speed_mem, ++// clock)); ++ } ++} ++ ++/* pxa_pcmcia_notifier() ++ * ^^^^^^^^^^^^^^^^^^^^^^^^ ++ * When changing the processor core clock frequency, it is necessary ++ * to adjust the MECR timings accordingly. We've recorded the timings ++ * requested by Card Services, so this is just a matter of finding ++ * out what our current speed is, and then recomputing the new MECR ++ * values. ++ * ++ * Returns: 0 on success, -1 on error ++ */ ++static int pxa_pcmcia_notifier(struct notifier_block *nb, ++ unsigned long val, void *data){ ++ struct cpufreq_info *ci = data; ++ ++ switch(val){ ++ case CPUFREQ_MINMAX: ++ ++ break; ++ ++ case CPUFREQ_PRECHANGE: ++ ++ if(ci->new_freq > ci->old_freq){ ++ DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, pre-updating\n", ++ __FUNCTION__, ++ ci->new_freq / 1000, (ci->new_freq / 100) % 10, ++ ci->old_freq / 1000, (ci->old_freq / 100) % 10); ++ pxa_pcmcia_update_mecr(ci->new_freq); ++ } ++ ++ break; ++ ++ case CPUFREQ_POSTCHANGE: ++ ++ if(ci->new_freq < ci->old_freq){ ++ DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, post-updating\n", ++ __FUNCTION__, ++ ci->new_freq / 1000, (ci->new_freq / 100) % 10, ++ ci->old_freq / 1000, (ci->old_freq / 100) % 10); ++ pxa_pcmcia_update_mecr(ci->new_freq); ++ } ++ ++ break; ++ ++ default: ++ printk(KERN_ERR "%s(): unknown CPU frequency event %lx\n", __FUNCTION__, ++ val); ++ return -1; ++ ++ } ++ ++ return 0; ++ ++} ++ ++static struct notifier_block pxa_pcmcia_notifier_block = { ++ notifier_call: pxa_pcmcia_notifier ++}; ++ ++#endif ++ +--- /dev/null ++++ linux-2.4.27/drivers/pcmcia/pxa/pxa.h +@@ -0,0 +1,233 @@ ++/* ++ * linux/drivers/pcmcia/pxa/pxa.h ++ * ++ * Author: George Davis ++ * Created: Jan 10, 2002 ++ * Copyright: MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Originally based upon linux/drivers/pcmcia/sa1100_generic.h ++ * ++ */ ++ ++/*====================================================================== ++ ++ Device driver for the PCMCIA control functionality of Intel ++ PXA250/210 microprocessors. ++ ++ The contents of this file are subject to the Mozilla Public ++ License Version 1.1 (the "License"); you may not use this file ++ except in compliance with the License. You may obtain a copy of ++ the License at http://www.mozilla.org/MPL/ ++ ++ Software distributed under the License is distributed on an "AS ++ IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ++ implied. See the License for the specific language governing ++ rights and limitations under the License. ++ ++ The initial developer of the original code is John G. Dorsey ++ <john+@cs.cmu.edu>. Portions created by John G. Dorsey are ++ Copyright (C) 1999 John G. Dorsey. All Rights Reserved. ++ ++ Alternatively, the contents of this file may be used under the ++ terms of the GNU Public License version 2 (the "GPL"), in which ++ case the provisions of the GPL are applicable instead of the ++ above. If you wish to allow the use of your version of this file ++ only under the terms of the GPL and not to allow others to use ++ your version of this file under the MPL, indicate your decision ++ by deleting the provisions above and replace them with the notice ++ and other provisions required by the GPL. If you do not delete ++ the provisions above, a recipient may use your version of this ++ file under either the MPL or the GPL. ++ ++======================================================================*/ ++ ++#if !defined(_PCMCIA_PXA_H) ++# define _PCMCIA_PXA_H ++ ++#include <pcmcia/cs_types.h> ++#include <pcmcia/ss.h> ++#include <pcmcia/bulkmem.h> ++#include <pcmcia/cistpl.h> ++#include "../cs_internal.h" ++ ++#include <asm/arch/pcmcia.h> ++ ++ ++/* MECR: Expansion Memory Configuration Register ++ * (SA-1100 Developers Manual, p.10-13; SA-1110 Developers Manual, p.10-24) ++ * ++ * MECR layout is: ++ * ++ * FAST1 BSM1<4:0> BSA1<4:0> BSIO1<4:0> FAST0 BSM0<4:0> BSA0<4:0> BSIO0<4:0> ++ * ++ * (This layout is actually true only for the SA-1110; the FASTn bits are ++ * reserved on the SA-1100.) ++ */ ++ ++#define MCXX_SETUP_MASK (0x7f) ++#define MCXX_ASST_MASK (0x1f) ++#define MCXX_HOLD_MASK (0x3f) ++#define MCXX_SETUP_SHIFT (0) ++#define MCXX_ASST_SHIFT (7) ++#define MCXX_HOLD_SHIFT (14) ++ ++ ++#define MECR_SET(mecr, sock, shift, mask, bs) \ ++((mecr)=((mecr)&~(((mask)<<(shift))<<\ ++ ((sock)==0?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT)))|\ ++ (((bs)<<(shift))<<((sock)==0?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT))) ++ ++#define MECR_GET(mecr, sock, shift, mask) \ ++((((mecr)>>(((sock)==0)?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT))>>\ ++ (shift))&(mask)) ++ ++#define MECR_BSIO_SET(mecr, sock, bs) \ ++MECR_SET((mecr), (sock), MECR_BSIO_SHIFT, MECR_BS_MASK, (bs)) ++ ++#define MECR_BSIO_GET(mecr, sock) \ ++MECR_GET((mecr), (sock), MECR_BSIO_SHIFT, MECR_BS_MASK) ++ ++#define MECR_BSA_SET(mecr, sock, bs) \ ++MECR_SET((mecr), (sock), MECR_BSA_SHIFT, MECR_BS_MASK, (bs)) ++ ++#define MECR_BSA_GET(mecr, sock) \ ++MECR_GET((mecr), (sock), MECR_BSA_SHIFT, MECR_BS_MASK) ++ ++#define MECR_BSM_SET(mecr, sock, bs) \ ++MECR_SET((mecr), (sock), MECR_BSM_SHIFT, MECR_BS_MASK, (bs)) ++ ++#define MECR_BSM_GET(mecr, sock) \ ++MECR_GET((mecr), (sock), MECR_BSM_SHIFT, MECR_BS_MASK) ++ ++#define MECR_FAST_SET(mecr, sock, fast) \ ++MECR_SET((mecr), (sock), MECR_FAST_SHIFT, MECR_FAST_MODE_MASK, (fast)) ++ ++#define MECR_FAST_GET(mecr, sock) \ ++MECR_GET((mecr), (sock), MECR_FAST_SHIFT, MECR_FAST_MODE_MASK) ++ ++ ++/* This function implements the BS value calculation for setting the MECR ++ * using integer arithmetic: ++ */ ++static inline unsigned int pxa_pcmcia_mecr_bs(unsigned int pcmcia_cycle_ns, ++ unsigned int cpu_clock_khz){ ++ unsigned int t = ((pcmcia_cycle_ns * cpu_clock_khz) / 6) - 1000000; ++ return (t / 1000000) + (((t % 1000000) == 0) ? 0 : 1); ++} ++ ++static inline u_int pxa_mcxx_hold(u_int pcmcia_cycle_ns, ++ u_int mem_clk_10khz){ ++ u_int code = pcmcia_cycle_ns * mem_clk_10khz; ++ return (code / 300000) + ((code % 300000) ? 1 : 0); ++} ++ ++static inline u_int pxa_mcxx_asst(u_int pcmcia_cycle_ns, ++ u_int mem_clk_10khz){ ++ u_int code = pcmcia_cycle_ns * mem_clk_10khz; ++ return (code / 300000) + ((code % 300000) ? 1 : 0); ++} ++ ++static inline u_int pxa_mcxx_setup(u_int pcmcia_cycle_ns, ++ u_int mem_clk_10khz){ ++ u_int code = pcmcia_cycle_ns * mem_clk_10khz; ++ return (code / 100000) + ((code % 100000) ? 1 : 0) + 1; ++} ++ ++/* This function returns the (approxmiate) command assertion period, in ++ * nanoseconds, for a given CPU clock frequency and MCXX_ASST value: ++ */ ++ ++static inline u_int pxa_pcmcia_cmd_time(u_int mem_clk_10khz, ++ u_int pcmcia_mcxx_asst){ ++ return (300000 * (pcmcia_mcxx_asst + 1) / mem_clk_10khz); ++} ++ ++ ++/* SA-1100 PCMCIA Memory and I/O timing ++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ * The SA-1110 Developer's Manual, section 10.2.5, says the following: ++ * ++ * "To calculate the recommended BS_xx value for each address space: ++ * divide the command width time (the greater of twIOWR and twIORD, ++ * or the greater of twWE and twOE) by processor cycle time; divide ++ * by 2; divide again by 3 (number of BCLK's per command assertion); ++ * round up to the next whole number; and subtract 1." ++ * ++ * The PC Card Standard, Release 7, section 4.13.4, says that twIORD ++ * has a minimum value of 165ns. Section 4.13.5 says that twIOWR has ++ * a minimum value of 165ns, as well. Section 4.7.2 (describing ++ * common and attribute memory write timing) says that twWE has a ++ * minimum value of 150ns for a 250ns cycle time (for 5V operation; ++ * see section 4.7.4), or 300ns for a 600ns cycle time (for 3.3V ++ * operation, also section 4.7.4). Section 4.7.3 says that taOE ++ * has a maximum value of 150ns for a 300ns cycle time (for 5V ++ * operation), or 300ns for a 600ns cycle time (for 3.3V operation). ++ * ++ * When configuring memory maps, Card Services appears to adopt the policy ++ * that a memory access time of "0" means "use the default." The default ++ * PCMCIA I/O command width time is 165ns. The default PCMCIA 5V attribute ++ * and memory command width time is 150ns; the PCMCIA 3.3V attribute and ++ * memory command width time is 300ns. ++ */ ++ ++/* The PXA 250 and PXA 210 Application Processors Developer's Manual ++ * was used to determine correct PXA_PCMCIA_IO_ACCES time ++ */ ++ ++#define PXA_PCMCIA_IO_ACCESS (165) ++ ++/* Default PC Card Common Memory timings*/ ++ ++#define PXA_PCMCIA_5V_MEM_ACCESS (250) ++#define PXA_PCMCIA_3V_MEM_ACCESS (250) ++ ++/* Atrribute Memory timing - must be constant via PC Card standart*/ ++ ++#define PXA_PCMCIA_ATTR_MEM_ACCESS (300) ++ ++ ++/* The socket driver actually works nicely in interrupt-driven form, ++ * so the (relatively infrequent) polling is "just to be sure." ++ */ ++#define PXA_PCMCIA_POLL_PERIOD (2*HZ) ++ ++ ++/* This structure encapsulates per-socket state which we might need to ++ * use when responding to a Card Services query of some kind. ++ */ ++struct pxa_pcmcia_socket { ++ socket_state_t cs_state; ++ struct pcmcia_state k_state; ++ unsigned int irq; ++ void (*handler)(void *, unsigned int); ++ void *handler_info; ++ pccard_io_map io_map[MAX_IO_WIN]; ++ pccard_mem_map mem_map[MAX_WIN]; ++ ioaddr_t virt_io, phys_attr, phys_mem; ++ unsigned short speed_io, speed_attr, speed_mem; ++}; ++ ++ ++/* I/O pins replacing memory pins ++ * (PCMCIA System Architecture, 2nd ed., by Don Anderson, p.75) ++ * ++ * These signals change meaning when going from memory-only to ++ * memory-or-I/O interface: ++ */ ++#define iostschg bvd1 ++#define iospkr bvd2 ++ ++ ++/* ++ * Declaration for all implementation specific low_level operations. ++ */ ++extern struct pcmcia_low_level lubbock_pcmcia_ops; ++extern struct pcmcia_low_level pxa_idp_pcmcia_ops; ++extern struct pcmcia_low_level cerf_pcmcia_ops; ++extern struct pcmcia_low_level trizeps2_pcmcia_ops; ++ ++#endif /* !defined(_PCMCIA_PXA_H) */ +--- /dev/null ++++ linux-2.4.27/drivers/pcmcia/pxa/pxa_idp.c +@@ -0,0 +1,297 @@ ++/* ++ * linux/drivers/pcmcia/pxa/pxa_idp.c ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Copyright (c) 2002 Accelent Systems, Inc. All Rights Reserved ++ * ++ * Platform specific routines for the Accelent PXA250 IDP, based on those ++ * first done for the Lubbock. ++ * ++ * Version 1.0 2002-05-02 Jeff Sutherland <jeffs@accelent.com> ++ * ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/sched.h> ++ ++#include <pcmcia/ss.h> ++ ++#include <asm/delay.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/arch/pcmcia.h> ++ ++static int ++pxa_idp_pcmcia_init(struct pcmcia_init *init) ++{ ++ int return_val = 0; ++ ++ /* Set PCMCIA Socket 0 power to standby mode. ++ * PXA IDP has dedicated CPLD pins for all this stuff :-) ++ */ ++ ++ /* both slots disabled, reset NOT active */ ++ IDP_CPLD_PCCARD_EN = PCC0_ENABLE | PCC1_ENABLE; ++ ++ IDP_CPLD_PCCARD_PWR = 0; //all power to both slots off ++ ++ GPDR(IRQ_TO_GPIO_2_80(PCMCIA_S0_CD_VALID)) &= ++ ~GPIO_bit(IRQ_TO_GPIO_2_80(PCMCIA_S0_CD_VALID)); ++ GPDR(IRQ_TO_GPIO_2_80(PCMCIA_S1_CD_VALID)) &= ++ ~GPIO_bit(IRQ_TO_GPIO_2_80(PCMCIA_S1_CD_VALID)); ++ ++ set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(PCMCIA_S0_CD_VALID), ++ GPIO_BOTH_EDGES); ++ set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(PCMCIA_S1_CD_VALID), ++ GPIO_BOTH_EDGES); ++ ++ /* irq's for slots: */ ++ GPDR(IRQ_TO_GPIO_2_80(PCMCIA_S0_RDYINT)) &= ++ ~GPIO_bit(IRQ_TO_GPIO_2_80(PCMCIA_S0_RDYINT)); ++ GPDR(IRQ_TO_GPIO_2_80(PCMCIA_S1_RDYINT)) &= ++ ~GPIO_bit(IRQ_TO_GPIO_2_80(PCMCIA_S1_RDYINT)); ++ ++ set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(PCMCIA_S0_RDYINT), ++ GPIO_FALLING_EDGE); ++ set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(PCMCIA_S1_RDYINT), ++ GPIO_FALLING_EDGE); ++ ++ return_val = ++ request_irq(PCMCIA_S0_CD_VALID, init->handler, SA_INTERRUPT, ++ "PXA PCMCIA CD0", NULL); ++ ++ if (return_val < 0) ++ return -1; ++ ++ return_val += ++ request_irq(PCMCIA_S1_CD_VALID, init->handler, SA_INTERRUPT, ++ "PXA PCMCIA CD1", NULL); ++ ++ if (return_val < 0) { ++ free_irq(PCMCIA_S0_CD_VALID, NULL); ++ return -1; ++ } ++ ++ return 2; ++} ++ ++static int ++pxa_idp_pcmcia_shutdown(void) ++{ ++ ++ free_irq(PCMCIA_S0_CD_VALID, NULL); ++ free_irq(PCMCIA_S1_CD_VALID, NULL); ++ ++ IDP_CPLD_PCCARD_EN = 0x03; //disable slots ++ udelay(200); ++ IDP_CPLD_PCCARD_PWR = 0; //shut off all power ++ ++ return 0; ++} ++ ++static int ++pxa_idp_pcmcia_socket_state(struct pcmcia_state_array *state_array) ++{ ++ unsigned long status; ++ int return_val = 1; ++ int i; ++ volatile unsigned long *stat_regs[2] = { &IDP_CPLD_PCCARD0_STATUS, ++ &IDP_CPLD_PCCARD1_STATUS ++ }; ++ ++ if (state_array->size < 2) ++ return -1; ++ ++ memset(state_array->state, 0, ++ (state_array->size) * sizeof (struct pcmcia_state)); ++ ++ for (i = 0; i < 2; i++) { ++ ++ status = *stat_regs[i]; ++ ++ /* this one is a gpio */ ++ state_array->state[i].detect = (PCC_DETECT(i)) ? 0 : 1; ++ ++ state_array->state[i].ready = ++ ((status & _PCC_IRQ) == 0) ? 0 : 1; ++ state_array->state[i].bvd1 = (status & PCC_BVD1) ? 0 : 1; ++ state_array->state[i].bvd2 = (status & PCC_BVD2) ? 0 : 1; ++ state_array->state[i].wrprot = ++ (status & _PCC_WRPROT) ? 1 : 0; ++ state_array->state[i].vs_3v = (status & PCC_VS1) ? 0 : 1; ++ state_array->state[i].vs_Xv = (status & PCC_VS2) ? 0 : 1; ++ } ++ ++ return return_val; ++} ++ ++static int ++pxa_idp_pcmcia_get_irq_info(struct pcmcia_irq_info *info) ++{ ++ switch (info->sock) { ++ case 0: ++ info->irq = PCMCIA_S0_RDYINT; ++ break; ++ ++ case 1: ++ info->irq = PCMCIA_S1_RDYINT; ++ break; ++ ++ default: ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int ++pxa_idp_pcmcia_configure_socket(unsigned int sock, socket_state_t *state) ++{ ++ /* The PXA Idp uses the Maxim MAX1602, with the following connections: ++ * ++ * Socket 0 (PCMCIA): ++ * MAX1602 PXA_IDP Register ++ * Pin Signal IDP_CPLD_PCCARD_PWR: ++ * ----- ------- ---------------------- ++ * A0VPP PCC0_PWR0 bit0 ++ * A1VPP PCC0_PWR1 bit1 ++ * A0VCC PCC0_PWR2 bit2 ++ * A1VCC PCC0_PWR3 bit3 ++ * VX VCC ++ * VY +3.3V ++ * 12IN +12V ++ * CODE +3.3V Cirrus Code, CODE = High (VY) ++ * ++ * Socket 1 (PCMCIA): ++ * MAX1602 PXA_IDP Register ++ * Pin Signal IDP_CPLD_PCCARD_PWR: ++ * ----- ------- ---------------------- ++ * A0VPP PCC1_PWR0 bit4 ++ * A1VPP PCC1_PWR1 bit5 ++ * A0VCC PCC1_PWR2 bit6 ++ * A1VCC PCC1_PWR3 bit7 ++ * VX VCC ++ * VY +3.3V ++ * 12IN +12V ++ * CODE +3.3V Cirrus Code, CODE = High (VY) ++ * ++ */ ++ ++ switch (sock) { ++ case 0: ++ switch (state->Vcc) { ++ case 0: ++ IDP_CPLD_PCCARD_EN |= PCC0_ENABLE; // disable socket ++ udelay(200); ++ IDP_CPLD_PCCARD_PWR &= ~(PCC0_PWR2 | PCC0_PWR3); ++ break; ++ ++ case 33: ++ IDP_CPLD_PCCARD_PWR &= ~(PCC0_PWR2 | PCC0_PWR3); ++ IDP_CPLD_PCCARD_PWR |= PCC0_PWR3; ++ IDP_CPLD_PCCARD_EN &= ~PCC0_ENABLE; //turn it on ++ break; ++ ++ case 50: ++ IDP_CPLD_PCCARD_PWR &= ~(PCC0_PWR2 | PCC0_PWR3); ++ IDP_CPLD_PCCARD_PWR |= PCC0_PWR2; ++ IDP_CPLD_PCCARD_EN &= ~PCC0_ENABLE; ++ break; ++ ++ default: ++ printk(KERN_ERR "%s(): unrecognized Vcc %u\n", ++ __FUNCTION__, state->Vcc); ++ return -1; ++ } ++ ++ switch (state->Vpp) { ++ case 0: ++ IDP_CPLD_PCCARD_PWR &= ~(PCC0_PWR0 | PCC0_PWR1); ++ break; ++ ++ case 120: ++ IDP_CPLD_PCCARD_PWR &= ~(PCC0_PWR0 | PCC0_PWR1); ++ IDP_CPLD_PCCARD_PWR |= PCC0_PWR1; ++ break; ++ ++ default: ++ if (state->Vpp == state->Vcc) ++ IDP_CPLD_PCCARD_PWR = ++ (IDP_CPLD_PCCARD_PWR & ++ ~(PCC0_PWR0 | PCC0_PWR1)) | PCC0_PWR0; ++ else { ++ printk(KERN_ERR "%s(): unrecognized Vpp %u\n", ++ __FUNCTION__, state->Vpp); ++ return -1; ++ } ++ } ++ ++ IDP_CPLD_PCCARD_EN = ++ (state->flags & SS_RESET) ? (IDP_CPLD_PCCARD_EN | PCC0_RESET) ++ : (IDP_CPLD_PCCARD_EN & ~PCC0_RESET); ++ break; ++ ++ case 1: ++ switch (state->Vcc) { ++ case 0: ++ IDP_CPLD_PCCARD_EN |= PCC1_ENABLE; // disable socket ++ udelay(200); ++ IDP_CPLD_PCCARD_PWR &= ~(PCC1_PWR2 | PCC1_PWR3); ++ break; ++ ++ case 33: ++ IDP_CPLD_PCCARD_PWR &= ~(PCC1_PWR2 | PCC1_PWR3); ++ IDP_CPLD_PCCARD_PWR |= PCC1_PWR3; ++ IDP_CPLD_PCCARD_EN &= ~PCC1_ENABLE; //turn it on ++ break; ++ ++ case 50: ++ IDP_CPLD_PCCARD_PWR &= ~(PCC1_PWR2 | PCC1_PWR3); ++ IDP_CPLD_PCCARD_PWR |= PCC1_PWR2; ++ IDP_CPLD_PCCARD_EN &= ~PCC1_ENABLE; ++ break; ++ ++ default: ++ printk(KERN_ERR "%s(): unrecognized Vcc %u\n", ++ __FUNCTION__, state->Vcc); ++ return -1; ++ } ++ ++ switch (state->Vpp) { ++ case 0: ++ IDP_CPLD_PCCARD_PWR &= ~(PCC1_PWR0 | PCC1_PWR1); ++ break; ++ ++ case 120: ++ IDP_CPLD_PCCARD_PWR &= ~(PCC1_PWR0 | PCC1_PWR1); ++ IDP_CPLD_PCCARD_PWR |= PCC1_PWR1; ++ break; ++ ++ default: ++ if (state->Vpp == state->Vcc) ++ IDP_CPLD_PCCARD_PWR = ++ (IDP_CPLD_PCCARD_PWR & ++ ~(PCC1_PWR0 | PCC1_PWR1)) | PCC1_PWR0; ++ else { ++ printk(KERN_ERR "%s(): unrecognized Vpp %u\n", ++ __FUNCTION__, state->Vpp); ++ return -1; ++ } ++ } ++ IDP_CPLD_PCCARD_EN = (state->flags & SS_RESET) ? (IDP_CPLD_PCCARD_EN | PCC1_RESET) ++ : (IDP_CPLD_PCCARD_EN & ~PCC1_RESET); ++ break; ++ } ++ return 0; ++} ++ ++struct pcmcia_low_level pxa_idp_pcmcia_ops = { ++ pxa_idp_pcmcia_init, ++ pxa_idp_pcmcia_shutdown, ++ pxa_idp_pcmcia_socket_state, ++ pxa_idp_pcmcia_get_irq_info, ++ pxa_idp_pcmcia_configure_socket ++}; +--- /dev/null ++++ linux-2.4.27/drivers/pcmcia/pxa/trizeps2.c +@@ -0,0 +1,187 @@ ++/* ++ * linux/drivers/pcmcia/pxa/trizeps2.c ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Copyright (c) 2002 Accelent Systems, Inc. All Rights Reserved ++ * ++ * Platform specific routines for the Keith-n-Koep Trizeps-II, based on IDP ++ * ++ * Copyright (c) 2003 Teradyne DS, Ltd. ++ * Port to Trizeps-2 MT6N board by Luc De Cock ++ * ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/sched.h> ++ ++#include <pcmcia/ss.h> ++ ++#include <asm/delay.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/arch/pcmcia.h> ++ ++static int trizeps2_pcmcia_init(struct pcmcia_init *init) ++{ ++ int return_val = 0; ++ unsigned short *bcr = (unsigned short *) TRIZEPS2_BCR_BASE; ++ unsigned short val; ++ ++ /* reset the PCMCIA controller */ ++ val = trizeps2_bcr_shadow | BCR_PCMCIA_RESET; ++ *bcr = val; ++ udelay(500); ++ /* un-reset it again */ ++ trizeps2_bcr_shadow &= ~BCR_PCMCIA_RESET; ++ /* enable the PCMCIA buffer */ ++ trizeps2_bcr_shadow &= ~(1 << 5); ++ *bcr = trizeps2_bcr_shadow; ++ ++ GPDR(IRQ_TO_GPIO_2_80(PCMCIA_S_CD_VALID)) &= ++ ~GPIO_bit(IRQ_TO_GPIO_2_80(PCMCIA_S_CD_VALID)); ++ set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(PCMCIA_S_CD_VALID), ++ PCMCIA_S_CD_VALID_EDGE); ++ GPDR(IRQ_TO_GPIO(PCMCIA_S_RDYINT)) &= ++ ~GPIO_bit(IRQ_TO_GPIO(PCMCIA_S_RDYINT)); ++ set_GPIO_IRQ_edge(IRQ_TO_GPIO(PCMCIA_S_RDYINT), ++ PCMCIA_S_RDYINT_EDGE); ++ ++ return_val = request_irq(PCMCIA_S_CD_VALID, init->handler, SA_INTERRUPT, ++ "PXA PCMCIA CD", NULL); ++ if (return_val < 0) { ++ return -1; ++ } ++ /* only 1 slot */ ++ return 1; ++} ++ ++static int trizeps2_pcmcia_shutdown(void) ++{ ++ free_irq(PCMCIA_S_CD_VALID, NULL); ++ ++ unsigned short *bcr = (unsigned short *) TRIZEPS2_BCR_BASE; ++ trizeps2_bcr_shadow |= (1 << 5); /* pcmcia buffer off */ ++ *bcr = trizeps2_bcr_shadow; ++ trizeps2_bcr_shadow &= 0xFFF0; /* pcmcia control logic grounded */ ++ *bcr = trizeps2_bcr_shadow; ++ ++ return 0; ++} ++ ++static int trizeps2_pcmcia_socket_state(struct pcmcia_state_array *state_array) ++{ ++ unsigned long status; ++ int return_val = 1; ++ volatile unsigned short *stat_regs[1] = { ++ &TRIZEPS2_PCCARD_STATUS ++ }; ++ ++ if (state_array->size < 1) ++ return -1; ++ ++ memset(state_array->state, 0, ++ (state_array->size) * sizeof (struct pcmcia_state)); ++ ++ status = *stat_regs[0]; ++ ++ /* this one is a gpio */ ++ state_array->state[0].detect = (PCC_DETECT) ? 0 : 1; ++ state_array->state[0].ready = (PCC_READY) ? 1 : 0; ++ state_array->state[0].bvd1 = (status & PCC_BVD1) ? 1 : 0; ++ state_array->state[0].bvd2 = (status & PCC_BVD2) ? 1 : 0; ++ state_array->state[0].wrprot = 0; /* r/w all the time */ ++ state_array->state[0].vs_3v = (status & PCC_VS1) ? 0 : 1; ++ state_array->state[0].vs_Xv = (status & PCC_VS2) ? 0 : 1; ++ ++ return return_val; ++} ++ ++static int trizeps2_pcmcia_get_irq_info(struct pcmcia_irq_info *info) ++{ ++ switch (info->sock) { ++ case 0: ++ info->irq = PCMCIA_S_RDYINT; ++ break; ++ ++ default: ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int trizeps2_pcmcia_configure_socket(unsigned int sock, socket_state_t *state) ++{ ++ unsigned short cntr_logic = trizeps2_bcr_shadow & 0xF; ++ unsigned short *bcr = (unsigned short *) TRIZEPS2_BCR_BASE; ++ ++ /* configure Vcc and Vpp */ ++ switch (sock) { ++ case 0: ++ switch (state->Vcc) { ++ case 0: ++ cntr_logic &= ~(PCC_3V | PCC_5V); ++ break; ++ ++ case 33: ++ cntr_logic &= ~(PCC_3V | PCC_5V); ++ cntr_logic |= PCC_3V; ++ break; ++ ++ case 50: ++ cntr_logic &= ~(PCC_3V | PCC_5V); ++ cntr_logic |= PCC_5V; ++ break; ++ ++ default: ++ printk(KERN_ERR "%s(): unrecognized Vcc %u\n", ++ __FUNCTION__, state->Vcc); ++ return -1; ++ } ++ ++ switch (state->Vpp) { ++ case 0: ++ cntr_logic &= ~(PCC_EN0 | PCC_EN1); ++ break; ++ ++ case 120: ++ cntr_logic &= ~(PCC_EN0 | PCC_EN1); ++ cntr_logic |= PCC_EN1; ++ break; ++ ++ default: ++ if (state->Vpp == state->Vcc) { ++ cntr_logic &= ~(PCC_EN0 | PCC_EN1); ++ cntr_logic |= PCC_EN0; ++ } ++ else { ++ printk(KERN_ERR "%s(): unrecognized Vpp %u\n", ++ __FUNCTION__, state->Vpp); ++ return -1; ++ } ++ } ++ trizeps2_bcr_shadow &= ~(PCC_EN0 | PCC_EN1 | PCC_3V | PCC_5V | ++ BCR_PCMCIA_RESET); ++ trizeps2_bcr_shadow |= cntr_logic; ++ *bcr = trizeps2_bcr_shadow; ++ /* reset PCMCIA controller if requested */ ++ trizeps2_bcr_shadow |= ++ (state->flags & SS_RESET) ? BCR_PCMCIA_RESET : 0; ++ *bcr = trizeps2_bcr_shadow; ++ udelay(500); ++ break; ++ } ++ return 0; ++} ++ ++struct pcmcia_low_level trizeps2_pcmcia_ops = { ++ trizeps2_pcmcia_init, ++ trizeps2_pcmcia_shutdown, ++ trizeps2_pcmcia_socket_state, ++ trizeps2_pcmcia_get_irq_info, ++ trizeps2_pcmcia_configure_socket ++}; ++ +--- linux-2.4.27/drivers/pcmcia/sa1100_cerf.c~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/pcmcia/sa1100_cerf.c +@@ -7,15 +7,25 @@ + */ + #include <linux/kernel.h> + #include <linux/sched.h> ++#include <linux/delay.h> + + #include <asm/hardware.h> + #include <asm/irq.h> +-#include "sa1100_generic.h" + +-#ifdef CONFIG_SA1100_CERF_CPLD +-#define CERF_SOCKET 0 ++#include <pcmcia/ss.h> ++#include <asm/arch/pcmcia.h> ++#include "sa1100_cerf.h" ++ ++/* ++ * Set this to zero to remove all the debug statements via ++ * dead code elimination ++ */ ++//#define DEBUGGING 1 ++ ++#if DEBUGGING ++static unsigned int pcmcia_debug = DEBUGGING; + #else +-#define CERF_SOCKET 1 ++#define pcmcia_debug 0 /* gcc will remove all the debug code for us */ + #endif + + static struct irqs { +@@ -23,122 +33,178 @@ + unsigned int gpio; + const char *str; + } irqs[] = { +- { IRQ_GPIO_CF_CD, GPIO_CF_CD, "CF_CD" }, +- { IRQ_GPIO_CF_BVD2, GPIO_CF_BVD2, "CF_BVD2" }, +- { IRQ_GPIO_CF_BVD1, GPIO_CF_BVD1, "CF_BVD1" } ++ { PCMCIA_IRQ_CF_CD, PCMCIA_GPIO_CF_CD_EDGE, "CF_CD" }, ++ { PCMCIA_IRQ_CF_BVD2, PCMCIA_GPIO_CF_BVD2_EDGE, "CF_BVD2" }, ++ { PCMCIA_IRQ_CF_BVD1, PCMCIA_GPIO_CF_BVD1_EDGE, "CF_BVD1" } + }; + ++static void cerf_pcmcia_reset( void) ++{ ++ int i; ++ ++ // Make sure SKTSEL is 0 (single slot) ++ set_GPIO_mode(54 | GPIO_OUT); ++ GPCR1 = GPIO_bit(54); ++ set_GPIO_mode(GPIO54_pSKTSEL_MD); ++ ++ PCMCIA_GPCR = PCMCIA_GPIO_CF_RESET_MASK; ++ mdelay(300); ++ ++ PCMCIA_GPSR = PCMCIA_GPIO_CF_RESET_MASK; ++ udelay(20); ++ ++ PCMCIA_GPCR = PCMCIA_GPIO_CF_RESET_MASK; ++ mdelay(50); ++ ++ for( i=0; i<10; i++) ++ { ++ if( cerf_pcmcia_level_ready()) break; ++ mdelay(100); ++ } ++} ++ + static int cerf_pcmcia_init(struct pcmcia_init *init) + { +- int i, res; ++ int i, res; + +- set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE ); ++ if( pcmcia_debug) ++ printk( KERN_INFO "cerf_pcmcia_init: enter\n"); + +- for (i = 0; i < ARRAY_SIZE(irqs); i++) { +- set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_NO_EDGES); +- res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT, +- irqs[i].str, NULL); +- if (res) +- goto irq_err; +- } ++ cerf_pcmcia_set_gpio_direction(); + +- return 2; ++ set_GPIO_IRQ_edge( PCMCIA_GPIO_CF_IRQ_EDGE, GPIO_FALLING_EDGE ); + +- irq_err: +- printk(KERN_ERR "%s: Request for IRQ%d failed\n", __FUNCTION__, irqs[i].irq); ++ for (i = 0; i < ARRAY_SIZE(irqs); i++) { + +- while (i--) +- free_irq(irqs[i].irq, NULL); ++ set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_BOTH_EDGES); + +- return -1; ++ res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT, ++ irqs[i].str, NULL); ++ if (res) ++ goto irq_err; ++ } ++ ++ printk( KERN_INFO "PCMCIA for Cerf: OK\n"); ++ ++ return CERF_SOCKET+1; /* last socket used +1 */ ++ ++irq_err: ++ printk(KERN_ERR "%s: Request for IRQ%d failed\n", ++ __FUNCTION__, irqs[i].irq); ++ ++ while (i--) ++ free_irq(irqs[i].irq, NULL); ++ ++ return -1; + } + + static int cerf_pcmcia_shutdown(void) + { +- int i; ++ int i; ++ if( pcmcia_debug) ++ printk( KERN_INFO "cerf_pcmcia_shutdown: enter\n"); + +- for (i = 0; i < ARRAY_SIZE(irqs); i++) +- free_irq(irqs[i].irq, NULL); ++ for (i = 0; i < ARRAY_SIZE(irqs); i++) ++ free_irq(irqs[i].irq, NULL); + +- return 0; ++ return 0; + } + +-static int cerf_pcmcia_socket_state(struct pcmcia_state_array +- *state_array){ +- unsigned long levels; +- int i = CERF_SOCKET; ++static int cerf_pcmcia_socket_state(struct pcmcia_state_array *state_array) ++{ ++ int i = CERF_SOCKET; + +- if(state_array->size<2) return -1; ++ if( pcmcia_debug > 3) ++ printk( KERN_INFO "cerf_pcmcia_socket_state: i=%d, size=%d\n", ++ i, state_array->size); + +- levels=GPLR; ++ memset(state_array->state, 0, ++ (state_array->size)*sizeof(struct pcmcia_state)); + +- state_array->state[i].detect=((levels & GPIO_CF_CD)==0)?1:0; +- state_array->state[i].ready=(levels & GPIO_CF_IRQ)?1:0; +- state_array->state[i].bvd1=(levels & GPIO_CF_BVD1)?1:0; +- state_array->state[i].bvd2=(levels & GPIO_CF_BVD2)?1:0; +- state_array->state[i].wrprot=0; +- state_array->state[i].vs_3v=1; +- state_array->state[i].vs_Xv=0; ++ state_array->state[i].detect = cerf_pcmcia_level_detect(); ++ state_array->state[i].ready = cerf_pcmcia_level_ready(); ++ state_array->state[i].bvd1 = cerf_pcmcia_level_bvd1(); ++ state_array->state[i].bvd2 = cerf_pcmcia_level_bvd2(); ++ state_array->state[i].wrprot=0; ++ state_array->state[i].vs_3v=1; ++ state_array->state[i].vs_Xv=0; + +- return 1; ++ if( pcmcia_debug > 3) ++ printk( KERN_INFO "cerf_pcmcia_socket_state: " ++ "detect=%d ready=%d bvd1=%d bvd2=%d\n", ++ state_array->state[i].detect, ++ state_array->state[i].ready, ++ state_array->state[i].bvd1, ++ state_array->state[i].bvd2); ++ ++ return 1; + } + + static int cerf_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ + +- if(info->sock>1) return -1; ++ if( pcmcia_debug) ++ printk( KERN_INFO "cerf_pcmcia_get_irq_info: " ++ "sock=%d\n", info->sock); + +- if (info->sock == CERF_SOCKET) +- info->irq=IRQ_GPIO_CF_IRQ; ++ if(info->sock>1) return -1; + +- return 0; ++ if (info->sock == CERF_SOCKET) ++ info->irq=PCMCIA_IRQ_CF_IRQ; ++ ++ if( pcmcia_debug) ++ printk( KERN_INFO "cerf_pcmcia_get_irq_info: irq=%d\n",info->irq); ++ ++ return 0; + } + +-static int cerf_pcmcia_configure_socket(const struct pcmcia_configure +- *configure) ++static int cerf_pcmcia_configure_socket( unsigned int sock, socket_state_t *state) + { +- if(configure->sock>1) +- return -1; ++ if( pcmcia_debug) ++ printk( KERN_INFO "cerf_pcmcia_configure_socket:" ++ "sock=%d vcc=%d flags=%x\n", ++ sock, state->Vcc, state->flags); + +- if (configure->sock != CERF_SOCKET) +- return 0; ++ if(sock>1) ++ return -1; + +- switch(configure->vcc){ +- case 0: +- break; ++ if (sock != CERF_SOCKET) ++ return 0; + +- case 50: +- case 33: +-#ifdef CONFIG_SA1100_CERF_CPLD +- GPCR = GPIO_PWR_SHUTDOWN; ++ switch(state->Vcc){ ++ case 0: ++ break; ++ ++ case 50: ++ case 33: ++#if defined(CONFIG_SA1100_CERF_CPLD) ++ PCMCIA_GPDR |= PCMCIA_PWR_SHUTDOWN; ++ PCMCIA_GPCR |= PCMCIA_PWR_SHUTDOWN; + #endif +- break; ++ /* voltage selected automatically */ ++ break; + +- default: +- printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, +- configure->vcc); +- return -1; +- } ++ default: ++ printk(KERN_ERR "%s(): unrecognized Vcc %u\n", ++ __FUNCTION__, state->Vcc); ++ return -1; ++ } + +- if(configure->reset) +- { +-#ifdef CONFIG_SA1100_CERF_CPLD +- GPSR = GPIO_CF_RESET; +-#endif +- } +- else +- { +-#ifdef CONFIG_SA1100_CERF_CPLD +- GPCR = GPIO_CF_RESET; +-#endif +- } ++ if(state->flags&SS_RESET) ++ { ++ cerf_pcmcia_reset(); ++ } + +- return 0; ++ return 0; + } + ++#ifdef CONFIG_SA1100_CERF + static int cerf_pcmcia_socket_init(int sock) + { + int i; + ++ if( pcmcia_debug) ++ printk( KERN_INFO "cerf_pcmcia_socket_init: sock=%d\n",sock); ++ + if (sock == CERF_SOCKET) + for (i = 0; i < ARRAY_SIZE(irqs); i++) + set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_BOTH_EDGES); +@@ -150,21 +216,26 @@ + { + int i; + ++ if( pcmcia_debug) ++ printk( KERN_INFO "cerf_pcmcia_socket_suspend: sock=%d\n",sock); ++ + if (sock == CERF_SOCKET) + for (i = 0; i < ARRAY_SIZE(irqs); i++) + set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_NO_EDGES); + + return 0; + } ++#endif + + struct pcmcia_low_level cerf_pcmcia_ops = { +- init: cerf_pcmcia_init, +- shutdown: cerf_pcmcia_shutdown, +- socket_state: cerf_pcmcia_socket_state, +- get_irq_info: cerf_pcmcia_get_irq_info, +- configure_socket: cerf_pcmcia_configure_socket, ++init: cerf_pcmcia_init, ++shutdown: cerf_pcmcia_shutdown, ++socket_state: cerf_pcmcia_socket_state, ++get_irq_info: cerf_pcmcia_get_irq_info, ++configure_socket: cerf_pcmcia_configure_socket, + +- socket_init: cerf_pcmcia_socket_init, +- socket_suspend: cerf_pcmcia_socket_suspend, ++#ifdef CONFIG_SA1100_CERF ++socket_init: cerf_pcmcia_socket_init, ++socket_suspend: cerf_pcmcia_socket_suspend, ++#endif + }; +- +--- /dev/null ++++ linux-2.4.27/drivers/pcmcia/sa1100_cerf.h +@@ -0,0 +1,138 @@ ++/* ++ * drivers/pcmcia/cerf.h ++ * ++ * PCMCIA implementation routines for CerfBoard ++ * Based off the Assabet. ++ * ++ */ ++#ifndef _LINUX_PCMCIA_CERF_H ++#define _LINUX_PCMCIA_CERF_H ++ ++#include <linux/config.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/arch/pcmcia.h> ++ ++#ifdef CONFIG_PXA_CERF /* PXA */ ++ ++#define PCMCIA_GPCR GPCR0 ++#define PCMCIA_GPSR GPSR0 ++ ++#define PCMCIA_GPIO_CF_CD 14 ++#define PCMCIA_GPIO_CF_IRQ 13 ++#define PCMCIA_GPIO_CF_RESET 12 ++#ifdef CONFIG_PXA_CERF_PDA ++# define PCMCIA_GPIO_CF_BVD1 11 ++# define PCMCIA_GPIO_CF_BVD2 10 ++#elif defined( CONFIG_PXA_CERF_BOARD) ++# define PCMCIA_GPIO_CF_BVD1 32 ++# define PCMCIA_GPIO_CF_BVD2 10 ++#endif ++ ++#define PCMCIA_GPIO_CF_CD_MASK (GPIO_bit(PCMCIA_GPIO_CF_CD)) ++#define PCMCIA_GPIO_CF_IRQ_MASK (GPIO_bit(PCMCIA_GPIO_CF_IRQ)) ++#define PCMCIA_GPIO_CF_RESET_MASK (GPIO_bit(PCMCIA_GPIO_CF_RESET)) ++#define PCMCIA_GPIO_CF_BVD1_MASK (GPIO_bit(PCMCIA_GPIO_CF_BVD1)) ++#define PCMCIA_GPIO_CF_BVD2_MASK (GPIO_bit(PCMCIA_GPIO_CF_BVD2)) ++ ++#define PCMCIA_GPIO_CF_CD_EDGE PCMCIA_GPIO_CF_CD ++#define PCMCIA_GPIO_CF_IRQ_EDGE PCMCIA_GPIO_CF_IRQ ++#define PCMCIA_GPIO_CF_RESET_EDGE PCMCIA_GPIO_CF_RESET ++#define PCMCIA_GPIO_CF_BVD1_EDGE PCMCIA_GPIO_CF_BVD1 ++#define PCMCIA_GPIO_CF_BVD2_EDGE PCMCIA_GPIO_CF_BVD2 ++ ++#define PCMCIA_IRQ_CF_CD IRQ_GPIO(PCMCIA_GPIO_CF_CD) ++#define PCMCIA_IRQ_CF_IRQ IRQ_GPIO(PCMCIA_GPIO_CF_IRQ) ++#define PCMCIA_IRQ_CF_BVD1 IRQ_GPIO(PCMCIA_GPIO_CF_BVD1) ++#define PCMCIA_IRQ_CF_BVD2 IRQ_GPIO(PCMCIA_GPIO_CF_BVD2) ++ ++#define PCMCIA_PWR_SHUTDOWN 0 /* not needed */ ++#define CERF_SOCKET 0 ++ ++inline void cerf_pcmcia_set_gpio_direction(void) ++{ ++ GPDR(PCMCIA_GPIO_CF_CD) &= ~(PCMCIA_GPIO_CF_CD_MASK); ++ GPDR(PCMCIA_GPIO_CF_BVD1) &= ~(PCMCIA_GPIO_CF_BVD1_MASK); ++ GPDR(PCMCIA_GPIO_CF_BVD2) &= ~(PCMCIA_GPIO_CF_BVD2_MASK); ++ GPDR(PCMCIA_GPIO_CF_IRQ) &= ~(PCMCIA_GPIO_CF_IRQ_MASK); ++ GPDR(PCMCIA_GPIO_CF_RESET)|= (PCMCIA_GPIO_CF_RESET_MASK); ++} ++ ++inline int cerf_pcmcia_level_detect( void) ++{ ++ return ((GPLR(PCMCIA_GPIO_CF_CD)&PCMCIA_GPIO_CF_CD_MASK)==0)?1:0; ++} ++inline int cerf_pcmcia_level_ready( void) ++{ ++ return (GPLR(PCMCIA_GPIO_CF_IRQ)&PCMCIA_GPIO_CF_IRQ_MASK)?1:0; ++} ++inline int cerf_pcmcia_level_bvd1( void) ++{ ++ return (GPLR(PCMCIA_GPIO_CF_BVD1)&PCMCIA_GPIO_CF_BVD1_MASK)?1:0; ++} ++inline int cerf_pcmcia_level_bvd2( void) ++{ ++ return (GPLR(PCMCIA_GPIO_CF_BVD2)&PCMCIA_GPIO_CF_BVD2_MASK)?1:0; ++} ++ ++#elif defined(CONFIG_SA1100_CERF) /* SA1100 */ ++ ++#define PCMCIA_GPDR GPDR ++#define PCMCIA_GPCR GPCR ++#define PCMCIA_GPSR GPSR ++#define PCMCIA_GPLR GPLR ++ ++#define PCMCIA_GPIO_CF_CD_MASK GPIO_CF_CD ++#define PCMCIA_GPIO_CF_IRQ_MASK GPIO_CF_IRQ ++#define PCMCIA_GPIO_CF_RESET_MASK GPIO_CF_RESET ++#define PCMCIA_GPIO_CF_BVD1_MASK GPIO_CF_BVD1 ++#define PCMCIA_GPIO_CF_BVD2_MASK GPIO_CF_BVD2 ++ ++#define PCMCIA_GPIO_CF_CD_EDGE PCMCIA_GPIO_CF_CD_MASK ++#define PCMCIA_GPIO_CF_IRQ_EDGE PCMCIA_GPIO_CF_IRQ_MASK ++#define PCMCIA_GPIO_CF_RESET_EDGE PCMCIA_GPIO_CF_RESET_MASK ++#define PCMCIA_GPIO_CF_BVD1_EDGE PCMCIA_GPIO_CF_BVD1_MASK ++#define PCMCIA_GPIO_CF_BVD2_EDGE PCMCIA_GPIO_CF_BVD2_MASK ++ ++#define PCMCIA_IRQ_CF_CD IRQ_GPIO_CF_CD ++#define PCMCIA_IRQ_CF_IRQ IRQ_GPIO_CF_IRQ ++#define PCMCIA_IRQ_CF_BVD1 IRQ_GPIO_CF_BVD1 ++#define PCMCIA_IRQ_CF_BVD2 IRQ_GPIO_CF_BVD2 ++ ++#define PCMCIA_PWR_SHUTDOWN GPIO_PWR_SHUTDOWN ++ ++#ifdef CONFIG_SA1100_CERF_CPLD ++#define CERF_SOCKET 0 ++#else ++#define CERF_SOCKET 1 ++#endif ++ ++inline void cerf_pcmcia_set_gpio_direction(void) ++{ ++ PCMCIA_GPDR &= ~(PCMCIA_GPIO_CF_CD_MASK | ++ PCMCIA_GPIO_CF_BVD1_MASK | ++ PCMCIA_GPIO_CF_BVD2_MASK | ++ PCMCIA_GPIO_CF_IRQ_MASK); ++ PCMCIA_GPDR |= PCMCIA_GPIO_CF_RESET_MASK; ++} ++ ++inline int cerf_pcmcia_level_detect( void) ++{ ++ return ((PCMCIA_GPLR & PCMCIA_GPIO_CF_CD_MASK)==0)?1:0; ++} ++inline int cerf_pcmcia_level_ready( void) ++{ ++ return (PCMCIA_GPLR & PCMCIA_GPIO_CF_IRQ_MASK)?1:0; ++} ++inline int cerf_pcmcia_level_bvd1( void) ++{ ++ return (PCMCIA_GPLR & PCMCIA_GPIO_CF_BVD1_MASK)?1:0; ++} ++inline int cerf_pcmcia_level_bvd2( void) ++{ ++ return (PCMCIA_GPLR & PCMCIA_GPIO_CF_BVD2_MASK)?1:0; ++} ++ ++#endif ++ ++#endif +--- linux-2.4.27/drivers/sound/Config.in~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/sound/Config.in +@@ -239,6 +239,7 @@ + dep_tristate ' VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS + fi + dep_tristate ' Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS $CONFIG_ARCH_NETWINDER ++ dep_tristate ' Intel PXA250/210 AC97 audio' CONFIG_SOUND_PXA_AC97 $CONFIG_ARCH_PXA $CONFIG_SOUND + fi + + dep_tristate ' TV card (bt848) mixer support' CONFIG_SOUND_TVMIXER $CONFIG_SOUND $CONFIG_I2C +--- linux-2.4.27/drivers/sound/Makefile~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/sound/Makefile +@@ -11,7 +11,7 @@ + msnd.o opl3.o sb_common.o sequencer_syms.o \ + sound_core.o sound_syms.o uart401.o \ + nm256_audio.o ac97.o ac97_codec.o aci.o \ +- sa1100-audio.o ++ sa1100-audio.o pxa-audio.o pxa-ac97.o + + # Each configuration option enables a list of files. + +@@ -85,6 +85,7 @@ + obj-$(CONFIG_SOUND_SA1111_UDA1341) += sa1111-uda1341.o + obj-$(CONFIG_SOUND_SA1111_AC97) += sa1111-ac97.o ac97_codec.o + obj-$(CONFIG_SOUND_SA1100SSP) += sa1100ssp.o ++obj-$(CONFIG_SOUND_PXA_AC97)+= pxa-ac97.o pxa-audio.o ac97_codec.o + obj-$(CONFIG_SOUND_EMU10K1) += ac97_codec.o + obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o + obj-$(CONFIG_SOUND_RME96XX) += rme96xx.o +--- linux-2.4.27/drivers/sound/ac97_codec.c~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/sound/ac97_codec.c +@@ -155,6 +155,7 @@ + {0x45838308, "ESS Allegro ES1988", &null_ops}, + {0x49434511, "ICE1232", &null_ops}, /* I hope --jk */ + {0x4e534331, "National Semiconductor LM4549", &null_ops}, ++ {0x50534304, "Philips UCB1400", &default_ops}, + {0x53494c22, "Silicon Laboratory Si3036", &null_ops}, + {0x53494c23, "Silicon Laboratory Si3038", &null_ops}, + {0x545200FF, "TriTech TR?????", &tritech_m_ops}, +--- /dev/null ++++ linux-2.4.27/drivers/sound/pxa-ac97.c +@@ -0,0 +1,370 @@ ++/* ++ * linux/drivers/sound/pxa-ac97.c -- AC97 interface for the Cotula chip ++ * ++ * Author: Nicolas Pitre ++ * Created: Aug 15, 2001 ++ * Copyright: MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * AC97 GPIO Changes:- ++ * In order to read/write codec GPIO bits using AC97 link slot 12, ++ * all IO to AC97_GPIO_STATUS must be via the Xscale modem codec ++ * address space. ++ * Liam Girdwood <liam.girdwood@wolfsonmicro.com> ++ */ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/pci.h> ++#include <linux/completion.h> ++#include <linux/delay.h> ++#include <linux/poll.h> ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++#include <linux/ac97_codec.h> ++ ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++#include <asm/semaphore.h> ++#include <asm/dma.h> ++ ++#include "pxa-audio.h" ++ ++static struct completion CAR_completion; ++static int waitingForMask; ++static DECLARE_MUTEX(CAR_mutex); ++ ++static u16 pxa_ac97_read(struct ac97_codec *codec, u8 reg) ++{ ++ u16 val = -1; ++ ++ down(&CAR_mutex); ++ if (!(CAR & CAR_CAIP)) { ++ volatile u32 *reg_addr; ++ ++ // if we are reading the GPIO status then this is cached ++ // in hardware so we don't need to read over the link. ++ if (reg == AC97_GPIO_STATUS) { ++ reg_addr = (u32 *)&PMC_REG_BASE + (reg >> 1); ++ val = *reg_addr; ++ return val; ++ } ++ ++ reg_addr = (u32 *)&PAC_REG_BASE + (reg >> 1); ++ ++ waitingForMask=GSR_SDONE; ++ ++ init_completion(&CAR_completion); ++ (void)*reg_addr; //start read access across the ac97 link ++ wait_for_completion(&CAR_completion); ++ ++ if (GSR & GSR_RDCS) { ++ GSR |= GSR_RDCS; //write a 1 to clear ++ printk(KERN_CRIT __FUNCTION__": read codec register timeout.\n"); ++ } ++ ++ init_completion(&CAR_completion); ++ val = *reg_addr; //valid data now but we've just started another cycle... ++ wait_for_completion(&CAR_completion); ++ ++ } else { ++ printk(KERN_CRIT __FUNCTION__": CAR_CAIP already set\n"); ++ } ++ up(&CAR_mutex); ++ //printk("%s(0x%02x) = 0x%04x\n", __FUNCTION__, reg, val); ++ return val; ++} ++ ++static void pxa_ac97_write(struct ac97_codec *codec, u8 reg, u16 val) ++{ ++ down(&CAR_mutex); ++ if (!(CAR & CAR_CAIP)) { ++ volatile u32 *reg_addr; ++ ++ // if we are writing to the codec GPIO using slot 12 ++ // then we have to write to the modem register space ++ if (reg == AC97_GPIO_STATUS) { ++ reg_addr = (u32 *)&PMC_REG_BASE + (reg >> 1); ++ *reg_addr = val; ++ return; ++ } ++ ++ reg_addr = (u32 *)&PAC_REG_BASE + (reg >> 1); ++ ++ waitingForMask=GSR_CDONE; ++ init_completion(&CAR_completion); ++ *reg_addr = val; ++ wait_for_completion(&CAR_completion); ++ } else { ++ printk(KERN_CRIT __FUNCTION__": CAR_CAIP already set\n"); ++ } ++ up(&CAR_mutex); ++ //printk("%s(0x%02x, 0x%04x)\n", __FUNCTION__, reg, val); ++} ++ ++static void pxa_ac97_irq(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ int gsr = GSR; ++ GSR = gsr & (GSR_SDONE|GSR_CDONE); //write a 1 to clear ++ if (gsr & waitingForMask) ++ { ++ complete(&CAR_completion); ++ } ++} ++ ++static struct ac97_codec pxa_ac97_codec = { ++ codec_read: pxa_ac97_read, ++ codec_write: pxa_ac97_write, ++}; ++ ++static DECLARE_MUTEX(pxa_ac97_mutex); ++static int pxa_ac97_refcount; ++ ++int pxa_ac97_get(struct ac97_codec **codec) ++{ ++ int ret; ++ ++ *codec = NULL; ++ down(&pxa_ac97_mutex); ++ ++ if (!pxa_ac97_refcount) { ++ ret = request_irq(IRQ_AC97, pxa_ac97_irq, 0, "AC97", NULL); ++ if (ret) ++ return ret; ++ ++ CKEN |= CKEN2_AC97; ++ set_GPIO_mode(GPIO31_SYNC_AC97_MD); ++ set_GPIO_mode(GPIO30_SDATA_OUT_AC97_MD); ++ set_GPIO_mode(GPIO28_BITCLK_AC97_MD); ++ set_GPIO_mode(GPIO29_SDATA_IN_AC97_MD); ++ ++ GCR = 0; ++ udelay(10); ++ GCR = GCR_COLD_RST|GCR_CDONE_IE|GCR_SDONE_IE; ++ while (!(GSR & GSR_PCR)) { ++ schedule(); ++ } ++ ++ ret = ac97_probe_codec(&pxa_ac97_codec); ++ if (ret != 1) { ++ free_irq(IRQ_AC97, NULL); ++ GCR = GCR_ACLINK_OFF; ++ CKEN &= ~CKEN2_AC97; ++ return ret; ++ } ++ ++ // need little hack for UCB1400 (should be moved elsewhere) ++ pxa_ac97_write(&pxa_ac97_codec,AC97_EXTENDED_STATUS,1); ++ //pxa_ac97_write(&pxa_ac97_codec, 0x6a, 0x1ff7); ++ pxa_ac97_write(&pxa_ac97_codec, 0x6a, 0x0050); ++ pxa_ac97_write(&pxa_ac97_codec, 0x6c, 0x0030); ++ } ++ ++ pxa_ac97_refcount++; ++ up(&pxa_ac97_mutex); ++ *codec = &pxa_ac97_codec; ++ return 0; ++} ++ ++void pxa_ac97_put(void) ++{ ++ down(&pxa_ac97_mutex); ++ pxa_ac97_refcount--; ++ if (!pxa_ac97_refcount) { ++ GCR = GCR_ACLINK_OFF; ++ CKEN &= ~CKEN2_AC97; ++ free_irq(IRQ_AC97, NULL); ++ } ++ up(&pxa_ac97_mutex); ++} ++ ++EXPORT_SYMBOL(pxa_ac97_get); ++EXPORT_SYMBOL(pxa_ac97_put); ++ ++ ++/* ++ * Audio Mixer stuff ++ */ ++ ++static audio_state_t ac97_audio_state; ++static audio_stream_t ac97_audio_in; ++ ++static int mixer_ioctl( struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ int ret, val; ++ ++ ret = pxa_ac97_codec.mixer_ioctl(&pxa_ac97_codec, cmd, arg); ++ if (ret) ++ return ret; ++ ++ /* We must snoop for some commands to provide our own extra processing */ ++ switch (cmd) { ++ case SOUND_MIXER_WRITE_RECSRC: ++ /* ++ * According to the PXA250 spec, mic-in should use different ++ * DRCMR and different AC97 FIFO. ++ * Unfortunately current UCB1400 versions (up to ver 2A) don't ++ * produce slot 6 for the audio input frame, therefore the PXA ++ * AC97 mic-in FIFO is always starved. ++ */ ++#if 0 ++ ret = get_user(val, (int *)arg); ++ if (ret) ++ return ret; ++ pxa_audio_clear_buf(&ac97_audio_in); ++ *ac97_audio_in.drcmr = 0; ++ if (val & (1 << SOUND_MIXER_MIC)) { ++ ac97_audio_in.dcmd = DCMD_RXMCDR; ++ ac97_audio_in.drcmr = &DRCMRRXMCDR; ++ ac97_audio_in.dev_addr = __PREG(MCDR); ++ } else { ++ ac97_audio_in.dcmd = DCMD_RXPCDR; ++ ac97_audio_in.drcmr = &DRCMRRXPCDR; ++ ac97_audio_in.dev_addr = __PREG(PCDR); ++ } ++ if (ac97_audio_state.rd_ref) ++ *ac97_audio_in.drcmr = ++ ac97_audio_in.dma_ch | DRCMR_MAPVLD; ++#endif ++ break; ++ } ++ return 0; ++} ++ ++static struct file_operations mixer_fops = { ++ ioctl: mixer_ioctl, ++ llseek: no_llseek, ++ owner: THIS_MODULE ++}; ++ ++/* ++ * AC97 codec ioctls ++ */ ++ ++static int codec_adc_rate = 48000; ++static int codec_dac_rate = 48000; ++ ++static int ac97_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ int ret; ++ long val; ++ ++ switch(cmd) { ++ case SNDCTL_DSP_STEREO: ++ ret = get_user(val, (int *) arg); ++ if (ret) ++ return ret; ++ /* FIXME: do we support mono? */ ++ ret = (val == 0) ? -EINVAL : 1; ++ return put_user(ret, (int *) arg); ++ ++ case SNDCTL_DSP_CHANNELS: ++ case SOUND_PCM_READ_CHANNELS: ++ /* FIXME: do we support mono? */ ++ return put_user(2, (long *) arg); ++ ++ case SNDCTL_DSP_SPEED: ++ ret = get_user(val, (long *) arg); ++ if (ret) ++ return ret; ++ if (file->f_mode & FMODE_READ) ++ codec_adc_rate = ac97_set_adc_rate(&pxa_ac97_codec, val); ++ if (file->f_mode & FMODE_WRITE) ++ codec_dac_rate = ac97_set_dac_rate(&pxa_ac97_codec, val); ++ /* fall through */ ++ ++ case SOUND_PCM_READ_RATE: ++ if (file->f_mode & FMODE_READ) ++ val = codec_adc_rate; ++ if (file->f_mode & FMODE_WRITE) ++ val = codec_dac_rate; ++ return put_user(val, (long *) arg); ++ ++ case SNDCTL_DSP_SETFMT: ++ case SNDCTL_DSP_GETFMTS: ++ /* FIXME: can we do other fmts? */ ++ return put_user(AFMT_S16_LE, (long *) arg); ++ ++ default: ++ /* Maybe this is meant for the mixer (As per OSS Docs) */ ++ return mixer_ioctl(inode, file, cmd, arg); ++ } ++ return 0; ++} ++ ++ ++/* ++ * Audio stuff ++ */ ++ ++static audio_stream_t ac97_audio_out = { ++ name: "AC97 audio out", ++ dcmd: DCMD_TXPCDR, ++ drcmr: &DRCMRTXPCDR, ++ dev_addr: __PREG(PCDR), ++}; ++ ++static audio_stream_t ac97_audio_in = { ++ name: "AC97 audio in", ++ dcmd: DCMD_RXPCDR, ++ drcmr: &DRCMRRXPCDR, ++ dev_addr: __PREG(PCDR), ++}; ++ ++static audio_state_t ac97_audio_state = { ++ output_stream: &ac97_audio_out, ++ input_stream: &ac97_audio_in, ++ client_ioctl: ac97_ioctl, ++ sem: __MUTEX_INITIALIZER(ac97_audio_state.sem), ++}; ++ ++static int ac97_audio_open(struct inode *inode, struct file *file) ++{ ++ return pxa_audio_attach(inode, file, &ac97_audio_state); ++} ++ ++/* ++ * Missing fields of this structure will be patched with the call ++ * to pxa_audio_attach(). ++ */ ++ ++static struct file_operations ac97_audio_fops = { ++ open: ac97_audio_open, ++ owner: THIS_MODULE ++}; ++ ++ ++static int __init pxa_ac97_init(void) ++{ ++ int ret; ++ struct ac97_codec *dummy; ++ ++ ret = pxa_ac97_get(&dummy); ++ if (ret) ++ return ret; ++ ++ ac97_audio_state.dev_dsp = register_sound_dsp(&ac97_audio_fops, -1); ++ pxa_ac97_codec.dev_mixer = register_sound_mixer(&mixer_fops, -1); ++ ++ return 0; ++} ++ ++static void __exit pxa_ac97_exit(void) ++{ ++ unregister_sound_dsp(ac97_audio_state.dev_dsp); ++ unregister_sound_mixer(pxa_ac97_codec.dev_mixer); ++ pxa_ac97_put(); ++} ++ ++ ++module_init(pxa_ac97_init); ++module_exit(pxa_ac97_exit); ++ +--- /dev/null ++++ linux-2.4.27/drivers/sound/pxa-audio.c +@@ -0,0 +1,853 @@ ++/* ++ * linux/drivers/sound/pxa-audio.c -- audio interface for the Cotula chip ++ * ++ * Author: Nicolas Pitre ++ * Created: Aug 15, 2001 ++ * Copyright: MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/slab.h> ++#include <linux/pci.h> ++#include <linux/poll.h> ++#include <linux/sound.h> ++#include <linux/soundcard.h> ++ ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++#include <asm/semaphore.h> ++#include <asm/dma.h> ++ ++#include "pxa-audio.h" ++ ++ ++#define AUDIO_NBFRAGS_DEFAULT 8 ++#define AUDIO_FRAGSIZE_DEFAULT 8192 ++ ++#define MAX_DMA_SIZE 4096 ++#define DMA_DESC_SIZE sizeof(pxa_dma_desc) ++ ++ ++/* ++ * This function frees all buffers ++ */ ++#define audio_clear_buf pxa_audio_clear_buf ++ ++void pxa_audio_clear_buf(audio_stream_t * s) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ int frag; ++ ++ if (!s->buffers) ++ return; ++ ++ /* Ensure DMA isn't running */ ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ add_wait_queue(&s->stop_wq, &wait); ++ DCSR(s->dma_ch) = DCSR_STOPIRQEN; ++ schedule(); ++ remove_wait_queue(&s->stop_wq, &wait); ++ ++ /* free DMA buffers */ ++ for (frag = 0; frag < s->nbfrags; frag++) { ++ audio_buf_t *b = &s->buffers[frag]; ++ if (!b->master) ++ continue; ++ consistent_free(b->data, b->master, b->dma_desc->dsadr); ++ } ++ ++ /* free descriptor ring */ ++ if (s->buffers->dma_desc) ++ consistent_free(s->buffers->dma_desc, ++ s->nbfrags * s->descs_per_frag * DMA_DESC_SIZE, ++ s->dma_desc_phys); ++ ++ /* free buffer structure array */ ++ kfree(s->buffers); ++ s->buffers = NULL; ++} ++ ++/* ++ * This function allocates the DMA descriptor array and buffer data space ++ * according to the current number of fragments and fragment size. ++ */ ++static int audio_setup_buf(audio_stream_t * s) ++{ ++ pxa_dma_desc *dma_desc; ++ dma_addr_t dma_desc_phys; ++ int nb_desc, frag, i, buf_size = 0; ++ char *dma_buf = NULL; ++ dma_addr_t dma_buf_phys = 0; ++ ++ if (s->buffers) ++ return -EBUSY; ++ ++ /* Our buffer structure array */ ++ s->buffers = kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL); ++ if (!s->buffers) ++ goto err; ++ memzero(s->buffers, sizeof(audio_buf_t) * s->nbfrags); ++ ++ /* ++ * Our DMA descriptor array: ++ * for Each fragment we have one checkpoint descriptor plus one ++ * descriptor per MAX_DMA_SIZE byte data blocks. ++ */ ++ nb_desc = (1 + (s->fragsize + MAX_DMA_SIZE - 1)/MAX_DMA_SIZE) * s->nbfrags; ++ dma_desc = consistent_alloc(GFP_KERNEL, ++ nb_desc * DMA_DESC_SIZE, ++ &dma_desc_phys, ++ 0); ++ if (!dma_desc) ++ goto err; ++ s->descs_per_frag = nb_desc / s->nbfrags; ++ s->buffers->dma_desc = dma_desc; ++ s->dma_desc_phys = dma_desc_phys; ++ for (i = 0; i < nb_desc - 1; i++) ++ dma_desc[i].ddadr = dma_desc_phys + (i + 1) * DMA_DESC_SIZE; ++ dma_desc[i].ddadr = dma_desc_phys; ++ ++ /* Our actual DMA buffers */ ++ for (frag = 0; frag < s->nbfrags; frag++) { ++ audio_buf_t *b = &s->buffers[frag]; ++ ++ /* ++ * Let's allocate non-cached memory for DMA buffers. ++ * We try to allocate all memory at once. ++ * If this fails (a common reason is memory fragmentation), ++ * then we'll try allocating smaller buffers. ++ */ ++ if (!buf_size) { ++ buf_size = (s->nbfrags - frag) * s->fragsize; ++ do { ++ dma_buf = consistent_alloc(GFP_KERNEL, ++ buf_size, ++ &dma_buf_phys, ++ 0); ++ if (!dma_buf) ++ buf_size -= s->fragsize; ++ } while (!dma_buf && buf_size); ++ if (!dma_buf) ++ goto err; ++ b->master = buf_size; ++ memzero(dma_buf, buf_size); ++ } ++ ++ /* ++ * Set up our checkpoint descriptor. Since the count ++ * is always zero, we'll abuse the dsadr and dtadr fields ++ * just in case this one is picked up by the hardware ++ * while processing SOUND_DSP_GETPTR. ++ */ ++ dma_desc->dsadr = dma_buf_phys; ++ dma_desc->dtadr = dma_buf_phys; ++ dma_desc->dcmd = DCMD_ENDIRQEN; ++ if (s->output && !s->mapped) ++ dma_desc->ddadr |= DDADR_STOP; ++ b->dma_desc = dma_desc++; ++ ++ /* set up the actual data descriptors */ ++ for (i = 0; (i * MAX_DMA_SIZE) < s->fragsize; i++) { ++ dma_desc[i].dsadr = (s->output) ? ++ (dma_buf_phys + i*MAX_DMA_SIZE) : s->dev_addr; ++ dma_desc[i].dtadr = (s->output) ? ++ s->dev_addr : (dma_buf_phys + i*MAX_DMA_SIZE); ++ dma_desc[i].dcmd = s->dcmd | ++ ((s->fragsize < MAX_DMA_SIZE) ? ++ s->fragsize : MAX_DMA_SIZE); ++ } ++ dma_desc += i; ++ ++ /* handle buffer pointers */ ++ b->data = dma_buf; ++ dma_buf += s->fragsize; ++ dma_buf_phys += s->fragsize; ++ buf_size -= s->fragsize; ++ } ++ ++ s->usr_frag = s->dma_frag = 0; ++ s->bytecount = 0; ++ s->fragcount = 0; ++ sema_init(&s->sem, (s->output) ? s->nbfrags : 0); ++ return 0; ++ ++err: ++ printk("pxa-audio: unable to allocate audio memory\n "); ++ audio_clear_buf(s); ++ return -ENOMEM; ++} ++ ++/* ++ * Our DMA interrupt handler ++ */ ++static void audio_dma_irq(int ch, void *dev_id, struct pt_regs *regs) ++{ ++ audio_stream_t *s = dev_id; ++ u_int dcsr; ++ ++ dcsr = DCSR(ch); ++ DCSR(ch) = dcsr & ~DCSR_STOPIRQEN; ++ ++ if (!s->buffers) { ++ printk("AC97 DMA: wow... received IRQ for channel %d but no buffer exists\n", ch); ++ return; ++ } ++ ++ if (dcsr & DCSR_BUSERR) ++ printk("AC97 DMA: bus error interrupt on channel %d\n", ch); ++ ++ if (dcsr & DCSR_ENDINTR) { ++ u_long cur_dma_desc; ++ u_int cur_dma_frag; ++ ++ /* ++ * Find out which DMA desc is current. Note that DDADR ++ * points to the next desc, not the current one. ++ */ ++ cur_dma_desc = DDADR(ch) - s->dma_desc_phys - DMA_DESC_SIZE; ++ ++ /* ++ * Let the compiler nicely optimize constant divisors into ++ * multiplications for the common cases which is much faster. ++ * Common cases: x = 1 + (1 << y) for y = [0..3] ++ */ ++ switch (s->descs_per_frag) { ++ case 2: cur_dma_frag = cur_dma_desc / (2*DMA_DESC_SIZE); break; ++ case 3: cur_dma_frag = cur_dma_desc / (3*DMA_DESC_SIZE); break; ++ case 5: cur_dma_frag = cur_dma_desc / (5*DMA_DESC_SIZE); break; ++ case 9: cur_dma_frag = cur_dma_desc / (9*DMA_DESC_SIZE); break; ++ default: cur_dma_frag = ++ cur_dma_desc / (s->descs_per_frag * DMA_DESC_SIZE); ++ } ++ ++ /* Account for possible wrap back of cur_dma_desc above */ ++ if (cur_dma_frag >= s->nbfrags) ++ cur_dma_frag = s->nbfrags - 1; ++ ++ while (s->dma_frag != cur_dma_frag) { ++ if (!s->mapped) { ++ /* ++ * This fragment is done - set the checkpoint ++ * descriptor to STOP until it is gets ++ * processed by the read or write function. ++ */ ++ s->buffers[s->dma_frag].dma_desc->ddadr |= DDADR_STOP; ++ up(&s->sem); ++ } ++ if (++s->dma_frag >= s->nbfrags) ++ s->dma_frag = 0; ++ ++ /* Accounting */ ++ s->bytecount += s->fragsize; ++ s->fragcount++; ++ } ++ ++ /* ... and for polling processes */ ++ wake_up(&s->frag_wq); ++ } ++ ++ if ((dcsr & DCSR_STOPIRQEN) && (dcsr & DCSR_STOPSTATE)) ++ wake_up(&s->stop_wq); ++} ++ ++/* ++ * Validate and sets up buffer fragments, etc. ++ */ ++static int audio_set_fragments(audio_stream_t *s, int val) ++{ ++ if (s->mapped || DCSR(s->dma_ch) & DCSR_RUN) ++ return -EBUSY; ++ if (s->buffers) ++ audio_clear_buf(s); ++ s->nbfrags = (val >> 16) & 0x7FFF; ++ val &= 0xffff; ++ if (val < 5) ++ val = 5; ++ if (val > 15) ++ val = 15; ++ s->fragsize = 1 << val; ++ if (s->nbfrags < 2) ++ s->nbfrags = 2; ++ if (s->nbfrags * s->fragsize > 256 * 1024) ++ s->nbfrags = 256 * 1024 / s->fragsize; ++ if (audio_setup_buf(s)) ++ return -ENOMEM; ++ return val|(s->nbfrags << 16); ++} ++ ++ ++/* ++ * The fops functions ++ */ ++ ++static int audio_write(struct file *file, const char *buffer, ++ size_t count, loff_t * ppos) ++{ ++ const char *buffer0 = buffer; ++ audio_state_t *state = (audio_state_t *)file->private_data; ++ audio_stream_t *s = state->output_stream; ++ int chunksize, ret = 0; ++ ++ if (ppos != &file->f_pos) ++ return -ESPIPE; ++ if (s->mapped) ++ return -ENXIO; ++ if (!s->buffers && audio_setup_buf(s)) ++ return -ENOMEM; ++ ++ while (count > 0) { ++ audio_buf_t *b = &s->buffers[s->usr_frag]; ++ ++ /* Grab a fragment */ ++ if (file->f_flags & O_NONBLOCK) { ++ ret = -EAGAIN; ++ if (down_trylock(&s->sem)) ++ break; ++ } else { ++ ret = -ERESTARTSYS; ++ if (down_interruptible(&s->sem)) ++ break; ++ } ++ ++ /* Feed the current buffer */ ++ chunksize = s->fragsize - b->offset; ++ if (chunksize > count) ++ chunksize = count; ++ if (copy_from_user(b->data + b->offset, buffer, chunksize)) { ++ up(&s->sem); ++ return -EFAULT; ++ } ++ b->offset += chunksize; ++ buffer += chunksize; ++ count -= chunksize; ++ if (b->offset < s->fragsize) { ++ up(&s->sem); ++ break; ++ } ++ ++ /* ++ * Activate DMA on current buffer. ++ * We unlock this fragment's checkpoint descriptor and ++ * kick DMA if it is idle. Using checkpoint descriptors ++ * allows for control operations without the need for ++ * stopping the DMA channel if it is already running. ++ */ ++ b->offset = 0; ++ b->dma_desc->ddadr &= ~DDADR_STOP; ++ if (DCSR(s->dma_ch) & DCSR_STOPSTATE) { ++ DDADR(s->dma_ch) = b->dma_desc->ddadr; ++ DCSR(s->dma_ch) = DCSR_RUN; ++ } ++ ++ /* move the index to the next fragment */ ++ if (++s->usr_frag >= s->nbfrags) ++ s->usr_frag = 0; ++ } ++ ++ if ((buffer - buffer0)) ++ ret = buffer - buffer0; ++ return ret; ++} ++ ++ ++static int audio_read(struct file *file, char *buffer, ++ size_t count, loff_t * ppos) ++{ ++ char *buffer0 = buffer; ++ audio_state_t *state = file->private_data; ++ audio_stream_t *s = state->input_stream; ++ int chunksize, ret = 0; ++ ++ if (ppos != &file->f_pos) ++ return -ESPIPE; ++ if (s->mapped) ++ return -ENXIO; ++ if (!s->buffers && audio_setup_buf(s)) ++ return -ENOMEM; ++ ++ while (count > 0) { ++ audio_buf_t *b = &s->buffers[s->usr_frag]; ++ ++ /* prime DMA */ ++ if (DCSR(s->dma_ch) & DCSR_STOPSTATE) { ++ DDADR(s->dma_ch) = ++ s->buffers[s->dma_frag].dma_desc->ddadr; ++ DCSR(s->dma_ch) = DCSR_RUN; ++ } ++ ++ /* Wait for a buffer to become full */ ++ if (file->f_flags & O_NONBLOCK) { ++ ret = -EAGAIN; ++ if (down_trylock(&s->sem)) ++ break; ++ } else { ++ ret = -ERESTARTSYS; ++ if (down_interruptible(&s->sem)) ++ break; ++ } ++ ++ /* Grab data from current buffer */ ++ chunksize = s->fragsize - b->offset; ++ if (chunksize > count) ++ chunksize = count; ++ if (copy_to_user(buffer, b->data + b->offset, chunksize)) { ++ up(&s->sem); ++ return -EFAULT; ++ } ++ b->offset += chunksize; ++ buffer += chunksize; ++ count -= chunksize; ++ if (b->offset < s->fragsize) { ++ up(&s->sem); ++ break; ++ } ++ ++ /* ++ * Make this buffer available for DMA again. ++ * We unlock this fragment's checkpoint descriptor and ++ * kick DMA if it is idle. Using checkpoint descriptors ++ * allows for control operations without the need for ++ * stopping the DMA channel if it is already running. ++ */ ++ b->offset = 0; ++ b->dma_desc->ddadr &= ~DDADR_STOP; ++ ++ /* move the index to the next fragment */ ++ if (++s->usr_frag >= s->nbfrags) ++ s->usr_frag = 0; ++ } ++ ++ if ((buffer - buffer0)) ++ ret = buffer - buffer0; ++ return ret; ++} ++ ++ ++static int audio_sync(struct file *file) ++{ ++ audio_state_t *state = file->private_data; ++ audio_stream_t *s = state->output_stream; ++ audio_buf_t *b; ++ pxa_dma_desc *final_desc; ++ u_long dcmd_save = 0; ++ DECLARE_WAITQUEUE(wait, current); ++ ++ if (!(file->f_mode & FMODE_WRITE) || !s->buffers || s->mapped) ++ return 0; ++ ++ /* ++ * Send current buffer if it contains data. Be sure to send ++ * a full sample count. ++ */ ++ final_desc = NULL; ++ b = &s->buffers[s->usr_frag]; ++ if (b->offset &= ~3) { ++ final_desc = &b->dma_desc[1 + b->offset/MAX_DMA_SIZE]; ++ b->offset &= (MAX_DMA_SIZE-1); ++ dcmd_save = final_desc->dcmd; ++ final_desc->dcmd = b->offset | s->dcmd | DCMD_ENDIRQEN; ++ final_desc->ddadr |= DDADR_STOP; ++ b->offset = 0; ++ b->dma_desc->ddadr &= ~DDADR_STOP; ++ if (DCSR(s->dma_ch) & DCSR_STOPSTATE) { ++ DDADR(s->dma_ch) = b->dma_desc->ddadr; ++ DCSR(s->dma_ch) = DCSR_RUN; ++ } ++ } ++ ++ /* Wait for DMA to complete. */ ++ set_current_state(TASK_INTERRUPTIBLE); ++#if 0 ++ /* ++ * The STOPSTATE IRQ never seem to occur if DCSR_STOPIRQEN is set ++ * along wotj DCSR_RUN. Silicon bug? ++ */ ++ add_wait_queue(&s->stop_wq, &wait); ++ DCSR(s->dma_ch) |= DCSR_STOPIRQEN; ++ schedule(); ++#else ++ add_wait_queue(&s->frag_wq, &wait); ++ while ((DCSR(s->dma_ch) & DCSR_RUN) && !signal_pending(current)) { ++ schedule(); ++ set_current_state(TASK_INTERRUPTIBLE); ++ } ++#endif ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&s->frag_wq, &wait); ++ ++ /* Restore the descriptor chain. */ ++ if (final_desc) { ++ final_desc->dcmd = dcmd_save; ++ final_desc->ddadr &= ~DDADR_STOP; ++ b->dma_desc->ddadr |= DDADR_STOP; ++ } ++ return 0; ++} ++ ++ ++static unsigned int audio_poll(struct file *file, ++ struct poll_table_struct *wait) ++{ ++ audio_state_t *state = file->private_data; ++ audio_stream_t *is = state->input_stream; ++ audio_stream_t *os = state->output_stream; ++ unsigned int mask = 0; ++ ++ if (file->f_mode & FMODE_READ) { ++ /* Start audio input if not already active */ ++ if (!is->buffers && audio_setup_buf(is)) ++ return -ENOMEM; ++ if (DCSR(is->dma_ch) & DCSR_STOPSTATE) { ++ DDADR(is->dma_ch) = ++ is->buffers[is->dma_frag].dma_desc->ddadr; ++ DCSR(is->dma_ch) = DCSR_RUN; ++ } ++ poll_wait(file, &is->frag_wq, wait); ++ } ++ ++ if (file->f_mode & FMODE_WRITE) { ++ if (!os->buffers && audio_setup_buf(os)) ++ return -ENOMEM; ++ poll_wait(file, &os->frag_wq, wait); ++ } ++ ++ if (file->f_mode & FMODE_READ) ++ if (( is->mapped && is->bytecount > 0) || ++ (!is->mapped && atomic_read(&is->sem.count) > 0)) ++ mask |= POLLIN | POLLRDNORM; ++ ++ if (file->f_mode & FMODE_WRITE) ++ if (( os->mapped && os->bytecount > 0) || ++ (!os->mapped && atomic_read(&os->sem.count) > 0)) ++ mask |= POLLOUT | POLLWRNORM; ++ ++ return mask; ++} ++ ++ ++static int audio_ioctl( struct inode *inode, struct file *file, ++ uint cmd, ulong arg) ++{ ++ audio_state_t *state = file->private_data; ++ audio_stream_t *os = state->output_stream; ++ audio_stream_t *is = state->input_stream; ++ long val; ++ ++ switch (cmd) { ++ case OSS_GETVERSION: ++ return put_user(SOUND_VERSION, (int *)arg); ++ ++ case SNDCTL_DSP_GETBLKSIZE: ++ if (file->f_mode & FMODE_WRITE) ++ return put_user(os->fragsize, (int *)arg); ++ else ++ return put_user(is->fragsize, (int *)arg); ++ ++ case SNDCTL_DSP_GETCAPS: ++ val = DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP; ++ if (is && os) ++ val |= DSP_CAP_DUPLEX; ++ return put_user(val, (int *)arg); ++ ++ case SNDCTL_DSP_SETFRAGMENT: ++ if (get_user(val, (long *) arg)) ++ return -EFAULT; ++ if (file->f_mode & FMODE_READ) { ++ int ret = audio_set_fragments(is, val); ++ if (ret < 0) ++ return ret; ++ ret = put_user(ret, (int *)arg); ++ if (ret) ++ return ret; ++ } ++ if (file->f_mode & FMODE_WRITE) { ++ int ret = audio_set_fragments(os, val); ++ if (ret < 0) ++ return ret; ++ ret = put_user(ret, (int *)arg); ++ if (ret) ++ return ret; ++ } ++ return 0; ++ ++ case SNDCTL_DSP_SYNC: ++ return audio_sync(file); ++ ++ case SNDCTL_DSP_SETDUPLEX: ++ return 0; ++ ++ case SNDCTL_DSP_POST: ++ return 0; ++ ++ case SNDCTL_DSP_GETTRIGGER: ++ val = 0; ++ if (file->f_mode & FMODE_READ && DCSR(is->dma_ch) & DCSR_RUN) ++ val |= PCM_ENABLE_INPUT; ++ if (file->f_mode & FMODE_WRITE && DCSR(os->dma_ch) & DCSR_RUN) ++ val |= PCM_ENABLE_OUTPUT; ++ return put_user(val, (int *)arg); ++ ++ case SNDCTL_DSP_SETTRIGGER: ++ if (get_user(val, (int *)arg)) ++ return -EFAULT; ++ if (file->f_mode & FMODE_READ) { ++ if (val & PCM_ENABLE_INPUT) { ++ if (!is->buffers && audio_setup_buf(is)) ++ return -ENOMEM; ++ if (!(DCSR(is->dma_ch) & DCSR_RUN)) { ++ audio_buf_t *b = &is->buffers[is->dma_frag]; ++ DDADR(is->dma_ch) = b->dma_desc->ddadr; ++ DCSR(is->dma_ch) = DCSR_RUN; ++ } ++ } else { ++ DCSR(is->dma_ch) = 0; ++ } ++ } ++ if (file->f_mode & FMODE_WRITE) { ++ if (val & PCM_ENABLE_OUTPUT) { ++ if (!os->buffers && audio_setup_buf(os)) ++ return -ENOMEM; ++ if (!(DCSR(os->dma_ch) & DCSR_RUN)) { ++ audio_buf_t *b = &os->buffers[os->dma_frag]; ++ DDADR(os->dma_ch) = b->dma_desc->ddadr; ++ DCSR(os->dma_ch) = DCSR_RUN; ++ } ++ } else { ++ DCSR(os->dma_ch) = 0; ++ } ++ } ++ return 0; ++ ++ case SNDCTL_DSP_GETOSPACE: ++ case SNDCTL_DSP_GETISPACE: ++ { ++ audio_buf_info inf = { 0, }; ++ audio_stream_t *s = (cmd == SNDCTL_DSP_GETOSPACE) ? os : is; ++ ++ if ((s == is && !(file->f_mode & FMODE_READ)) || ++ (s == os && !(file->f_mode & FMODE_WRITE))) ++ return -EINVAL; ++ if (!s->buffers && audio_setup_buf(s)) ++ return -ENOMEM; ++ inf.bytes = atomic_read(&s->sem.count) * s->fragsize; ++ inf.bytes -= s->buffers[s->usr_frag].offset; ++ inf.fragments = inf.bytes / s->fragsize; ++ inf.fragsize = s->fragsize; ++ inf.fragstotal = s->nbfrags; ++ return copy_to_user((void *)arg, &inf, sizeof(inf)); ++ } ++ ++ case SNDCTL_DSP_GETOPTR: ++ case SNDCTL_DSP_GETIPTR: ++ { ++ count_info inf = { 0, }; ++ audio_stream_t *s = (cmd == SNDCTL_DSP_GETOPTR) ? os : is; ++ dma_addr_t ptr; ++ int bytecount, offset, flags; ++ ++ if ((s == is && !(file->f_mode & FMODE_READ)) || ++ (s == os && !(file->f_mode & FMODE_WRITE))) ++ return -EINVAL; ++ if (DCSR(s->dma_ch) & DCSR_RUN) { ++ audio_buf_t *b; ++ save_flags_cli(flags); ++ ptr = (s->output) ? DSADR(s->dma_ch) : DTADR(s->dma_ch); ++ b = &s->buffers[s->dma_frag]; ++ offset = ptr - b->dma_desc->dsadr; ++ if (offset >= s->fragsize) ++ offset = s->fragsize - 4; ++ } else { ++ save_flags(flags); ++ offset = 0; ++ } ++ inf.ptr = s->dma_frag * s->fragsize + offset; ++ bytecount = s->bytecount + offset; ++ s->bytecount = -offset; ++ inf.blocks = s->fragcount; ++ s->fragcount = 0; ++ restore_flags(flags); ++ if (bytecount < 0) ++ bytecount = 0; ++ inf.bytes = bytecount; ++ return copy_to_user((void *)arg, &inf, sizeof(inf)); ++ } ++ ++ case SNDCTL_DSP_NONBLOCK: ++ file->f_flags |= O_NONBLOCK; ++ return 0; ++ ++ case SNDCTL_DSP_RESET: ++ if (file->f_mode & FMODE_WRITE) ++ audio_clear_buf(os); ++ if (file->f_mode & FMODE_READ) ++ audio_clear_buf(is); ++ return 0; ++ ++ default: ++ return state->client_ioctl(inode, file, cmd, arg); ++ } ++ ++ return 0; ++} ++ ++ ++static int audio_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ audio_state_t *state = file->private_data; ++ audio_stream_t *s; ++ unsigned long size, vma_addr; ++ int i, ret; ++ ++ if (vma->vm_pgoff != 0) ++ return -EINVAL; ++ ++ if (vma->vm_flags & VM_WRITE) { ++ if (!state->wr_ref) ++ return -EINVAL;; ++ s = state->output_stream; ++ } else if (vma->vm_flags & VM_READ) { ++ if (!state->rd_ref) ++ return -EINVAL; ++ s = state->input_stream; ++ } else return -EINVAL; ++ ++ if (s->mapped) ++ return -EINVAL; ++ size = vma->vm_end - vma->vm_start; ++ if (size != s->fragsize * s->nbfrags) ++ return -EINVAL; ++ if (!s->buffers && audio_setup_buf(s)) ++ return -ENOMEM; ++ vma_addr = vma->vm_start; ++ for (i = 0; i < s->nbfrags; i++) { ++ audio_buf_t *buf = &s->buffers[i]; ++ if (!buf->master) ++ continue; ++ ret = remap_page_range(vma_addr, buf->dma_desc->dsadr, ++ buf->master, vma->vm_page_prot); ++ if (ret) ++ return ret; ++ vma_addr += buf->master; ++ } ++ for (i = 0; i < s->nbfrags; i++) ++ s->buffers[i].dma_desc->ddadr &= ~DDADR_STOP; ++ s->mapped = 1; ++ return 0; ++} ++ ++ ++static int audio_release(struct inode *inode, struct file *file) ++{ ++ audio_state_t *state = file->private_data; ++ ++ down(&state->sem); ++ ++ if (file->f_mode & FMODE_READ) { ++ audio_clear_buf(state->input_stream); ++ *state->input_stream->drcmr = 0; ++ pxa_free_dma(state->input_stream->dma_ch); ++ state->rd_ref = 0; ++ } ++ ++ if (file->f_mode & FMODE_WRITE) { ++ audio_sync(file); ++ audio_clear_buf(state->output_stream); ++ *state->output_stream->drcmr = 0; ++ pxa_free_dma(state->output_stream->dma_ch); ++ state->wr_ref = 0; ++ } ++ ++ up(&state->sem); ++ return 0; ++} ++ ++ ++int pxa_audio_attach(struct inode *inode, struct file *file, ++ audio_state_t *state) ++{ ++ audio_stream_t *is = state->input_stream; ++ audio_stream_t *os = state->output_stream; ++ int err; ++ ++ down(&state->sem); ++ ++ /* access control */ ++ err = -ENODEV; ++ if ((file->f_mode & FMODE_WRITE) && !os) ++ goto out; ++ if ((file->f_mode & FMODE_READ) && !is) ++ goto out; ++ err = -EBUSY; ++ if ((file->f_mode & FMODE_WRITE) && state->wr_ref) ++ goto out; ++ if ((file->f_mode & FMODE_READ) && state->rd_ref) ++ goto out; ++ ++ /* request DMA channels */ ++ if (file->f_mode & FMODE_WRITE) { ++ err = pxa_request_dma(os->name, DMA_PRIO_LOW, ++ audio_dma_irq, os); ++ if (err < 0) ++ goto out; ++ os->dma_ch = err; ++ } ++ if (file->f_mode & FMODE_READ) { ++ err = pxa_request_dma(is->name, DMA_PRIO_LOW, ++ audio_dma_irq, is); ++ if (err < 0) { ++ if (file->f_mode & FMODE_WRITE) { ++ *os->drcmr = 0; ++ pxa_free_dma(os->dma_ch); ++ } ++ goto out; ++ } ++ is->dma_ch = err; ++ } ++ ++ file->private_data = state; ++ file->f_op->release = audio_release; ++ file->f_op->write = audio_write; ++ file->f_op->read = audio_read; ++ file->f_op->mmap = audio_mmap; ++ file->f_op->poll = audio_poll; ++ file->f_op->ioctl = audio_ioctl; ++ file->f_op->llseek = no_llseek; ++ ++ if ((file->f_mode & FMODE_WRITE)) { ++ state->wr_ref = 1; ++ os->fragsize = AUDIO_FRAGSIZE_DEFAULT; ++ os->nbfrags = AUDIO_NBFRAGS_DEFAULT; ++ os->output = 1; ++ os->mapped = 0; ++ init_waitqueue_head(&os->frag_wq); ++ init_waitqueue_head(&os->stop_wq); ++ *os->drcmr = os->dma_ch | DRCMR_MAPVLD; ++ } ++ if (file->f_mode & FMODE_READ) { ++ state->rd_ref = 1; ++ is->fragsize = AUDIO_FRAGSIZE_DEFAULT; ++ is->nbfrags = AUDIO_NBFRAGS_DEFAULT; ++ is->output = 0; ++ is->mapped = 0; ++ init_waitqueue_head(&is->frag_wq); ++ init_waitqueue_head(&is->stop_wq); ++ *is->drcmr = is->dma_ch | DRCMR_MAPVLD; ++ } ++ ++ err = 0; ++ ++out: ++ up(&state->sem); ++ return err; ++} ++ ++EXPORT_SYMBOL(pxa_audio_attach); ++EXPORT_SYMBOL(pxa_audio_clear_buf); ++ +--- /dev/null ++++ linux-2.4.27/drivers/sound/pxa-audio.h +@@ -0,0 +1,55 @@ ++/* ++ * linux/drivers/sound/pxa-audio.h -- audio interface for the Cotula chip ++ * ++ * Author: Nicolas Pitre ++ * Created: Aug 15, 2001 ++ * Copyright: MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++typedef struct { ++ int offset; /* current buffer position */ ++ char *data; /* actual buffer */ ++ pxa_dma_desc *dma_desc; /* pointer to the starting desc */ ++ int master; /* owner for buffer allocation, contain size whn true */ ++} audio_buf_t; ++ ++typedef struct { ++ char *name; /* stream identifier */ ++ audio_buf_t *buffers; /* pointer to audio buffer array */ ++ u_int usr_frag; /* user fragment index */ ++ u_int dma_frag; /* DMA fragment index */ ++ u_int fragsize; /* fragment size */ ++ u_int nbfrags; /* number of fragments */ ++ u_int dma_ch; /* DMA channel number */ ++ dma_addr_t dma_desc_phys; /* phys addr of descriptor ring */ ++ u_int descs_per_frag; /* nbr descriptors per fragment */ ++ int bytecount; /* nbr of processed bytes */ ++ int fragcount; /* nbr of fragment transitions */ ++ struct semaphore sem; /* account for fragment usage */ ++ wait_queue_head_t frag_wq; /* for poll(), etc. */ ++ wait_queue_head_t stop_wq; /* for users of DCSR_STOPIRQEN */ ++ u_long dcmd; /* DMA descriptor dcmd field */ ++ volatile u32 *drcmr; /* the DMA request channel to use */ ++ u_long dev_addr; /* device physical address for DMA */ ++ int mapped:1; /* mmap()'ed buffers */ ++ int output:1; /* 0 for input, 1 for output */ ++} audio_stream_t; ++ ++typedef struct { ++ audio_stream_t *output_stream; ++ audio_stream_t *input_stream; ++ int dev_dsp; /* audio device handle */ ++ int rd_ref:1; /* open reference for recording */ ++ int wr_ref:1; /* open reference for playback */ ++ int (*client_ioctl)(struct inode *, struct file *, uint, ulong); ++ struct semaphore sem; /* prevent races in attach/release */ ++} audio_state_t; ++ ++extern int pxa_audio_attach(struct inode *inode, struct file *file, ++ audio_state_t *state); ++extern void pxa_audio_clear_buf(audio_stream_t *s); ++ +--- linux-2.4.27/drivers/sound/sa1100-audio.c~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/sound/sa1100-audio.c +@@ -148,7 +148,8 @@ + do { + dmabuf = consistent_alloc(GFP_KERNEL|GFP_DMA, + dmasize, +- &dmaphys); ++ &dmaphys, ++ 0); + if (!dmabuf) + dmasize -= s->fragsize; + } while (!dmabuf && dmasize); +--- linux-2.4.27/drivers/video/Config.in~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/video/Config.in +@@ -50,6 +50,15 @@ + if [ "$CONFIG_FB_SA1100" = "y" -a "$CONFIG_SA1100_CERF_CPLD" = "y" ]; then + bool 'Cerfboard Backlight (CerfPDA)' CONFIG_SA1100_CERF_LCD_BACKLIGHT + fi ++ tristate ' PXA LCD support' CONFIG_FB_PXA $CONFIG_ARCH_PXA ++ if [ "$CONFIG_FB_PXA" != "n" ]; then ++ choice 'LCD Bit Depth' \ ++ "8-Bpp CONFIG_FB_PXA_8BPP \ ++ 16-Bpp CONFIG_FB_PXA_16BPP" Bit-Depth ++ fi ++ if [ "$CONFIG_FB_PXA" != "n" -a "$CONFIG_ARCH_LUBBOCK" = "y" ]; then ++ bool ' Lubbock QVGA LCD support instead of DSTN' CONFIG_FB_PXA_QVGA ++ fi + fi + dep_tristate ' CyberPro 2000/2010/5000 support' CONFIG_FB_CYBER2000 $CONFIG_PCI + if [ "$CONFIG_APOLLO" = "y" ]; then +@@ -295,7 +304,7 @@ + if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_MAC" = "y" -o \ + "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ + "$CONFIG_FB_TX3912" = "y" -o "$CONFIG_FB_CLPS711X" = "y" -o \ +- "$CONFIG_FB_DBMX1" = "y" ]; then ++ "$CONFIG_FB_DBMX1" = "y" -o "$CONFIG_FB_PXA" = "y" ]; then + define_tristate CONFIG_FBCON_CFB2 y + define_tristate CONFIG_FBCON_CFB4 y + else +@@ -329,7 +338,7 @@ + "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" -o \ + "$CONFIG_FB_STI" = "y" -o "$CONFIG_FB_HP300" = "y" -o \ + "$CONFIG_FB_INTEL" = "y" -o \ +- "$CONFIG_FB_DBMX1" = "y" ]; then ++ "$CONFIG_FB_DBMX1" = "y" -o "$CONFIG_FB_PXA" = "y" ]; then + define_tristate CONFIG_FBCON_CFB8 y + else + if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \ +@@ -372,7 +381,7 @@ + "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \ + "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" -o \ + "$CONFIG_FB_NEOMAGIC" = "y" -o "$CONFIG_FB_INTEL" = "y" -o \ +- "$CONFIG_FB_ANAKIN" = "y" -o \ ++ "$CONFIG_FB_ANAKIN" = "y" -o "$CONFIG_FB_PXA" = "y" -o \ + "$CONFIG_FB_DBMX1" = "y" ]; then + define_tristate CONFIG_FBCON_CFB16 y + else +--- linux-2.4.27/drivers/video/Makefile~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/video/Makefile +@@ -14,7 +14,7 @@ + fbcon-vga.o fbcon-iplan2p2.o fbcon-iplan2p4.o \ + fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \ + fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \ +- fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o \ ++ fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o pxafb.o \ + cyber2000fb.o sa1100fb.o fbcon-hga.o fbgen.o + + # Each configuration option enables a list of files. +@@ -129,6 +129,10 @@ + obj-$(CONFIG_FB_BWTWO) += bwtwofb.o + obj-$(CONFIG_FB_HGA) += hgafb.o + obj-$(CONFIG_FB_SA1100) += sa1100fb.o ++obj-$(CONFIG_FB_PXA) += pxafb.o ++ifeq ($(CONFIG_PXA_CERF_PDA),y) ++ obj-$(CONFIG_FB_PXA) += lcdctrl.o lcdctrl_cerf.o ++endif + obj-$(CONFIG_FB_DBMX1) += dbmx1fb.o + obj-$(CONFIG_FB_VIRTUAL) += vfb.o + obj-$(CONFIG_FB_HIT) += hitfb.o fbgen.o +--- linux-2.4.27/drivers/video/fbmem.c~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/video/fbmem.c +@@ -109,6 +109,7 @@ + extern int chips_init(void); + extern int g364fb_init(void); + extern int sa1100fb_init(void); ++extern int pxafb_init(void); + extern int fm2fb_init(void); + extern int fm2fb_setup(char*); + extern int q40fb_init(void); +@@ -305,6 +306,9 @@ + #ifdef CONFIG_FB_SA1100 + { "sa1100", sa1100fb_init, NULL }, + #endif ++#ifdef CONFIG_FB_PXA ++ { "pxa", pxafb_init, NULL }, ++#endif + #ifdef CONFIG_FB_SUN3 + { "sun3", sun3fb_init, sun3fb_setup }, + #endif +@@ -677,13 +681,13 @@ + #elif defined(__i386__) || defined(__x86_64__) + if (boot_cpu_data.x86 > 3) + pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; +-#elif defined(__arm__) || defined(__mips__) ++#elif defined(__mips__) + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + #elif defined(__sh__) + pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE; + #elif defined(__hppa__) + pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; +-#elif defined(__ia64__) ++#elif defined(__ia64__) || defined(__arm__) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + #elif defined(__hppa__) + pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; +--- /dev/null ++++ linux-2.4.27/drivers/video/lcdctrl.c +@@ -0,0 +1,223 @@ ++/* ++ * lcdctrl.c ++ * ++ * Generic LCD control for brightness, contrast, etc. ++ * Device specific drivers implement a lcdctrl_device and ++ * provides access to it via lcdctrl_device_get_ops(). ++ * ++ * Copyright (C) 2002 Intrinsyc Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * History: ++ * Mar 2002: Initial version [FB] ++ * ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/ctype.h> ++#include <linux/mm.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++ ++#include <asm/system.h> ++#include <asm/hardware.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++ ++#include <video/lcdctrl.h> ++ ++/* ++ * Set this to zero to remove all the debug statements via ++ * dead code elimination. ++ */ ++#define DEBUGGING 0 ++ ++#if DEBUGGING ++static unsigned int lcd_debug = DEBUGGING; ++#else ++#define lcd_debug 0 ++#endif ++ ++/* -- prototypes -- */ ++ ++static int lcdctrl_ioctl(struct inode * inode, struct file *filp, ++ unsigned int cmd , unsigned long arg); ++static int lcdctrl_open(struct inode *inode, struct file *filp); ++static int lcdctrl_close(struct inode *inode, struct file *filp); ++ ++/* -- variables -- */ ++ ++struct lcdctrl_device *lcd_device; ++ ++static int intensity; ++static int brightness; ++static int contrast; ++ ++static int enabled; ++static int sync_needed; ++static int chrdev_major; ++ ++static struct file_operations lcdctrl_fops = { ++ ioctl: lcdctrl_ioctl, ++ open: lcdctrl_open, ++ release: lcdctrl_close ++}; ++ ++/* -- ioctl -- */ ++ ++static int lcdctrl_ioctl(struct inode * inode, struct file *filp, ++ unsigned int cmd , unsigned long arg) ++{ ++ int ret; ++ ret = -EINVAL; ++ ++ if( lcd_debug) ++ printk(KERN_INFO "lcdctrl_ioctl: cmd=%d, arg=%ld\n", cmd, arg); ++ ++ switch(cmd) ++ { ++ case _LCDCTRL_IOCTL_ON: ++ ret = lcdctrl_enable(); ++ break; ++ case _LCDCTRL_IOCTL_OFF: ++ ret = lcdctrl_disable(); ++ break; ++ case _LCDCTRL_IOCTL_INTENSITY: ++ if ((arg >=0) && (arg <= 100)) ++ ret = lcdctrl_set_intensity(arg); ++ break; ++ case _LCDCTRL_IOCTL_BRIGHTNESS: ++ if ((arg >=0) && (arg <= 100)) ++ ret = lcdctrl_set_brightness(arg); ++ break; ++ case _LCDCTRL_IOCTL_CONTRAST: ++ if ((arg >=0) && (arg <= 100)) ++ ret = lcdctrl_set_contrast(arg, LCD_NO_SYNC); ++ break; ++ case _LCDCTRL_IOCTL_GET_BRIGHTNESS: ++ ret = brightness; ++ break; ++ case _LCDCTRL_IOCTL_GET_CONTRAST: ++ ret = contrast; ++ break; ++ case _LCDCTRL_IOCTL_GET_INTENSITY: ++ ret = intensity; ++ break; ++ ++ default: ++ printk(KERN_ERR "lcdctrl_ioctl: invalid ioctl\n"); ++ break; ++ } ++ ++ return ret; ++} ++ ++static int lcdctrl_open(struct inode *inode, struct file *filp) ++{ ++// MOD_INC_USE_COUNT; ++ return 0; ++} ++ ++static int lcdctrl_close(struct inode *inode, struct file *filp) ++{ ++// MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++/* -- -- */ ++ ++int lcdctrl_enable( void) ++{ ++ int result; ++ ++ if( enabled) return 0; ++ ++ result = lcd_device->enable(); ++ ++ lcdctrl_set_intensity( intensity); ++ lcdctrl_set_brightness( brightness); ++ lcdctrl_set_contrast( contrast, sync_needed); ++ sync_needed = LCD_NO_SYNC; ++ ++ enabled = 1; ++ return result; ++} ++ ++int lcdctrl_disable( void) ++{ ++ enabled = 0; ++ return lcd_device->disable(); ++} ++ ++int lcdctrl_set_intensity( int i) ++{ ++ intensity = i; ++ return lcd_device->set_intensity( i); ++} ++ ++int lcdctrl_set_brightness( int b) ++{ ++ brightness = b; ++ return lcd_device->set_brightness( b); ++} ++ ++int lcdctrl_set_contrast( int c, int sync) ++{ ++ contrast = c; ++ return lcd_device->set_contrast( c, sync); ++} ++ ++int lcdctrl_get_intensity( void) ++{ ++ return intensity; ++} ++ ++int lcdctrl_get_brightness( void) ++{ ++ return brightness; ++} ++ ++int lcdctrl_get_contrast( void) ++{ ++ return contrast; ++} ++ ++/* -- -- */ ++ ++/* the device specific driver should implement this */ ++struct lcdctrl_device *lcdctrl_device_get_ops(void); ++ ++int lcdctrl_init( void) ++{ ++ int ret; ++ ++ lcd_device = lcdctrl_device_get_ops(); ++ ++ if( !lcd_device) ++ { ++ printk(KERN_ERR "lcdctrl_init: No lcd_device registered.\n"); ++ return -EINVAL; ++ } ++ ++ ret = lcd_device->init( &intensity, &brightness, &contrast); ++ ++ sync_needed = LCD_SYNC_NEEDED; ++ ++ if( ret == 0) ++ { ++ chrdev_major = ++ register_chrdev( 0,_LCD_CONTROL_NAME,&lcdctrl_fops); ++ if( lcd_debug) ++ printk(KERN_INFO "lcdctrl_init: OK\n"); ++ } ++ return ret; ++} +--- /dev/null ++++ linux-2.4.27/drivers/video/lcdctrl_cerf.c +@@ -0,0 +1,175 @@ ++/* ++ * lcdctrl_cerf.c ++ * ++ * Cerf LCD control for brightness and contrast. ++ * ++ * Copyright (C) 2002 Intrinsyc Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * History: ++ * Mar 2002: Initial version [FB] ++ * ++ */ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/ctype.h> ++#include <linux/mm.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++ ++#include <asm/system.h> ++#include <asm/hardware.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/uaccess.h> ++#include <asm/arch/cerf_ucb1400gpio.h> ++ ++#include <video/lcdctrl.h> ++ ++/* ++ * Set this to zero to remove all the debug statements via ++ * dead code elimination. ++ */ ++#define DEBUGGING 0 ++ ++#if DEBUGGING ++static unsigned int lcd_debug = DEBUGGING; ++#else ++#define lcd_debug 0 ++#endif ++ ++#define LCD_MAX_INTENSITY 0 ++#define LCD_MAX_BRIGHTNESS 15 ++#define LCD_MAX_CONTRAST 100 ++ ++#define LCD_DEFAULT_INTENSITY 0 ++#define LCD_DEFAULT_BRIGHTNESS 14*100/(LCD_MAX_BRIGHTNESS) ++#define LCD_DEFAULT_CONTRAST 90*100/(LCD_MAX_CONTRAST) ++ ++#define UP 1 ++#define DOWN 0 ++ ++/* -- prototypes -- */ ++ ++static int cerf_lcdctrl_init( int *intensity, int *brightness, int *contrast); ++static int cerf_lcdctrl_enable(void); ++static int cerf_lcdctrl_disable(void); ++static int cerf_lcdctrl_set_intensity( int i); ++static int cerf_lcdctrl_set_brightness( int b); ++static int cerf_lcdctrl_set_contrast( int c, int sync); ++ ++static void cerf_lcdctrl_contrast_step( int direction); ++ ++/* -- variables -- */ ++ ++static int dev_contrast; ++ ++/* -- -- */ ++ ++static struct lcdctrl_device cerf_dev = { ++ init: cerf_lcdctrl_init, ++ enable: cerf_lcdctrl_enable, ++ disable: cerf_lcdctrl_disable, ++ set_intensity: cerf_lcdctrl_set_intensity, ++ set_brightness: cerf_lcdctrl_set_brightness, ++ set_contrast: cerf_lcdctrl_set_contrast ++}; ++ ++static int cerf_lcdctrl_enable( void) ++{ ++ cerf_ucb1400gpio_lcd_enable(); ++ ++ return 0; ++} ++ ++static int cerf_lcdctrl_disable( void) ++{ ++ cerf_ucb1400gpio_lcd_disable(); ++ ++ return 0; ++} ++ ++static int cerf_lcdctrl_set_intensity( int i) ++{ ++ int dev_intensity = LCD_MAX_INTENSITY*i/100; ++ if( lcd_debug) ++ printk(KERN_INFO "cerf_lcdctrl_set_intensity: " ++ "dev_intensity = %d\n", dev_intensity); ++ return 0; ++} ++ ++static int cerf_lcdctrl_set_brightness( int b) ++{ ++ int dev_brightness = LCD_MAX_BRIGHTNESS*b/100; ++ outw( dev_brightness, CERF_PDA_CPLD+CERF_PDA_CPLD_BRIGHTNESS); ++ if( lcd_debug) ++ printk(KERN_INFO "cerf_lcdctrl_set_brightness: " ++ "dev_brightness = %d\n", dev_brightness); ++ return 0; ++} ++ ++static int cerf_lcdctrl_set_contrast( int c, int sync) ++{ ++ int new_dev_contrast = LCD_MAX_CONTRAST*c/100; ++ int i; ++ int count; ++ int direction = UP; ++ if( sync == LCD_SYNC_NEEDED) ++ { ++ /* In order to sync we step down to the lowest contrast level */ ++ for( i=0; i<LCD_MAX_CONTRAST; i++) ++ cerf_lcdctrl_contrast_step(DOWN); ++ dev_contrast = 0; ++ } ++ ++ count = new_dev_contrast - dev_contrast; ++ if( count < 0) ++ { ++ /* new contrast is lower then current setting */ ++ direction = DOWN; ++ count = -count; ++ } ++ ++ for( i=0; i<count; i++) ++ cerf_lcdctrl_contrast_step(direction); ++ ++ if( lcd_debug) ++ printk(KERN_INFO "cerf_lcdctrl_set_contrast: " ++ "dev_contrast = %d\n", new_dev_contrast); ++ dev_contrast = new_dev_contrast; ++ ++ return 0; ++} ++ ++/* -- -- */ ++ ++static void cerf_lcdctrl_contrast_step( int direction) ++{ ++ cerf_ucb1400gpio_lcd_contrast_step( direction); ++} ++ ++/* -- -- */ ++ ++static int cerf_lcdctrl_init( int *intensity, int *brightness, int *contrast) ++{ ++ *intensity = LCD_DEFAULT_INTENSITY; ++ *brightness = LCD_DEFAULT_BRIGHTNESS; ++ *contrast = LCD_DEFAULT_CONTRAST; ++ ++ if( lcd_debug) ++ printk(KERN_INFO "cerf_lcdctrl_init: OK\n"); ++ return 0; ++} ++ ++/* this is the hook for lcdctrl to access to the device specifics */ ++struct lcdctrl_device *lcdctrl_device_get_ops(void) ++{ ++ return &cerf_dev; ++} +--- /dev/null ++++ linux-2.4.27/drivers/video/pxafb.c +@@ -0,0 +1,1410 @@ ++/* ++ * linux/drivers/video/pxafb.c ++ * ++ * Copyright (C) 1999 Eric A. Thomas ++ * Based on acornfb.c Copyright (C) Russell King. ++ * ++ * 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. ++ * ++ * Intel PXA250/210 LCD Controller Frame Buffer Driver ++ * ++ * Please direct your questions and comments on this driver to the following ++ * email address: ++ * ++ * linux-arm-kernel@lists.arm.linux.org.uk ++ * ++ * ++ * Code Status: ++ * ++ * 2001/08/03: <cbrake@accelent.com> ++ * - Ported from SA1100 to PXA250 ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/errno.h> ++#include <linux/string.h> ++#include <linux/interrupt.h> ++#include <linux/slab.h> ++#include <linux/fb.h> ++#include <linux/delay.h> ++#include <linux/pm.h> ++#include <linux/init.h> ++#include <linux/notifier.h> ++#include <linux/cpufreq.h> ++ ++#include <asm/hardware.h> ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <asm/mach-types.h> ++#include <asm/uaccess.h> ++ ++#include <video/fbcon.h> ++#include <video/fbcon-mfb.h> ++#include <video/fbcon-cfb4.h> ++#include <video/fbcon-cfb8.h> ++#include <video/fbcon-cfb16.h> ++#include <video/lcdctrl.h> /* brightness, contrast, etc. control */ ++ ++/* ++ * debugging? ++ */ ++#define DEBUG 0 ++/* ++ * Complain if VAR is out of range. ++ */ ++#define DEBUG_VAR 1 ++ ++#undef ASSABET_PAL_VIDEO ++ ++#include "pxafb.h" ++ ++void (*pxafb_blank_helper)(int blank); ++EXPORT_SYMBOL(pxafb_blank_helper); ++ ++/* ++ * IMHO this looks wrong. In 8BPP, length should be 8. ++ */ ++static struct pxafb_rgb rgb_8 = { ++ red: { offset: 0, length: 4, }, ++ green: { offset: 0, length: 4, }, ++ blue: { offset: 0, length: 4, }, ++ transp: { offset: 0, length: 0, }, ++}; ++ ++static struct pxafb_rgb def_rgb_16 = { ++ red: { offset: 11, length: 5, }, ++ green: { offset: 5, length: 6, }, ++ blue: { offset: 0, length: 5, }, ++ transp: { offset: 0, length: 0, }, ++}; ++ ++static struct pxafb_mach_info pxa_fb_info __initdata = { ++ pixclock: LCD_PIXCLOCK, /* clock period in ps */ ++ bpp: LCD_BPP, ++ xres: LCD_XRES, ++ yres: LCD_YRES, ++ hsync_len: LCD_HORIZONTAL_SYNC_PULSE_WIDTH, ++ vsync_len: LCD_VERTICAL_SYNC_PULSE_WIDTH, ++ left_margin: LCD_BEGIN_OF_LINE_WAIT_COUNT, ++ upper_margin: LCD_BEGIN_FRAME_WAIT_COUNT, ++ right_margin: LCD_END_OF_LINE_WAIT_COUNT, ++ lower_margin: LCD_END_OF_FRAME_WAIT_COUNT, ++ sync: LCD_SYNC, ++ lccr0: LCD_LCCR0, ++ lccr3: LCD_LCCR3 ++}; ++ ++static struct pxafb_mach_info * __init ++pxafb_get_machine_info(struct pxafb_info *fbi) ++{ ++ return &pxa_fb_info; ++} ++ ++static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *); ++static void set_ctrlr_state(struct pxafb_info *fbi, u_int state); ++ ++static inline void pxafb_schedule_task(struct pxafb_info *fbi, u_int state) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ /* ++ * We need to handle two requests being made at the same time. ++ * There are two important cases: ++ * 1. When we are changing VT (C_REENABLE) while unblanking (C_ENABLE) ++ * We must perform the unblanking, which will do our REENABLE for us. ++ * 2. When we are blanking, but immediately unblank before we have ++ * blanked. We do the "REENABLE" thing here as well, just to be sure. ++ */ ++ if (fbi->task_state == C_ENABLE && state == C_REENABLE) ++ state = (u_int) -1; ++ if (fbi->task_state == C_DISABLE && state == C_ENABLE) ++ state = C_REENABLE; ++ ++ if (state != (u_int)-1) { ++ fbi->task_state = state; ++ schedule_task(&fbi->task); ++ } ++ local_irq_restore(flags); ++} ++ ++/* ++ * Get the VAR structure pointer for the specified console ++ */ ++static inline struct fb_var_screeninfo *get_con_var(struct fb_info *info, int con) ++{ ++ struct pxafb_info *fbi = (struct pxafb_info *)info; ++ return (con == fbi->currcon || con == -1) ? &fbi->fb.var : &fb_display[con].var; ++} ++ ++/* ++ * Get the DISPLAY structure pointer for the specified console ++ */ ++static inline struct display *get_con_display(struct fb_info *info, int con) ++{ ++ struct pxafb_info *fbi = (struct pxafb_info *)info; ++ return (con < 0) ? fbi->fb.disp : &fb_display[con]; ++} ++ ++/* ++ * Get the CMAP pointer for the specified console ++ */ ++static inline struct fb_cmap *get_con_cmap(struct fb_info *info, int con) ++{ ++ struct pxafb_info *fbi = (struct pxafb_info *)info; ++ return (con == fbi->currcon || con == -1) ? &fbi->fb.cmap : &fb_display[con].cmap; ++} ++ ++static inline u_int ++chan_to_field(u_int chan, struct fb_bitfield *bf) ++{ ++ chan &= 0xffff; ++ chan >>= 16 - bf->length; ++ return chan << bf->offset; ++} ++ ++static int ++pxafb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue, ++ u_int trans, struct fb_info *info) ++{ ++ struct pxafb_info *fbi = (struct pxafb_info *)info; ++ u_int val, ret = 1; ++ ++ if (regno < fbi->palette_size) { ++ val = ((red >> 0) & 0xf800); ++ val |= ((green >> 5) & 0x07e0); ++ val |= ((blue >> 11) & 0x001f); ++ ++ fbi->palette_cpu[regno] = val; ++ ret = 0; ++ } ++ return ret; ++} ++ ++static int ++pxafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ++ u_int trans, struct fb_info *info) ++{ ++ struct pxafb_info *fbi = (struct pxafb_info *)info; ++ u_int val; ++ int ret = 1; ++ ++ /* ++ * If greyscale is true, then we convert the RGB value ++ * to greyscale no mater what visual we are using. ++ */ ++ if (fbi->fb.var.grayscale) ++ red = green = blue = (19595 * red + 38470 * green + ++ 7471 * blue) >> 16; ++ ++ switch (fbi->fb.disp->visual) { ++ case FB_VISUAL_TRUECOLOR: ++ case FB_VISUAL_DIRECTCOLOR: ++ /* ++ * 12 or 16-bit True Colour. We encode the RGB value ++ * according to the RGB bitfield information. ++ */ ++ if (regno <= 16) { ++ u16 *pal = fbi->fb.pseudo_palette; ++ ++ val = chan_to_field(red, &fbi->fb.var.red); ++ val |= chan_to_field(green, &fbi->fb.var.green); ++ val |= chan_to_field(blue, &fbi->fb.var.blue); ++ ++ pal[regno] = val; ++ ret = 0; ++ } ++ break; ++ ++ case FB_VISUAL_PSEUDOCOLOR: ++ ret = pxafb_setpalettereg(regno, red, green, blue, trans, info); ++ break; ++ } ++ ++ return ret; ++} ++ ++/* ++ * pxafb_decode_var(): ++ * Get the video params out of 'var'. If a value doesn't fit, round it up, ++ * if it's too big, return -EINVAL. ++ * ++ * Suggestion: Round up in the following order: bits_per_pixel, xres, ++ * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale, ++ * bitfields, horizontal timing, vertical timing. ++ */ ++static int pxafb_validate_var(struct fb_var_screeninfo *var, ++ struct pxafb_info *fbi) ++{ ++ int ret = -EINVAL; ++ ++ if (var->xres < MIN_XRES) ++ var->xres = MIN_XRES; ++ if (var->yres < MIN_YRES) ++ var->yres = MIN_YRES; ++ if (var->xres > fbi->max_xres) ++ var->xres = fbi->max_xres; ++ if (var->yres > fbi->max_yres) ++ var->yres = fbi->max_yres; ++ var->xres_virtual = ++ var->xres_virtual < var->xres ? var->xres : var->xres_virtual; ++ var->yres_virtual = ++ var->yres_virtual < var->yres ? var->yres : var->yres_virtual; ++ ++ DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel); ++ switch (var->bits_per_pixel) { ++#ifdef FBCON_HAS_CFB4 ++ case 4: ret = 0; break; ++#endif ++#ifdef FBCON_HAS_CFB8 ++ case 8: ret = 0; break; ++#endif ++#ifdef FBCON_HAS_CFB16 ++ case 12: ++ /* make sure we are in passive mode */ ++ if (!(fbi->lccr0 & LCCR0_PAS)) ++ ret = 0; ++ break; ++ ++ case 16: ++ /* ++ * 16 bits works apparemtly fine in passive mode for those, ++ * so don't complain ++ */ ++ if (machine_is_lubbock() || ++ machine_is_pxa_cerf()) { ++ ret = 0; ++ } else ++ /* make sure we are in active mode */ ++ if ((fbi->lccr0 & LCCR0_PAS)) ++ ret = 0; ++ break; ++#endif ++ default: ++ break; ++ } ++ ++ return ret; ++} ++ ++static inline void pxafb_set_truecolor(u_int is_true_color) ++{ ++ DPRINTK("true_color = %d\n", is_true_color); ++} ++ ++static void ++pxafb_hw_set_var(struct fb_var_screeninfo *var, struct pxafb_info *fbi) ++{ ++ ++ fb_set_cmap(&fbi->fb.cmap, 1, pxafb_setcolreg, &fbi->fb); ++ ++ /* Set board control register to handle new color depth */ ++ pxafb_set_truecolor(var->bits_per_pixel >= 16); ++ ++ pxafb_activate_var(var, fbi); ++ ++} ++ ++/* ++ * pxafb_set_var(): ++ * Set the user defined part of the display for the specified console ++ */ ++static int ++pxafb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) ++{ ++ struct pxafb_info *fbi = (struct pxafb_info *)info; ++ struct fb_var_screeninfo *dvar = get_con_var(&fbi->fb, con); ++ struct display *display = get_con_display(&fbi->fb, con); ++ int err, chgvar = 0, rgbidx; ++ ++ DPRINTK("set_var\n"); ++ ++ /* ++ * Decode var contents into a par structure, adjusting any ++ * out of range values. ++ */ ++ err = pxafb_validate_var(var, fbi); ++ if (err) ++ return err; ++ ++ if (var->activate & FB_ACTIVATE_TEST) ++ return 0; ++ ++ if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) ++ return -EINVAL; ++ ++ if (dvar->xres != var->xres) ++ chgvar = 1; ++ if (dvar->yres != var->yres) ++ chgvar = 1; ++ if (dvar->xres_virtual != var->xres_virtual) ++ chgvar = 1; ++ if (dvar->yres_virtual != var->yres_virtual) ++ chgvar = 1; ++ if (dvar->bits_per_pixel != var->bits_per_pixel) ++ chgvar = 1; ++ if (con < 0) ++ chgvar = 0; ++ ++ switch (var->bits_per_pixel) { ++#ifdef FBCON_HAS_CFB4 ++ case 4: ++ if (fbi->cmap_static) ++ display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR; ++ else ++ display->visual = FB_VISUAL_PSEUDOCOLOR; ++ display->line_length = var->xres / 2; ++ display->dispsw = &fbcon_cfb4; ++ rgbidx = RGB_8; ++ break; ++#endif ++#ifdef FBCON_HAS_CFB8 ++ case 8: ++ if (fbi->cmap_static) ++ display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR; ++ else ++ display->visual = FB_VISUAL_PSEUDOCOLOR; ++ display->line_length = var->xres; ++ display->dispsw = &fbcon_cfb8; ++ rgbidx = RGB_8; ++ break; ++#endif ++#ifdef FBCON_HAS_CFB16 ++ case 12: ++ case 16: ++ display->visual = FB_VISUAL_TRUECOLOR; ++ display->line_length = var->xres * 2; ++ display->dispsw = &fbcon_cfb16; ++ display->dispsw_data = fbi->fb.pseudo_palette; ++ rgbidx = RGB_16; ++ break; ++#endif ++ default: ++ rgbidx = 0; ++ display->dispsw = &fbcon_dummy; ++ break; ++ } ++ ++ display->screen_base = fbi->screen_cpu; ++ display->next_line = display->line_length; ++ display->type = fbi->fb.fix.type; ++ display->type_aux = fbi->fb.fix.type_aux; ++ display->ypanstep = fbi->fb.fix.ypanstep; ++ display->ywrapstep = fbi->fb.fix.ywrapstep; ++ display->can_soft_blank = 1; ++ display->inverse = 0; ++ ++ *dvar = *var; ++ dvar->activate &= ~FB_ACTIVATE_ALL; ++ ++ /* ++ * Copy the RGB parameters for this display ++ * from the machine specific parameters. ++ */ ++ dvar->red = fbi->rgb[rgbidx]->red; ++ dvar->green = fbi->rgb[rgbidx]->green; ++ dvar->blue = fbi->rgb[rgbidx]->blue; ++ dvar->transp = fbi->rgb[rgbidx]->transp; ++ ++ DPRINTK("RGBT length = %d:%d:%d:%d\n", ++ dvar->red.length, dvar->green.length, dvar->blue.length, ++ dvar->transp.length); ++ ++ DPRINTK("RGBT offset = %d:%d:%d:%d\n", ++ dvar->red.offset, dvar->green.offset, dvar->blue.offset, ++ dvar->transp.offset); ++ ++ /* ++ * Update the old var. The fbcon drivers still use this. ++ * Once they are using fbi->fb.var, this can be dropped. ++ */ ++ display->var = *dvar; ++ ++ /* ++ * If we are setting all the virtual consoles, also set the ++ * defaults used to create new consoles. ++ */ ++ if (var->activate & FB_ACTIVATE_ALL) ++ fbi->fb.disp->var = *dvar; ++ ++ /* ++ * If the console has changed and the console has defined ++ * a changevar function, call that function. ++ */ ++ if (chgvar && info && fbi->fb.changevar) ++ fbi->fb.changevar(con); ++ ++ /* If the current console is selected, activate the new var. */ ++ if (con != fbi->currcon) ++ return 0; ++ ++ pxafb_hw_set_var(dvar, fbi); ++ ++ return 0; ++} ++ ++static int ++__do_set_cmap(struct fb_cmap *cmap, int kspc, int con, ++ struct fb_info *info) ++{ ++ struct pxafb_info *fbi = (struct pxafb_info *)info; ++ struct fb_cmap *dcmap = get_con_cmap(info, con); ++ int err = 0; ++ ++ if (con == -1) ++ con = fbi->currcon; ++ ++ /* no colormap allocated? (we always have "this" colour map allocated) */ ++ if (con >= 0) ++ err = fb_alloc_cmap(&fb_display[con].cmap, fbi->palette_size, 0); ++ ++ if (!err && con == fbi->currcon) ++ err = fb_set_cmap(cmap, kspc, pxafb_setcolreg, info); ++ ++ if (!err) ++ fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1); ++ ++ return err; ++} ++ ++static int ++pxafb_set_cmap(struct fb_cmap *cmap, int kspc, int con, ++ struct fb_info *info) ++{ ++ struct display *disp = get_con_display(info, con); ++ ++ if (disp->visual == FB_VISUAL_TRUECOLOR) ++ return -EINVAL; ++ ++ return __do_set_cmap(cmap, kspc, con, info); ++} ++ ++static int ++pxafb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) ++{ ++ struct display *display = get_con_display(info, con); ++ ++ *fix = info->fix; ++ ++ fix->line_length = display->line_length; ++ fix->visual = display->visual; ++ return 0; ++} ++ ++static int ++pxafb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) ++{ ++ *var = *get_con_var(info, con); ++ return 0; ++} ++ ++static int ++pxafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) ++{ ++ struct fb_cmap *dcmap = get_con_cmap(info, con); ++ fb_copy_cmap(dcmap, cmap, kspc ? 0 : 2); ++ return 0; ++} ++ ++static struct fb_ops pxafb_ops = { ++ owner: THIS_MODULE, ++ fb_get_fix: pxafb_get_fix, ++ fb_get_var: pxafb_get_var, ++ fb_set_var: pxafb_set_var, ++ fb_get_cmap: pxafb_get_cmap, ++ fb_set_cmap: pxafb_set_cmap, ++}; ++ ++/* ++ * pxafb_switch(): ++ * Change to the specified console. Palette and video mode ++ * are changed to the console's stored parameters. ++ * ++ * Uh oh, this can be called from a tasklet (IRQ) ++ */ ++static int pxafb_switch(int con, struct fb_info *info) ++{ ++ struct pxafb_info *fbi = (struct pxafb_info *)info; ++ struct display *disp; ++ struct fb_cmap *cmap; ++ ++ DPRINTK("con=%d info->modename=%s\n", con, fbi->fb.modename); ++ ++ if (con == fbi->currcon) ++ return 0; ++ ++ if (fbi->currcon >= 0) { ++ disp = fb_display + fbi->currcon; ++ ++ /* ++ * Save the old colormap and video mode. ++ */ ++ disp->var = fbi->fb.var; ++ ++ if (disp->cmap.len) ++ fb_copy_cmap(&fbi->fb.cmap, &disp->cmap, 0); ++ } ++ ++ fbi->currcon = con; ++ disp = fb_display + con; ++ ++ /* ++ * Make sure that our colourmap contains 256 entries. ++ */ ++ fb_alloc_cmap(&fbi->fb.cmap, 256, 0); ++ ++ if (disp->cmap.len) ++ cmap = &disp->cmap; ++ else ++ cmap = fb_default_cmap(1 << disp->var.bits_per_pixel); ++ ++ fb_copy_cmap(cmap, &fbi->fb.cmap, 0); ++ ++ fbi->fb.var = disp->var; ++ fbi->fb.var.activate = FB_ACTIVATE_NOW; ++ ++ pxafb_set_var(&fbi->fb.var, con, info); ++ return 0; ++} ++ ++/* ++ * Formal definition of the VESA spec: ++ * On ++ * This refers to the state of the display when it is in full operation ++ * Stand-By ++ * This defines an optional operating state of minimal power reduction with ++ * the shortest recovery time ++ * Suspend ++ * This refers to a level of power management in which substantial power ++ * reduction is achieved by the display. The display can have a longer ++ * recovery time from this state than from the Stand-by state ++ * Off ++ * This indicates that the display is consuming the lowest level of power ++ * and is non-operational. Recovery from this state may optionally require ++ * the user to manually power on the monitor ++ * ++ * Now, the fbdev driver adds an additional state, (blank), where they ++ * turn off the video (maybe by colormap tricks), but don't mess with the ++ * video itself: think of it semantically between on and Stand-By. ++ * ++ * So here's what we should do in our fbdev blank routine: ++ * ++ * VESA_NO_BLANKING (mode 0) Video on, front/back light on ++ * VESA_VSYNC_SUSPEND (mode 1) Video on, front/back light off ++ * VESA_HSYNC_SUSPEND (mode 2) Video on, front/back light off ++ * VESA_POWERDOWN (mode 3) Video off, front/back light off ++ * ++ * This will match the matrox implementation. ++ */ ++/* ++ * pxafb_blank(): ++ * Blank the display by setting all palette values to zero. Note, the ++ * 12 and 16 bpp modes don't really use the palette, so this will not ++ * blank the display in all modes. ++ */ ++static void pxafb_blank(int blank, struct fb_info *info) ++{ ++ struct pxafb_info *fbi = (struct pxafb_info *)info; ++ int i; ++ ++ DPRINTK("pxafb_blank: blank=%d info->modename=%s\n", blank, ++ fbi->fb.modename); ++ ++ switch (blank) { ++ case VESA_POWERDOWN: ++ case VESA_VSYNC_SUSPEND: ++ case VESA_HSYNC_SUSPEND: ++ if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR || ++ fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR) ++ for (i = 0; i < fbi->palette_size; i++) ++ pxafb_setpalettereg(i, 0, 0, 0, 0, info); ++ pxafb_schedule_task(fbi, C_DISABLE); ++ if (pxafb_blank_helper) ++ pxafb_blank_helper(blank); ++ break; ++ ++ case VESA_NO_BLANKING: ++ if (pxafb_blank_helper) ++ pxafb_blank_helper(blank); ++ if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR || ++ fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR) ++ fb_set_cmap(&fbi->fb.cmap, 1, pxafb_setcolreg, info); ++ pxafb_schedule_task(fbi, C_ENABLE); ++ } ++} ++ ++static int pxafb_updatevar(int con, struct fb_info *info) ++{ ++ DPRINTK("entered\n"); ++ return 0; ++} ++ ++/* ++ * Calculate the PCD value from the clock rate (in picoseconds). ++ * We take account of the PPCR clock setting. ++ */ ++static inline int get_pcd(unsigned int pixclock) ++{ ++ unsigned int pcd; ++ ++ if (pixclock) { ++ pcd = get_lclk_frequency_10khz() * pixclock; ++ pcd /= 100000000; ++ pcd += 1; /* make up for integer math truncations */ ++ } else { ++ printk(KERN_WARNING "Please convert me to use the PCD calculations\n"); ++ pcd = 0; ++ } ++ return pcd; ++} ++ ++/* ++ * pxafb_activate_var(): ++ * Configures LCD Controller based on entries in var parameter. Settings are ++ * only written to the controller if changes were made. ++ */ ++static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *fbi) ++{ ++ struct pxafb_lcd_reg new_regs; ++// u_int pcd = get_pcd(var->pixclock); ++ u_long flags; ++ ++ DPRINTK("Configuring PXA LCD\n"); ++ ++ DPRINTK("var: xres=%d hslen=%d lm=%d rm=%d\n", ++ var->xres, var->hsync_len, ++ var->left_margin, var->right_margin); ++ DPRINTK("var: yres=%d vslen=%d um=%d bm=%d\n", ++ var->yres, var->vsync_len, ++ var->upper_margin, var->lower_margin); ++ ++#if DEBUG_VAR ++ if (var->xres < 16 || var->xres > 1024) ++ printk(KERN_ERR "%s: invalid xres %d\n", ++ fbi->fb.fix.id, var->xres); ++ if (var->hsync_len < 1 || var->hsync_len > 64) ++ printk(KERN_ERR "%s: invalid hsync_len %d\n", ++ fbi->fb.fix.id, var->hsync_len); ++ if (var->left_margin < 1 || var->left_margin > 255) ++ printk(KERN_ERR "%s: invalid left_margin %d\n", ++ fbi->fb.fix.id, var->left_margin); ++ if (var->right_margin < 1 || var->right_margin > 255) ++ printk(KERN_ERR "%s: invalid right_margin %d\n", ++ fbi->fb.fix.id, var->right_margin); ++ if (var->yres < 1 || var->yres > 1024) ++ printk(KERN_ERR "%s: invalid yres %d\n", ++ fbi->fb.fix.id, var->yres); ++ if (var->vsync_len < 1 || var->vsync_len > 64) ++ printk(KERN_ERR "%s: invalid vsync_len %d\n", ++ fbi->fb.fix.id, var->vsync_len); ++ if (var->upper_margin < 0 || var->upper_margin > 255) ++ printk(KERN_ERR "%s: invalid upper_margin %d\n", ++ fbi->fb.fix.id, var->upper_margin); ++ if (var->lower_margin < 0 || var->lower_margin > 255) ++ printk(KERN_ERR "%s: invalid lower_margin %d\n", ++ fbi->fb.fix.id, var->lower_margin); ++#endif ++ ++#if defined (CONFIG_PXA_CERF_PDA) ++ new_regs.lccr0 = fbi->lccr0; ++ new_regs.lccr1 = ++ LCCR1_DisWdth(var->xres) + ++ LCCR1_HorSnchWdth(var->hsync_len) + ++ LCCR1_BegLnDel(var->left_margin) + ++ LCCR1_EndLnDel(var->right_margin); ++ ++ new_regs.lccr2 = ++ LCCR2_DisHght(var->yres) + ++ LCCR2_VrtSnchWdth(var->vsync_len) + ++ LCCR2_BegFrmDel(var->upper_margin) + ++ LCCR2_EndFrmDel(var->lower_margin); ++ ++ new_regs.lccr3 = fbi->lccr3 ++ | ++ (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) | ++ (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL); ++#elif defined (CONFIG_FB_PXA_QVGA) ++ new_regs.lccr0 = fbi->lccr0; ++ new_regs.lccr1 = ++ LCCR1_DisWdth(var->xres) + ++ LCCR1_HorSnchWdth(var->hsync_len) + ++ LCCR1_BegLnDel(var->left_margin) + ++ LCCR1_EndLnDel(var->right_margin); ++ new_regs.lccr2 = ++ LCCR2_DisHght(var->yres) + ++ LCCR2_VrtSnchWdth(var->vsync_len) + ++ LCCR2_BegFrmDel(var->upper_margin) + ++ LCCR2_EndFrmDel(var->lower_margin); ++ new_regs.lccr3 = fbi->lccr3; ++#else ++ // FIXME using hardcoded values for now ++ new_regs.lccr0 = fbi->lccr0; ++// | ++// LCCR0_LEN | LCCR0_LDM | LCCR0_BAM | ++// LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0); ++ ++ new_regs.lccr1 = 0x3030A7F; ++// LCCR1_DisWdth(var->xres) + ++// LCCR1_HorSnchWdth(var->hsync_len) + ++// LCCR1_BegLnDel(var->left_margin) + ++// LCCR1_EndLnDel(var->right_margin); ++ ++ new_regs.lccr2 = 0x4EF; ++// LCCR2_DisHght(var->yres) + ++// LCCR2_VrtSnchWdth(var->vsync_len) + ++// LCCR2_BegFrmDel(var->upper_margin) + ++// LCCR2_EndFrmDel(var->lower_margin); ++ ++ new_regs.lccr3 = fbi->lccr3; ++// | ++// (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) | ++// (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL) | ++// LCCR3_ACBsCntOff; ++#endif ++ ++// if (pcd) ++// new_regs.lccr3 |= LCCR3_PixClkDiv(pcd); ++ ++ DPRINTK("nlccr0 = 0x%08x\n", new_regs.lccr0); ++ DPRINTK("nlccr1 = 0x%08x\n", new_regs.lccr1); ++ DPRINTK("nlccr2 = 0x%08x\n", new_regs.lccr2); ++ DPRINTK("nlccr3 = 0x%08x\n", new_regs.lccr3); ++ ++ /* Update shadow copy atomically */ ++ local_irq_save(flags); ++ ++ /* setup dma descriptors */ ++ fbi->dmadesc_fblow_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 3*16); ++ fbi->dmadesc_fbhigh_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 2*16); ++ fbi->dmadesc_palette_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 1*16); ++ ++ fbi->dmadesc_fblow_dma = fbi->palette_dma - 3*16; ++ fbi->dmadesc_fbhigh_dma = fbi->palette_dma - 2*16; ++ fbi->dmadesc_palette_dma = fbi->palette_dma - 1*16; ++ ++ #define BYTES_PER_PANEL ((fbi->lccr0 & LCCR0_SDS) ? (var->xres * var->yres * var->bits_per_pixel / 8 / 2) : \ ++ (var->xres * var->yres * var->bits_per_pixel / 8)) ++ ++ /* populate descriptors */ ++ fbi->dmadesc_fblow_cpu->fdadr = fbi->dmadesc_fblow_dma; ++ fbi->dmadesc_fblow_cpu->fsadr = fbi->screen_dma + BYTES_PER_PANEL; ++ fbi->dmadesc_fblow_cpu->fidr = 0; ++ fbi->dmadesc_fblow_cpu->ldcmd = BYTES_PER_PANEL; ++ ++ fbi->fdadr1 = fbi->dmadesc_fblow_dma; /* only used in dual-panel mode */ ++ ++ fbi->dmadesc_fbhigh_cpu->fsadr = fbi->screen_dma; ++ fbi->dmadesc_fbhigh_cpu->fidr = 0; ++ fbi->dmadesc_fbhigh_cpu->ldcmd = BYTES_PER_PANEL; ++ ++ fbi->dmadesc_palette_cpu->fsadr = fbi->palette_dma; ++ fbi->dmadesc_palette_cpu->fidr = 0; ++ fbi->dmadesc_palette_cpu->ldcmd = (fbi->palette_size * 2) | LDCMD_PAL; ++ ++ if( var->bits_per_pixel < 12) ++ { ++ /* assume any mode with <12 bpp is palette driven */ ++ fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_fbhigh_dma; ++ fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_palette_dma; ++ fbi->fdadr0 = fbi->dmadesc_palette_dma; /* flips back and forth between pal and fbhigh */ ++ } ++ else ++ { ++ /* palette shouldn't be loaded in true-color mode */ ++ fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_fbhigh_dma; ++ fbi->fdadr0 = fbi->dmadesc_fbhigh_dma; /* no pal just fbhigh */ ++ } ++ ++ DPRINTK("fbi->dmadesc_fblow_cpu = 0x%x\n", fbi->dmadesc_fblow_cpu); ++ DPRINTK("fbi->dmadesc_fbhigh_cpu = 0x%x\n", fbi->dmadesc_fbhigh_cpu); ++ DPRINTK("fbi->dmadesc_palette_cpu = 0x%x\n", fbi->dmadesc_palette_cpu); ++ DPRINTK("fbi->dmadesc_fblow_dma = 0x%x\n", fbi->dmadesc_fblow_dma); ++ DPRINTK("fbi->dmadesc_fbhigh_dma = 0x%x\n", fbi->dmadesc_fbhigh_dma); ++ DPRINTK("fbi->dmadesc_palette_dma = 0x%x\n", fbi->dmadesc_palette_dma); ++ ++ DPRINTK("fbi->dmadesc_fblow_cpu->fdadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fdadr); ++ DPRINTK("fbi->dmadesc_fbhigh_cpu->fdadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fdadr); ++ DPRINTK("fbi->dmadesc_palette_cpu->fdadr = 0x%x\n", fbi->dmadesc_palette_cpu->fdadr); ++ ++ DPRINTK("fbi->dmadesc_fblow_cpu->fsadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fsadr); ++ DPRINTK("fbi->dmadesc_fbhigh_cpu->fsadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fsadr); ++ DPRINTK("fbi->dmadesc_palette_cpu->fsadr = 0x%x\n", fbi->dmadesc_palette_cpu->fsadr); ++ ++ DPRINTK("fbi->dmadesc_fblow_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fblow_cpu->ldcmd); ++ DPRINTK("fbi->dmadesc_fbhigh_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fbhigh_cpu->ldcmd); ++ DPRINTK("fbi->dmadesc_palette_cpu->ldcmd = 0x%x\n", fbi->dmadesc_palette_cpu->ldcmd); ++ ++ fbi->reg_lccr0 = new_regs.lccr0; ++ fbi->reg_lccr1 = new_regs.lccr1; ++ fbi->reg_lccr2 = new_regs.lccr2; ++ fbi->reg_lccr3 = new_regs.lccr3; ++ local_irq_restore(flags); ++ ++ /* ++ * Only update the registers if the controller is enabled ++ * and something has changed. ++ */ ++ if ((LCCR0 != fbi->reg_lccr0) || (LCCR1 != fbi->reg_lccr1) || ++ (LCCR2 != fbi->reg_lccr2) || (LCCR3 != fbi->reg_lccr3) || ++ (FDADR0 != fbi->fdadr0) || (FDADR1 != fbi->fdadr1)) ++ pxafb_schedule_task(fbi, C_REENABLE); ++ ++ return 0; ++} ++ ++/* ++ * NOTE! The following functions are purely helpers for set_ctrlr_state. ++ * Do not call them directly; set_ctrlr_state does the correct serialisation ++ * to ensure that things happen in the right way 100% of time time. ++ * -- rmk ++ */ ++ ++/* ++ * FIXME: move LCD power stuff into pxafb_power_up_lcd() ++ * Also, I'm expecting that the backlight stuff should ++ * be handled differently. ++ */ ++static void pxafb_backlight_on(struct pxafb_info *fbi) ++{ ++ DPRINTK("backlight on\n"); ++ ++#ifdef CONFIG_ARCH_PXA_IDP ++ if(machine_is_pxa_idp()) { ++ FB_BACKLIGHT_ON(); ++ } ++#endif ++} ++ ++/* ++ * FIXME: move LCD power stuf into pxafb_power_down_lcd() ++ * Also, I'm expecting that the backlight stuff should ++ * be handled differently. ++ */ ++static void pxafb_backlight_off(struct pxafb_info *fbi) ++{ ++ DPRINTK("backlight off\n"); ++ ++#ifdef CONFIG_ARCH_PXA_IDP ++ if(machine_is_pxa_idp()) { ++ FB_BACKLIGHT_OFF(); ++ } ++#endif ++ ++} ++ ++static void pxafb_power_up_lcd(struct pxafb_info *fbi) ++{ ++ DPRINTK("LCD power on\n"); ++ CKEN |= CKEN16_LCD; ++ ++ if(machine_is_pxa_cerf()) { ++ lcdctrl_enable(); ++ } ++ ++#if CONFIG_ARCH_PXA_IDP ++ /* set GPIOs, etc */ ++ if(machine_is_pxa_idp()) { ++ // FIXME need to add proper delays ++ FB_PWR_ON(); ++ FB_VLCD_ON(); // FIXME this should be after scanning starts ++ } ++#endif ++} ++ ++static void pxafb_power_down_lcd(struct pxafb_info *fbi) ++{ ++ DPRINTK("LCD power off\n"); ++ CKEN &= ~CKEN16_LCD; ++ ++ if(machine_is_pxa_cerf()) { ++ lcdctrl_disable(); ++ } ++ ++ /* set GPIOs, etc */ ++#if CONFIG_ARCH_PXA_IDP ++ if(machine_is_pxa_idp()) { ++ // FIXME need to add proper delays ++ FB_PWR_OFF(); ++ FB_VLCD_OFF(); // FIXME this should be before scanning stops ++ } ++#endif ++ ++} ++ ++static void pxafb_setup_gpio(struct pxafb_info *fbi) ++{ ++ unsigned int lccr0; ++ ++ /* ++ * setup is based on type of panel supported ++ */ ++ ++ lccr0 = fbi->lccr0; ++ ++ /* 4 bit interface */ ++ if ((lccr0 & LCCR0_CMS) && (lccr0 & LCCR0_SDS) && !(lccr0 & LCCR0_DPD)) ++ { ++ // bits 58-61 ++ GPDR1 |= (0xf << 26); ++ GAFR1_U = (GAFR1_U & ~(0xff << 20)) | (0xaa << 20); ++ ++ // bits 74-77 ++ GPDR2 |= (0xf << 10); ++ GAFR2_L = (GAFR2_L & ~(0xff << 20)) | (0xaa << 20); ++ } ++ ++ /* 8 bit interface */ ++ else if (((lccr0 & LCCR0_CMS) && ((lccr0 & LCCR0_SDS) || (lccr0 & LCCR0_DPD))) || ++ (!(lccr0 & LCCR0_CMS) && !(lccr0 & LCCR0_PAS) && !(lccr0 & LCCR0_SDS))) ++ { ++ // bits 58-65 ++ GPDR1 |= (0x3f << 26); ++ GPDR2 |= (0x3); ++ ++ GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20); ++ GAFR2_L = (GAFR2_L & ~0xf) | (0xa); ++ ++ // bits 74-77 ++ GPDR2 |= (0xf << 10); ++ GAFR2_L = (GAFR2_L & ~(0xff << 20)) | (0xaa << 20); ++ } ++ ++ /* 16 bit interface */ ++ else if (!(lccr0 & LCCR0_CMS) && ((lccr0 & LCCR0_SDS) || (lccr0 & LCCR0_PAS))) ++ { ++ // bits 58-77 ++ GPDR1 |= (0x3f << 26); ++ GPDR2 |= 0x00003fff; ++ ++ GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20); ++ GAFR2_L = (GAFR2_L & 0xf0000000) | 0x0aaaaaaa; ++ } ++ else ++ { ++ printk( KERN_ERR "pxafb_setup_gpio: unable to determine bits per pixel\n"); ++ } ++} ++ ++static void pxafb_enable_controller(struct pxafb_info *fbi) ++{ ++ DPRINTK("Enabling LCD controller\n"); ++ ++ /* Sequence from 11.7.10 */ ++ LCCR3 = fbi->reg_lccr3; ++ LCCR2 = fbi->reg_lccr2; ++ LCCR1 = fbi->reg_lccr1; ++ LCCR0 = fbi->reg_lccr0 & ~LCCR0_ENB; ++ ++ /* FIXME we used to have LCD power control here */ ++ ++ FDADR0 = fbi->fdadr0; ++ FDADR1 = fbi->fdadr1; ++ LCCR0 |= LCCR0_ENB; ++ ++ DPRINTK("FDADR0 = 0x%08x\n", (unsigned int)FDADR0); ++ DPRINTK("FDADR1 = 0x%08x\n", (unsigned int)FDADR1); ++ DPRINTK("LCCR0 = 0x%08x\n", (unsigned int)LCCR0); ++ DPRINTK("LCCR1 = 0x%08x\n", (unsigned int)LCCR1); ++ DPRINTK("LCCR2 = 0x%08x\n", (unsigned int)LCCR2); ++ DPRINTK("LCCR3 = 0x%08x\n", (unsigned int)LCCR3); ++} ++ ++static void pxafb_disable_controller(struct pxafb_info *fbi) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ ++ DPRINTK("Disabling LCD controller\n"); ++ ++ /* FIXME add power down GPIO stuff here */ ++ ++ add_wait_queue(&fbi->ctrlr_wait, &wait); ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ ++ LCSR = 0xffffffff; /* Clear LCD Status Register */ ++ LCCR0 &= ~LCCR0_LDM; /* Enable LCD Disable Done Interrupt */ ++ LCCR0 &= ~LCCR0_ENB; /* Disable LCD Controller */ ++ ++ schedule_timeout(20 * HZ / 1000); ++ current->state = TASK_RUNNING; ++ remove_wait_queue(&fbi->ctrlr_wait, &wait); ++} ++ ++/* ++ * pxafb_handle_irq: Handle 'LCD DONE' interrupts. ++ */ ++static void pxafb_handle_irq(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ struct pxafb_info *fbi = dev_id; ++ unsigned int lcsr = LCSR; ++ ++ if (lcsr & LCSR_LDD) { ++ LCCR0 |= LCCR0_LDM; ++ wake_up(&fbi->ctrlr_wait); ++ } ++ ++ LCSR = lcsr; ++} ++ ++/* ++ * This function must be called from task context only, since it will ++ * sleep when disabling the LCD controller, or if we get two contending ++ * processes trying to alter state. ++ */ ++static void set_ctrlr_state(struct pxafb_info *fbi, u_int state) ++{ ++ u_int old_state; ++ ++ down(&fbi->ctrlr_sem); ++ ++ old_state = fbi->state; ++ ++ switch (state) { ++ case C_DISABLE_CLKCHANGE: ++ /* ++ * Disable controller for clock change. If the ++ * controller is already disabled, then do nothing. ++ */ ++ if (old_state != C_DISABLE) { ++ fbi->state = state; ++ pxafb_disable_controller(fbi); ++ } ++ break; ++ ++ case C_DISABLE: ++ /* ++ * Disable controller ++ */ ++ if (old_state != C_DISABLE) { ++ fbi->state = state; ++ ++ pxafb_backlight_off(fbi); ++ if (old_state != C_DISABLE_CLKCHANGE) ++ pxafb_disable_controller(fbi); ++ pxafb_power_down_lcd(fbi); ++ } ++ break; ++ ++ case C_ENABLE_CLKCHANGE: ++ /* ++ * Enable the controller after clock change. Only ++ * do this if we were disabled for the clock change. ++ */ ++ if (old_state == C_DISABLE_CLKCHANGE) { ++ fbi->state = C_ENABLE; ++ pxafb_enable_controller(fbi); ++ } ++ break; ++ ++ case C_REENABLE: ++ /* ++ * Re-enable the controller only if it was already ++ * enabled. This is so we reprogram the control ++ * registers. ++ */ ++ if (old_state == C_ENABLE) { ++ pxafb_disable_controller(fbi); ++ pxafb_setup_gpio(fbi); ++ pxafb_enable_controller(fbi); ++ } ++ break; ++ ++ case C_ENABLE: ++ /* ++ * Power up the LCD screen, enable controller, and ++ * turn on the backlight. ++ */ ++ if (old_state != C_ENABLE) { ++ fbi->state = C_ENABLE; ++ pxafb_setup_gpio(fbi); ++ pxafb_power_up_lcd(fbi); ++ pxafb_enable_controller(fbi); ++ pxafb_backlight_on(fbi); ++ } ++ break; ++ } ++ up(&fbi->ctrlr_sem); ++} ++ ++/* ++ * Our LCD controller task (which is called when we blank or unblank) ++ * via keventd. ++ */ ++static void pxafb_task(void *dummy) ++{ ++ struct pxafb_info *fbi = dummy; ++ u_int state = xchg(&fbi->task_state, -1); ++ ++ set_ctrlr_state(fbi, state); ++} ++ ++#ifdef CONFIG_CPU_FREQ ++/* ++ * CPU clock speed change handler. We need to adjust the LCD timing ++ * parameters when the CPU clock is adjusted by the power management ++ * subsystem. ++ */ ++static int ++pxafb_clkchg_notifier(struct notifier_block *nb, unsigned long val, ++ void *data) ++{ ++ struct pxafb_info *fbi = TO_INF(nb, clockchg); ++ u_int pcd; ++ ++ switch (val) { ++ case CPUFREQ_MINMAX: ++ /* todo: fill in min/max values */ ++ break; ++ ++ case CPUFREQ_PRECHANGE: ++ set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE); ++ break; ++ ++ case CPUFREQ_POSTCHANGE: ++ pcd = get_pcd(fbi->fb.var.pixclock); ++ fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd); ++ set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE); ++ break; ++ } ++ return 0; ++} ++#endif ++ ++#ifdef CONFIG_PM ++/* ++ * Power management hook. Note that we won't be called from IRQ context, ++ * unlike the blank functions above, so we may sleep. ++ */ ++static int ++pxafb_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) ++{ ++ struct pxafb_info *fbi = pm_dev->data; ++ ++ DPRINTK("pm_callback: %d\n", req); ++ ++ if (req == PM_SUSPEND || req == PM_RESUME) { ++ int state = (int)data; ++ ++ if (state == 0) { ++ /* Enter D0. */ ++ set_ctrlr_state(fbi, C_ENABLE); ++ } else { ++ /* Enter D1-D3. Disable the LCD controller. */ ++ set_ctrlr_state(fbi, C_DISABLE); ++ } ++ } ++ DPRINTK("done\n"); ++ return 0; ++} ++#endif ++ ++/* ++ * pxafb_map_video_memory(): ++ * Allocates the DRAM memory for the frame buffer. This buffer is ++ * remapped into a non-cached, non-buffered, memory region to ++ * allow palette and pixel writes to occur without flushing the ++ * cache. Once this area is remapped, all virtual memory ++ * access to the video memory should occur at the new region. ++ */ ++static int __init pxafb_map_video_memory(struct pxafb_info *fbi) ++{ ++ u_long palette_mem_size; ++ ++ /* ++ * We reserve one page for the palette, plus the size ++ * of the framebuffer. ++ * ++ * layout of stuff in memory ++ * ++ * fblow descriptor ++ * fbhigh descriptor ++ * palette descriptor ++ * palette ++ * page boundary-> ++ * frame buffer ++ */ ++ fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE); ++ fbi->map_cpu = consistent_alloc(GFP_KERNEL, fbi->map_size, ++ &fbi->map_dma, PTE_BUFFERABLE); ++ ++ if (fbi->map_cpu) { ++ fbi->screen_cpu = fbi->map_cpu + PAGE_SIZE; ++ fbi->screen_dma = fbi->map_dma + PAGE_SIZE; ++ fbi->fb.fix.smem_start = fbi->screen_dma; ++ ++ fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16; ++ ++ palette_mem_size = fbi->palette_size * sizeof(u16); ++ ++ DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size); ++ ++ fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size); ++ fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size; ++ ++ } ++ ++ return fbi->map_cpu ? 0 : -ENOMEM; ++} ++ ++/* Fake monspecs to fill in fbinfo structure */ ++static struct fb_monspecs monspecs __initdata = { ++ 30000, 70000, 50, 65, 0 /* Generic */ ++}; ++ ++ ++static struct pxafb_info * __init pxafb_init_fbinfo(void) ++{ ++ struct pxafb_mach_info *inf; ++ struct pxafb_info *fbi; ++ ++ fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(struct display) + ++ sizeof(u16) * 16, GFP_KERNEL); ++ if (!fbi) ++ return NULL; ++ ++ memset(fbi, 0, sizeof(struct pxafb_info) + sizeof(struct display)); ++ ++ fbi->currcon = -1; ++ ++ strcpy(fbi->fb.fix.id, PXA_NAME); ++ ++ fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS; ++ fbi->fb.fix.type_aux = 0; ++ fbi->fb.fix.xpanstep = 0; ++ fbi->fb.fix.ypanstep = 0; ++ fbi->fb.fix.ywrapstep = 0; ++ fbi->fb.fix.accel = FB_ACCEL_NONE; ++ ++ fbi->fb.var.nonstd = 0; ++ fbi->fb.var.activate = FB_ACTIVATE_NOW; ++ fbi->fb.var.height = -1; ++ fbi->fb.var.width = -1; ++ fbi->fb.var.accel_flags = 0; ++ fbi->fb.var.vmode = FB_VMODE_NONINTERLACED; ++ ++ strcpy(fbi->fb.modename, PXA_NAME); ++ strcpy(fbi->fb.fontname, "Acorn8x8"); ++ ++ fbi->fb.fbops = &pxafb_ops; ++ fbi->fb.changevar = NULL; ++ fbi->fb.switch_con = pxafb_switch; ++ fbi->fb.updatevar = pxafb_updatevar; ++ fbi->fb.blank = pxafb_blank; ++ fbi->fb.flags = FBINFO_FLAG_DEFAULT; ++ fbi->fb.node = -1; ++ fbi->fb.monspecs = monspecs; ++ fbi->fb.disp = (struct display *)(fbi + 1); ++ fbi->fb.pseudo_palette = (void *)(fbi->fb.disp + 1); ++ ++ fbi->rgb[RGB_8] = &rgb_8; ++ fbi->rgb[RGB_16] = &def_rgb_16; ++ ++ inf = pxafb_get_machine_info(fbi); ++ ++ fbi->max_xres = inf->xres; ++ fbi->fb.var.xres = inf->xres; ++ fbi->fb.var.xres_virtual = inf->xres; ++ fbi->max_yres = inf->yres; ++ fbi->fb.var.yres = inf->yres; ++ fbi->fb.var.yres_virtual = inf->yres; ++ fbi->max_bpp = inf->bpp; ++ fbi->fb.var.bits_per_pixel = inf->bpp; ++ fbi->fb.var.pixclock = inf->pixclock; ++ fbi->fb.var.hsync_len = inf->hsync_len; ++ fbi->fb.var.left_margin = inf->left_margin; ++ fbi->fb.var.right_margin = inf->right_margin; ++ fbi->fb.var.vsync_len = inf->vsync_len; ++ fbi->fb.var.upper_margin = inf->upper_margin; ++ fbi->fb.var.lower_margin = inf->lower_margin; ++ fbi->fb.var.sync = inf->sync; ++ fbi->fb.var.grayscale = inf->cmap_greyscale; ++ fbi->cmap_inverse = inf->cmap_inverse; ++ fbi->cmap_static = inf->cmap_static; ++ fbi->lccr0 = inf->lccr0; ++ fbi->lccr3 = inf->lccr3; ++ fbi->state = C_DISABLE; ++ fbi->task_state = (u_char)-1; ++ fbi->fb.fix.smem_len = fbi->max_xres * fbi->max_yres * ++ fbi->max_bpp / 8; ++ ++ init_waitqueue_head(&fbi->ctrlr_wait); ++ INIT_TQUEUE(&fbi->task, pxafb_task, fbi); ++ init_MUTEX(&fbi->ctrlr_sem); ++ ++ return fbi; ++} ++ ++int __init pxafb_init(void) ++{ ++ struct pxafb_info *fbi; ++ int ret; ++ ++ fbi = pxafb_init_fbinfo(); ++ ret = -ENOMEM; ++ if (!fbi) ++ goto failed; ++ ++ if(machine_is_pxa_cerf()) { ++ // brightness&contrast is handled via lcdctrl. ++ lcdctrl_init(); ++ } ++ ++ /* Initialize video memory */ ++ ret = pxafb_map_video_memory(fbi); ++ if (ret) ++ goto failed; ++ ++ ret = request_irq(IRQ_LCD, pxafb_handle_irq, SA_INTERRUPT, ++ "LCD", fbi); ++ if (ret) { ++ printk(KERN_ERR "pxafb: failed in request_irq: %d\n", ret); ++ goto failed; ++ } ++ ++ pxafb_set_var(&fbi->fb.var, -1, &fbi->fb); ++ ++ ret = register_framebuffer(&fbi->fb); ++ if (ret < 0) ++ goto failed; ++ ++#ifdef CONFIG_PM ++ /* ++ * Note that the console registers this as well, but we want to ++ * power down the display prior to sleeping. ++ */ ++ fbi->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, pxafb_pm_callback); ++ if (fbi->pm) ++ fbi->pm->data = fbi; ++#endif ++#ifdef CONFIG_CPU_FREQ ++ fbi->clockchg.notifier_call = pxafb_clkchg_notifier; ++ cpufreq_register_notifier(&fbi->clockchg); ++#endif ++ ++ /* ++ * Ok, now enable the LCD controller ++ */ ++ set_ctrlr_state(fbi, C_ENABLE); ++ ++ /* This driver cannot be unloaded at the moment */ ++ MOD_INC_USE_COUNT; ++ ++ return 0; ++ ++failed: ++ if (fbi) ++ kfree(fbi); ++ return ret; ++} ++ ++ ++#ifdef MODULE ++module_init(pxafb_init); ++#endif ++ ++MODULE_DESCRIPTION("loadable framebuffer driver for PXA"); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ linux-2.4.27/drivers/video/pxafb.h +@@ -0,0 +1,238 @@ ++/* ++ * linux/drivers/video/pxafb.h ++ * -- Intel PXA250/210 LCD Controller Frame Buffer Device ++ * ++ * Copyright (C) 1999 Eric A. Thomas ++ * Based on acornfb.c Copyright (C) Russell King. ++ * ++ * 2001-08-03: Cliff Brake <cbrake@acclent.com> ++ * - ported SA1100 code to PXA ++ * ++ * 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. ++ */ ++ ++/* ++ * These are the bitfields for each ++ * display depth that we support. ++ */ ++struct pxafb_rgb { ++ struct fb_bitfield red; ++ struct fb_bitfield green; ++ struct fb_bitfield blue; ++ struct fb_bitfield transp; ++}; ++ ++/* ++ * This structure describes the machine which we are running on. ++ */ ++struct pxafb_mach_info { ++ u_long pixclock; ++ ++ u_short xres; ++ u_short yres; ++ ++ u_char bpp; ++ u_char hsync_len; ++ u_char left_margin; ++ u_char right_margin; ++ ++ u_char vsync_len; ++ u_char upper_margin; ++ u_char lower_margin; ++ u_char sync; ++ ++ u_int cmap_greyscale:1, ++ cmap_inverse:1, ++ cmap_static:1, ++ unused:29; ++ ++ u_int lccr0; ++ u_int lccr3; ++}; ++ ++/* Shadows for LCD controller registers */ ++struct pxafb_lcd_reg { ++ unsigned int lccr0; ++ unsigned int lccr1; ++ unsigned int lccr2; ++ unsigned int lccr3; ++}; ++ ++/* PXA LCD DMA descriptor */ ++struct pxafb_dma_descriptor { ++ unsigned int fdadr; ++ unsigned int fsadr; ++ unsigned int fidr; ++ unsigned int ldcmd; ++}; ++ ++#define RGB_8 (0) ++#define RGB_16 (1) ++#define NR_RGB 2 ++ ++struct pxafb_info { ++ struct fb_info fb; ++ signed int currcon; ++ ++ struct pxafb_rgb *rgb[NR_RGB]; ++ ++ u_int max_bpp; ++ u_int max_xres; ++ u_int max_yres; ++ ++ /* ++ * These are the addresses we mapped ++ * the framebuffer memory region to. ++ */ ++ ++ /* raw memory addresses */ ++ dma_addr_t map_dma; /* physical */ ++ u_char * map_cpu; /* virtual */ ++ u_int map_size; ++ ++ /* addresses of pieces placed in raw buffer */ ++ u_char * screen_cpu; /* virtual address of frame buffer */ ++ dma_addr_t screen_dma; /* physical address of frame buffer */ ++ u16 * palette_cpu; /* virtual address of palette memory */ ++ dma_addr_t palette_dma; /* physical address of palette memory */ ++ u_int palette_size; ++ ++ /* DMA descriptors */ ++ struct pxafb_dma_descriptor * dmadesc_fblow_cpu; ++ dma_addr_t dmadesc_fblow_dma; ++ struct pxafb_dma_descriptor * dmadesc_fbhigh_cpu; ++ dma_addr_t dmadesc_fbhigh_dma; ++ struct pxafb_dma_descriptor * dmadesc_palette_cpu; ++ dma_addr_t dmadesc_palette_dma; ++ ++ dma_addr_t fdadr0; ++ dma_addr_t fdadr1; ++ ++ u_int lccr0; ++ u_int lccr3; ++ u_int cmap_inverse:1, ++ cmap_static:1, ++ unused:30; ++ ++ u_int reg_lccr0; ++ u_int reg_lccr1; ++ u_int reg_lccr2; ++ u_int reg_lccr3; ++ ++ volatile u_char state; ++ volatile u_char task_state; ++ struct semaphore ctrlr_sem; ++ wait_queue_head_t ctrlr_wait; ++ struct tq_struct task; ++ ++#ifdef CONFIG_PM ++ struct pm_dev *pm; ++#endif ++#ifdef CONFIG_CPU_FREQ ++ struct notifier_block clockchg; ++#endif ++}; ++ ++#define __type_entry(ptr,type,member) ((type *)((char *)(ptr)-offsetof(type,member))) ++ ++#define TO_INF(ptr,member) __type_entry(ptr,struct pxafb_info,member) ++ ++/* ++ * These are the actions for set_ctrlr_state ++ */ ++#define C_DISABLE (0) ++#define C_ENABLE (1) ++#define C_DISABLE_CLKCHANGE (2) ++#define C_ENABLE_CLKCHANGE (3) ++#define C_REENABLE (4) ++ ++#define PXA_NAME "PXA" ++ ++/* ++ * Debug macros ++ */ ++#if DEBUG ++# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) ++#else ++# define DPRINTK(fmt, args...) ++#endif ++ ++/* ++ * Minimum X and Y resolutions ++ */ ++#define MIN_XRES 64 ++#define MIN_YRES 64 ++ ++/* ++ * Are we configured for 8 or 16 bits per pixel? ++ */ ++#ifdef CONFIG_FB_PXA_8BPP ++# define PXAFB_BPP 8 ++# define PXAFB_BPP_BITS 0x03 ++#elif CONFIG_FB_PXA_16BPP ++# define PXAFB_BPP 16 ++# define PXAFB_BPP_BITS 0x04 ++#endif ++ ++#if defined(CONFIG_ARCH_LUBBOCK) ++#define LCD_PIXCLOCK 150000 ++#define LCD_BPP PXAFB_BPP ++#ifdef CONFIG_FB_PXA_QVGA ++#define LCD_XRES 320 ++#define LCD_YRES 240 ++#define LCD_HORIZONTAL_SYNC_PULSE_WIDTH 51 ++#define LCD_VERTICAL_SYNC_PULSE_WIDTH 1 ++#define LCD_BEGIN_OF_LINE_WAIT_COUNT 1 ++#define LCD_BEGIN_FRAME_WAIT_COUNT 8 ++#define LCD_END_OF_LINE_WAIT_COUNT 1 ++#define LCD_END_OF_FRAME_WAIT_COUNT 1 ++#define LCD_SYNC (FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT) ++#define LCD_LCCR0 0x003008F8 ++#define LCD_LCCR3 (0x0040FF0C | (PXAFB_BPP_BITS << 24)) ++#else ++#define LCD_XRES 640 ++#define LCD_YRES 480 ++#define LCD_HORIZONTAL_SYNC_PULSE_WIDTH 1 ++#define LCD_VERTICAL_SYNC_PULSE_WIDTH 1 ++#define LCD_BEGIN_OF_LINE_WAIT_COUNT 3 ++#define LCD_BEGIN_FRAME_WAIT_COUNT 0 ++#define LCD_END_OF_LINE_WAIT_COUNT 3 ++#define LCD_END_OF_FRAME_WAIT_COUNT 0 ++#define LCD_SYNC (FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT) ++#define LCD_LCCR0 0x0030087C ++#define LCD_LCCR3 (0x0040FF0C | (PXAFB_BPP_BITS << 24)) ++#endif ++ ++#elif defined (CONFIG_ARCH_PXA_IDP) ++#define LCD_PIXCLOCK 150000 ++#define LCD_BPP PXAFB_BPP ++#define LCD_XRES 640 ++#define LCD_YRES 480 ++#define LCD_HORIZONTAL_SYNC_PULSE_WIDTH 1 ++#define LCD_VERTICAL_SYNC_PULSE_WIDTH 1 ++#define LCD_BEGIN_OF_LINE_WAIT_COUNT 3 ++#define LCD_BEGIN_FRAME_WAIT_COUNT 0 ++#define LCD_END_OF_LINE_WAIT_COUNT 3 ++#define LCD_END_OF_FRAME_WAIT_COUNT 0 ++#define LCD_SYNC (FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT) ++#define LCD_LCCR0 0x0030087C ++#define LCD_LCCR3 (0x0040FF0C | (PXAFB_BPP_BITS << 24)) ++ ++#elif defined CONFIG_PXA_CERF_PDA ++#define LCD_PIXCLOCK 171521 ++#define LCD_BPP PXAFB_BPP ++#define LCD_XRES 240 ++#define LCD_YRES 320 ++#define LCD_HORIZONTAL_SYNC_PULSE_WIDTH 7 ++#define LCD_VERTICAL_SYNC_PULSE_WIDTH 2 ++#define LCD_BEGIN_OF_LINE_WAIT_COUNT 17 ++#define LCD_BEGIN_FRAME_WAIT_COUNT 0 ++#define LCD_END_OF_LINE_WAIT_COUNT 17 ++#define LCD_END_OF_FRAME_WAIT_COUNT 0 ++#define LCD_SYNC (FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT) ++#define LCD_LCCR0 (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_QDM | LCCR0_BM | LCCR0_OUM) ++#define LCD_LCCR3 (LCCR3_PCP | LCCR3_PixClkDiv(0x12) | LCCR3_Bpp(PXAFB_BPP_BITS) | LCCR3_Acb(0x18)) ++ ++#endif +--- linux-2.4.27/drivers/video/sa1100fb.c~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/drivers/video/sa1100fb.c +@@ -2175,7 +2175,7 @@ + */ + fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE); + fbi->map_cpu = consistent_alloc(GFP_KERNEL, fbi->map_size, +- &fbi->map_dma); ++ &fbi->map_dma, PTE_BUFFERABLE); + + if (fbi->map_cpu) { + fbi->screen_cpu = fbi->map_cpu + PAGE_SIZE; +--- linux-2.4.27/fs/Config.in~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/fs/Config.in +@@ -51,6 +51,9 @@ + int 'JFFS2 debugging verbosity (0 = quiet, 2 = noisy)' CONFIG_JFFS2_FS_DEBUG 0 + fi + tristate 'Compressed ROM file system support' CONFIG_CRAMFS ++dep_mbool ' Use linear addressing for cramfs' CONFIG_CRAMFS_LINEAR $CONFIG_CRAMFS ++dep_bool ' Support XIP on linear cramfs' CONFIG_CRAMFS_LINEAR_XIP $CONFIG_CRAMFS_LINEAR ++dep_bool ' Root file system on linear cramfs' CONFIG_ROOT_CRAMFS_LINEAR $CONFIG_CRAMFS_LINEAR + bool 'Virtual memory file system support (former shm fs)' CONFIG_TMPFS + define_bool CONFIG_RAMFS y + +--- linux-2.4.27/fs/cramfs/inode.c~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/fs/cramfs/inode.c +@@ -4,11 +4,29 @@ + * Copyright (C) 1999 Linus Torvalds. + * + * This file is released under the GPL. +- */ +- +-/* ++ * + * These are the VFS interfaces to the compressed rom filesystem. + * The actual compression is based on zlib, see the other files. ++ * ++ * Linear Addressing code ++ * Copyright (C) 2000 Shane Nay. ++ * ++ * Allows you to have a linearly addressed cramfs filesystem. ++ * Saves the need for buffer, and the munging of the buffer. ++ * Savings a bit over 32k with default PAGE_SIZE, BUFFER_SIZE ++ * etc. Usefull on embedded platform with ROM :-). ++ * ++ * Downsides- Currently linear addressed cramfs partitions ++ * don't co-exist with block cramfs partitions. ++ * ++ * 28-Dec-2000: XIP mode for linear cramfs ++ * Copyright (C) 2000 Robert Leslie <rob@mars.org> ++ * ++ * Dynamic allocation of linear cramfs space by Nicolas Pitre ++ * Copyright (C) 2003 Monta Vista Software, Inc. ++ * ++ * Linear cramfs now requires that you pass the physaddr= parameter to ++ * the mount process. Allows for multiple linear cramfs partitions. + */ + + #include <linux/module.h> +@@ -16,10 +34,12 @@ + #include <linux/pagemap.h> + #include <linux/init.h> + #include <linux/string.h> ++#include <linux/kernel.h> + #include <linux/locks.h> + #include <linux/blkdev.h> + #include <linux/cramfs_fs.h> + #include <asm/semaphore.h> ++#include <asm/io.h> + + #include <asm/uaccess.h> + +@@ -28,6 +48,8 @@ + #define CRAMFS_SB_BLOCKS u.cramfs_sb.blocks + #define CRAMFS_SB_FILES u.cramfs_sb.files + #define CRAMFS_SB_FLAGS u.cramfs_sb.flags ++#define CRAMFS_SB_LINEAR_PHYS_ADDR u.cramfs_sb.linear_phys_addr ++#define CRAMFS_SB_LINEAR_VIRT_ADDR u.cramfs_sb.linear_virt_addr + + static struct super_operations cramfs_ops; + static struct inode_operations cramfs_dir_inode_operations; +@@ -42,6 +64,74 @@ + #define CRAMINO(x) ((x)->offset?(x)->offset<<2:1) + #define OFFSET(x) ((x)->i_ino) + ++ ++#ifdef CONFIG_CRAMFS_LINEAR_XIP ++ ++static int cramfs_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ unsigned long address, length; ++ struct inode *inode = file->f_dentry->d_inode; ++ struct super_block *sb = inode->i_sb; ++ ++ /* this is only used in the case of read-only maps for XIP */ ++ ++ if (vma->vm_flags & VM_WRITE) ++ return generic_file_mmap(file, vma); ++ ++ if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) ++ return -EINVAL; ++ ++ address = PAGE_ALIGN(sb->CRAMFS_SB_LINEAR_PHYS_ADDR + OFFSET(inode)); ++ address += vma->vm_pgoff << PAGE_SHIFT; ++ ++ length = vma->vm_end - vma->vm_start; ++ ++ if (length > inode->i_size) ++ length = inode->i_size; ++ ++ length = PAGE_ALIGN(length); ++ ++ ++#if 0 ++ /* Doing the following makes it slower and more broken. bdl */ ++ /* ++ * Accessing memory above the top the kernel knows about or ++ * through a file pointer that was marked O_SYNC will be ++ * done non-cached. ++ */ ++ vma->vm_page_prot = ++ __pgprot((pgprot_val(vma->vm_page_prot) & ~_CACHE_MASK) ++ | _CACHE_UNCACHED); ++#endif ++ ++ /* ++ * Don't dump addresses that are not real memory to a core file. ++ */ ++ vma->vm_flags |= VM_IO; ++ flush_tlb_page(vma, address); ++ if (remap_page_range(vma->vm_start, address, length, ++ vma->vm_page_prot)) ++ return -EAGAIN; ++ ++#ifdef DEBUG_CRAMFS_XIP ++ printk("cramfs_mmap: mapped %s at 0x%08lx, length %lu to vma 0x%08lx" ++ ", page_prot 0x%08lx\n", ++ file->f_dentry->d_name.name, address, length, ++ vma->vm_start, pgprot_val(vma->vm_page_prot)); ++#endif ++ ++ return 0; ++} ++ ++static struct file_operations cramfs_linear_xip_fops = { ++ read: generic_file_read, ++ mmap: cramfs_mmap, ++}; ++ ++#define CRAMFS_INODE_IS_XIP(x) ((x)->i_mode & S_ISVTX) ++ ++#endif ++ + static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inode * cramfs_inode) + { + struct inode * inode = new_inode(sb); +@@ -60,7 +150,11 @@ + without -noleaf option. */ + insert_inode_hash(inode); + if (S_ISREG(inode->i_mode)) { ++#ifdef CONFIG_CRAMFS_LINEAR_XIP ++ inode->i_fop = CRAMFS_INODE_IS_XIP(inode) ? &cramfs_linear_xip_fops : &generic_ro_fops; ++#else + inode->i_fop = &generic_ro_fops; ++#endif + inode->i_data.a_ops = &cramfs_aops; + } else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &cramfs_dir_inode_operations; +@@ -76,6 +170,18 @@ + return inode; + } + ++#ifdef CONFIG_CRAMFS_LINEAR ++/* ++ * Return a pointer to the block in the linearly addressed cramfs image. ++ */ ++static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned int len) ++{ ++ if (!len) ++ return NULL; ++ return (void*)(sb->CRAMFS_SB_LINEAR_VIRT_ADDR + offset); ++} ++ ++#else /* Not linear addressing - aka regular block mode. */ + /* + * We have our own block cache: don't fill up the buffer cache + * with the rom-image, because the way the filesystem is set +@@ -192,19 +298,59 @@ + } + return read_buffers[buffer] + offset; + } +- ++#endif /* !CONFIG_CRAMFS_LINEAR */ + + static struct super_block * cramfs_read_super(struct super_block *sb, void *data, int silent) + { ++#ifndef CONFIG_CRAMFS_LINEAR + int i; ++#else ++ char *p; ++#endif + struct cramfs_super super; + unsigned long root_offset; + struct super_block * retval = NULL; + ++#ifndef CONFIG_CRAMFS_LINEAR + /* Invalidate the read buffers on mount: think disk change.. */ + for (i = 0; i < READ_BUFFERS; i++) + buffer_blocknr[i] = -1; + ++#else ++ ++ /* ++ * The physical location of the cramfs image is specified as ++ * a mount parameter. This parameter is mandatory for obvious ++ * reasons. Some validation is made on the phys address but this ++ * is not exhaustive and we count on the fact that someone using ++ * this feature is supposed to know what he/she's doing. ++ */ ++ if (!data || !(p = strstr((char *)data, "physaddr="))) { ++ printk(KERN_ERR "cramfs: unknown physical address for linear cramfs image\n"); ++ goto out; ++ } ++ sb->CRAMFS_SB_LINEAR_PHYS_ADDR = simple_strtoul(p + 9, NULL, 0); ++ if (sb->CRAMFS_SB_LINEAR_PHYS_ADDR & (PAGE_SIZE-1)) { ++ printk(KERN_ERR "cramfs: physical address 0x%lx for linear cramfs isn't aligned to a page boundary\n", ++ sb->CRAMFS_SB_LINEAR_PHYS_ADDR); ++ goto out; ++ } ++ if (sb->CRAMFS_SB_LINEAR_PHYS_ADDR == 0) { ++ printk(KERN_ERR "cramfs: physical address for linear cramfs image can't be 0\n"); ++ goto out; ++ } ++ printk(KERN_INFO "cramfs: checking physical address 0x%lx for linear cramfs image\n", ++ sb->CRAMFS_SB_LINEAR_PHYS_ADDR); ++ ++ /* Map only one page for now. Will remap it when fs size is known. */ ++ sb->CRAMFS_SB_LINEAR_VIRT_ADDR = ++ ioremap(sb->CRAMFS_SB_LINEAR_PHYS_ADDR, PAGE_SIZE); ++ if (!sb->CRAMFS_SB_LINEAR_VIRT_ADDR) { ++ printk(KERN_ERR "cramfs: ioremap of the linear cramfs image failed\n"); ++ goto out; ++ } ++#endif ++ + down(&read_mutex); + /* Read the first block and get the superblock from it */ + memcpy(&super, cramfs_read(sb, 0, sizeof(super)), sizeof(super)); +@@ -256,8 +402,26 @@ + /* Set it all up.. */ + sb->s_op = &cramfs_ops; + sb->s_root = d_alloc_root(get_cramfs_inode(sb, &super.root)); ++ ++#ifdef CONFIG_CRAMFS_LINEAR ++ /* Remap the whole filesystem now */ ++ iounmap(sb->CRAMFS_SB_LINEAR_VIRT_ADDR); ++ printk(KERN_INFO "cramfs: linear cramfs image appears to be %lu KB in size\n", ++ sb->CRAMFS_SB_SIZE/1024); ++ sb->CRAMFS_SB_LINEAR_VIRT_ADDR = ++ ioremap(sb->CRAMFS_SB_LINEAR_PHYS_ADDR, sb->CRAMFS_SB_SIZE); ++ if (!sb->CRAMFS_SB_LINEAR_VIRT_ADDR) { ++ printk(KERN_ERR "cramfs: ioremap of the linear cramfs image failed\n"); ++ goto out; ++ } ++#endif ++ + retval = sb; + out: ++#ifdef CONFIG_CRAMFS_LINEAR ++ if (!retval && sb->CRAMFS_SB_LINEAR_VIRT_ADDR) ++ iounmap(sb->CRAMFS_SB_LINEAR_VIRT_ADDR); ++#endif + return retval; + } + +@@ -390,6 +554,18 @@ + + maxblock = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; + bytes_filled = 0; ++#ifdef CONFIG_CRAMFS_LINEAR_XIP ++ if (page->index < maxblock && CRAMFS_INODE_IS_XIP(inode)) { ++ struct super_block *sb = inode->i_sb; ++ u32 blkptr_offset = PAGE_ALIGN(OFFSET(inode)) + ++ page->index * PAGE_CACHE_SIZE; ++ memcpy( page_address(page), ++ (void*)(sb->CRAMFS_SB_LINEAR_VIRT_ADDR + blkptr_offset), ++ PAGE_CACHE_SIZE ); ++ bytes_filled = PAGE_CACHE_SIZE; ++ pgdata = kmap(page); ++ } else ++#endif + if (page->index < maxblock) { + struct super_block *sb = inode->i_sb; + u32 blkptr_offset = OFFSET(inode) + page->index*4; +@@ -446,7 +622,11 @@ + statfs: cramfs_statfs, + }; + ++#ifndef CONFIG_CRAMFS_LINEAR + static DECLARE_FSTYPE_DEV(cramfs_fs_type, "cramfs", cramfs_read_super); ++#else ++static DECLARE_FSTYPE(cramfs_fs_type, "cramfs", cramfs_read_super, 0); ++#endif + + static int __init init_cramfs_fs(void) + { +--- /dev/null ++++ linux-2.4.27/fs/cramfs/mkcramfs.c +@@ -0,0 +1,821 @@ ++/* ++ * mkcramfs - make a cramfs file system, optionally with XIP files. ++ * ++ * Copyright (C) 1999-2001 Transmeta Corporation ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <sys/types.h> ++#include <stdio.h> ++#include <sys/stat.h> ++#include <unistd.h> ++#include <sys/mman.h> ++#include <sys/fcntl.h> ++#include <dirent.h> ++#include <stdlib.h> ++#include <errno.h> ++#include <string.h> ++#include <assert.h> ++#include <getopt.h> ++#include <linux/cramfs_fs.h> ++#include <zlib.h> ++ ++#define PAD_SIZE 512 /* only 0 and 512 supported by kernel */ ++ ++static const char *progname = "mkcramfs"; ++ ++/* N.B. If you change the disk format of cramfs, please update fs/cramfs/README. */ ++ ++/* Input status of 0 to print help and exit without an error. */ ++static void usage(int status) ++{ ++ FILE *stream = status ? stderr : stdout; ++ ++ fprintf(stream, "usage: %s [-h] [-e edition] [-i file] [-n name] dirname outfile\n" ++ " -h print this help\n" ++ " -E make all warnings errors (non-zero exit status)\n" ++ " -e edition set edition number (part of fsid)\n" ++ " -i file insert a file image into the filesystem (requires >= 2.4.0)\n" ++ " -n name set name of cramfs filesystem\n" ++ " -p pad by %d bytes for boot code\n" ++ " -s sort directory entries (old option, ignored)\n" ++ " -x make marked files eXecute In Place\n" ++ " -z make explicit holes (requires >= 2.3.39)\n" ++ " dirname root of the filesystem to be compressed\n" ++ " outfile output file\n", progname, PAD_SIZE); ++ ++ exit(status); ++} ++ ++#define PAGE_SIZE (4096) ++#define PAGE_ALIGN(x) (((x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) ++#define ROM_OFFSET 0 ++#define ROM_ALIGN(x) (PAGE_ALIGN((x) + ROM_OFFSET) - ROM_OFFSET) ++#define PAGE_CACHE_SIZE (4096) ++/* The kernel assumes PAGE_CACHE_SIZE as block size. */ ++static unsigned int blksize = PAGE_CACHE_SIZE; ++static long total_blocks = 0, total_nodes = 1; /* pre-count the root node */ ++static int image_length = 0; ++ ++/* ++ * If opt_holes is set, then mkcramfs can create explicit holes in the ++ * data, which saves 26 bytes per hole (which is a lot smaller a ++ * saving than most most filesystems). ++ * ++ * Note that kernels up to at least 2.3.39 don't support cramfs holes, ++ * which is why this is turned off by default. ++ */ ++static int opt_edition = 0; ++static int opt_errors = 0; ++static int opt_holes = 0; ++static int opt_xip = 0; ++static int opt_pad = 0; ++static char *opt_image = NULL; ++static char *opt_name = NULL; ++ ++static int warn_dev, warn_gid, warn_namelen, warn_skip, warn_size, warn_uid; ++ ++#ifndef MIN ++# define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) ++#endif ++ ++/* In-core version of inode / directory entry. */ ++struct entry { ++ /* stats */ ++ char *name; ++ unsigned int mode, size, uid, gid; ++ ++ /* FS data */ ++ void *uncompressed; ++ /* points to other identical file */ ++ struct entry *same; ++ unsigned int offset; /* pointer to compressed data in archive */ ++ unsigned int dir_offset; /* Where in the archive is the directory entry? */ ++ ++ /* organization */ ++ struct entry *child; /* null for non-directories and empty directories */ ++ struct entry *next; ++}; ++ ++/* ++ * The longest file name component to allow for in the input directory tree. ++ * Ext2fs (and many others) allow up to 255 bytes. A couple of filesystems ++ * allow longer (e.g. smbfs 1024), but there isn't much use in supporting ++ * >255-byte names in the input directory tree given that such names get ++ * truncated to 255 bytes when written to cramfs. ++ */ ++#define MAX_INPUT_NAMELEN 255 ++ ++static int find_identical_file(struct entry *orig,struct entry *newfile) ++{ ++ if(orig==newfile) return 1; ++ if(!orig) return 0; ++ if(orig->size==newfile->size && orig->uncompressed && !memcmp(orig->uncompressed,newfile->uncompressed,orig->size)) { ++ newfile->same=orig; ++ return 1; ++ } ++ return find_identical_file(orig->child,newfile) || ++ find_identical_file(orig->next,newfile); ++} ++ ++static void eliminate_doubles(struct entry *root,struct entry *orig) { ++ if(orig) { ++ if(orig->size && orig->uncompressed) ++ find_identical_file(root,orig); ++ eliminate_doubles(root,orig->child); ++ eliminate_doubles(root,orig->next); ++ } ++} ++ ++/* ++ * We define our own sorting function instead of using alphasort which ++ * uses strcoll and changes ordering based on locale information. ++ */ ++static int cramsort (const void *a, const void *b) ++{ ++ return strcmp ((*(const struct dirent **) a)->d_name, ++ (*(const struct dirent **) b)->d_name); ++} ++ ++static unsigned int parse_directory(struct entry *root_entry, const char *name, struct entry **prev, loff_t *fslen_ub) ++{ ++ struct dirent **dirlist; ++ int totalsize = 0, dircount, dirindex; ++ char *path, *endpath; ++ size_t len = strlen(name); ++ ++ /* Set up the path. */ ++ /* TODO: Reuse the parent's buffer to save memcpy'ing and duplication. */ ++ path = malloc(len + 1 + MAX_INPUT_NAMELEN + 1); ++ if (!path) { ++ perror(NULL); ++ exit(8); ++ } ++ memcpy(path, name, len); ++ endpath = path + len; ++ *endpath = '/'; ++ endpath++; ++ ++ /* read in the directory and sort */ ++ dircount = scandir(name, &dirlist, 0, cramsort); ++ ++ if (dircount < 0) { ++ perror(name); ++ exit(8); ++ } ++ ++ /* process directory */ ++ for (dirindex = 0; dirindex < dircount; dirindex++) { ++ struct dirent *dirent; ++ struct entry *entry; ++ struct stat st; ++ int size; ++ size_t namelen; ++ ++ dirent = dirlist[dirindex]; ++ ++ /* Ignore "." and ".." - we won't be adding them to the archive */ ++ if (dirent->d_name[0] == '.') { ++ if (dirent->d_name[1] == '\0') ++ continue; ++ if (dirent->d_name[1] == '.') { ++ if (dirent->d_name[2] == '\0') ++ continue; ++ } ++ } ++ namelen = strlen(dirent->d_name); ++ if (namelen > MAX_INPUT_NAMELEN) { ++ fprintf(stderr, ++ "Very long (%u bytes) filename `%s' found.\n" ++ " Please increase MAX_INPUT_NAMELEN in mkcramfs.c and recompile. Exiting.\n", ++ namelen, dirent->d_name); ++ exit(8); ++ } ++ memcpy(endpath, dirent->d_name, namelen + 1); ++ ++ if (lstat(path, &st) < 0) { ++ perror(endpath); ++ warn_skip = 1; ++ continue; ++ } ++ entry = calloc(1, sizeof(struct entry)); ++ if (!entry) { ++ perror(NULL); ++ exit(8); ++ } ++ entry->name = strdup(dirent->d_name); ++ if (!entry->name) { ++ perror(NULL); ++ exit(8); ++ } ++ if (namelen > 255) { ++ /* Can't happen when reading from ext2fs. */ ++ ++ /* TODO: we ought to avoid chopping in half ++ multi-byte UTF8 characters. */ ++ entry->name[namelen = 255] = '\0'; ++ warn_namelen = 1; ++ } ++ entry->mode = st.st_mode; ++ entry->size = st.st_size; ++ entry->uid = st.st_uid; ++ if (entry->uid >= 1 << CRAMFS_UID_WIDTH) ++ warn_uid = 1; ++ entry->gid = st.st_gid; ++ if (entry->gid >= 1 << CRAMFS_GID_WIDTH) ++ /* TODO: We ought to replace with a default ++ gid instead of truncating; otherwise there ++ are security problems. Maybe mode should ++ be &= ~070. Same goes for uid once Linux ++ supports >16-bit uids. */ ++ warn_gid = 1; ++ size = sizeof(struct cramfs_inode) + ((namelen + 3) & ~3); ++ *fslen_ub += size; ++ if (S_ISDIR(st.st_mode)) { ++ entry->size = parse_directory(root_entry, path, &entry->child, fslen_ub); ++ } else if (S_ISREG(st.st_mode)) { ++ /* TODO: We ought to open files in do_compress, one ++ at a time, instead of amassing all these memory ++ maps during parse_directory (which don't get used ++ until do_compress anyway). As it is, we tend to ++ get EMFILE errors (especially if mkcramfs is run ++ by non-root). ++ ++ While we're at it, do analagously for symlinks ++ (which would just save a little memory). */ ++ int fd = open(path, O_RDONLY); ++ if (fd < 0) { ++ perror(path); ++ warn_skip = 1; ++ continue; ++ } ++ if (entry->size) { ++ if ((entry->size >= 1 << CRAMFS_SIZE_WIDTH)) { ++ warn_size = 1; ++ entry->size = (1 << CRAMFS_SIZE_WIDTH) - 1; ++ } ++ ++ entry->uncompressed = mmap(NULL, entry->size, PROT_READ, MAP_PRIVATE, fd, 0); ++ if (-1 == (int) (long) entry->uncompressed) { ++ perror("mmap"); ++ exit(8); ++ } ++ } ++ close(fd); ++ } else if (S_ISLNK(st.st_mode)) { ++ entry->uncompressed = malloc(entry->size); ++ if (!entry->uncompressed) { ++ perror(NULL); ++ exit(8); ++ } ++ if (readlink(path, entry->uncompressed, entry->size) < 0) { ++ perror(path); ++ warn_skip = 1; ++ continue; ++ } ++ } else if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) { ++ /* maybe we should skip sockets */ ++ entry->size = 0; ++ } else { ++ entry->size = st.st_rdev; ++ if (entry->size & -(1<<CRAMFS_SIZE_WIDTH)) ++ warn_dev = 1; ++ } ++ ++ if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { ++ int blocks = ((entry->size - 1) / blksize + 1); ++ ++ /* block pointers & data expansion allowance + data */ ++ if(entry->size) ++ *fslen_ub += (4+26)*blocks + entry->size + 3; ++ } ++ ++ if (opt_xip && entry->mode & S_ISVTX) { ++ /* worse case, depending on where the offsets falls, ++ * a single XIP entry could expand the sizeof the ++ * file system by 8k, since we're aligning the start ++ * and end on page boundary. ++ */ ++ *fslen_ub += 2*PAGE_CACHE_SIZE; ++ } ++ ++ /* Link it into the list */ ++ *prev = entry; ++ prev = &entry->next; ++ totalsize += size; ++ } ++ free(path); ++ free(dirlist); /* allocated by scandir() with malloc() */ ++ return totalsize; ++} ++ ++/* Returns sizeof(struct cramfs_super), which includes the root inode. */ ++static unsigned int write_superblock(struct entry *root, char *base, int size) ++{ ++ struct cramfs_super *super = (struct cramfs_super *) base; ++ unsigned int offset = sizeof(struct cramfs_super) + image_length; ++ ++ if (opt_pad) { ++ offset += opt_pad; ++ } ++ ++ super->magic = CRAMFS_MAGIC; ++ super->flags = CRAMFS_FLAG_FSID_VERSION_2 | CRAMFS_FLAG_SORTED_DIRS; ++ if (opt_holes) ++ super->flags |= CRAMFS_FLAG_HOLES; ++ if (image_length > 0) ++ super->flags |= CRAMFS_FLAG_SHIFTED_ROOT_OFFSET; ++ super->size = size; ++ memcpy(super->signature, CRAMFS_SIGNATURE, sizeof(super->signature)); ++ ++ super->fsid.crc = crc32(0L, Z_NULL, 0); ++ super->fsid.edition = opt_edition; ++ super->fsid.blocks = total_blocks; ++ super->fsid.files = total_nodes; ++ ++ memset(super->name, 0x00, sizeof(super->name)); ++ if (opt_name) ++ strncpy(super->name, opt_name, sizeof(super->name)); ++ else ++ strncpy(super->name, "Compressed", sizeof(super->name)); ++ ++ super->root.mode = root->mode; ++ super->root.uid = root->uid; ++ super->root.gid = root->gid; ++ super->root.size = root->size; ++ super->root.offset = offset >> 2; ++ ++ return offset; ++} ++ ++static void set_data_offset(struct entry *entry, char *base, unsigned long offset) ++{ ++ struct cramfs_inode *inode = (struct cramfs_inode *) (base + entry->dir_offset); ++#ifdef DEBUG ++ assert ((offset & 3) == 0); ++#endif /* DEBUG */ ++ if (offset >= (1 << (2 + CRAMFS_OFFSET_WIDTH))) { ++ fprintf(stderr, "filesystem too big. Exiting.\n"); ++ exit(8); ++ } ++ inode->offset = (offset >> 2); ++} ++ ++ ++/* ++ * We do a width-first printout of the directory ++ * entries, using a stack to remember the directories ++ * we've seen. ++ */ ++#define MAXENTRIES (100) ++static unsigned int write_directory_structure(struct entry *entry, char *base, unsigned int offset) ++{ ++ int stack_entries = 0; ++ struct entry *entry_stack[MAXENTRIES]; ++ ++ for (;;) { ++ int dir_start = stack_entries; ++ while (entry) { ++ struct cramfs_inode *inode = (struct cramfs_inode *) (base + offset); ++ size_t len = strlen(entry->name); ++ ++ entry->dir_offset = offset; ++ ++ inode->mode = entry->mode; ++ inode->uid = entry->uid; ++ inode->gid = entry->gid; ++ inode->size = entry->size; ++ inode->offset = 0; ++ /* Non-empty directories, regfiles and symlinks will ++ write over inode->offset later. */ ++ ++ offset += sizeof(struct cramfs_inode); ++ total_nodes++; /* another node */ ++ memcpy(base + offset, entry->name, len); ++ /* Pad up the name to a 4-byte boundary */ ++ while (len & 3) { ++ *(base + offset + len) = '\0'; ++ len++; ++ } ++ inode->namelen = len >> 2; ++ offset += len; ++ ++ /* TODO: this may get it wrong for chars >= 0x80. ++ Most filesystems use UTF8 encoding for filenames, ++ whereas the console is a single-byte character ++ set like iso-latin-1. */ ++ printf(" %s\n", entry->name); ++ if (entry->child) { ++ if (stack_entries >= MAXENTRIES) { ++ fprintf(stderr, "Exceeded MAXENTRIES. Raise this value in mkcramfs.c and recompile. Exiting.\n"); ++ exit(8); ++ } ++ entry_stack[stack_entries] = entry; ++ stack_entries++; ++ } ++ entry = entry->next; ++ } ++ ++ /* ++ * Reverse the order the stack entries pushed during ++ * this directory, for a small optimization of disk ++ * access in the created fs. This change makes things ++ * `ls -UR' order. ++ */ ++ { ++ struct entry **lo = entry_stack + dir_start; ++ struct entry **hi = entry_stack + stack_entries; ++ struct entry *tmp; ++ ++ while (lo < --hi) { ++ tmp = *lo; ++ *lo++ = *hi; ++ *hi = tmp; ++ } ++ } ++ ++ /* Pop a subdirectory entry from the stack, and recurse. */ ++ if (!stack_entries) ++ break; ++ stack_entries--; ++ entry = entry_stack[stack_entries]; ++ ++ set_data_offset(entry, base, offset); ++ printf("'%s':\n", entry->name); ++ entry = entry->child; ++ } ++ return offset; ++} ++ ++static int is_zero(char const *begin, unsigned len) ++{ ++ if (opt_holes) ++ /* Returns non-zero iff the first LEN bytes from BEGIN are ++ all NULs. */ ++ return (len-- == 0 || ++ (begin[0] == '\0' && ++ (len-- == 0 || ++ (begin[1] == '\0' && ++ (len-- == 0 || ++ (begin[2] == '\0' && ++ (len-- == 0 || ++ (begin[3] == '\0' && ++ memcmp(begin, begin + 4, len) == 0)))))))); ++ else ++ /* Never create holes. */ ++ return 0; ++} ++ ++static unsigned int do_xip(char *base, unsigned int offset, ++ char const *name, char *uncompressed, ++ unsigned int size) ++{ ++ unsigned int start, end; ++ ++ /* align to page boundary */ ++ ++ start = ROM_ALIGN(offset); ++ memset(base + offset, 0, start - offset); ++ ++ memcpy(base + start, uncompressed, size); ++ ++ /* pad to page boundary */ ++ ++ end = ROM_ALIGN(start + size); ++ memset(base + start + size, 0, end - (start + size)); ++ ++ printf("XIP (%u+%u bytes)\toffset %u\t%s\n", ++ size, (end - offset) - size, offset, name); ++ ++ return end; ++} ++ ++/* ++ * One 4-byte pointer per block and then the actual blocked ++ * output. The first block does not need an offset pointer, ++ * as it will start immediately after the pointer block; ++ * so the i'th pointer points to the end of the i'th block ++ * (i.e. the start of the (i+1)'th block or past EOF). ++ * ++ * Note that size > 0, as a zero-sized file wouldn't ever ++ * have gotten here in the first place. ++ */ ++static unsigned int do_compress(char *base, unsigned int offset, char const *name, char *uncompressed, unsigned int size) ++{ ++ unsigned long original_size = size; ++ unsigned long original_offset = offset; ++ unsigned long new_size; ++ unsigned long blocks = (size - 1) / blksize + 1; ++ unsigned long curr = offset + 4 * blocks; ++ int change; ++ ++ total_blocks += blocks; ++ ++ do { ++ unsigned long len = 2 * blksize; ++ unsigned int input = size; ++ if (input > blksize) ++ input = blksize; ++ size -= input; ++ if (!is_zero (uncompressed, input)) { ++ compress(base + curr, &len, uncompressed, input); ++ curr += len; ++ } ++ uncompressed += input; ++ ++ if (len > blksize*2) { ++ /* (I don't think this can happen with zlib.) */ ++ printf("AIEEE: block \"compressed\" to > 2*blocklength (%ld)\n", len); ++ exit(8); ++ } ++ ++ *(u32 *) (base + offset) = curr; ++ offset += 4; ++ } while (size); ++ ++ curr = (curr + 3) & ~3; ++ new_size = curr - original_offset; ++ /* TODO: Arguably, original_size in these 2 lines should be ++ st_blocks * 512. But if you say that then perhaps ++ administrative data should also be included in both. */ ++ change = new_size - original_size; ++ printf("%6.2f%% (%+d bytes)\toffset %lu\t%s\n", ++ (change * 100) / (double) original_size, change, original_offset, name); ++ ++ return curr; ++} ++ ++ ++/* ++ * Traverse the entry tree, writing data for every item that has ++ * non-null entry->compressed (i.e. every symlink and non-empty ++ * regfile). ++ */ ++static unsigned int write_data(struct entry *entry, char *base, unsigned int offset) ++{ ++ do { ++ if (entry->uncompressed) { ++ if(entry->same) { ++ set_data_offset(entry, base, entry->same->offset); ++ entry->offset=entry->same->offset; ++ } else { ++ set_data_offset(entry, base, offset); ++ entry->offset=offset; ++ if (opt_xip && entry->mode & S_ISVTX) ++ offset = do_xip(base, offset, entry->name, entry->uncompressed, entry->size); ++ else ++ offset = do_compress(base, offset, entry->name, entry->uncompressed, entry->size); ++ } ++ } ++ else if (entry->child) ++ offset = write_data(entry->child, base, offset); ++ entry=entry->next; ++ } while (entry); ++ return offset; ++} ++ ++static unsigned int write_file(char *file, char *base, unsigned int offset) ++{ ++ int fd; ++ char *buf; ++ ++ fd = open(file, O_RDONLY); ++ if (fd < 0) { ++ perror(file); ++ exit(8); ++ } ++ buf = mmap(NULL, image_length, PROT_READ, MAP_PRIVATE, fd, 0); ++ memcpy(base + offset, buf, image_length); ++ munmap(buf, image_length); ++ close (fd); ++ /* Pad up the image_length to a 4-byte boundary */ ++ while (image_length & 3) { ++ *(base + offset + image_length) = '\0'; ++ image_length++; ++ } ++ return (offset + image_length); ++} ++ ++/* ++ * Maximum size fs you can create is roughly 256MB. (The last file's ++ * data must begin within 256MB boundary but can extend beyond that.) ++ * ++ * Note that if you want it to fit in a ROM then you're limited to what the ++ * hardware and kernel can support (64MB?). ++ */ ++#define MAXFSLEN ((((1 << CRAMFS_OFFSET_WIDTH) - 1) << 2) /* offset */ \ ++ + (1 << CRAMFS_SIZE_WIDTH) - 1 /* filesize */ \ ++ + (1 << CRAMFS_SIZE_WIDTH) * 4 / PAGE_CACHE_SIZE /* block pointers */ ) ++ ++ ++/* ++ * Usage: ++ * ++ * mkcramfs directory-name outfile ++ * ++ * where "directory-name" is simply the root of the directory ++ * tree that we want to generate a compressed filesystem out ++ * of. ++ */ ++int main(int argc, char **argv) ++{ ++ struct stat st; /* used twice... */ ++ struct entry *root_entry; ++ char *rom_image; ++ ssize_t offset, written; ++ int fd; ++ /* initial guess (upper-bound) of required filesystem size */ ++ loff_t fslen_ub = sizeof(struct cramfs_super); ++ char const *dirname, *outfile; ++ u32 crc = crc32(0L, Z_NULL, 0); ++ int c; /* for getopt */ ++ ++ total_blocks = 0; ++ ++ if (argc) ++ progname = argv[0]; ++ ++ /* command line options */ ++ while ((c = getopt(argc, argv, "hEe:i:n:psxz")) != EOF) { ++ switch (c) { ++ case 'h': ++ usage(0); ++ case 'E': ++ opt_errors = 1; ++ break; ++ case 'e': ++ opt_edition = atoi(optarg); ++ break; ++ case 'i': ++ opt_image = optarg; ++ if (lstat(opt_image, &st) < 0) { ++ perror(opt_image); ++ exit(16); ++ } ++ image_length = st.st_size; /* may be padded later */ ++ fslen_ub += (image_length + 3); /* 3 is for padding */ ++ break; ++ case 'n': ++ opt_name = optarg; ++ break; ++ case 'p': ++ opt_pad = PAD_SIZE; ++ fslen_ub += PAD_SIZE; ++ break; ++ case 's': ++ /* old option, ignored */ ++ break; ++ case 'x': ++ opt_xip = 1; ++ break; ++ case 'z': ++ opt_holes = 1; ++ break; ++ } ++ } ++ ++ if ((argc - optind) != 2) ++ usage(16); ++ dirname = argv[optind]; ++ outfile = argv[optind + 1]; ++ ++ if (stat(dirname, &st) < 0) { ++ perror(dirname); ++ exit(16); ++ } ++ fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666); ++ ++ root_entry = calloc(1, sizeof(struct entry)); ++ if (!root_entry) { ++ perror(NULL); ++ exit(8); ++ } ++ root_entry->mode = st.st_mode; ++ root_entry->uid = st.st_uid; ++ root_entry->gid = st.st_gid; ++ ++ root_entry->size = parse_directory(root_entry, dirname, &root_entry->child, &fslen_ub); ++ ++ /* always allocate a multiple of blksize bytes because that's ++ what we're going to write later on */ ++ fslen_ub = ((fslen_ub - 1) | (blksize - 1)) + 1; ++ ++ if (fslen_ub > MAXFSLEN) { ++ fprintf(stderr, ++ "warning: guestimate of required size (upper bound) is %LdMB, but maximum image size is %uMB. We might die prematurely.\n", ++ fslen_ub >> 20, ++ MAXFSLEN >> 20); ++ fslen_ub = MAXFSLEN; ++ } ++ ++ /* find duplicate files. TODO: uses the most inefficient algorithm ++ possible. */ ++ eliminate_doubles(root_entry,root_entry); ++ ++ /* TODO: Why do we use a private/anonymous mapping here ++ followed by a write below, instead of just a shared mapping ++ and a couple of ftruncate calls? Is it just to save us ++ having to deal with removing the file afterwards? If we ++ really need this huge anonymous mapping, we ought to mmap ++ in smaller chunks, so that the user doesn't need nn MB of ++ RAM free. If the reason is to be able to write to ++ un-mmappable block devices, then we could try shared mmap ++ and revert to anonymous mmap if the shared mmap fails. */ ++ rom_image = mmap(NULL, fslen_ub?fslen_ub:1, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ++ ++ if (-1 == (int) (long) rom_image) { ++ perror("ROM image map"); ++ exit(8); ++ } ++ ++ /* Skip the first opt_pad bytes for boot loader code */ ++ offset = opt_pad; ++ memset(rom_image, 0x00, opt_pad); ++ ++ /* Skip the superblock and come back to write it later. */ ++ offset += sizeof(struct cramfs_super); ++ ++ /* Insert a file image. */ ++ if (opt_image) { ++ printf("Including: %s\n", opt_image); ++ offset = write_file(opt_image, rom_image, offset); ++ } ++ ++ offset = write_directory_structure(root_entry->child, rom_image, offset); ++ printf("Directory data: %d bytes\n", offset); ++ ++ offset = write_data(root_entry, rom_image, offset); ++ ++ /* We always write a multiple of blksize bytes, so that ++ losetup works. */ ++ offset = ((offset - 1) | (blksize - 1)) + 1; ++ printf("Everything: %d kilobytes\n", offset >> 10); ++ ++ /* Write the superblock now that we can fill in all of the fields. */ ++ write_superblock(root_entry, rom_image+opt_pad, offset); ++ printf("Super block: %d bytes\n", sizeof(struct cramfs_super)); ++ ++ /* Put the checksum in. */ ++ crc = crc32(crc, (rom_image+opt_pad), (offset-opt_pad)); ++ ((struct cramfs_super *) (rom_image+opt_pad))->fsid.crc = crc; ++ printf("CRC: %x\n", crc); ++ ++ /* Check to make sure we allocated enough space. */ ++ if (fslen_ub < offset) { ++ fprintf(stderr, "not enough space allocated for ROM image (%Ld allocated, %d used)\n", ++ fslen_ub, offset); ++ exit(8); ++ } ++ ++ written = write(fd, rom_image, offset); ++ if (written < 0) { ++ perror("ROM image"); ++ exit(8); ++ } ++ if (offset != written) { ++ fprintf(stderr, "ROM image write failed (%d %d)\n", written, offset); ++ exit(8); ++ } ++ ++ /* (These warnings used to come at the start, but they scroll off the ++ screen too quickly.) */ ++ if (warn_namelen) /* (can't happen when reading from ext2fs) */ ++ fprintf(stderr, /* bytes, not chars: think UTF8. */ ++ "warning: filenames truncated to 255 bytes.\n"); ++ if (warn_skip) ++ fprintf(stderr, "warning: files were skipped due to errors.\n"); ++ if (warn_size) ++ fprintf(stderr, ++ "warning: file sizes truncated to %luMB (minus 1 byte).\n", ++ 1L << (CRAMFS_SIZE_WIDTH - 20)); ++ if (warn_uid) /* (not possible with current Linux versions) */ ++ fprintf(stderr, ++ "warning: uids truncated to %u bits. (This may be a security concern.)\n", ++ CRAMFS_UID_WIDTH); ++ if (warn_gid) ++ fprintf(stderr, ++ "warning: gids truncated to %u bits. (This may be a security concern.)\n", ++ CRAMFS_GID_WIDTH); ++ if (warn_dev) ++ fprintf(stderr, ++ "WARNING: device numbers truncated to %u bits. This almost certainly means\n" ++ "that some device files will be wrong.\n", ++ CRAMFS_OFFSET_WIDTH); ++ if (opt_errors && ++ (warn_namelen||warn_skip||warn_size||warn_uid||warn_gid||warn_dev)) ++ exit(8); ++ return 0; ++} +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/bitfield.h +@@ -0,0 +1,113 @@ ++/* ++ * FILE bitfield.h ++ * ++ * Version 1.1 ++ * Author Copyright (c) Marc A. Viredaz, 1998 ++ * DEC Western Research Laboratory, Palo Alto, CA ++ * Date April 1998 (April 1997) ++ * System Advanced RISC Machine (ARM) ++ * Language C or ARM Assembly ++ * Purpose Definition of macros to operate on bit fields. ++ */ ++ ++ ++ ++#ifndef __BITFIELD_H ++#define __BITFIELD_H ++ ++#ifndef __ASSEMBLY__ ++#define UData(Data) ((unsigned long) (Data)) ++#else ++#define UData(Data) (Data) ++#endif ++ ++ ++/* ++ * MACRO: Fld ++ * ++ * Purpose ++ * The macro "Fld" encodes a bit field, given its size and its shift value ++ * with respect to bit 0. ++ * ++ * Note ++ * A more intuitive way to encode bit fields would have been to use their ++ * mask. However, extracting size and shift value information from a bit ++ * field's mask is cumbersome and might break the assembler (255-character ++ * line-size limit). ++ * ++ * Input ++ * Size Size of the bit field, in number of bits. ++ * Shft Shift value of the bit field with respect to bit 0. ++ * ++ * Output ++ * Fld Encoded bit field. ++ */ ++ ++#define Fld(Size, Shft) (((Size) << 16) + (Shft)) ++ ++ ++/* ++ * MACROS: FSize, FShft, FMsk, FAlnMsk, F1stBit ++ * ++ * Purpose ++ * The macros "FSize", "FShft", "FMsk", "FAlnMsk", and "F1stBit" return ++ * the size, shift value, mask, aligned mask, and first bit of a ++ * bit field. ++ * ++ * Input ++ * Field Encoded bit field (using the macro "Fld"). ++ * ++ * Output ++ * FSize Size of the bit field, in number of bits. ++ * FShft Shift value of the bit field with respect to bit 0. ++ * FMsk Mask for the bit field. ++ * FAlnMsk Mask for the bit field, aligned on bit 0. ++ * F1stBit First bit of the bit field. ++ */ ++ ++#define FSize(Field) ((Field) >> 16) ++#define FShft(Field) ((Field) & 0x0000FFFF) ++#define FMsk(Field) (((UData (1) << FSize (Field)) - 1) << FShft (Field)) ++#define FAlnMsk(Field) ((UData (1) << FSize (Field)) - 1) ++#define F1stBit(Field) (UData (1) << FShft (Field)) ++ ++ ++/* ++ * MACRO: FInsrt ++ * ++ * Purpose ++ * The macro "FInsrt" inserts a value into a bit field by shifting the ++ * former appropriately. ++ * ++ * Input ++ * Value Bit-field value. ++ * Field Encoded bit field (using the macro "Fld"). ++ * ++ * Output ++ * FInsrt Bit-field value positioned appropriately. ++ */ ++ ++#define FInsrt(Value, Field) \ ++ (UData (Value) << FShft (Field)) ++ ++ ++/* ++ * MACRO: FExtr ++ * ++ * Purpose ++ * The macro "FExtr" extracts the value of a bit field by masking and ++ * shifting it appropriately. ++ * ++ * Input ++ * Data Data containing the bit-field to be extracted. ++ * Field Encoded bit field (using the macro "Fld"). ++ * ++ * Output ++ * FExtr Bit-field value. ++ */ ++ ++#define FExtr(Data, Field) \ ++ ((UData (Data) >> FShft (Field)) & FAlnMsk (Field)) ++ ++ ++#endif /* __BITFIELD_H */ +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/cerf.h +@@ -0,0 +1,177 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/cerf.h ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++/* ++ * Add CerfBoard Specifics here... ++ */ ++ ++/* ++ * Memory sizes ++ */ ++ ++#define CERF_RAM_BASE 0xa0000000 ++ ++#ifdef CONFIG_PXA_CERF_RAM_128MB ++#define CERF_RAM_SIZE 128*1024*1024 ++ ++#elif defined (CONFIG_PXA_CERF_RAM_64MB) ++#define CERF_RAM_SIZE 64*1024*1024 ++ ++#elif defined (CONFIG_PXA_CERF_RAM_32MB) ++#define CERF_RAM_SIZE 32*1024*1024 ++ ++#elif defined (CONFIG_PXA_CERF_RAM_16MB) ++#define CERF_RAM_SIZE 16*1024*1024 ++#endif ++ ++/* ++ * CS memory timing via Static Memory Control Register (MSC0-2) ++ */ ++ ++#define MSC_CS(cs,val) ((val)<<((cs&1)<<4)) ++ ++#define MSC_RBUFF_SHIFT 15 ++#define MSC_RBUFF_SLOW (0) ++#define MSC_RBUFF_FAST (1) ++#define MSC_RBUFF(x) ((x)<<MSC_RBUFF_SHIFT) ++ ++#define MSC_RRR_SHIFT 12 ++#define MSC_RRR(x) ((x)<<MSC_RRR_SHIFT) ++ ++#define MSC_RDN_SHIFT 8 ++#define MSC_RDN(x) ((x)<<MSC_RDN_SHIFT) ++ ++#define MSC_RDF_SHIFT 4 ++#define MSC_RDF(x) ((x)<<MSC_RDF_SHIFT) ++ ++#define MSC_RBW_SHIFT 3 ++#define MSC_RBW(x) ((x)<<MSC_RBW_SHIFT) ++ ++#define MSC_RT_SHIFT 0 ++#define MSC_RT(x) ((x)<<MSC_RT_SHIFT) ++ ++/* ++ * IO Pins for devices ++ */ ++ ++#define CERF_FLASH_BASE 0xe8000000 ++#define CERF_FLASH_SIZE 0x02000000 ++#define CERF_FLASH_PHYS PXA_CS0_PHYS ++ ++#define CERF_ETH_BASE 0xf0000000 ++#define CERF_ETH_SIZE 0x00100000 ++#define CERF_ETH_PHYS PXA_CS1_PHYS ++ ++#define CERF_BT_BASE 0xf2000000 ++#define CERF_BT_SIZE 0x00100000 ++#define CERF_BT_PHYS PXA_CS2_PHYS ++ ++#define CERF_SERIAL_BASE 0xf3000000 ++#define CERF_SERIAL_SIZE 0x00100000 ++#define CERF_SERIAL_PHYS PXA_CS3_PHYS ++ ++#define CERF_CPLD_BASE 0xf1000000 ++#define CERF_CPLD_SIZE 0x00100000 ++#define CERF_CPLD_PHYS PXA_CS4_PHYS ++ ++#define CERF_PDA_CPLD_WRCLRINT (0x0) ++#define CERF_PDA_CPLD_BRIGHTNESS (0x2) ++#define CERF_PDA_CPLD_KEYPAD_A (0x6) ++#define CERF_PDA_CPLD_BATTFAULT (0x8) ++#define CERF_PDA_CPLD_KEYPAD_B (0xa) ++#define CERF_PDA_CPLD_SOUND_ENA (0xc) ++ ++#define CERF_PDA_SOUND_ENABLE 0x1 ++#define CERF_PDA_DEFAULT_BRIGHTNESS 0x9 ++ ++/* ++ * Access functions (registers are 4-bit wide) ++ */ ++ ++#define CERF_PDA_CPLD CERF_CPLD_BASE ++ ++#define CERF_PDA_CPLD_Get(x, y) (*((char*)(CERF_PDA_CPLD + (x))) & (y)) ++#define CERF_PDA_CPLD_Set(x, y, z) (*((char*)(CERF_PDA_CPLD + (x))) = (*((char*)(CERF_PDA_CPLD + (x))) & ~(z)) | (y)) ++#define CERF_PDA_CPLD_UnSet(x, y, z) (*((char*)(CERF_PDA_CPLD + (x))) = (*((char*)(CERF_PDA_CPLD + (x))) & ~(z)) & ~(y)) ++ ++/* ++ * IO and IRQ settings for cs8900 ethernet chip ++ */ ++#define CERF_ETH_IO CERF_ETH_BASE ++#define CERF_ETH_IRQ GPIO_2_80_TO_IRQ(21) ++ ++/* ++ * We only have one LED on the XScale CerfPDA so only the ++ * time or idle should ever be selected. ++ */ ++#define CERF_HEARTBEAT_LED 0x1 ++#define CERF_SYS_BUSY_LED 0x2 ++ ++#define CERF_HEARTBEAT_LED_GPIO 16 // GPIO 4 ++#define CERF_SYS_BUSY_LED_GPIO 16 // GPIO 4 ++ ++#define CERF_HEARTBEAT_LED_ON (GPSR0 = CERF_HEARTBEAT_LED_GPIO) ++#define CERF_HEARTBEAT_LED_OFF (GPCR0 = CERF_HEARTBEAT_LED_GPIO) ++#define CERF_SYS_BUSY_LED_ON (GPSR0 = CERF_SYS_BUSY_LED_GPIO) ++#define CERF_SYS_BUSY_LED_OFF (GPCR0 = CERF_SYS_BUSY_LED_GPIO) ++ ++/* ++ * UCB 1400 gpio ++ */ ++ ++#define CERF_GPIO_UCB1400_IRQ 32 ++ ++#define UCB_IO_0 (1 << 0) ++#define UCB_IO_1 (1 << 1) ++#define UCB_IO_2 (1 << 2) ++#define UCB_IO_3 (1 << 3) ++#define UCB_IO_4 (1 << 4) ++#define UCB_IO_5 (1 << 5) ++#define UCB_IO_6 (1 << 6) ++#define UCB_IO_7 (1 << 7) ++#define UCB_IO_8 (1 << 8) ++#define UCB_IO_9 (1 << 9) ++ ++#define UCB1400_GPIO_CONT_CS UCB_IO_0 ++#define UCB1400_GPIO_CONT_DOWN UCB_IO_1 ++#define UCB1400_GPIO_CONT_INC UCB_IO_2 ++#define UCB1400_GPIO_CONT_ENA UCB_IO_3 ++#define UCB1400_GPIO_LCD_RESET UCB_IO_4 ++#define UCB1400_GPIO_IRDA_ENABLE UCB_IO_5 ++#define UCB1400_GPIO_BT_ENABLE UCB_IO_6 ++#define UCB1400_GPIO_TEST_P1 UCB_IO_7 ++#define UCB1400_GPIO_TEST_P2 UCB_IO_8 ++#define UCB1400_GPIO_TEST_P3 UCB_IO_9 ++ ++/* ++ * IRQ for devices ++ */ ++#define UCB1400_IRQ(x) (NR_IRQS + 1 + (x)) ++ ++#define IRQ_UCB1400_IO0 UCB1400_IRQ(0) ++#define IRQ_UCB1400_IO1 UCB1400_IRQ(1) ++#define IRQ_UCB1400_IO2 UCB1400_IRQ(2) ++#define IRQ_UCB1400_IO3 UCB1400_IRQ(3) ++#define IRQ_UCB1400_IO4 UCB1400_IRQ(4) ++#define IRQ_UCB1400_IO5 UCB1400_IRQ(5) ++#define IRQ_UCB1400_IO6 UCB1400_IRQ(6) ++#define IRQ_UCB1400_IO7 UCB1400_IRQ(7) ++#define IRQ_UCB1400_IO8 UCB1400_IRQ(8) ++#define IRQ_UCB1400_IO9 UCB1400_IRQ(9) ++ ++#define IRQ_UCB1400_CONT_CS IRQ_UCB1400_IO0 ++#define IRQ_UCB1400_CONT_DOWN IRQ_UCB1400_IO1 ++#define IRQ_UCB1400_CONT_INC IRQ_UCB1400_IO2 ++#define IRQ_UCB1400_CONT_ENA IRQ_UCB1400_IO3 ++#define IRQ_UCB1400_LCD_RESET IRQ_UCB1400_IO4 ++#define IRQ_UCB1400_IRDA_ENABLE IRQ_UCB1400_IO5 ++#define IRQ_UCB1400_BT_ENABLE IRQ_UCB1400_IO6 ++#define IRQ_UCB1400_TEST_P1 IRQ_UCB1400_IO7 ++#define IRQ_UCB1400_TEST_P2 IRQ_UCB1400_IO8 ++#define IRQ_UCB1400_TEST_P3 IRQ_UCB1400_IO9 ++ +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/cerf_ucb1400gpio.h +@@ -0,0 +1,30 @@ ++/* ++ * cerf_ucb1400gpio.h ++ * ++ * UCB1400 GPIO control stuff for the cerf. ++ * ++ * Copyright (C) 2002 Intrinsyc Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * History: ++ * Mar 2002: Initial version [FB] ++ * ++ */ ++/* -- lcd -- */ ++extern void cerf_ucb1400gpio_lcd_enable( void); ++extern void cerf_ucb1400gpio_lcd_disable( void); ++extern void cerf_ucb1400gpio_lcd_contrast_step( int direction); ++ ++/* -- irda -- */ ++extern void cerf_ucb1400gpio_irda_enable( void); ++extern void cerf_ucb1400gpio_irda_disable( void); ++ ++/* -- bt -- */ ++extern void cerf_ucb1400gpio_bt_enable( void); ++extern void cerf_ucb1400gpio_bt_disable( void); ++ ++/* -- init -- */ ++extern int cerf_ucb1400gpio_init(void); +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/csb226.h +@@ -0,0 +1,99 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/csb226.h ++ * ++ * Author: Robert Schwebel (stolen from lubbock.h) ++ * Created: Oct 30, 2002 ++ * Copyright: Pengutronix ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#define CSB226_FPGA_PHYS PXA_CS2_PHYS ++ ++#define CSB226_FPGA_VIRT (0xf0000000) /* phys 0x08000000 */ ++#define CSB226_ETH_BASE (0xf1000000) /* phys 0x0c000000 */ ++ ++#define CSB226_P2V(x) ((x) - CSB226_FPGA_PHYS + CSB226_FPGA_VIRT) ++#define CSB226_V2P(x) ((x) - CSB226_FPGA_VIRT + CSB226_FPGA_PHYS) ++ ++#ifndef __ASSEMBLY__ ++# define __CSB226_REG(x) (*((volatile unsigned long *)CSB226_P2V(x))) ++#else ++# define __CSB226_REG(x) CSB226_P2V(x) ++#endif ++ ++ ++/* register physical addresses */ ++#define _CSB226_MISC_WR (CSB226_FPGA_PHYS + 0x080) ++#define _CSB226_MISC_RD (CSB226_FPGA_PHYS + 0x090) ++#define _CSB226_IRQ_MASK_EN (CSB226_FPGA_PHYS + 0x0C0) ++#define _CSB226_IRQ_SET_CLR (CSB226_FPGA_PHYS + 0x0D0) ++#define _CSB226_GP (CSB226_FPGA_PHYS + 0x100) ++ ++ ++ ++/* register virtual addresses */ ++ ++#define CSB226_MISC_WR __CSB226_REG(_CSB226_MISC_WR) ++#define CSB226_MISC_RD __CSB226_REG(_CSB226_MISC_RD) ++#define CSB226_IRQ_MASK_EN __CSB226_REG(_CSB226_IRQ_MASK_EN) ++#define CSB226_IRQ_SET_CLR __CSB226_REG(_CSB226_IRQ_SET_CLR) ++#define CSB226_GP __CSB226_REG(_CSB226_GP) ++ ++ ++/* GPIOs */ ++ ++#define GPIO_CSB226_IRQ 0 ++#define IRQ_GPIO_CSB226_IRQ IRQ_GPIO0 ++ ++ ++/* ++ * LED macros ++ */ ++ ++// #define LEDS_BASE LUB_DISC_BLNK_LED ++ ++// 8 discrete leds available for general use: ++ ++/* ++#define D28 0x1 ++#define D27 0x2 ++#define D26 0x4 ++#define D25 0x8 ++#define D24 0x10 ++#define D23 0x20 ++#define D22 0x40 ++#define D21 0x80 ++*/ ++ ++/* Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays so ++* be sure to not monkey with them here. ++*/ ++ ++/* ++#define HEARTBEAT_LED D28 ++#define SYS_BUSY_LED D27 ++#define HEXLEDS_BASE LUB_HEXLED ++ ++#define HEARTBEAT_LED_ON (LEDS_BASE &= ~HEARTBEAT_LED) ++#define HEARTBEAT_LED_OFF (LEDS_BASE |= HEARTBEAT_LED) ++#define SYS_BUSY_LED_OFF (LEDS_BASE |= SYS_BUSY_LED) ++#define SYS_BUSY_LED_ON (LEDS_BASE &= ~SYS_BUSY_LED) ++ ++// use x = D26-D21 for these, please... ++#define DISCRETE_LED_ON(x) (LEDS_BASE &= ~(x)) ++#define DISCRETE_LED_OFF(x) (LEDS_BASE |= (x)) ++*/ ++ ++#ifndef __ASSEMBLY__ ++ ++//extern int hexled_val = 0; ++ ++#endif ++ ++/* ++#define BUMP_COUNTER (HEXLEDS_BASE = hexled_val++) ++#define DEC_COUNTER (HEXLEDS_BASE = hexled_val--) ++*/ +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/dma.h +@@ -0,0 +1,49 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/dma.h ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista Software, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef __ASM_ARCH_DMA_H ++#define __ASM_ARCH_DMA_H ++ ++#define MAX_DMA_ADDRESS 0xffffffff ++ ++/* No DMA as the rest of the world see it */ ++#define MAX_DMA_CHANNELS 0 ++ ++/* ++ * Descriptor structure for PXA's DMA engine ++ * Note: this structure must always be aligned to a 16-byte boundary. ++ */ ++ ++typedef struct { ++ volatile u32 ddadr; /* Points to the next descriptor + flags */ ++ volatile u32 dsadr; /* DSADR value for the current transfer */ ++ volatile u32 dtadr; /* DTADR value for the current transfer */ ++ volatile u32 dcmd; /* DCMD value for the current transfer */ ++} pxa_dma_desc; ++ ++/* ++ * DMA registration ++ */ ++ ++typedef enum { ++ DMA_PRIO_HIGH = 0, ++ DMA_PRIO_MEDIUM = 4, ++ DMA_PRIO_LOW = 8 ++} pxa_dma_prio; ++ ++int pxa_request_dma (char *name, ++ pxa_dma_prio prio, ++ void (*irq_handler)(int, void *, struct pt_regs *), ++ void *data); ++ ++void pxa_free_dma (int dma_ch); ++ ++#endif /* _ASM_ARCH_DMA_H */ +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/hardware.h +@@ -0,0 +1,142 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/hardware.h ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_ARCH_HARDWARE_H ++#define __ASM_ARCH_HARDWARE_H ++ ++#include <linux/config.h> ++#include <asm/mach-types.h> ++ ++ ++/* ++ * These are statically mapped PCMCIA IO space for designs using it as a ++ * generic IO bus, typically with ISA parts, hardwired IDE interfaces, etc. ++ * The actual PCMCIA code is mapping required IO region at run time. ++ */ ++#define PCMCIA_IO_0_BASE 0xf6000000 ++#define PCMCIA_IO_1_BASE 0xf7000000 ++ ++ ++/* ++ * XIP kernel text mapping. ++ * Note: the exact virtual address is also specified in arch/arm/Makefile. ++ */ ++#ifdef CONFIG_XIP_KERNEL ++#define KERNEL_XIP_BASE_PHYS (CONFIG_XIP_PHYS_ADDR & 0xffe00000) ++#define KERNEL_XIP_BASE_VIRT 0xe8000000 ++#endif ++ ++ ++/* ++ * We requires absolute addresses. ++ */ ++#define PCIO_BASE 0 ++ ++/* ++ * Workarounds for at least 2 errata so far require this. ++ * The mapping is set in mach-pxa/generic.c. ++ */ ++#define UNCACHED_PHYS_0 0xff000000 ++#define UNCACHED_ADDR UNCACHED_PHYS_0 ++ ++/* ++ * Intel PXA internal I/O mappings: ++ * ++ * 0x40000000 - 0x41ffffff <--> 0xf8000000 - 0xf9ffffff ++ * 0x44000000 - 0x45ffffff <--> 0xfa000000 - 0xfbffffff ++ * 0x48000000 - 0x49ffffff <--> 0xfc000000 - 0xfdffffff ++ */ ++ ++#define io_p2v(x) ( ((x) | 0xbe000000) ^ (~((x) >> 1) & 0x06000000) ) ++#define io_v2p( x ) ( ((x) & 0x41ffffff) ^ ( ((x) & 0x06000000) << 1) ) ++ ++#ifndef __ASSEMBLY__ ++ ++#if 0 ++# define __REG(x) (*((volatile u32 *)io_p2v(x))) ++#else ++/* ++ * This __REG() version gives the same results as the one above, except ++ * that we are fooling gcc somehow so it generates far better and smaller ++ * assembly code for access to contigous registers. It's a shame that gcc ++ * doesn't guess this by itself. ++ */ ++#include <asm/types.h> ++typedef struct { volatile u32 offset[4096]; } __regbase; ++# define __REGP(x) ((__regbase *)((x)&~4095))->offset[((x)&4095)>>2] ++# define __REG(x) __REGP(io_p2v(x)) ++#endif ++ ++/* Let's kick gcc's ass again... */ ++# define __REG2(x,y) \ ++ ( __builtin_constant_p(y) ? (__REG((x) + (y))) \ ++ : (*(volatile u32 *)((u32)&__REG(x) + (y))) ) ++ ++# define __PREG(x) (io_v2p((u32)&(x))) ++ ++#else ++ ++# define __REG(x) io_p2v(x) ++# define __PREG(x) io_v2p(x) ++ ++#endif ++ ++#include "pxa-regs.h" ++ ++#ifndef __ASSEMBLY__ ++ ++/* ++ * GPIO edge detection for IRQs: ++ * IRQs are generated on Falling-Edge, Rising-Edge, or both. ++ * This must be called *before* the corresponding IRQ is registered. ++ * Use this instead of directly setting GRER/GFER. ++ */ ++#define GPIO_FALLING_EDGE 1 ++#define GPIO_RISING_EDGE 2 ++#define GPIO_BOTH_EDGES 3 ++extern void set_GPIO_IRQ_edge( int gpio_nr, int edge_mask ); ++ ++/* ++ * Handy routine to set GPIO alternate functions ++ */ ++extern void set_GPIO_mode( int gpio_mode ); ++ ++/* ++ * return current lclk frequency in units of 10kHz ++ */ ++extern unsigned int get_lclk_frequency_10khz(void); ++ ++/* ++ * return current clk frequency in units of 1kHz ++ */ ++extern unsigned int get_clk_frequency_khz( int info); ++ ++#endif ++ ++ ++/* ++ * Implementation specifics ++ */ ++ ++//#ifdef CONFIG_ARCH_LUBBOCK ++#include "lubbock.h" ++//#endif ++ ++//#ifdef CONFIG_ARCH_PXA_IDP ++#include "idp.h" ++//#endif ++ ++//#ifdef CONFIG_ARCH_PXA_CERF ++#include "cerf.h" ++//#endif ++ ++#endif /* _ASM_ARCH_HARDWARE_H */ +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/ide.h +@@ -0,0 +1,59 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/ide.h ++ * ++ * Author: George Davis ++ * Created: Jan 10, 2002 ++ * Copyright: MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * ++ * Originally based upon linux/include/asm-arm/arch-sa1100/ide.h ++ * ++ */ ++ ++#include <linux/config.h> ++#include <asm/irq.h> ++#include <asm/hardware.h> ++#include <asm/mach-types.h> ++ ++ ++/* ++ * Set up a hw structure for a specified data port, control port and IRQ. ++ * This should follow whatever the default interface uses. ++ */ ++static __inline__ void ++ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq) ++{ ++ ide_ioreg_t reg; ++ ++ memset(hw, 0, sizeof(*hw)); ++ ++ reg = (ide_ioreg_t)data_port; ++ ++ hw->io_ports[IDE_DATA_OFFSET] = reg + 0; ++ hw->io_ports[IDE_ERROR_OFFSET] = reg + 1; ++ hw->io_ports[IDE_NSECTOR_OFFSET] = reg + 2; ++ hw->io_ports[IDE_SECTOR_OFFSET] = reg + 3; ++ hw->io_ports[IDE_LCYL_OFFSET] = reg + 4; ++ hw->io_ports[IDE_HCYL_OFFSET] = reg + 5; ++ hw->io_ports[IDE_SELECT_OFFSET] = reg + 6; ++ hw->io_ports[IDE_STATUS_OFFSET] = reg + 7; ++ ++ hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port; ++ ++ if (irq) ++ *irq = 0; ++} ++ ++ ++/* ++ * Register the standard ports for this architecture with the IDE driver. ++ */ ++static __inline__ void ++ide_init_default_hwifs(void) ++{ ++ /* Nothing to declare... */ ++} +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/idp.h +@@ -0,0 +1,468 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/idp.h ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Copyright (c) 2001 Cliff Brake, Accelent Systems Inc. ++ * ++ * 2001-09-13: Cliff Brake <cbrake@accelent.com> ++ * Initial code ++ * ++ */ ++ ++ ++/* ++ * Note: this file must be safe to include in assembly files ++ */ ++ ++/* comment out following if you have a rev01 board */ ++#define PXA_IDP_REV02 1 ++//#undef PXA_IDP_REV02 ++ ++#ifdef PXA_IDP_REV02 ++ ++//Use this as well for 0017-x004 and greater pcb's: ++#define PXA_IDP_REV04 1 ++ ++#define IDP_FLASH_PHYS (PXA_CS0_PHYS) ++#define IDP_ALT_FLASH_PHYS (PXA_CS1_PHYS) ++#define IDP_MEDIAQ_PHYS (PXA_CS3_PHYS) ++#define IDP_IDE_PHYS (PXA_CS5_PHYS + 0x03000000) ++#define IDP_ETH_PHYS (PXA_CS5_PHYS + 0x03400000) ++#define IDP_COREVOLT_PHYS (PXA_CS5_PHYS + 0x03800000) ++#define IDP_CPLD_PHYS (PXA_CS5_PHYS + 0x03C00000) ++ ++ ++/* ++ * virtual memory map ++ */ ++ ++#define IDP_IDE_BASE (0xf0000000) ++#define IDP_IDE_SIZE (1*1024*1024) ++ ++#define IDP_ETH_BASE (IDP_IDE_BASE + IDP_IDE_SIZE) ++#define IDP_ETH_SIZE (1*1024*1024) ++#define ETH_BASE IDP_ETH_BASE //smc9194 driver compatibility issue ++ ++#define IDP_COREVOLT_BASE (IDP_ETH_BASE + IDP_ETH_SIZE) ++#define IDP_COREVOLT_SIZE (1*1024*1024) ++ ++#define IDP_CPLD_BASE (IDP_COREVOLT_BASE + IDP_COREVOLT_SIZE) ++#define IDP_CPLD_SIZE (1*1024*1024) ++ ++#if (IDP_CPLD_BASE + IDP_CPLD_SIZE) > 0xfc000000 ++#error Your custom IO space is getting a bit large !! ++#endif ++ ++#define CPLD_P2V(x) ((x) - IDP_CPLD_PHYS + IDP_CPLD_BASE) ++#define CPLD_V2P(x) ((x) - IDP_CPLD_BASE + IDP_CPLD_PHYS) ++ ++#ifndef __ASSEMBLY__ ++# define __CPLD_REG(x) (*((volatile unsigned long *)CPLD_P2V(x))) ++#else ++# define __CPLD_REG(x) CPLD_P2V(x) ++#endif ++ ++/* board level registers in the CPLD: (offsets from CPLD_BASE) */ ++ ++#define _IDP_CPLD_REV (IDP_CPLD_PHYS + 0x00) ++#define _IDP_CPLD_PERIPH_PWR (IDP_CPLD_PHYS + 0x04) ++#define _IDP_CPLD_LED_CONTROL (IDP_CPLD_PHYS + 0x08) ++#define _IDP_CPLD_KB_COL_HIGH (IDP_CPLD_PHYS + 0x0C) ++#define _IDP_CPLD_KB_COL_LOW (IDP_CPLD_PHYS + 0x10) ++#define _IDP_CPLD_PCCARD_EN (IDP_CPLD_PHYS + 0x14) ++#define _IDP_CPLD_GPIOH_DIR (IDP_CPLD_PHYS + 0x18) ++#define _IDP_CPLD_GPIOH_VALUE (IDP_CPLD_PHYS + 0x1C) ++#define _IDP_CPLD_GPIOL_DIR (IDP_CPLD_PHYS + 0x20) ++#define _IDP_CPLD_GPIOL_VALUE (IDP_CPLD_PHYS + 0x24) ++#define _IDP_CPLD_PCCARD_PWR (IDP_CPLD_PHYS + 0x28) ++#define _IDP_CPLD_MISC_CTRL (IDP_CPLD_PHYS + 0x2C) ++#define _IDP_CPLD_LCD (IDP_CPLD_PHYS + 0x30) ++#define _IDP_CPLD_FLASH_WE (IDP_CPLD_PHYS + 0x34) ++ ++#define _IDP_CPLD_KB_ROW (IDP_CPLD_PHYS + 0x50) ++#define _IDP_CPLD_PCCARD0_STATUS (IDP_CPLD_PHYS + 0x54) ++#define _IDP_CPLD_PCCARD1_STATUS (IDP_CPLD_PHYS + 0x58) ++#define _IDP_CPLD_MISC_STATUS (IDP_CPLD_PHYS + 0x5C) ++ ++/* FPGA register virtual addresses */ ++ ++#define IDP_CPLD_REV __CPLD_REG(_IDP_CPLD_REV) ++#define IDP_CPLD_PERIPH_PWR __CPLD_REG(_IDP_CPLD_PERIPH_PWR) ++#define IDP_CPLD_LED_CONTROL __CPLD_REG(_IDP_CPLD_LED_CONTROL) ++#define IDP_CPLD_KB_COL_HIGH __CPLD_REG(_IDP_CPLD_KB_COL_HIGH) ++#define IDP_CPLD_KB_COL_LOW __CPLD_REG(_IDP_CPLD_KB_COL_LOW) ++#define IDP_CPLD_PCCARD_EN __CPLD_REG(_IDP_CPLD_PCCARD_EN) ++#define IDP_CPLD_GPIOH_DIR __CPLD_REG(_IDP_CPLD_GPIOH_DIR) ++#define IDP_CPLD_GPIOH_VALUE __CPLD_REG(_IDP_CPLD_GPIOH_VALUE) ++#define IDP_CPLD_GPIOL_DIR __CPLD_REG(_IDP_CPLD_GPIOL_DIR) ++#define IDP_CPLD_GPIOL_VALUE __CPLD_REG(_IDP_CPLD_GPIOL_VALUE) ++#define IDP_CPLD_PCCARD_PWR __CPLD_REG(_IDP_CPLD_PCCARD_PWR) ++#define IDP_CPLD_MISC_CTRL __CPLD_REG(_IDP_CPLD_MISC_CTRL) ++#define IDP_CPLD_LCD __CPLD_REG(_IDP_CPLD_LCD) ++#define IDP_CPLD_FLASH_WE __CPLD_REG(_IDP_CPLD_FLASH_WE) ++ ++#define IDP_CPLD_KB_ROW __CPLD_REG(_IDP_CPLD_KB_ROW) ++#define IDP_CPLD_PCCARD0_STATUS __CPLD_REG(_IDP_CPLD_PCCARD0_STATUS) ++#define IDP_CPLD_PCCARD1_STATUS __CPLD_REG(_IDP_CPLD_PCCARD1_STATUS) ++#define IDP_CPLD_MISC_STATUS __CPLD_REG(_IDP_CPLD_MISC_STATUS) ++ ++ ++/* ++ * Bit masks for various registers ++ */ ++// IDP_CPLD_PCCARD_PWR ++#define PCC0_PWR0 (1 << 0) ++#define PCC0_PWR1 (1 << 1) ++#define PCC0_PWR2 (1 << 2) ++#define PCC0_PWR3 (1 << 3) ++#define PCC1_PWR0 (1 << 4) ++#define PCC1_PWR1 (1 << 5) ++#define PCC1_PWR2 (1 << 6) ++#define PCC1_PWR3 (1 << 7) ++ ++// IDP_CPLD_PCCARD_EN ++#define PCC0_RESET (1 << 6) ++#define PCC1_RESET (1 << 7) ++#define PCC0_ENABLE (1 << 0) ++#define PCC1_ENABLE (1 << 1) ++ ++// IDP_CPLD_PCCARDx_STATUS ++#define _PCC_WRPROT (1 << 7) // 7-4 read as low true ++#define _PCC_RESET (1 << 6) ++#define _PCC_IRQ (1 << 5) ++#define _PCC_INPACK (1 << 4) ++#define PCC_BVD2 (1 << 3) ++#define PCC_BVD1 (1 << 2) ++#define PCC_VS2 (1 << 1) ++#define PCC_VS1 (1 << 0) ++ ++#define PCC_DETECT(x) (GPLR(7 + (x)) & GPIO_bit(7 + (x))) ++ ++/* ++ * Macros for LCD Driver ++ */ ++ ++#ifdef CONFIG_FB_PXA ++ ++#define FB_BACKLIGHT_ON() (IDP_CPLD_LCD |= (1<<1)) ++#define FB_BACKLIGHT_OFF() (IDP_CPLD_LCD &= ~(1<<1)) ++ ++#define FB_PWR_ON() (IDP_CPLD_LCD |= (1<< 0)) ++#define FB_PWR_OFF() (IDP_CPLD_LCD &= ~(1<<0)) ++ ++#define FB_VLCD_ON() (IDP_CPLD_LCD |= (1<<2)) ++#define FB_VLCD_OFF() (IDP_CPLD_LCD &= ~(1<<2)) ++ ++#endif ++ ++/* A listing of interrupts used by external hardware devices */ ++ ++#ifdef PXA_IDP_REV04 ++#define TOUCH_PANEL_IRQ IRQ_GPIO(5) ++#define IDE_IRQ IRQ_GPIO(21) ++#else ++#define TOUCH_PANEL_IRQ IRQ_GPIO(21) ++#define IDE_IRQ IRQ_GPIO(5) ++#endif ++ ++#define TOUCH_PANEL_IRQ_EDGE GPIO_FALLING_EDGE ++ ++#define IDE_IRQ_EDGE GPIO_RISING_EDGE ++ ++#define ETHERNET_IRQ IRQ_GPIO(4) ++#define ETHERNET_IRQ_EDGE GPIO_RISING_EDGE ++ ++#define IDE_IRQ_EDGE GPIO_RISING_EDGE ++ ++#define PCMCIA_S0_CD_VALID IRQ_GPIO(7) ++#define PCMCIA_S0_CD_VALID_EDGE GPIO_BOTH_EDGES ++ ++#define PCMCIA_S1_CD_VALID IRQ_GPIO(8) ++#define PCMCIA_S1_CD_VALID_EDGE GPIO_BOTH_EDGES ++ ++#define PCMCIA_S0_RDYINT IRQ_GPIO(19) ++#define PCMCIA_S1_RDYINT IRQ_GPIO(22) ++ ++/* ++ * Macros for LED Driver ++ */ ++ ++/* leds 0 = ON */ ++#define IDP_HB_LED (1<<5) ++#define IDP_BUSY_LED (1<<6) ++ ++#define IDP_LEDS_MASK (IDP_HB_LED | IDP_BUSY_LED) ++ ++#define IDP_WRITE_LEDS(value) (IDP_CPLD_LED_CONTROL = (IDP_CPLD_LED_CONTROL & (~(IDP_LEDS_MASK)) | value)) ++ ++/* ++ * macros for MTD driver ++ */ ++ ++#define FLASH_WRITE_PROTECT_DISABLE() ((IDP_CPLD_FLASH_WE) &= ~(0x1)) ++#define FLASH_WRITE_PROTECT_ENABLE() ((IDP_CPLD_FLASH_WE) |= (0x1)) ++ ++/* ++ * macros for matrix keyboard driver ++ */ ++ ++#define KEYBD_MATRIX_NUMBER_INPUTS 7 ++#define KEYBD_MATRIX_NUMBER_OUTPUTS 14 ++ ++#define KEYBD_MATRIX_INVERT_OUTPUT_LOGIC FALSE ++#define KEYBD_MATRIX_INVERT_INPUT_LOGIC FALSE ++ ++#define KEYBD_MATRIX_SETTLING_TIME_US 100 ++#define KEYBD_MATRIX_KEYSTATE_DEBOUNCE_CONSTANT 2 ++ ++#define KEYBD_MATRIX_SET_OUTPUTS(outputs) \ ++{\ ++ IDP_CPLD_KB_COL_LOW = outputs;\ ++ IDP_CPLD_KB_COL_HIGH = outputs >> 7;\ ++} ++ ++#define KEYBD_MATRIX_GET_INPUTS(inputs) \ ++{\ ++ inputs = (IDP_CPLD_KB_ROW & 0x7f);\ ++} ++ ++//------------------------------------------------------------------------------ ++ ++#else // must be rev 01 ++ ++/* ----------------------------------------------------------------------------- ++ * following is for rev01 boards only ++ */ ++ ++#define IDP_FLASH_PHYS (PXA_CS0_PHYS) ++#define IDP_ALT_FLASH_PHYS (PXA_CS1_PHYS) ++#define IDP_MEDIAQ_PHYS (PXA_CS3_PHYS) ++#define IDP_CTRL_PORT_PHYS (PXA_CS5_PHYS + 0x02C00000) ++#define IDP_IDE_PHYS (PXA_CS5_PHYS + 0x03000000) ++#define IDP_ETH_PHYS (PXA_CS5_PHYS + 0x03400000) ++#define IDP_COREVOLT_PHYS (PXA_CS5_PHYS + 0x03800000) ++#define IDP_CPLD_PHYS (PXA_CS5_PHYS + 0x03C00000) ++ ++ ++/* ++ * virtual memory map ++ */ ++ ++#define IDP_CTRL_PORT_BASE (0xf0000000) ++#define IDP_CTRL_PORT_SIZE (1*1024*1024) ++ ++#define IDP_IDE_BASE (IDP_CTRL_PORT_BASE + IDP_CTRL_PORT_SIZE) ++#define IDP_IDE_SIZE (1*1024*1024) ++ ++#define IDP_ETH_BASE (IDP_IDE_BASE + IDP_IDE_SIZE) ++#define IDP_ETH_SIZE (1*1024*1024) ++ ++#define IDP_COREVOLT_BASE (IDP_ETH_BASE + IDP_ETH_SIZE) ++#define IDP_COREVOLT_SIZE (1*1024*1024) ++ ++#define IDP_CPLD_BASE (IDP_COREVOLT_BASE + IDP_COREVOLT_SIZE) ++#define IDP_CPLD_SIZE (1*1024*1024) ++ ++#if (IDP_CPLD_BASE + IDP_CPLD_SIZE) > 0xfc000000 ++#error Your custom IO space is getting a bit large !! ++#endif ++ ++#define CPLD_P2V(x) ((x) - IDP_CPLD_PHYS + IDP_CPLD_BASE) ++#define CPLD_V2P(x) ((x) - IDP_CPLD_BASE + IDP_CPLD_PHYS) ++ ++#ifndef __ASSEMBLY__ ++# define __CPLD_REG(x) (*((volatile unsigned long *)CPLD_P2V(x))) ++#else ++# define __CPLD_REG(x) CPLD_P2V(x) ++#endif ++ ++/* board level registers in the CPLD: (offsets from CPLD_BASE) */ ++ ++#define _IDP_CPLD_LED_CONTROL (IDP_CPLD_PHYS + 0x00) ++#define _IDP_CPLD_PERIPH_PWR (IDP_CPLD_PHYS + 0x04) ++#define _IDP_CPLD_CIR (IDP_CPLD_PHYS + 0x08) ++#define _IDP_CPLD_KB_COL_HIGH (IDP_CPLD_PHYS + 0x0C) ++#define _IDP_CPLD_KB_COL_LOW (IDP_CPLD_PHYS + 0x10) ++#define _IDP_CPLD_PCCARD_EN (IDP_CPLD_PHYS + 0x14) ++#define _IDP_CPLD_GPIOH_DIR (IDP_CPLD_PHYS + 0x18) ++#define _IDP_CPLD_GPIOH_VALUE (IDP_CPLD_PHYS + 0x1C) ++#define _IDP_CPLD_GPIOL_DIR (IDP_CPLD_PHYS + 0x20) ++#define _IDP_CPLD_GPIOL_VALUE (IDP_CPLD_PHYS + 0x24) ++#define _IDP_CPLD_MISC (IDP_CPLD_PHYS + 0x28) ++#define _IDP_CPLD_PCCARD0_STATUS (IDP_CPLD_PHYS + 0x2C) ++#define _IDP_CPLD_PCCARD1_STATUS (IDP_CPLD_PHYS + 0x30) ++ ++/* FPGA register virtual addresses */ ++#define IDP_CPLD_LED_CONTROL __CPLD_REG(_IDP_CPLD_LED_CONTROL) /* write only */ ++#define IDP_CPLD_PERIPH_PWR __CPLD_REG(_IDP_CPLD_PERIPH_PWR) /* write only */ ++#define IDP_CPLD_CIR __CPLD_REG(_IDP_CPLD_CIR) /* write only */ ++#define IDP_CPLD_KB_COL_HIGH __CPLD_REG(_IDP_CPLD_KB_COL_HIGH) /* write only */ ++#define IDP_CPLD_KB_COL_LOW __CPLD_REG(_IDP_CPLD_KB_COL_LOW) /* write only */ ++#define IDP_CPLD_PCCARD_EN __CPLD_REG(_IDP_CPLD_PCCARD_EN) /* write only */ ++#define IDP_CPLD_GPIOH_DIR __CPLD_REG(_IDP_CPLD_GPIOH_DIR) /* write only */ ++#define IDP_CPLD_GPIOH_VALUE __CPLD_REG(_IDP_CPLD_GPIOH_VALUE) /* write only */ ++#define IDP_CPLD_GPIOL_DIR __CPLD_REG(_IDP_CPLD_GPIOL_DIR) /* write only */ ++#define IDP_CPLD_GPIOL_VALUE __CPLD_REG(_IDP_CPLD_GPIOL_VALUE) /* write only */ ++#define IDP_CPLD_MISC __CPLD_REG(_IDP_CPLD_MISC) /* read only */ ++#define IDP_CPLD_PCCARD0_STATUS __CPLD_REG(_IDP_CPLD_PCCARD0_STATUS) /* read only */ ++#define IDP_CPLD_PCCARD1_STATUS __CPLD_REG(_IDP_CPLD_PCCARD1_STATUS) /* read only */ ++ ++ ++#ifndef __ASSEMBLY__ ++ ++/* shadow registers for write only registers */ ++extern unsigned int idp_cpld_led_control_shadow; ++extern unsigned int idp_cpld_periph_pwr_shadow; ++extern unsigned int idp_cpld_cir_shadow; ++extern unsigned int idp_cpld_kb_col_high_shadow; ++extern unsigned int idp_cpld_kb_col_low_shadow; ++extern unsigned int idp_cpld_pccard_en_shadow; ++extern unsigned int idp_cpld_gpioh_dir_shadow; ++extern unsigned int idp_cpld_gpioh_value_shadow; ++extern unsigned int idp_cpld_gpiol_dir_shadow; ++extern unsigned int idp_cpld_gpiol_value_shadow; ++ ++extern unsigned int idp_control_port_shadow; ++ ++/* ++ * macros to write to write only register ++ * ++ * none of these macros are protected from ++ * multiple drivers using them in interrupt context. ++ */ ++ ++#define WRITE_IDP_CPLD_LED_CONTROL(value, mask) \ ++{\ ++ idp_cpld_led_control_shadow = ((value & mask) | (idp_cpld_led_control_shadow & ~mask));\ ++ IDP_CPLD_LED_CONTROL = idp_cpld_led_control_shadow;\ ++} ++#define WRITE_IDP_CPLD_PERIPH_PWR(value, mask) \ ++{\ ++ idp_cpld_periph_pwr_shadow = ((value & mask) | (idp_cpld_periph_pwr_shadow & ~mask));\ ++ IDP_CPLD_PERIPH_PWR = idp_cpld_periph_pwr_shadow;\ ++} ++#define WRITE_IDP_CPLD_CIR(value, mask) \ ++{\ ++ idp_cpld_cir_shadow = ((value & mask) | (idp_cpld_cir_shadow & ~mask));\ ++ IDP_CPLD_CIR = idp_cpld_cir_shadow;\ ++} ++#define WRITE_IDP_CPLD_KB_COL_HIGH(value, mask) \ ++{\ ++ idp_cpld_kb_col_high_shadow = ((value & mask) | (idp_cpld_kb_col_high_shadow & ~mask));\ ++ IDP_CPLD_KB_COL_HIGH = idp_cpld_kb_col_high_shadow;\ ++} ++#define WRITE_IDP_CPLD_KB_COL_LOW(value, mask) \ ++{\ ++ idp_cpld_kb_col_low_shadow = ((value & mask) | (idp_cpld_kb_col_low_shadow & ~mask));\ ++ IDP_CPLD_KB_COL_LOW = idp_cpld_kb_col_low_shadow;\ ++} ++#define WRITE_IDP_CPLD_PCCARD_EN(value, mask) \ ++{\ ++ idp_cpld_ = ((value & mask) | (idp_cpld_led_control_shadow & ~mask));\ ++ IDP_CPLD_LED_CONTROL = idp_cpld_led_control_shadow;\ ++} ++#define WRITE_IDP_CPLD_GPIOH_DIR(value, mask) \ ++{\ ++ idp_cpld_gpioh_dir_shadow = ((value & mask) | (idp_cpld_gpioh_dir_shadow & ~mask));\ ++ IDP_CPLD_GPIOH_DIR = idp_cpld_gpioh_dir_shadow;\ ++} ++#define WRITE_IDP_CPLD_GPIOH_VALUE(value, mask) \ ++{\ ++ idp_cpld_gpioh_value_shadow = ((value & mask) | (idp_cpld_gpioh_value_shadow & ~mask));\ ++ IDP_CPLD_GPIOH_VALUE = idp_cpld_gpioh_value_shadow;\ ++} ++#define WRITE_IDP_CPLD_GPIOL_DIR(value, mask) \ ++{\ ++ idp_cpld_gpiol_dir_shadow = ((value & mask) | (idp_cpld_gpiol_dir_shadow & ~mask));\ ++ IDP_CPLD_GPIOL_DIR = idp_cpld_gpiol_dir_shadow;\ ++} ++#define WRITE_IDP_CPLD_GPIOL_VALUE(value, mask) \ ++{\ ++ idp_cpld_gpiol_value_shadow = ((value & mask) | (idp_cpld_gpiol_value_shadow & ~mask));\ ++ IDP_CPLD_GPIOL_VALUE = idp_cpld_gpiol_value_shadow;\ ++} ++ ++#define WRITE_IDP_CONTROL_PORT(value, mask) \ ++{\ ++ idp_control_port_shadow = ((value & mask) | (idp_control_port_shadow & ~mask));\ ++ (*((volatile unsigned long *)IDP_CTRL_PORT_BASE)) = idp_control_port_shadow;\ ++} ++ ++#endif ++ ++/* A listing of interrupts used by external hardware devices */ ++ ++#define TOUCH_PANEL_IRQ IRQ_GPIO(21) ++#define TOUCH_PANEL_IRQ_EGDE GPIO_FALLING_EDGE ++ ++#define ETHERNET_IRQ IRQ_GPIO(4) ++#define ETHERNET_IRQ_EDGE GPIO_RISING_EDGE ++ ++/* ++ * Bit masks for various registers ++ */ ++ ++ ++/* control port */ ++#define IDP_CONTROL_PORT_PCSLOT0_0 (1 << 0) ++#define IDP_CONTROL_PORT_PCSLOT0_1 (1 << 1) ++#define IDP_CONTROL_PORT_PCSLOT0_2 (1 << 2) ++#define IDP_CONTROL_PORT_PCSLOT0_3 (1 << 3) ++#define IDP_CONTROL_PORT_PCSLOT1_1 (1 << 4) ++#define IDP_CONTROL_PORT_PCSLOT1_2 (1 << 5) ++#define IDP_CONTROL_PORT_PCSLOT1_3 (1 << 6) ++#define IDP_CONTROL_PORT_PCSLOT1_4 (1 << 7) ++#define IDP_CONTROL_PORT_SERIAL1_EN (1 << 9) ++#define IDP_CONTROL_PORT_SERIAL2_EN (1 << 10) ++#define IDP_CONTROL_PORT_SERIAL3_EN (1 << 11) ++#define IDP_CONTROL_PORT_IRDA_FIR (1 << 12) ++#define IDP_CONTROL_PORT_IRDA_M0 (1 << 13) ++#define IDP_CONTROL_PORT_IRDA_M1 (1 << 14) ++#define IDP_CONTROL_PORT_I2S_PWR (1 << 15) ++#define IDP_CONTROL_PORT_FLASH_WP (1 << 19) ++#define IDP_CONTROL_PORT_MILL_EN (1 << 20) ++#define IDP_CONTROL_PORT_LCD_PWR (1 << 21) ++#define IDP_CONTROL_PORT_LCD_BKLEN (1 << 22) ++#define IDP_CONTROL_PORT_LCD_ENAVLCD (1 << 23) ++ ++/* ++ * Macros for LCD Driver ++ */ ++ ++#ifdef CONFIG_FB_PXA ++ ++#define FB_BACKLIGHT_ON() WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_LCD_BKLEN, IDP_CONTROL_PORT_LCD_BKLEN) ++#define FB_BACKLIGHT_OFF() WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_LCD_BKLEN) ++ ++#define FB_PWR_ON() WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_LCD_PWR, IDP_CONTROL_PORT_LCD_PWR) ++#define FB_PWR_OFF() WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_LCD_PWR) ++ ++#define FB_VLCD_ON() WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_LCD_ENAVLCD, IDP_CONTROL_PORT_LCD_ENAVLCD) ++#define FB_VLCD_OFF() WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_LCD_ENAVLCD) ++ ++#endif ++ ++ ++/* ++ * Macros for LED Driver ++ */ ++ ++/* leds 0 = ON */ ++#define IDP_HB_LED 0x1 ++#define IDP_BUSY_LED 0x2 ++ ++#define IDP_LEDS_MASK (IDP_HB_LED | IDP_BUSY_LED) ++ ++#define IDP_WRITE_LEDS(value) WRITE_IDP_CPLD_LED_CONTROL(value, IDP_LEDS_MASK) ++ ++/* ++ * macros for MTD driver ++ */ ++ ++#define FLASH_WRITE_PROTECT_DISABLE() WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_FLASH_WP) ++#define FLASH_WRITE_PROTECT_ENABLE() WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_FLASH_WP, IDP_CONTROL_PORT_FLASH_WP) ++ ++#endif +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/innokom.h +@@ -0,0 +1,47 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/innokom.h ++ * ++ * (c) 2003 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++/* ++ * GPIOs ++ */ ++#define GPIO_INNOKOM_RESET 3 ++#define GPIO_INNOKOM_SW_UPDATE 11 ++#define GPIO_INNOKOM_ETH 59 ++ ++/* ++ * ethernet chip (SMSC91C111) ++ */ ++#define INNOKOM_ETH_PHYS PXA_CS5_PHYS ++#define INNOKOM_ETH_BASE (0xf0000000) /* phys 0x14000000 */ ++#define INNOKOM_ETH_SIZE (1*1024*1024) ++#define INNOKOM_ETH_IRQ IRQ_GPIO(GPIO_INNOKOM_ETH) ++#define INNOKOM_ETH_IRQ_EDGE GPIO_RISING_EDGE ++ ++/* ++ * virtual to physical conversion macros ++ */ ++#define INNOKOM_P2V(x) ((x) - INNOKOM_FPGA_PHYS + INNOKOM_FPGA_VIRT) ++#define INNOKOM_V2P(x) ((x) - INNOKOM_FPGA_VIRT + INNOKOM_FPGA_PHYS) ++ ++#ifndef __ASSEMBLY__ ++# define __INNOKOM_REG(x) (*((volatile unsigned long *)INNOKOM_P2V(x))) ++#else ++# define __INNOKOM_REG(x) INNOKOM_P2V(x) ++#endif +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/io.h +@@ -0,0 +1,34 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/io.h ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef __ASM_ARM_ARCH_IO_H ++#define __ASM_ARM_ARCH_IO_H ++ ++#define IO_SPACE_LIMIT 0xffffffff ++ ++/* ++ * We don't actually have real ISA nor PCI buses, but there is so many ++ * drivers out there that might just work if we fake them... ++ */ ++#define __io(a) (a) ++#define __mem_pci(a) ((unsigned long)(a)) ++#define __mem_isa(a) ((unsigned long)(a)) ++ ++/* ++ * Generic virtual read/write ++ */ ++#define __arch_getw(a) (*(volatile unsigned short *)(a)) ++#define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v)) ++ ++#define iomem_valid_addr(iomem,sz) (1) ++#define iomem_to_phys(iomem) (iomem) ++ ++#endif +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/irq.h +@@ -0,0 +1,19 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/irq.h ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#define fixup_irq(x) (x) ++ ++/* ++ * This prototype is required for cascading of multiplexed interrupts. ++ * Since it doesn't exist elsewhere, we'll put it here for now. ++ */ ++extern void do_IRQ(int irq, struct pt_regs *regs); +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/irqs.h +@@ -0,0 +1,137 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/irqs.h ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#define PXA_IRQ_SKIP 7 /* The first 7 IRQs are not yet used */ ++#define PXA_IRQ(x) ((x) - PXA_IRQ_SKIP) ++ ++#define IRQ_HWUART PXA_IRQ(7) /* HWUART Transmit/Receive/Error */ ++#define IRQ_GPIO0 PXA_IRQ(8) /* GPIO0 Edge Detect */ ++#define IRQ_GPIO1 PXA_IRQ(9) /* GPIO1 Edge Detect */ ++#define IRQ_GPIO_2_80 PXA_IRQ(10) /* GPIO[2-80] Edge Detect */ ++#define IRQ_USB PXA_IRQ(11) /* USB Service */ ++#define IRQ_PMU PXA_IRQ(12) /* Performance Monitoring Unit */ ++#define IRQ_I2S PXA_IRQ(13) /* I2S Interrupt */ ++#define IRQ_AC97 PXA_IRQ(14) /* AC97 Interrupt */ ++#define IRQ_ASSP PXA_IRQ(15) /* Audio SSP Service Request */ ++#define IRQ_NSSP PXA_IRQ(16) /* Network SSP Service Request */ ++#define IRQ_LCD PXA_IRQ(17) /* LCD Controller Service Request */ ++#define IRQ_I2C PXA_IRQ(18) /* I2C Service Request */ ++#define IRQ_ICP PXA_IRQ(19) /* ICP Transmit/Receive/Error */ ++#define IRQ_STUART PXA_IRQ(20) /* STUART Transmit/Receive/Error */ ++#define IRQ_BTUART PXA_IRQ(21) /* BTUART Transmit/Receive/Error */ ++#define IRQ_FFUART PXA_IRQ(22) /* FFUART Transmit/Receive/Error*/ ++#define IRQ_MMC PXA_IRQ(23) /* MMC Status/Error Detection */ ++#define IRQ_SSP PXA_IRQ(24) /* SSP Service Request */ ++#define IRQ_DMA PXA_IRQ(25) /* DMA Channel Service Request */ ++#define IRQ_OST0 PXA_IRQ(26) /* OS Timer match 0 */ ++#define IRQ_OST1 PXA_IRQ(27) /* OS Timer match 1 */ ++#define IRQ_OST2 PXA_IRQ(28) /* OS Timer match 2 */ ++#define IRQ_OST3 PXA_IRQ(29) /* OS Timer match 3 */ ++#define IRQ_RTC1Hz PXA_IRQ(30) /* RTC HZ Clock Tick */ ++#define IRQ_RTCAlrm PXA_IRQ(31) /* RTC Alarm */ ++ ++#define GPIO_2_80_TO_IRQ(x) \ ++ PXA_IRQ((x) - 2 + 32) ++#define IRQ_GPIO(x) (((x) < 2) ? (IRQ_GPIO0 + (x)) : GPIO_2_80_TO_IRQ(x)) ++ ++#define IRQ_TO_GPIO_2_80(i) \ ++ ((i) - PXA_IRQ(32) + 2) ++#define IRQ_TO_GPIO(i) ((i) - (((i) > IRQ_GPIO1) ? IRQ_GPIO(2) - 2 : IRQ_GPIO(0))) ++ ++#define NR_IRQS (IRQ_GPIO(80) + 1) ++ ++#if defined(CONFIG_SA1111) ++ ++#define IRQ_SA1111_START (IRQ_GPIO(80) + 1) ++#define SA1111_IRQ(x) (IRQ_SA1111_START + (x)) ++ ++#define IRQ_GPAIN0 SA1111_IRQ(0) ++#define IRQ_GPAIN1 SA1111_IRQ(1) ++#define IRQ_GPAIN2 SA1111_IRQ(2) ++#define IRQ_GPAIN3 SA1111_IRQ(3) ++#define IRQ_GPBIN0 SA1111_IRQ(4) ++#define IRQ_GPBIN1 SA1111_IRQ(5) ++#define IRQ_GPBIN2 SA1111_IRQ(6) ++#define IRQ_GPBIN3 SA1111_IRQ(7) ++#define IRQ_GPBIN4 SA1111_IRQ(8) ++#define IRQ_GPBIN5 SA1111_IRQ(9) ++#define IRQ_GPCIN0 SA1111_IRQ(10) ++#define IRQ_GPCIN1 SA1111_IRQ(11) ++#define IRQ_GPCIN2 SA1111_IRQ(12) ++#define IRQ_GPCIN3 SA1111_IRQ(13) ++#define IRQ_GPCIN4 SA1111_IRQ(14) ++#define IRQ_GPCIN5 SA1111_IRQ(15) ++#define IRQ_GPCIN6 SA1111_IRQ(16) ++#define IRQ_GPCIN7 SA1111_IRQ(17) ++#define IRQ_MSTXINT SA1111_IRQ(18) ++#define IRQ_MSRXINT SA1111_IRQ(19) ++#define IRQ_MSSTOPERRINT SA1111_IRQ(20) ++#define IRQ_TPTXINT SA1111_IRQ(21) ++#define IRQ_TPRXINT SA1111_IRQ(22) ++#define IRQ_TPSTOPERRINT SA1111_IRQ(23) ++#define SSPXMTINT SA1111_IRQ(24) ++#define SSPRCVINT SA1111_IRQ(25) ++#define SSPROR SA1111_IRQ(26) ++#define AUDXMTDMADONEA SA1111_IRQ(32) ++#define AUDRCVDMADONEA SA1111_IRQ(33) ++#define AUDXMTDMADONEB SA1111_IRQ(34) ++#define AUDRCVDMADONEB SA1111_IRQ(35) ++#define AUDTFSR SA1111_IRQ(36) ++#define AUDRFSR SA1111_IRQ(37) ++#define AUDTUR SA1111_IRQ(38) ++#define AUDROR SA1111_IRQ(39) ++#define AUDDTS SA1111_IRQ(40) ++#define AUDRDD SA1111_IRQ(41) ++#define AUDSTO SA1111_IRQ(42) ++#define USBPWR SA1111_IRQ(43) ++#define NIRQHCIM SA1111_IRQ(44) ++#define HCIBUFFACC SA1111_IRQ(45) ++#define HCIRMTWKP SA1111_IRQ(46) ++#define NHCIMFCIR SA1111_IRQ(47) ++#define PORT_RESUME SA1111_IRQ(48) ++#define S0_READY_NINT SA1111_IRQ(49) ++#define S1_READY_NINT SA1111_IRQ(50) ++#define S0_CD_VALID SA1111_IRQ(51) ++#define S1_CD_VALID SA1111_IRQ(52) ++#define S0_BVD1_STSCHG SA1111_IRQ(53) ++#define S1_BVD1_STSCHG SA1111_IRQ(54) ++ ++#define SA1111_IRQ_MAX SA1111_IRQ(54) ++ ++#undef NR_IRQS ++#define NR_IRQS (SA1111_IRQ_MAX + 1) ++ ++#endif // defined(CONFIG_SA1111) ++ ++#if defined(CONFIG_ARCH_LUBBOCK) || defined(CONFIG_ARCH_PXA_IDP) ++#if CONFIG_SA1111 ++#define LUBBOCK_IRQ(x) (SA1111_IRQ_MAX + 1 + (x)) ++#else ++#define LUBBOCK_IRQ(x) (IRQ_GPIO(80) + 1 + (x)) ++#endif ++ ++#define LUBBOCK_SD_IRQ LUBBOCK_IRQ(0) ++#define LUBBOCK_SA1111_IRQ LUBBOCK_IRQ(1) ++#define LUBBOCK_USB_IRQ LUBBOCK_IRQ(2) ++#define LUBBOCK_ETH_IRQ LUBBOCK_IRQ(3) ++#define LUBBOCK_UCB1400_IRQ LUBBOCK_IRQ(4) ++#define LUBBOCK_BB_IRQ LUBBOCK_IRQ(5) ++#define LUBBOCK_USB_DISC_IRQ LUBBOCK_IRQ(6) /* usb disconnect */ ++#define LUBBOCK_LAST_IRQ LUBBOCK_IRQ(6) ++ ++#undef NR_IRQS ++#define NR_IRQS (LUBBOCK_LAST_IRQ + 1) ++ ++#endif // CONFIG_ARCH_LUBBOCK ++ ++ ++ +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/keyboard.h +@@ -0,0 +1,29 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/keyboard.h ++ * ++ * This file contains the architecture specific keyboard definitions ++ */ ++ ++#ifndef _PXA_KEYBOARD_H ++#define _PXA_KEYBOARD_H ++ ++#include <linux/config.h> ++#include <asm/mach-types.h> ++#include <asm/hardware.h> ++ ++extern struct kbd_ops_struct *kbd_ops; ++ ++#define kbd_disable_irq() do { } while(0); ++#define kbd_enable_irq() do { } while(0); ++ ++extern int sa1111_kbd_init_hw(void); ++ ++static inline void kbd_init_hw(void) ++{ ++ if (machine_is_lubbock()) ++ sa1111_kbd_init_hw(); ++} ++ ++ ++#endif /* _PXA_KEYBOARD_H */ ++ +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/lubbock.h +@@ -0,0 +1,113 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/lubbock.h ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#define LUBBOCK_FPGA_PHYS PXA_CS2_PHYS ++#define LUBBOCK_FPGA_VIRT (0xf0000000) /* phys 0x08000000 */ ++#define LUBBOCK_ETH_PHYS PXA_CS3_PHYS ++#define LUBBOCK_ETH_VIRT (0xf1000000) ++#define LUBBOCK_SA1111_BASE (0xf4000000) /* phys 0x10000000 */ ++ ++#define LUB_P2V(x) ((x) - LUBBOCK_FPGA_PHYS + LUBBOCK_FPGA_VIRT) ++#define LUB_V2P(x) ((x) - LUBBOCK_FPGA_VIRT + LUBBOCK_FPGA_PHYS) ++ ++#ifndef __ASSEMBLY__ ++# define __LUB_REG(x) (*((volatile unsigned long *)LUB_P2V(x))) ++#else ++# define __LUB_REG(x) LUB_P2V(x) ++#endif ++ ++/* board level registers in the CPLD: (offsets from CPLD_BASE) */ ++ ++#define WHOAMI 0 // card ID's (see programmers manual) ++#define HEX_LED 0x10 // R/W access to 8 7 segment displays ++#define DISC_BLNK_LED 0x40 // R/W [15-8] enables for hex leds, [7-0] discrete LEDs ++#define CONF_SWITCHES 0x50 // RO [1] flash wrt prot, [0] 0= boot from rom, 1= flash ++#define USER_SWITCHES 0x60 // RO [15-8] dip switches, [7-0] 2 hex encoding switches ++#define MISC_WR 0x80 // R/W various system controls -see manual ++#define MISC_RD 0x90 // RO various system status bits -see manual ++//#define LUB_IRQ_MASK_EN 0xC0 // R/W 0= mask, 1= enable of TS, codec, ethernet, USB, SA1111, and card det. irq's ++//#define LUB_IRQ_SET_CLR 0xD0 // R/W 1= set, 0 = clear IRQ's from TS, codec, etc... ++//#define LUB_GP 0x100 // R/W [15-0] 16 bits of general purpose I/o for hacking ++ ++ ++/* FPGA register physical addresses */ ++#define _LUB_WHOAMI (LUBBOCK_FPGA_PHYS + 0x000) ++#define _LUB_HEXLED (LUBBOCK_FPGA_PHYS + 0x010) ++#define _LUB_DISC_BLNK_LED (LUBBOCK_FPGA_PHYS + 0x040) ++#define _LUB_CONF_SWITCHES (LUBBOCK_FPGA_PHYS + 0x050) ++#define _LUB_USER_SWITCHES (LUBBOCK_FPGA_PHYS + 0x060) ++#define _LUB_MISC_WR (LUBBOCK_FPGA_PHYS + 0x080) ++#define _LUB_MISC_RD (LUBBOCK_FPGA_PHYS + 0x090) ++#define _LUB_IRQ_MASK_EN (LUBBOCK_FPGA_PHYS + 0x0C0) ++#define _LUB_IRQ_SET_CLR (LUBBOCK_FPGA_PHYS + 0x0D0) ++#define _LUB_GP (LUBBOCK_FPGA_PHYS + 0x100) ++ ++/* FPGA register virtual addresses */ ++#define LUB_WHOAMI __LUB_REG(_LUB_WHOAMI) ++#define LUB_HEXLED __LUB_REG(_LUB_HEXLED) ++#define LUB_DISC_BLNK_LED __LUB_REG(_LUB_DISC_BLNK_LED) ++#define LUB_CONF_SWITCHES __LUB_REG(_LUB_CONF_SWITCHES) ++#define LUB_USER_SWITCHES __LUB_REG(_LUB_USER_SWITCHES) ++#define LUB_MISC_WR __LUB_REG(_LUB_MISC_WR) ++#define LUB_MISC_RD __LUB_REG(_LUB_MISC_RD) ++#define LUB_IRQ_MASK_EN __LUB_REG(_LUB_IRQ_MASK_EN) ++#define LUB_IRQ_SET_CLR __LUB_REG(_LUB_IRQ_SET_CLR) ++#define LUB_GP __LUB_REG(_LUB_GP) ++ ++/* GPIOs */ ++ ++#define GPIO_LUBBOCK_IRQ 0 ++#define IRQ_GPIO_LUBBOCK_IRQ IRQ_GPIO0 ++ ++ ++/* ++ * LED macros ++ */ ++ ++#define LEDS_BASE LUB_DISC_BLNK_LED ++ ++// 8 discrete leds available for general use: ++ ++#define D28 0x1 ++#define D27 0x2 ++#define D26 0x4 ++#define D25 0x8 ++#define D24 0x10 ++#define D23 0x20 ++#define D22 0x40 ++#define D21 0x80 ++ ++/* Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays so ++* be sure to not monkey with them here. ++*/ ++ ++#define HEARTBEAT_LED D28 ++#define SYS_BUSY_LED D27 ++#define HEXLEDS_BASE LUB_HEXLED ++ ++#define HEARTBEAT_LED_ON (LEDS_BASE &= ~HEARTBEAT_LED) ++#define HEARTBEAT_LED_OFF (LEDS_BASE |= HEARTBEAT_LED) ++#define SYS_BUSY_LED_OFF (LEDS_BASE |= SYS_BUSY_LED) ++#define SYS_BUSY_LED_ON (LEDS_BASE &= ~SYS_BUSY_LED) ++ ++// use x = D26-D21 for these, please... ++#define DISCRETE_LED_ON(x) (LEDS_BASE &= ~(x)) ++#define DISCRETE_LED_OFF(x) (LEDS_BASE |= (x)) ++ ++#ifndef __ASSEMBLY__ ++ ++//extern int hexled_val = 0; ++ ++#endif ++ ++#define BUMP_COUNTER (HEXLEDS_BASE = hexled_val++) ++#define DEC_COUNTER (HEXLEDS_BASE = hexled_val--) +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/memory.h +@@ -0,0 +1,106 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/memory.h ++ * ++ * Author: Nicolas Pitre ++ * Copyright: (C) 2001 MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASM_ARCH_MEMORY_H ++#define __ASM_ARCH_MEMORY_H ++ ++ ++/* ++ * Task size: 3GB ++ */ ++#define TASK_SIZE (0xc0000000UL) ++#define TASK_SIZE_26 (0x04000000UL) ++ ++/* ++ * This decides where the kernel will search for a free chunk of vm ++ * space during mmap's. ++ */ ++#define TASK_UNMAPPED_BASE (TASK_SIZE / 3) ++ ++/* ++ * Page offset: 3GB ++ */ ++#define PAGE_OFFSET (0xc0000000UL) ++ ++/* ++ * Physical DRAM offset. ++ */ ++#define PHYS_OFFSET (0xa0000000UL) ++ ++/* ++ * physical vs virtual ram conversion ++ */ ++#define __virt_to_phys__is_a_macro ++#define __phys_to_virt__is_a_macro ++#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET) ++#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET) ++ ++/* ++ * Virtual view <-> DMA view memory address translations ++ * virt_to_bus: Used to translate the virtual address to an ++ * address suitable to be passed to set_dma_addr ++ * bus_to_virt: Used to convert an address for DMA operations ++ * to an address that the kernel can use. ++ */ ++#define __virt_to_bus__is_a_macro ++#define __bus_to_virt__is_a_macro ++#define __virt_to_bus(x) __virt_to_phys(x) ++#define __bus_to_virt(x) __phys_to_virt(x) ++ ++#ifdef CONFIG_DISCONTIGMEM ++/* ++ * The nodes are matched with the physical SDRAM banks as follows: ++ * ++ * node 0: 0xa0000000-0xa3ffffff --> 0xc0000000-0xc3ffffff ++ * node 1: 0xa4000000-0xa7ffffff --> 0xc4000000-0xc7ffffff ++ * node 2: 0xa8000000-0xabffffff --> 0xc8000000-0xcbffffff ++ * node 3: 0xac000000-0xafffffff --> 0xcc000000-0xcfffffff ++ */ ++ ++#define NR_NODES 4 ++ ++/* ++ * Given a kernel address, find the home node of the underlying memory. ++ */ ++#define KVADDR_TO_NID(addr) (((unsigned long)(addr) - PAGE_OFFSET) >> 26) ++ ++/* ++ * Given a page frame number, convert it to a node id. ++ */ ++#define PFN_TO_NID(pfn) (((pfn) - PHYS_PFN_OFFSET) >> (26 - PAGE_SHIFT)) ++ ++/* ++ * Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory ++ * and returns the mem_map of that node. ++ */ ++#define ADDR_TO_MAPBASE(kaddr) NODE_MEM_MAP(KVADDR_TO_NID(kaddr)) ++ ++/* ++ * Given a page frame number, find the owning node of the memory ++ * and returns the mem_map of that node. ++ */ ++#define PFN_TO_MAPBASE(pfn) NODE_MEM_MAP(PFN_TO_NID(pfn)) ++ ++/* ++ * Given a kaddr, LOCAL_MEM_MAP finds the owning node of the memory ++ * and returns the index corresponding to the appropriate page in the ++ * node's mem_map. ++ */ ++#define LOCAL_MAP_NR(addr) \ ++ (((unsigned long)(addr) & 0x03ffffff) >> PAGE_SHIFT) ++ ++#else ++ ++#define PFN_TO_NID(addr) (0) ++ ++#endif ++ ++#endif +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/param.h +@@ -0,0 +1,3 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/param.h ++ */ +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/pcmcia.h +@@ -0,0 +1,65 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/pcmcia.h ++ * ++ * Author: George Davis ++ * Created: Jan 10, 2002 ++ * Copyright: MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * ++ * Originally based upon linux/include/asm-arm/arch-sa1100/pcmcia.h ++ * ++ */ ++ ++#ifndef _ASM_ARCH_PCMCIA ++#define _ASM_ARCH_PCMCIA ++ ++ ++/* Ideally, we'd support up to MAX_SOCK sockets, but PXA250 only ++ * provides support for a maximum of two. ++ */ ++#define PXA_PCMCIA_MAX_SOCK (2) ++ ++ ++#ifndef __ASSEMBLY__ ++ ++struct pcmcia_init { ++ void (*handler)(int irq, void *dev, struct pt_regs *regs); ++}; ++ ++struct pcmcia_state { ++ unsigned detect: 1, ++ ready: 1, ++ bvd1: 1, ++ bvd2: 1, ++ wrprot: 1, ++ vs_3v: 1, ++ vs_Xv: 1; ++}; ++ ++struct pcmcia_state_array { ++ unsigned int size; ++ struct pcmcia_state *state; ++}; ++ ++struct pcmcia_irq_info { ++ unsigned int sock; ++ unsigned int irq; ++}; ++ ++struct pcmcia_low_level { ++ int (*init)(struct pcmcia_init *); ++ int (*shutdown)(void); ++ int (*socket_state)(struct pcmcia_state_array *); ++ int (*get_irq_info)(struct pcmcia_irq_info *); ++ int (*configure_socket)(unsigned int, socket_state_t *); ++}; ++ ++extern struct pcmcia_low_level *pcmcia_low_level; ++ ++#endif /* __ASSEMBLY__ */ ++ ++#endif +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/pxa-regs.h +@@ -0,0 +1,1327 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/pxa-regs.h ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef _PXA_REGS_H_ ++#define _PXA_REGS_H_ ++ ++#include "bitfield.h" ++ ++ ++// FIXME hack so that SA-1111.h will work [cb] ++ ++#ifndef __ASSEMBLY__ ++typedef unsigned short Word16 ; ++typedef unsigned int Word32 ; ++typedef Word32 Word ; ++typedef Word Quad [4] ; ++typedef void *Address ; ++typedef void (*ExcpHndlr) (void) ; ++#endif ++ ++/* ++ * PXA Chip selects ++ */ ++ ++#define PXA_CS0_PHYS 0x00000000 ++#define PXA_CS1_PHYS 0x04000000 ++#define PXA_CS2_PHYS 0x08000000 ++#define PXA_CS3_PHYS 0x0C000000 ++#define PXA_CS4_PHYS 0x10000000 ++#define PXA_CS5_PHYS 0x14000000 ++ ++ ++/* ++ * Personal Computer Memory Card International Association (PCMCIA) sockets ++ */ ++ ++#define PCMCIAPrtSp 0x04000000 /* PCMCIA Partition Space [byte] */ ++#define PCMCIASp (4*PCMCIAPrtSp) /* PCMCIA Space [byte] */ ++#define PCMCIAIOSp PCMCIAPrtSp /* PCMCIA I/O Space [byte] */ ++#define PCMCIAAttrSp PCMCIAPrtSp /* PCMCIA Attribute Space [byte] */ ++#define PCMCIAMemSp PCMCIAPrtSp /* PCMCIA Memory Space [byte] */ ++ ++#define PCMCIA0Sp PCMCIASp /* PCMCIA 0 Space [byte] */ ++#define PCMCIA0IOSp PCMCIAIOSp /* PCMCIA 0 I/O Space [byte] */ ++#define PCMCIA0AttrSp PCMCIAAttrSp /* PCMCIA 0 Attribute Space [byte] */ ++#define PCMCIA0MemSp PCMCIAMemSp /* PCMCIA 0 Memory Space [byte] */ ++ ++#define PCMCIA1Sp PCMCIASp /* PCMCIA 1 Space [byte] */ ++#define PCMCIA1IOSp PCMCIAIOSp /* PCMCIA 1 I/O Space [byte] */ ++#define PCMCIA1AttrSp PCMCIAAttrSp /* PCMCIA 1 Attribute Space [byte] */ ++#define PCMCIA1MemSp PCMCIAMemSp /* PCMCIA 1 Memory Space [byte] */ ++ ++#define _PCMCIA(Nb) /* PCMCIA [0..1] */ \ ++ (0x20000000 + (Nb)*PCMCIASp) ++#define _PCMCIAIO(Nb) _PCMCIA (Nb) /* PCMCIA I/O [0..1] */ ++#define _PCMCIAAttr(Nb) /* PCMCIA Attribute [0..1] */ \ ++ (_PCMCIA (Nb) + 2*PCMCIAPrtSp) ++#define _PCMCIAMem(Nb) /* PCMCIA Memory [0..1] */ \ ++ (_PCMCIA (Nb) + 3*PCMCIAPrtSp) ++ ++#define _PCMCIA0 _PCMCIA (0) /* PCMCIA 0 */ ++#define _PCMCIA0IO _PCMCIAIO (0) /* PCMCIA 0 I/O */ ++#define _PCMCIA0Attr _PCMCIAAttr (0) /* PCMCIA 0 Attribute */ ++#define _PCMCIA0Mem _PCMCIAMem (0) /* PCMCIA 0 Memory */ ++ ++#define _PCMCIA1 _PCMCIA (1) /* PCMCIA 1 */ ++#define _PCMCIA1IO _PCMCIAIO (1) /* PCMCIA 1 I/O */ ++#define _PCMCIA1Attr _PCMCIAAttr (1) /* PCMCIA 1 Attribute */ ++#define _PCMCIA1Mem _PCMCIAMem (1) /* PCMCIA 1 Memory */ ++ ++ ++ ++/* ++ * DMA Controller ++ */ ++ ++#define DCSR0 __REG(0x40000000) /* DMA Control / Status Register for Channel 0 */ ++#define DCSR1 __REG(0x40000004) /* DMA Control / Status Register for Channel 1 */ ++#define DCSR2 __REG(0x40000008) /* DMA Control / Status Register for Channel 2 */ ++#define DCSR3 __REG(0x4000000c) /* DMA Control / Status Register for Channel 3 */ ++#define DCSR4 __REG(0x40000010) /* DMA Control / Status Register for Channel 4 */ ++#define DCSR5 __REG(0x40000014) /* DMA Control / Status Register for Channel 5 */ ++#define DCSR6 __REG(0x40000018) /* DMA Control / Status Register for Channel 6 */ ++#define DCSR7 __REG(0x4000001c) /* DMA Control / Status Register for Channel 7 */ ++#define DCSR8 __REG(0x40000020) /* DMA Control / Status Register for Channel 8 */ ++#define DCSR9 __REG(0x40000024) /* DMA Control / Status Register for Channel 9 */ ++#define DCSR10 __REG(0x40000028) /* DMA Control / Status Register for Channel 10 */ ++#define DCSR11 __REG(0x4000002c) /* DMA Control / Status Register for Channel 11 */ ++#define DCSR12 __REG(0x40000030) /* DMA Control / Status Register for Channel 12 */ ++#define DCSR13 __REG(0x40000034) /* DMA Control / Status Register for Channel 13 */ ++#define DCSR14 __REG(0x40000038) /* DMA Control / Status Register for Channel 14 */ ++#define DCSR15 __REG(0x4000003c) /* DMA Control / Status Register for Channel 15 */ ++ ++#define DCSR(x) __REG2(0x40000000, (x) << 2) ++ ++#define DCSR_RUN (1 << 31) /* Run Bit (read / write) */ ++#define DCSR_NODESC (1 << 30) /* No-Descriptor Fetch (read / write) */ ++#define DCSR_STOPIRQEN (1 << 29) /* Stop Interrupt Enable (read / write) */ ++#define DCSR_REQPEND (1 << 8) /* Request Pending (read-only) */ ++#define DCSR_STOPSTATE (1 << 3) /* Stop State (read-only) */ ++#define DCSR_ENDINTR (1 << 2) /* End Interrupt (read / write) */ ++#define DCSR_STARTINTR (1 << 1) /* Start Interrupt (read / write) */ ++#define DCSR_BUSERR (1 << 0) /* Bus Error Interrupt (read / write) */ ++ ++#define DINT __REG(0x400000f0) /* DMA Interrupt Register */ ++ ++#define DRCMR0 __REG(0x40000100) /* Request to Channel Map Register for DREQ 0 */ ++#define DRCMR1 __REG(0x40000104) /* Request to Channel Map Register for DREQ 1 */ ++#define DRCMR2 __REG(0x40000108) /* Request to Channel Map Register for I2S receive Request */ ++#define DRCMR3 __REG(0x4000010c) /* Request to Channel Map Register for I2S transmit Request */ ++#define DRCMR4 __REG(0x40000110) /* Request to Channel Map Register for BTUART receive Request */ ++#define DRCMR5 __REG(0x40000114) /* Request to Channel Map Register for BTUART transmit Request. */ ++#define DRCMR6 __REG(0x40000118) /* Request to Channel Map Register for FFUART receive Request */ ++#define DRCMR7 __REG(0x4000011c) /* Request to Channel Map Register for FFUART transmit Request */ ++#define DRCMR8 __REG(0x40000120) /* Request to Channel Map Register for AC97 microphone Request */ ++#define DRCMR9 __REG(0x40000124) /* Request to Channel Map Register for AC97 modem receive Request */ ++#define DRCMR10 __REG(0x40000128) /* Request to Channel Map Register for AC97 modem transmit Request */ ++#define DRCMR11 __REG(0x4000012c) /* Request to Channel Map Register for AC97 audio receive Request */ ++#define DRCMR12 __REG(0x40000130) /* Request to Channel Map Register for AC97 audio transmit Request */ ++#define DRCMR13 __REG(0x40000134) /* Request to Channel Map Register for SSP receive Request */ ++#define DRCMR14 __REG(0x40000138) /* Request to Channel Map Register for SSP transmit Request */ ++#define DRCMR15 __REG(0x4000013c) /* Reserved */ ++#define DRCMR16 __REG(0x40000140) /* Reserved */ ++#define DRCMR17 __REG(0x40000144) /* Request to Channel Map Register for ICP receive Request */ ++#define DRCMR18 __REG(0x40000148) /* Request to Channel Map Register for ICP transmit Request */ ++#define DRCMR19 __REG(0x4000014c) /* Request to Channel Map Register for STUART receive Request */ ++#define DRCMR20 __REG(0x40000150) /* Request to Channel Map Register for STUART transmit Request */ ++#define DRCMR21 __REG(0x40000154) /* Request to Channel Map Register for MMC receive Request */ ++#define DRCMR22 __REG(0x40000158) /* Request to Channel Map Register for MMC transmit Request */ ++#define DRCMR23 __REG(0x4000015c) /* Reserved */ ++#define DRCMR24 __REG(0x40000160) /* Reserved */ ++#define DRCMR25 __REG(0x40000164) /* Request to Channel Map Register for USB endpoint 1 Request */ ++#define DRCMR26 __REG(0x40000168) /* Request to Channel Map Register for USB endpoint 2 Request */ ++#define DRCMR27 __REG(0x4000016C) /* Request to Channel Map Register for USB endpoint 3 Request */ ++#define DRCMR28 __REG(0x40000170) /* Request to Channel Map Register for USB endpoint 4 Request */ ++#define DRCMR29 __REG(0x40000174) /* Reserved */ ++#define DRCMR30 __REG(0x40000178) /* Request to Channel Map Register for USB endpoint 6 Request */ ++#define DRCMR31 __REG(0x4000017C) /* Request to Channel Map Register for USB endpoint 7 Request */ ++#define DRCMR32 __REG(0x40000180) /* Request to Channel Map Register for USB endpoint 8 Request */ ++#define DRCMR33 __REG(0x40000184) /* Request to Channel Map Register for USB endpoint 9 Request */ ++#define DRCMR34 __REG(0x40000188) /* Reserved */ ++#define DRCMR35 __REG(0x4000018C) /* Request to Channel Map Register for USB endpoint 11 Request */ ++#define DRCMR36 __REG(0x40000190) /* Request to Channel Map Register for USB endpoint 12 Request */ ++#define DRCMR37 __REG(0x40000194) /* Request to Channel Map Register for USB endpoint 13 Request */ ++#define DRCMR38 __REG(0x40000198) /* Request to Channel Map Register for USB endpoint 14 Request */ ++#define DRCMR39 __REG(0x4000019C) /* Reserved */ ++ ++#define DRCMRRXSADR DRCMR2 ++#define DRCMRTXSADR DRCMR3 ++#define DRCMRRXBTRBR DRCMR4 ++#define DRCMRTXBTTHR DRCMR5 ++#define DRCMRRXFFRBR DRCMR6 ++#define DRCMRTXFFTHR DRCMR7 ++#define DRCMRRXMCDR DRCMR8 ++#define DRCMRRXMODR DRCMR9 ++#define DRCMRTXMODR DRCMR10 ++#define DRCMRRXPCDR DRCMR11 ++#define DRCMRTXPCDR DRCMR12 ++#define DRCMRRXSSDR DRCMR13 ++#define DRCMRTXSSDR DRCMR14 ++#define DRCMRRXICDR DRCMR17 ++#define DRCMRTXICDR DRCMR18 ++#define DRCMRRXSTRBR DRCMR19 ++#define DRCMRTXSTTHR DRCMR20 ++#define DRCMRRXMMC DRCMR21 ++#define DRCMRTXMMC DRCMR22 ++ ++#define DRCMR_MAPVLD (1 << 7) /* Map Valid (read / write) */ ++#define DRCMR_CHLNUM 0x0f /* mask for Channel Number (read / write) */ ++ ++#define DDADR0 __REG(0x40000200) /* DMA Descriptor Address Register Channel 0 */ ++#define DSADR0 __REG(0x40000204) /* DMA Source Address Register Channel 0 */ ++#define DTADR0 __REG(0x40000208) /* DMA Target Address Register Channel 0 */ ++#define DCMD0 __REG(0x4000020c) /* DMA Command Address Register Channel 0 */ ++#define DDADR1 __REG(0x40000210) /* DMA Descriptor Address Register Channel 1 */ ++#define DSADR1 __REG(0x40000214) /* DMA Source Address Register Channel 1 */ ++#define DTADR1 __REG(0x40000218) /* DMA Target Address Register Channel 1 */ ++#define DCMD1 __REG(0x4000021c) /* DMA Command Address Register Channel 1 */ ++#define DDADR2 __REG(0x40000220) /* DMA Descriptor Address Register Channel 2 */ ++#define DSADR2 __REG(0x40000224) /* DMA Source Address Register Channel 2 */ ++#define DTADR2 __REG(0x40000228) /* DMA Target Address Register Channel 2 */ ++#define DCMD2 __REG(0x4000022c) /* DMA Command Address Register Channel 2 */ ++#define DDADR3 __REG(0x40000230) /* DMA Descriptor Address Register Channel 3 */ ++#define DSADR3 __REG(0x40000234) /* DMA Source Address Register Channel 3 */ ++#define DTADR3 __REG(0x40000238) /* DMA Target Address Register Channel 3 */ ++#define DCMD3 __REG(0x4000023c) /* DMA Command Address Register Channel 3 */ ++#define DDADR4 __REG(0x40000240) /* DMA Descriptor Address Register Channel 4 */ ++#define DSADR4 __REG(0x40000244) /* DMA Source Address Register Channel 4 */ ++#define DTADR4 __REG(0x40000248) /* DMA Target Address Register Channel 4 */ ++#define DCMD4 __REG(0x4000024c) /* DMA Command Address Register Channel 4 */ ++#define DDADR5 __REG(0x40000250) /* DMA Descriptor Address Register Channel 5 */ ++#define DSADR5 __REG(0x40000254) /* DMA Source Address Register Channel 5 */ ++#define DTADR5 __REG(0x40000258) /* DMA Target Address Register Channel 5 */ ++#define DCMD5 __REG(0x4000025c) /* DMA Command Address Register Channel 5 */ ++#define DDADR6 __REG(0x40000260) /* DMA Descriptor Address Register Channel 6 */ ++#define DSADR6 __REG(0x40000264) /* DMA Source Address Register Channel 6 */ ++#define DTADR6 __REG(0x40000268) /* DMA Target Address Register Channel 6 */ ++#define DCMD6 __REG(0x4000026c) /* DMA Command Address Register Channel 6 */ ++#define DDADR7 __REG(0x40000270) /* DMA Descriptor Address Register Channel 7 */ ++#define DSADR7 __REG(0x40000274) /* DMA Source Address Register Channel 7 */ ++#define DTADR7 __REG(0x40000278) /* DMA Target Address Register Channel 7 */ ++#define DCMD7 __REG(0x4000027c) /* DMA Command Address Register Channel 7 */ ++#define DDADR8 __REG(0x40000280) /* DMA Descriptor Address Register Channel 8 */ ++#define DSADR8 __REG(0x40000284) /* DMA Source Address Register Channel 8 */ ++#define DTADR8 __REG(0x40000288) /* DMA Target Address Register Channel 8 */ ++#define DCMD8 __REG(0x4000028c) /* DMA Command Address Register Channel 8 */ ++#define DDADR9 __REG(0x40000290) /* DMA Descriptor Address Register Channel 9 */ ++#define DSADR9 __REG(0x40000294) /* DMA Source Address Register Channel 9 */ ++#define DTADR9 __REG(0x40000298) /* DMA Target Address Register Channel 9 */ ++#define DCMD9 __REG(0x4000029c) /* DMA Command Address Register Channel 9 */ ++#define DDADR10 __REG(0x400002a0) /* DMA Descriptor Address Register Channel 10 */ ++#define DSADR10 __REG(0x400002a4) /* DMA Source Address Register Channel 10 */ ++#define DTADR10 __REG(0x400002a8) /* DMA Target Address Register Channel 10 */ ++#define DCMD10 __REG(0x400002ac) /* DMA Command Address Register Channel 10 */ ++#define DDADR11 __REG(0x400002b0) /* DMA Descriptor Address Register Channel 11 */ ++#define DSADR11 __REG(0x400002b4) /* DMA Source Address Register Channel 11 */ ++#define DTADR11 __REG(0x400002b8) /* DMA Target Address Register Channel 11 */ ++#define DCMD11 __REG(0x400002bc) /* DMA Command Address Register Channel 11 */ ++#define DDADR12 __REG(0x400002c0) /* DMA Descriptor Address Register Channel 12 */ ++#define DSADR12 __REG(0x400002c4) /* DMA Source Address Register Channel 12 */ ++#define DTADR12 __REG(0x400002c8) /* DMA Target Address Register Channel 12 */ ++#define DCMD12 __REG(0x400002cc) /* DMA Command Address Register Channel 12 */ ++#define DDADR13 __REG(0x400002d0) /* DMA Descriptor Address Register Channel 13 */ ++#define DSADR13 __REG(0x400002d4) /* DMA Source Address Register Channel 13 */ ++#define DTADR13 __REG(0x400002d8) /* DMA Target Address Register Channel 13 */ ++#define DCMD13 __REG(0x400002dc) /* DMA Command Address Register Channel 13 */ ++#define DDADR14 __REG(0x400002e0) /* DMA Descriptor Address Register Channel 14 */ ++#define DSADR14 __REG(0x400002e4) /* DMA Source Address Register Channel 14 */ ++#define DTADR14 __REG(0x400002e8) /* DMA Target Address Register Channel 14 */ ++#define DCMD14 __REG(0x400002ec) /* DMA Command Address Register Channel 14 */ ++#define DDADR15 __REG(0x400002f0) /* DMA Descriptor Address Register Channel 15 */ ++#define DSADR15 __REG(0x400002f4) /* DMA Source Address Register Channel 15 */ ++#define DTADR15 __REG(0x400002f8) /* DMA Target Address Register Channel 15 */ ++#define DCMD15 __REG(0x400002fc) /* DMA Command Address Register Channel 15 */ ++ ++#define DDADR(x) __REG2(0x40000200, (x) << 4) ++#define DSADR(x) __REG2(0x40000204, (x) << 4) ++#define DTADR(x) __REG2(0x40000208, (x) << 4) ++#define DCMD(x) __REG2(0x4000020c, (x) << 4) ++ ++#define DDADR_DESCADDR 0xfffffff0 /* Address of next descriptor (mask) */ ++#define DDADR_STOP (1 << 0) /* Stop (read / write) */ ++ ++#define DCMD_INCSRCADDR (1 << 31) /* Source Address Increment Setting. */ ++#define DCMD_INCTRGADDR (1 << 30) /* Target Address Increment Setting. */ ++#define DCMD_FLOWSRC (1 << 29) /* Flow Control by the source. */ ++#define DCMD_FLOWTRG (1 << 28) /* Flow Control by the target. */ ++#define DCMD_STARTIRQEN (1 << 22) /* Start Interrupt Enable */ ++#define DCMD_ENDIRQEN (1 << 21) /* End Interrupt Enable */ ++#define DCMD_ENDIAN (1 << 18) /* Device Endian-ness. */ ++#define DCMD_BURST8 (1 << 16) /* 8 byte burst */ ++#define DCMD_BURST16 (2 << 16) /* 16 byte burst */ ++#define DCMD_BURST32 (3 << 16) /* 32 byte burst */ ++#define DCMD_WIDTH1 (1 << 14) /* 1 byte width */ ++#define DCMD_WIDTH2 (2 << 14) /* 2 byte width (HalfWord) */ ++#define DCMD_WIDTH4 (3 << 14) /* 4 byte width (Word) */ ++#define DCMD_LENGTH 0x01fff /* length mask (max = 8K - 1) */ ++ ++/* default combinations */ ++#define DCMD_RXPCDR (DCMD_INCTRGADDR|DCMD_FLOWSRC|DCMD_BURST32|DCMD_WIDTH4) ++#define DCMD_RXMCDR (DCMD_INCTRGADDR|DCMD_FLOWSRC|DCMD_BURST32|DCMD_WIDTH4) ++#define DCMD_TXPCDR (DCMD_INCSRCADDR|DCMD_FLOWTRG|DCMD_BURST32|DCMD_WIDTH4) ++ ++ ++/* ++ * UARTs ++ */ ++ ++/* Full Function UART (FFUART) */ ++#define FFUART FFRBR ++#define FFRBR __REG(0x40100000) /* Receive Buffer Register (read only) */ ++#define FFTHR __REG(0x40100000) /* Transmit Holding Register (write only) */ ++#define FFIER __REG(0x40100004) /* Interrupt Enable Register (read/write) */ ++#define FFIIR __REG(0x40100008) /* Interrupt ID Register (read only) */ ++#define FFFCR __REG(0x40100008) /* FIFO Control Register (write only) */ ++#define FFLCR __REG(0x4010000C) /* Line Control Register (read/write) */ ++#define FFMCR __REG(0x40100010) /* Modem Control Register (read/write) */ ++#define FFLSR __REG(0x40100014) /* Line Status Register (read only) */ ++#define FFMSR __REG(0x40100018) /* Modem Status Register (read only) */ ++#define FFSPR __REG(0x4010001C) /* Scratch Pad Register (read/write) */ ++#define FFISR __REG(0x40100020) /* Infrared Selection Register (read/write) */ ++#define FFDLL __REG(0x40100000) /* Divisor Latch Low Register (DLAB = 1) (read/write) */ ++#define FFDLH __REG(0x40100004) /* Divisor Latch High Register (DLAB = 1) (read/write) */ ++ ++/* Bluetooth UART (BTUART) */ ++#define BTUART BTRBR ++#define BTRBR __REG(0x40200000) /* Receive Buffer Register (read only) */ ++#define BTTHR __REG(0x40200000) /* Transmit Holding Register (write only) */ ++#define BTIER __REG(0x40200004) /* Interrupt Enable Register (read/write) */ ++#define BTIIR __REG(0x40200008) /* Interrupt ID Register (read only) */ ++#define BTFCR __REG(0x40200008) /* FIFO Control Register (write only) */ ++#define BTLCR __REG(0x4020000C) /* Line Control Register (read/write) */ ++#define BTMCR __REG(0x40200010) /* Modem Control Register (read/write) */ ++#define BTLSR __REG(0x40200014) /* Line Status Register (read only) */ ++#define BTMSR __REG(0x40200018) /* Modem Status Register (read only) */ ++#define BTSPR __REG(0x4020001C) /* Scratch Pad Register (read/write) */ ++#define BTISR __REG(0x40200020) /* Infrared Selection Register (read/write) */ ++#define BTDLL __REG(0x40200000) /* Divisor Latch Low Register (DLAB = 1) (read/write) */ ++#define BTDLH __REG(0x40200004) /* Divisor Latch High Register (DLAB = 1) (read/write) */ ++ ++/* Standard UART (STUART) */ ++#define STUART STRBR ++#define STRBR __REG(0x40700000) /* Receive Buffer Register (read only) */ ++#define STTHR __REG(0x40700000) /* Transmit Holding Register (write only) */ ++#define STIER __REG(0x40700004) /* Interrupt Enable Register (read/write) */ ++#define STIIR __REG(0x40700008) /* Interrupt ID Register (read only) */ ++#define STFCR __REG(0x40700008) /* FIFO Control Register (write only) */ ++#define STLCR __REG(0x4070000C) /* Line Control Register (read/write) */ ++#define STMCR __REG(0x40700010) /* Modem Control Register (read/write) */ ++#define STLSR __REG(0x40700014) /* Line Status Register (read only) */ ++#define STMSR __REG(0x40700018) /* Reserved */ ++#define STSPR __REG(0x4070001C) /* Scratch Pad Register (read/write) */ ++#define STISR __REG(0x40700020) /* Infrared Selection Register (read/write) */ ++#define STDLL __REG(0x40700000) /* Divisor Latch Low Register (DLAB = 1) (read/write) */ ++#define STDLH __REG(0x40700004) /* Divisor Latch High Register (DLAB = 1) (read/write) */ ++ ++#define IER_DMAE (1 << 7) /* DMA Requests Enable */ ++#define IER_UUE (1 << 6) /* UART Unit Enable */ ++#define IER_NRZE (1 << 5) /* NRZ coding Enable */ ++#define IER_RTIOE (1 << 4) /* Receiver Time Out Interrupt Enable */ ++#define IER_MIE (1 << 3) /* Modem Interrupt Enable */ ++#define IER_RLSE (1 << 2) /* Receiver Line Status Interrupt Enable */ ++#define IER_TIE (1 << 1) /* Transmit Data request Interrupt Enable */ ++#define IER_RAVIE (1 << 0) /* Receiver Data Available Interrupt Enable */ ++ ++#define IIR_FIFOES1 (1 << 7) /* FIFO Mode Enable Status */ ++#define IIR_FIFOES0 (1 << 6) /* FIFO Mode Enable Status */ ++#define IIR_TOD (1 << 3) /* Time Out Detected */ ++#define IIR_IID2 (1 << 2) /* Interrupt Source Encoded */ ++#define IIR_IID1 (1 << 1) /* Interrupt Source Encoded */ ++#define IIR_IP (1 << 0) /* Interrupt Pending (active low) */ ++ ++#define FCR_ITL2 (1 << 7) /* Interrupt Trigger Level */ ++#define FCR_ITL1 (1 << 6) /* Interrupt Trigger Level */ ++#define FCR_RESETTF (1 << 2) /* Reset Transmitter FIFO */ ++#define FCR_RESETRF (1 << 1) /* Reset Receiver FIFO */ ++#define FCR_TRFIFOE (1 << 0) /* Transmit and Receive FIFO Enable */ ++#define FCR_ITL_1 (0) ++#define FCR_ITL_8 (FCR_ITL1) ++#define FCR_ITL_16 (FCR_ITL2) ++#define FCR_ITL_32 (FCR_ITL2|FCR_ITL1) ++ ++#define LCR_DLAB (1 << 7) /* Divisor Latch Access Bit */ ++#define LCR_SB (1 << 6) /* Set Break */ ++#define LCR_STKYP (1 << 5) /* Sticky Parity */ ++#define LCR_EPS (1 << 4) /* Even Parity Select */ ++#define LCR_PEN (1 << 3) /* Parity Enable */ ++#define LCR_STB (1 << 2) /* Stop Bit */ ++#define LCR_WLS1 (1 << 1) /* Word Length Select */ ++#define LCR_WLS0 (1 << 0) /* Word Length Select */ ++ ++#define LSR_FIFOE (1 << 7) /* FIFO Error Status */ ++#define LSR_TEMT (1 << 6) /* Transmitter Empty */ ++#define LSR_TDRQ (1 << 5) /* Transmit Data Request */ ++#define LSR_BI (1 << 4) /* Break Interrupt */ ++#define LSR_FE (1 << 3) /* Framing Error */ ++#define LSR_PE (1 << 2) /* Parity Error */ ++#define LSR_OE (1 << 1) /* Overrun Error */ ++#define LSR_DR (1 << 0) /* Data Ready */ ++ ++#define MCR_LOOP (1 << 4) */ ++#define MCR_OUT2 (1 << 3) /* force MSR_DCD in loopback mode */ ++#define MCR_OUT1 (1 << 2) /* force MSR_RI in loopback mode */ ++#define MCR_RTS (1 << 1) /* Request to Send */ ++#define MCR_DTR (1 << 0) /* Data Terminal Ready */ ++ ++#define MSR_DCD (1 << 7) /* Data Carrier Detect */ ++#define MSR_RI (1 << 6) /* Ring Indicator */ ++#define MSR_DSR (1 << 5) /* Data Set Ready */ ++#define MSR_CTS (1 << 4) /* Clear To Send */ ++#define MSR_DDCD (1 << 3) /* Delta Data Carrier Detect */ ++#define MSR_TERI (1 << 2) /* Trailing Edge Ring Indicator */ ++#define MSR_DDSR (1 << 1) /* Delta Data Set Ready */ ++#define MSR_DCTS (1 << 0) /* Delta Clear To Send */ ++ ++/* ++ * IrSR (Infrared Selection Register) ++ */ ++#define STISR_RXPL (1 << 4) /* Receive Data Polarity */ ++#define STISR_TXPL (1 << 3) /* Transmit Data Polarity */ ++#define STISR_XMODE (1 << 2) /* Transmit Pulse Width Select */ ++#define STISR_RCVEIR (1 << 1) /* Receiver SIR Enable */ ++#define STISR_XMITIR (1 << 0) /* Transmitter SIR Enable */ ++ ++ ++/* ++ * I2C registers ++ */ ++ ++#define IBMR __REG(0x40301680) /* I2C Bus Monitor Register - IBMR */ ++#define IDBR __REG(0x40301688) /* I2C Data Buffer Register - IDBR */ ++#define ICR __REG(0x40301690) /* I2C Control Register - ICR */ ++#define ISR __REG(0x40301698) /* I2C Status Register - ISR */ ++#define ISAR __REG(0x403016A0) /* I2C Slave Address Register - ISAR */ ++ ++#define ICR_START (1 << 0) /* start bit */ ++#define ICR_STOP (1 << 1) /* stop bit */ ++#define ICR_ACKNAK (1 << 2) /* send ACK(0) or NAK(1) */ ++#define ICR_TB (1 << 3) /* transfer byte bit */ ++#define ICR_MA (1 << 4) /* master abort */ ++#define ICR_SCLE (1 << 5) /* master clock enable */ ++#define ICR_IUE (1 << 6) /* unit enable */ ++#define ICR_GCD (1 << 7) /* general call disable */ ++#define ICR_ITEIE (1 << 8) /* enable tx interrupts */ ++#define ICR_IRFIE (1 << 9) /* enable rx interrupts */ ++#define ICR_BEIE (1 << 10) /* enable bus error ints */ ++#define ICR_SSDIE (1 << 11) /* slave STOP detected int enable */ ++#define ICR_ALDIE (1 << 12) /* enable arbitration interrupt */ ++#define ICR_SADIE (1 << 13) /* slave address detected int enable */ ++#define ICR_UR (1 << 14) /* unit reset */ ++ ++#define ISR_RWM (1 << 0) /* read/write mode */ ++#define ISR_ACKNAK (1 << 1) /* ack/nak status */ ++#define ISR_UB (1 << 2) /* unit busy */ ++#define ISR_IBB (1 << 3) /* bus busy */ ++#define ISR_SSD (1 << 4) /* slave stop detected */ ++#define ISR_ALD (1 << 5) /* arbitration loss detected */ ++#define ISR_ITE (1 << 6) /* tx buffer empty */ ++#define ISR_IRF (1 << 7) /* rx buffer full */ ++#define ISR_GCAD (1 << 8) /* general call address detected */ ++#define ISR_SAD (1 << 9) /* slave address detected */ ++#define ISR_BED (1 << 10) /* bus error no ACK/NAK */ ++ ++ ++/* ++ * Serial Audio Controller ++ */ ++ ++/* FIXME: This clash with SA1111 defines */ ++#ifndef CONFIG_SA1111 ++#define SACR0 __REG(0x40400000) /* Global Control Register */ ++#define SACR1 __REG(0x40400004) /* Serial Audio I 2 S/MSB-Justified Control Register */ ++#define SASR0 __REG(0x4040000C) /* Serial Audio I 2 S/MSB-Justified Interface and FIFO Status Register */ ++#define SAIMR __REG(0x40400014) /* Serial Audio Interrupt Mask Register */ ++#define SAICR __REG(0x40400018) /* Serial Audio Interrupt Clear Register */ ++#define SADIV __REG(0x40400060) /* Audio Clock Divider Register. */ ++#define SADR __REG(0x40400080) /* Serial Audio Data Register (TX and RX FIFO access Register). */ ++#endif ++ ++ ++/* ++ * AC97 Controller registers ++ */ ++ ++#define POCR __REG(0x40500000) /* PCM Out Control Register */ ++#define POCR_FEIE (1 << 3) /* FIFO Error Interrupt Enable */ ++ ++#define PICR __REG(0x40500004) /* PCM In Control Register */ ++#define PICR_FEIE (1 << 3) /* FIFO Error Interrupt Enable */ ++ ++#define MCCR __REG(0x40500008) /* Mic In Control Register */ ++#define MCCR_FEIE (1 << 3) /* FIFO Error Interrupt Enable */ ++ ++#define GCR __REG(0x4050000C) /* Global Control Register */ ++#define GCR_CDONE_IE (1 << 19) /* Command Done Interrupt Enable */ ++#define GCR_SDONE_IE (1 << 18) /* Status Done Interrupt Enable */ ++#define GCR_SECRDY_IEN (1 << 9) /* Secondary Ready Interrupt Enable */ ++#define GCR_PRIRDY_IEN (1 << 8) /* Primary Ready Interrupt Enable */ ++#define GCR_SECRES_IEN (1 << 5) /* Secondary Resume Interrupt Enable */ ++#define GCR_PRIRES_IEN (1 << 4) /* Primary Resume Interrupt Enable */ ++#define GCR_ACLINK_OFF (1 << 3) /* AC-link Shut Off */ ++#define GCR_WARM_RST (1 << 2) /* AC97 Warm Reset */ ++#define GCR_COLD_RST (1 << 1) /* AC'97 Cold Reset (0 = active) */ ++#define GCR_GIE (1 << 0) /* Codec GPI Interrupt Enable */ ++ ++#define POSR __REG(0x40500010) /* PCM Out Status Register */ ++#define POSR_FIFOE (1 << 4) /* FIFO error */ ++ ++#define PISR __REG(0x40500014) /* PCM In Status Register */ ++#define PISR_FIFOE (1 << 4) /* FIFO error */ ++ ++#define MCSR __REG(0x40500018) /* Mic In Status Register */ ++#define MCSR_FIFOE (1 << 4) /* FIFO error */ ++ ++#define GSR __REG(0x4050001C) /* Global Status Register */ ++#define GSR_CDONE (1 << 19) /* Command Done */ ++#define GSR_SDONE (1 << 18) /* Status Done */ ++#define GSR_RDCS (1 << 15) /* Read Completion Status */ ++#define GSR_BIT3SLT12 (1 << 14) /* Bit 3 of slot 12 */ ++#define GSR_BIT2SLT12 (1 << 13) /* Bit 2 of slot 12 */ ++#define GSR_BIT1SLT12 (1 << 12) /* Bit 1 of slot 12 */ ++#define GSR_SECRES (1 << 11) /* Secondary Resume Interrupt */ ++#define GSR_PRIRES (1 << 10) /* Primary Resume Interrupt */ ++#define GSR_SCR (1 << 9) /* Secondary Codec Ready */ ++#define GSR_PCR (1 << 8) /* Primary Codec Ready */ ++#define GSR_MINT (1 << 7) /* Mic In Interrupt */ ++#define GSR_POINT (1 << 6) /* PCM Out Interrupt */ ++#define GSR_PIINT (1 << 5) /* PCM In Interrupt */ ++#define GSR_MOINT (1 << 2) /* Modem Out Interrupt */ ++#define GSR_MIINT (1 << 1) /* Modem In Interrupt */ ++#define GSR_GSCI (1 << 0) /* Codec GPI Status Change Interrupt */ ++ ++#define CAR __REG(0x40500020) /* CODEC Access Register */ ++#define CAR_CAIP (1 << 0) /* Codec Access In Progress */ ++ ++#define PCDR __REG(0x40500040) /* PCM FIFO Data Register */ ++#define MCDR __REG(0x40500060) /* Mic-in FIFO Data Register */ ++ ++#define MOCR __REG(0x40500100) /* Modem Out Control Register */ ++#define MOCR_FEIE (1 << 3) /* FIFO Error */ ++ ++#define MICR __REG(0x40500108) /* Modem In Control Register */ ++#define MICR_FEIE (1 << 3) /* FIFO Error */ ++ ++#define MOSR __REG(0x40500110) /* Modem Out Status Register */ ++#define MOSR_FIFOE (1 << 4) /* FIFO error */ ++ ++#define MISR __REG(0x40500118) /* Modem In Status Register */ ++#define MISR_FIFOE (1 << 4) /* FIFO error */ ++ ++#define MODR __REG(0x40500140) /* Modem FIFO Data Register */ ++ ++#define PAC_REG_BASE __REG(0x40500200) /* Primary Audio Codec */ ++#define SAC_REG_BASE __REG(0x40500300) /* Secondary Audio Codec */ ++#define PMC_REG_BASE __REG(0x40500400) /* Primary Modem Codec */ ++#define SMC_REG_BASE __REG(0x40500500) /* Secondary Modem Codec */ ++ ++ ++/* ++ * USB Device Controller ++ */ ++#define UDC_RES1 __REG(0x40600004) /* UDC Undocumented - Reserved1 */ ++#define UDC_RES2 __REG(0x40600008) /* UDC Undocumented - Reserved2 */ ++#define UDC_RES3 __REG(0x4060000C) /* UDC Undocumented - Reserved3 */ ++ ++#define UDCCR __REG(0x40600000) /* UDC Control Register */ ++#define UDCCR_UDE (1 << 0) /* UDC enable */ ++#define UDCCR_UDA (1 << 1) /* UDC active */ ++#define UDCCR_RSM (1 << 2) /* Device resume */ ++#define UDCCR_RESIR (1 << 3) /* Resume interrupt request */ ++#define UDCCR_SUSIR (1 << 4) /* Suspend interrupt request */ ++#define UDCCR_SRM (1 << 5) /* Suspend/resume interrupt mask */ ++#define UDCCR_RSTIR (1 << 6) /* Reset interrupt request */ ++#define UDCCR_REM (1 << 7) /* Reset interrupt mask */ ++ ++#define UDCCS0 __REG(0x40600010) /* UDC Endpoint 0 Control/Status Register */ ++#define UDCCS0_OPR (1 << 0) /* OUT packet ready */ ++#define UDCCS0_IPR (1 << 1) /* IN packet ready */ ++#define UDCCS0_FTF (1 << 2) /* Flush Tx FIFO */ ++#define UDCCS0_DRWF (1 << 3) /* Device remote wakeup feature */ ++#define UDCCS0_SST (1 << 4) /* Sent stall */ ++#define UDCCS0_FST (1 << 5) /* Force stall */ ++#define UDCCS0_RNE (1 << 6) /* Receive FIFO no empty */ ++#define UDCCS0_SA (1 << 7) /* Setup active */ ++ ++/* Bulk IN - Endpoint 1,6,11 */ ++#define UDCCS1 __REG(0x40600014) /* UDC Endpoint 1 (IN) Control/Status Register */ ++#define UDCCS6 __REG(0x40600028) /* UDC Endpoint 6 (IN) Control/Status Register */ ++#define UDCCS11 __REG(0x4060003C) /* UDC Endpoint 11 (IN) Control/Status Register */ ++ ++#define UDCCS_BI_TFS (1 << 0) /* Transmit FIFO service */ ++#define UDCCS_BI_TPC (1 << 1) /* Transmit packet complete */ ++#define UDCCS_BI_FTF (1 << 2) /* Flush Tx FIFO */ ++#define UDCCS_BI_TUR (1 << 3) /* Transmit FIFO underrun */ ++#define UDCCS_BI_SST (1 << 4) /* Sent stall */ ++#define UDCCS_BI_FST (1 << 5) /* Force stall */ ++#define UDCCS_BI_TSP (1 << 7) /* Transmit short packet */ ++ ++/* Bulk OUT - Endpoint 2,7,12 */ ++#define UDCCS2 __REG(0x40600018) /* UDC Endpoint 2 (OUT) Control/Status Register */ ++#define UDCCS7 __REG(0x4060002C) /* UDC Endpoint 7 (OUT) Control/Status Register */ ++#define UDCCS12 __REG(0x40600040) /* UDC Endpoint 12 (OUT) Control/Status Register */ ++ ++#define UDCCS_BO_RFS (1 << 0) /* Receive FIFO service */ ++#define UDCCS_BO_RPC (1 << 1) /* Receive packet complete */ ++#define UDCCS_BO_DME (1 << 3) /* DMA enable */ ++#define UDCCS_BO_SST (1 << 4) /* Sent stall */ ++#define UDCCS_BO_FST (1 << 5) /* Force stall */ ++#define UDCCS_BO_RNE (1 << 6) /* Receive FIFO not empty */ ++#define UDCCS_BO_RSP (1 << 7) /* Receive short packet */ ++ ++/* Isochronous IN - Endpoint 3,8,13 */ ++#define UDCCS3 __REG(0x4060001C) /* UDC Endpoint 3 (IN) Control/Status Register */ ++#define UDCCS8 __REG(0x40600030) /* UDC Endpoint 8 (IN) Control/Status Register */ ++#define UDCCS13 __REG(0x40600044) /* UDC Endpoint 13 (IN) Control/Status Register */ ++ ++#define UDCCS_II_TFS (1 << 0) /* Transmit FIFO service */ ++#define UDCCS_II_TPC (1 << 1) /* Transmit packet complete */ ++#define UDCCS_II_FTF (1 << 2) /* Flush Tx FIFO */ ++#define UDCCS_II_TUR (1 << 3) /* Transmit FIFO underrun */ ++#define UDCCS_II_TSP (1 << 7) /* Transmit short packet */ ++ ++/* Isochronous OUT - Endpoint 4,9,14 */ ++#define UDCCS4 __REG(0x40600020) /* UDC Endpoint 4 (OUT) Control/Status Register */ ++#define UDCCS9 __REG(0x40600034) /* UDC Endpoint 9 (OUT) Control/Status Register */ ++#define UDCCS14 __REG(0x40600048) /* UDC Endpoint 14 (OUT) Control/Status Register */ ++ ++#define UDCCS_IO_RFS (1 << 0) /* Receive FIFO service */ ++#define UDCCS_IO_RPC (1 << 1) /* Receive packet complete */ ++#define UDCCS_IO_ROF (1 << 3) /* Receive overflow */ ++#define UDCCS_IO_DME (1 << 3) /* DMA enable */ ++#define UDCCS_IO_RNE (1 << 6) /* Receive FIFO not empty */ ++#define UDCCS_IO_RSP (1 << 7) /* Receive short packet */ ++ ++/* Interrupt IN - Endpoint 5,10,15 */ ++#define UDCCS5 __REG(0x40600024) /* UDC Endpoint 5 (Interrupt) Control/Status Register */ ++#define UDCCS10 __REG(0x40600038) /* UDC Endpoint 10 (Interrupt) Control/Status Register */ ++#define UDCCS15 __REG(0x4060004C) /* UDC Endpoint 15 (Interrupt) Control/Status Register */ ++ ++#define UDCCS_INT_TFS (1 << 0) /* Transmit FIFO service */ ++#define UDCCS_INT_TPC (1 << 1) /* Transmit packet complete */ ++#define UDCCS_INT_FTF (1 << 2) /* Flush Tx FIFO */ ++#define UDCCS_INT_TUR (1 << 3) /* Transmit FIFO underrun */ ++#define UDCCS_INT_SST (1 << 4) /* Sent stall */ ++#define UDCCS_INT_FST (1 << 5) /* Force stall */ ++#define UDCCS_INT_TSP (1 << 7) /* Transmit short packet */ ++ ++#define UFNRH __REG(0x40600060) /* UDC Frame Number Register High */ ++#define UFNRL __REG(0x40600064) /* UDC Frame Number Register Low */ ++#define UBCR2 __REG(0x40600068) /* UDC Byte Count Reg 2 */ ++#define UBCR4 __REG(0x4060006c) /* UDC Byte Count Reg 4 */ ++#define UBCR7 __REG(0x40600070) /* UDC Byte Count Reg 7 */ ++#define UBCR9 __REG(0x40600074) /* UDC Byte Count Reg 9 */ ++#define UBCR12 __REG(0x40600078) /* UDC Byte Count Reg 12 */ ++#define UBCR14 __REG(0x4060007c) /* UDC Byte Count Reg 14 */ ++#define UDDR0 __REG(0x40600080) /* UDC Endpoint 0 Data Register */ ++#define UDDR1 __REG(0x40600100) /* UDC Endpoint 1 Data Register */ ++#define UDDR2 __REG(0x40600180) /* UDC Endpoint 2 Data Register */ ++#define UDDR3 __REG(0x40600200) /* UDC Endpoint 3 Data Register */ ++#define UDDR4 __REG(0x40600400) /* UDC Endpoint 4 Data Register */ ++#define UDDR5 __REG(0x406000A0) /* UDC Endpoint 5 Data Register */ ++#define UDDR6 __REG(0x40600600) /* UDC Endpoint 6 Data Register */ ++#define UDDR7 __REG(0x40600680) /* UDC Endpoint 7 Data Register */ ++#define UDDR8 __REG(0x40600700) /* UDC Endpoint 8 Data Register */ ++#define UDDR9 __REG(0x40600900) /* UDC Endpoint 9 Data Register */ ++#define UDDR10 __REG(0x406000C0) /* UDC Endpoint 10 Data Register */ ++#define UDDR11 __REG(0x40600B00) /* UDC Endpoint 11 Data Register */ ++#define UDDR12 __REG(0x40600B80) /* UDC Endpoint 12 Data Register */ ++#define UDDR13 __REG(0x40600C00) /* UDC Endpoint 13 Data Register */ ++#define UDDR14 __REG(0x40600E00) /* UDC Endpoint 14 Data Register */ ++#define UDDR15 __REG(0x406000E0) /* UDC Endpoint 15 Data Register */ ++ ++#define UICR0 __REG(0x40600050) /* UDC Interrupt Control Register 0 */ ++ ++#define UICR0_IM0 (1 << 0) /* Interrupt mask ep 0 */ ++#define UICR0_IM1 (1 << 1) /* Interrupt mask ep 1 */ ++#define UICR0_IM2 (1 << 2) /* Interrupt mask ep 2 */ ++#define UICR0_IM3 (1 << 3) /* Interrupt mask ep 3 */ ++#define UICR0_IM4 (1 << 4) /* Interrupt mask ep 4 */ ++#define UICR0_IM5 (1 << 5) /* Interrupt mask ep 5 */ ++#define UICR0_IM6 (1 << 6) /* Interrupt mask ep 6 */ ++#define UICR0_IM7 (1 << 7) /* Interrupt mask ep 7 */ ++ ++#define UICR1 __REG(0x40600054) /* UDC Interrupt Control Register 1 */ ++ ++#define UICR1_IM8 (1 << 0) /* Interrupt mask ep 8 */ ++#define UICR1_IM9 (1 << 1) /* Interrupt mask ep 9 */ ++#define UICR1_IM10 (1 << 2) /* Interrupt mask ep 10 */ ++#define UICR1_IM11 (1 << 3) /* Interrupt mask ep 11 */ ++#define UICR1_IM12 (1 << 4) /* Interrupt mask ep 12 */ ++#define UICR1_IM13 (1 << 5) /* Interrupt mask ep 13 */ ++#define UICR1_IM14 (1 << 6) /* Interrupt mask ep 14 */ ++#define UICR1_IM15 (1 << 7) /* Interrupt mask ep 15 */ ++ ++#define USIR0 __REG(0x40600058) /* UDC Status Interrupt Register 0 */ ++ ++#define USIR0_IR0 (1 << 0) /* Interrup request ep 0 */ ++#define USIR0_IR1 (1 << 1) /* Interrup request ep 1 */ ++#define USIR0_IR2 (1 << 2) /* Interrup request ep 2 */ ++#define USIR0_IR3 (1 << 3) /* Interrup request ep 3 */ ++#define USIR0_IR4 (1 << 4) /* Interrup request ep 4 */ ++#define USIR0_IR5 (1 << 5) /* Interrup request ep 5 */ ++#define USIR0_IR6 (1 << 6) /* Interrup request ep 6 */ ++#define USIR0_IR7 (1 << 7) /* Interrup request ep 7 */ ++ ++#define USIR1 __REG(0x4060005C) /* UDC Status Interrupt Register 1 */ ++ ++#define USIR1_IR8 (1 << 0) /* Interrup request ep 8 */ ++#define USIR1_IR9 (1 << 1) /* Interrup request ep 9 */ ++#define USIR1_IR10 (1 << 2) /* Interrup request ep 10 */ ++#define USIR1_IR11 (1 << 3) /* Interrup request ep 11 */ ++#define USIR1_IR12 (1 << 4) /* Interrup request ep 12 */ ++#define USIR1_IR13 (1 << 5) /* Interrup request ep 13 */ ++#define USIR1_IR14 (1 << 6) /* Interrup request ep 14 */ ++#define USIR1_IR15 (1 << 7) /* Interrup request ep 15 */ ++ ++ ++/* ++ * Fast Infrared Communication Port ++ */ ++ ++#define ICCR0 __REG(0x40800000) /* ICP Control Register 0 */ ++#define ICCR1 __REG(0x40800004) /* ICP Control Register 1 */ ++#define ICCR2 __REG(0x40800008) /* ICP Control Register 2 */ ++#define ICDR __REG(0x4080000c) /* ICP Data Register */ ++#define ICSR0 __REG(0x40800014) /* ICP Status Register 0 */ ++#define ICSR1 __REG(0x40800018) /* ICP Status Register 1 */ ++ ++#define ICCR0_AME (1 << 7) /* Adress match enable */ ++#define ICCR0_TIE (1 << 6) /* Transmit FIFO interrupt enable */ ++#define ICCR0_RIE (1 << 5) /* Recieve FIFO interrupt enable */ ++#define ICCR0_RXE (1 << 4) /* Receive enable */ ++#define ICCR0_TXE (1 << 3) /* Transmit enable */ ++#define ICCR0_TUS (1 << 2) /* Transmit FIFO underrun select */ ++#define ICCR0_LBM (1 << 1) /* Loopback mode */ ++#define ICCR0_ITR (1 << 0) /* IrDA transmission */ ++ ++#define ICSR0_FRE (1 << 5) /* Framing error */ ++#define ICSR0_RFS (1 << 4) /* Receive FIFO service request */ ++#define ICSR0_TFS (1 << 3) /* Transnit FIFO service request */ ++#define ICSR0_RAB (1 << 2) /* Receiver abort */ ++#define ICSR0_TUR (1 << 1) /* Trunsmit FIFO underun */ ++#define ICSR0_EIF (1 << 0) /* End/Error in FIFO */ ++ ++#define ICSR1_ROR (1 << 6) /* Receiver FIFO underrun */ ++#define ICSR1_CRE (1 << 5) /* CRC error */ ++#define ICSR1_EOF (1 << 4) /* End of frame */ ++#define ICSR1_TNF (1 << 3) /* Transmit FIFO not full */ ++#define ICSR1_RNE (1 << 2) /* Receive FIFO not empty */ ++#define ICSR1_TBY (1 << 1) /* Tramsmiter busy flag */ ++#define ICSR1_RSY (1 << 0) /* Recevier synchronized flag */ ++ ++ ++/* ++ * Real Time Clock ++ */ ++ ++#define RCNR __REG(0x40900000) /* RTC Count Register */ ++#define RTAR __REG(0x40900004) /* RTC Alarm Register */ ++#define RTSR __REG(0x40900008) /* RTC Status Register */ ++#define RTTR __REG(0x4090000C) /* RTC Timer Trim Register */ ++ ++#define RTSR_HZE (1 << 3) /* HZ interrupt enable */ ++#define RTSR_ALE (1 << 2) /* RTC alarm interrupt enable */ ++#define RTSR_HZ (1 << 1) /* HZ rising-edge detected */ ++#define RTSR_AL (1 << 0) /* RTC alarm detected */ ++ ++ ++/* ++ * OS Timer & Match Registers ++ */ ++ ++#define OSMR0 __REG(0x40A00000) /* */ ++#define OSMR1 __REG(0x40A00004) /* */ ++#define OSMR2 __REG(0x40A00008) /* */ ++#define OSMR3 __REG(0x40A0000C) /* */ ++#define OSCR __REG(0x40A00010) /* OS Timer Counter Register */ ++#define OSSR __REG(0x40A00014) /* OS Timer Status Register */ ++#define OWER __REG(0x40A00018) /* OS Timer Watchdog Enable Register */ ++#define OIER __REG(0x40A0001C) /* OS Timer Interrupt Enable Register */ ++ ++#define OSSR_M3 (1 << 3) /* Match status channel 3 */ ++#define OSSR_M2 (1 << 2) /* Match status channel 2 */ ++#define OSSR_M1 (1 << 1) /* Match status channel 1 */ ++#define OSSR_M0 (1 << 0) /* Match status channel 0 */ ++ ++#define OWER_WME (1 << 0) /* Watchdog Match Enable */ ++ ++#define OIER_E3 (1 << 3) /* Interrupt enable channel 3 */ ++#define OIER_E2 (1 << 2) /* Interrupt enable channel 2 */ ++#define OIER_E1 (1 << 1) /* Interrupt enable channel 1 */ ++#define OIER_E0 (1 << 0) /* Interrupt enable channel 0 */ ++ ++ ++/* ++ * Pulse Width Modulator ++ */ ++ ++#define PWM_CTRL0 __REG(0x40B00000) /* PWM 0 Control Register */ ++#define PWM_PWDUTY0 __REG(0x40B00004) /* PWM 0 Duty Cycle Register */ ++#define PWM_PERVAL0 __REG(0x40B00008) /* PWM 0 Period Control Register */ ++ ++#define PWM_CTRL1 __REG(0x40C00000) /* PWM 1Control Register */ ++#define PWM_PWDUTY1 __REG(0x40C00004) /* PWM 1 Duty Cycle Register */ ++#define PWM_PERVAL1 __REG(0x40C00008) /* PWM 1 Period Control Register */ ++ ++ ++/* ++ * Interrupt Controller ++ */ ++ ++#define ICIP __REG(0x40D00000) /* Interrupt Controller IRQ Pending Register */ ++#define ICMR __REG(0x40D00004) /* Interrupt Controller Mask Register */ ++#define ICLR __REG(0x40D00008) /* Interrupt Controller Level Register */ ++#define ICFP __REG(0x40D0000C) /* Interrupt Controller FIQ Pending Register */ ++#define ICPR __REG(0x40D00010) /* Interrupt Controller Pending Register */ ++#define ICCR __REG(0x40D00014) /* Interrupt Controller Control Register */ ++ ++ ++/* ++ * General Purpose I/O ++ */ ++ ++#define GPLR0 __REG(0x40E00000) /* GPIO Pin-Level Register GPIO<31:0> */ ++#define GPLR1 __REG(0x40E00004) /* GPIO Pin-Level Register GPIO<63:32> */ ++#define GPLR2 __REG(0x40E00008) /* GPIO Pin-Level Register GPIO<80:64> */ ++ ++#define GPDR0 __REG(0x40E0000C) /* GPIO Pin Direction Register GPIO<31:0> */ ++#define GPDR1 __REG(0x40E00010) /* GPIO Pin Direction Register GPIO<63:32> */ ++#define GPDR2 __REG(0x40E00014) /* GPIO Pin Direction Register GPIO<80:64> */ ++ ++#define GPSR0 __REG(0x40E00018) /* GPIO Pin Output Set Register GPIO<31:0> */ ++#define GPSR1 __REG(0x40E0001C) /* GPIO Pin Output Set Register GPIO<63:32> */ ++#define GPSR2 __REG(0x40E00020) /* GPIO Pin Output Set Register GPIO<80:64> */ ++ ++#define GPCR0 __REG(0x40E00024) /* GPIO Pin Output Clear Register GPIO<31:0> */ ++#define GPCR1 __REG(0x40E00028) /* GPIO Pin Output Clear Register GPIO <63:32> */ ++#define GPCR2 __REG(0x40E0002C) /* GPIO Pin Output Clear Register GPIO <80:64> */ ++ ++#define GRER0 __REG(0x40E00030) /* GPIO Rising-Edge Detect Register GPIO<31:0> */ ++#define GRER1 __REG(0x40E00034) /* GPIO Rising-Edge Detect Register GPIO<63:32> */ ++#define GRER2 __REG(0x40E00038) /* GPIO Rising-Edge Detect Register GPIO<80:64> */ ++ ++#define GFER0 __REG(0x40E0003C) /* GPIO Falling-Edge Detect Register GPIO<31:0> */ ++#define GFER1 __REG(0x40E00040) /* GPIO Falling-Edge Detect Register GPIO<63:32> */ ++#define GFER2 __REG(0x40E00044) /* GPIO Falling-Edge Detect Register GPIO<80:64> */ ++ ++#define GEDR0 __REG(0x40E00048) /* GPIO Edge Detect Status Register GPIO<31:0> */ ++#define GEDR1 __REG(0x40E0004C) /* GPIO Edge Detect Status Register GPIO<63:32> */ ++#define GEDR2 __REG(0x40E00050) /* GPIO Edge Detect Status Register GPIO<80:64> */ ++ ++#define GAFR0_L __REG(0x40E00054) /* GPIO Alternate Function Select Register GPIO<15:0> */ ++#define GAFR0_U __REG(0x40E00058) /* GPIO Alternate Function Select Register GPIO<31:16> */ ++#define GAFR1_L __REG(0x40E0005C) /* GPIO Alternate Function Select Register GPIO<47:32> */ ++#define GAFR1_U __REG(0x40E00060) /* GPIO Alternate Function Select Register GPIO<63:48> */ ++#define GAFR2_L __REG(0x40E00064) /* GPIO Alternate Function Select Register GPIO<79:64> */ ++#define GAFR2_U __REG(0x40E00068) /* GPIO Alternate Function Select Register GPIO 80 */ ++ ++/* More handy macros. The argument is a literal GPIO number. */ ++ ++#define GPIO_bit(x) (1 << ((x) & 0x1f)) ++#define GPLR(x) __REG2(0x40E00000, ((x) & 0x60) >> 3) ++#define GPDR(x) __REG2(0x40E0000C, ((x) & 0x60) >> 3) ++#define GPSR(x) __REG2(0x40E00018, ((x) & 0x60) >> 3) ++#define GPCR(x) __REG2(0x40E00024, ((x) & 0x60) >> 3) ++#define GRER(x) __REG2(0x40E00030, ((x) & 0x60) >> 3) ++#define GFER(x) __REG2(0x40E0003C, ((x) & 0x60) >> 3) ++#define GEDR(x) __REG2(0x40E00048, ((x) & 0x60) >> 3) ++#define GAFR(x) __REG2(0x40E00054, ((x) & 0x70) >> 2) ++ ++/* GPIO alternate function assignments */ ++ ++#define GPIO1_RST 1 /* reset */ ++#define GPIO6_MMCCLK 6 /* MMC Clock */ ++#define GPIO8_48MHz 7 /* 48 MHz clock output */ ++#define GPIO8_MMCCS0 8 /* MMC Chip Select 0 */ ++#define GPIO9_MMCCS1 9 /* MMC Chip Select 1 */ ++#define GPIO10_RTCCLK 10 /* real time clock (1 Hz) */ ++#define GPIO11_3_6MHz 11 /* 3.6 MHz oscillator out */ ++#define GPIO12_32KHz 12 /* 32 kHz out */ ++#define GPIO13_MBGNT 13 /* memory controller grant */ ++#define GPIO14_MBREQ 14 /* alternate bus master request */ ++#define GPIO15_nCS_1 15 /* chip select 1 */ ++#define GPIO16_PWM0 16 /* PWM0 output */ ++#define GPIO17_PWM1 17 /* PWM1 output */ ++#define GPIO18_RDY 18 /* Ext. Bus Ready */ ++#define GPIO19_DREQ1 19 /* External DMA Request */ ++#define GPIO20_DREQ0 20 /* External DMA Request */ ++#define GPIO23_SCLK 23 /* SSP clock */ ++#define GPIO24_SFRM 24 /* SSP Frame */ ++#define GPIO25_STXD 25 /* SSP transmit */ ++#define GPIO26_SRXD 26 /* SSP receive */ ++#define GPIO27_SEXTCLK 27 /* SSP ext_clk */ ++#define GPIO28_BITCLK 28 /* AC97/I2S bit_clk */ ++#define GPIO29_SDATA_IN 29 /* AC97 Sdata_in0 / I2S Sdata_in */ ++#define GPIO30_SDATA_OUT 30 /* AC97/I2S Sdata_out */ ++#define GPIO31_SYNC 31 /* AC97/I2S sync */ ++#define GPIO32_SDATA_IN1 32 /* AC97 Sdata_in1 */ ++#define GPIO33_nCS_5 33 /* chip select 5 */ ++#define GPIO34_FFRXD 34 /* FFUART receive */ ++#define GPIO34_MMCCS0 34 /* MMC Chip Select 0 */ ++#define GPIO35_FFCTS 35 /* FFUART Clear to send */ ++#define GPIO36_FFDCD 36 /* FFUART Data carrier detect */ ++#define GPIO37_FFDSR 37 /* FFUART data set ready */ ++#define GPIO38_FFRI 38 /* FFUART Ring Indicator */ ++#define GPIO39_MMCCS1 39 /* MMC Chip Select 1 */ ++#define GPIO39_FFTXD 39 /* FFUART transmit data */ ++#define GPIO40_FFDTR 40 /* FFUART data terminal Ready */ ++#define GPIO41_FFRTS 41 /* FFUART request to send */ ++#define GPIO42_BTRXD 42 /* BTUART receive data */ ++#define GPIO43_BTTXD 43 /* BTUART transmit data */ ++#define GPIO44_BTCTS 44 /* BTUART clear to send */ ++#define GPIO45_BTRTS 45 /* BTUART request to send */ ++#define GPIO46_ICPRXD 46 /* ICP receive data */ ++#define GPIO46_STRXD 46 /* STD_UART receive data */ ++#define GPIO47_ICPTXD 47 /* ICP transmit data */ ++#define GPIO47_STTXD 47 /* STD_UART transmit data */ ++#define GPIO48_nPOE 48 /* Output Enable for Card Space */ ++#define GPIO49_nPWE 49 /* Write Enable for Card Space */ ++#define GPIO50_nPIOR 50 /* I/O Read for Card Space */ ++#define GPIO51_nPIOW 51 /* I/O Write for Card Space */ ++#define GPIO52_nPCE_1 52 /* Card Enable for Card Space */ ++#define GPIO53_nPCE_2 53 /* Card Enable for Card Space */ ++#define GPIO53_MMCCLK 53 /* MMC Clock */ ++#define GPIO54_MMCCLK 54 /* MMC Clock */ ++#define GPIO54_pSKTSEL 54 /* Socket Select for Card Space */ ++#define GPIO55_nPREG 55 /* Card Address bit 26 */ ++#define GPIO56_nPWAIT 56 /* Wait signal for Card Space */ ++#define GPIO57_nIOIS16 57 /* Bus Width select for I/O Card Space */ ++#define GPIO58_LDD_0 58 /* LCD data pin 0 */ ++#define GPIO59_LDD_1 59 /* LCD data pin 1 */ ++#define GPIO60_LDD_2 60 /* LCD data pin 2 */ ++#define GPIO61_LDD_3 61 /* LCD data pin 3 */ ++#define GPIO62_LDD_4 62 /* LCD data pin 4 */ ++#define GPIO63_LDD_5 63 /* LCD data pin 5 */ ++#define GPIO64_LDD_6 64 /* LCD data pin 6 */ ++#define GPIO65_LDD_7 65 /* LCD data pin 7 */ ++#define GPIO66_LDD_8 66 /* LCD data pin 8 */ ++#define GPIO66_MBREQ 66 /* alternate bus master req */ ++#define GPIO67_LDD_9 67 /* LCD data pin 9 */ ++#define GPIO67_MMCCS0 67 /* MMC Chip Select 0 */ ++#define GPIO68_LDD_10 68 /* LCD data pin 10 */ ++#define GPIO68_MMCCS1 68 /* MMC Chip Select 1 */ ++#define GPIO69_LDD_11 69 /* LCD data pin 11 */ ++#define GPIO69_MMCCLK 69 /* MMC_CLK */ ++#define GPIO70_LDD_12 70 /* LCD data pin 12 */ ++#define GPIO70_RTCCLK 70 /* Real Time clock (1 Hz) */ ++#define GPIO71_LDD_13 71 /* LCD data pin 13 */ ++#define GPIO71_3_6MHz 71 /* 3.6 MHz Oscillator clock */ ++#define GPIO72_LDD_14 72 /* LCD data pin 14 */ ++#define GPIO72_32kHz 72 /* 32 kHz clock */ ++#define GPIO73_LDD_15 73 /* LCD data pin 15 */ ++#define GPIO73_MBGNT 73 /* Memory controller grant */ ++#define GPIO74_LCD_FCLK 74 /* LCD Frame clock */ ++#define GPIO75_LCD_LCLK 75 /* LCD line clock */ ++#define GPIO76_LCD_PCLK 76 /* LCD Pixel clock */ ++#define GPIO77_LCD_ACBIAS 77 /* LCD AC Bias */ ++#define GPIO78_nCS_2 78 /* chip select 2 */ ++#define GPIO79_nCS_3 79 /* chip select 3 */ ++#define GPIO80_nCS_4 80 /* chip select 4 */ ++ ++/* GPIO alternate function mode & direction */ ++ ++#define GPIO_IN 0x000 ++#define GPIO_OUT 0x080 ++#define GPIO_ALT_FN_1_IN 0x100 ++#define GPIO_ALT_FN_1_OUT 0x180 ++#define GPIO_ALT_FN_2_IN 0x200 ++#define GPIO_ALT_FN_2_OUT 0x280 ++#define GPIO_ALT_FN_3_IN 0x300 ++#define GPIO_ALT_FN_3_OUT 0x380 ++#define GPIO_MD_MASK_NR 0x07f ++#define GPIO_MD_MASK_DIR 0x080 ++#define GPIO_MD_MASK_FN 0x300 ++ ++#define GPIO1_RTS_MD ( 1 | GPIO_ALT_FN_1_IN) ++#define GPIO6_MMCCLK_MD ( 6 | GPIO_ALT_FN_1_OUT) ++#define GPIO8_48MHz_MD ( 8 | GPIO_ALT_FN_1_OUT) ++#define GPIO8_MMCCS0_MD ( 8 | GPIO_ALT_FN_1_OUT) ++#define GPIO9_MMCCS1_MD ( 9 | GPIO_ALT_FN_1_OUT) ++#define GPIO10_RTCCLK_MD (10 | GPIO_ALT_FN_1_OUT) ++#define GPIO11_3_6MHz_MD (11 | GPIO_ALT_FN_1_OUT) ++#define GPIO12_32KHz_MD (12 | GPIO_ALT_FN_1_OUT) ++#define GPIO13_MBGNT_MD (13 | GPIO_ALT_FN_2_OUT) ++#define GPIO14_MBREQ_MD (14 | GPIO_ALT_FN_1_IN) ++#define GPIO15_nCS_1_MD (15 | GPIO_ALT_FN_2_OUT) ++#define GPIO16_PWM0_MD (16 | GPIO_ALT_FN_2_OUT) ++#define GPIO17_PWM1_MD (17 | GPIO_ALT_FN_2_OUT) ++#define GPIO18_RDY_MD (18 | GPIO_ALT_FN_1_IN) ++#define GPIO19_DREQ1_MD (19 | GPIO_ALT_FN_1_IN) ++#define GPIO20_DREQ0_MD (20 | GPIO_ALT_FN_1_IN) ++#define GPIO23_SCLK_md (23 | GPIO_ALT_FN_2_OUT) ++#define GPIO24_SFRM_MD (24 | GPIO_ALT_FN_2_OUT) ++#define GPIO25_STXD_MD (25 | GPIO_ALT_FN_2_OUT) ++#define GPIO26_SRXD_MD (26 | GPIO_ALT_FN_1_IN) ++#define GPIO27_SEXTCLK_MD (27 | GPIO_ALT_FN_1_IN) ++#define GPIO28_BITCLK_AC97_MD (28 | GPIO_ALT_FN_1_IN) ++#define GPIO28_BITCLK_I2S_MD (28 | GPIO_ALT_FN_2_IN) ++#define GPIO29_SDATA_IN_AC97_MD (29 | GPIO_ALT_FN_1_IN) ++#define GPIO29_SDATA_IN_I2S_MD (29 | GPIO_ALT_FN_2_IN) ++#define GPIO30_SDATA_OUT_AC97_MD (30 | GPIO_ALT_FN_2_OUT) ++#define GPIO30_SDATA_OUT_I2S_MD (30 | GPIO_ALT_FN_1_OUT) ++#define GPIO31_SYNC_AC97_MD (31 | GPIO_ALT_FN_2_OUT) ++#define GPIO31_SYNC_I2S_MD (31 | GPIO_ALT_FN_1_OUT) ++#define GPIO32_SDATA_IN1_AC97_MD (32 | GPIO_ALT_FN_1_IN) ++#define GPIO33_nCS_5_MD (33 | GPIO_ALT_FN_2_OUT) ++#define GPIO34_FFRXD_MD (34 | GPIO_ALT_FN_1_IN) ++#define GPIO34_MMCCS0_MD (34 | GPIO_ALT_FN_2_OUT) ++#define GPIO35_FFCTS_MD (35 | GPIO_ALT_FN_1_IN) ++#define GPIO36_FFDCD_MD (36 | GPIO_ALT_FN_1_IN) ++#define GPIO37_FFDSR_MD (37 | GPIO_ALT_FN_1_IN) ++#define GPIO38_FFRI_MD (38 | GPIO_ALT_FN_1_IN) ++#define GPIO39_MMCCS1_MD (39 | GPIO_ALT_FN_1_OUT) ++#define GPIO39_FFTXD_MD (39 | GPIO_ALT_FN_2_OUT) ++#define GPIO40_FFDTR_MD (40 | GPIO_ALT_FN_2_OUT) ++#define GPIO41_FFRTS_MD (41 | GPIO_ALT_FN_2_OUT) ++#define GPIO42_BTRXD_MD (42 | GPIO_ALT_FN_1_IN) ++#define GPIO43_BTTXD_MD (43 | GPIO_ALT_FN_2_OUT) ++#define GPIO44_BTCTS_MD (44 | GPIO_ALT_FN_1_IN) ++#define GPIO45_BTRTS_MD (45 | GPIO_ALT_FN_2_OUT) ++#define GPIO46_ICPRXD_MD (46 | GPIO_ALT_FN_1_IN) ++#define GPIO46_STRXD_MD (46 | GPIO_ALT_FN_2_IN) ++#define GPIO47_ICPTXD_MD (47 | GPIO_ALT_FN_2_OUT) ++#define GPIO47_STTXD_MD (47 | GPIO_ALT_FN_1_OUT) ++#define GPIO48_nPOE_MD (48 | GPIO_ALT_FN_2_OUT) ++#define GPIO49_nPWE_MD (49 | GPIO_ALT_FN_2_OUT) ++#define GPIO50_nPIOR_MD (50 | GPIO_ALT_FN_2_OUT) ++#define GPIO51_nPIOW_MD (51 | GPIO_ALT_FN_2_OUT) ++#define GPIO52_nPCE_1_MD (52 | GPIO_ALT_FN_2_OUT) ++#define GPIO53_nPCE_2_MD (53 | GPIO_ALT_FN_2_OUT) ++#define GPIO53_MMCCLK_MD (53 | GPIO_ALT_FN_1_OUT) ++#define GPIO54_MMCCLK_MD (54 | GPIO_ALT_FN_1_OUT) ++#define GPIO54_pSKTSEL_MD (54 | GPIO_ALT_FN_2_OUT) ++#define GPIO55_nPREG_MD (55 | GPIO_ALT_FN_2_OUT) ++#define GPIO56_nPWAIT_MD (56 | GPIO_ALT_FN_1_IN) ++#define GPIO57_nIOIS16_MD (57 | GPIO_ALT_FN_1_IN) ++#define GPIO58_LDD_0_MD (58 | GPIO_ALT_FN_2_OUT) ++#define GPIO59_LDD_1_MD (59 | GPIO_ALT_FN_2_OUT) ++#define GPIO60_LDD_2_MD (60 | GPIO_ALT_FN_2_OUT) ++#define GPIO61_LDD_3_MD (61 | GPIO_ALT_FN_2_OUT) ++#define GPIO62_LDD_4_MD (62 | GPIO_ALT_FN_2_OUT) ++#define GPIO63_LDD_5_MD (63 | GPIO_ALT_FN_2_OUT) ++#define GPIO64_LDD_6_MD (64 | GPIO_ALT_FN_2_OUT) ++#define GPIO65_LDD_7_MD (65 | GPIO_ALT_FN_2_OUT) ++#define GPIO66_LDD_8_MD (66 | GPIO_ALT_FN_2_OUT) ++#define GPIO66_MBREQ_MD (66 | GPIO_ALT_FN_1_IN) ++#define GPIO67_LDD_9_MD (67 | GPIO_ALT_FN_2_OUT) ++#define GPIO67_MMCCS0_MD (67 | GPIO_ALT_FN_1_OUT) ++#define GPIO68_LDD_10_MD (68 | GPIO_ALT_FN_2_OUT) ++#define GPIO68_MMCCS1_MD (68 | GPIO_ALT_FN_1_OUT) ++#define GPIO69_LDD_11_MD (69 | GPIO_ALT_FN_2_OUT) ++#define GPIO69_MMCCLK_MD (69 | GPIO_ALT_FN_1_OUT) ++#define GPIO70_LDD_12_MD (70 | GPIO_ALT_FN_2_OUT) ++#define GPIO70_RTCCLK_MD (70 | GPIO_ALT_FN_1_OUT) ++#define GPIO71_LDD_13_MD (71 | GPIO_ALT_FN_2_OUT) ++#define GPIO71_3_6MHz_MD (71 | GPIO_ALT_FN_1_OUT) ++#define GPIO72_LDD_14_MD (72 | GPIO_ALT_FN_2_OUT) ++#define GPIO72_32kHz_MD (72 | GPIO_ALT_FN_1_OUT) ++#define GPIO73_LDD_15_MD (73 | GPIO_ALT_FN_2_OUT) ++#define GPIO73_MBGNT_MD (73 | GPIO_ALT_FN_1_OUT) ++#define GPIO74_LCD_FCLK_MD (74 | GPIO_ALT_FN_2_OUT) ++#define GPIO75_LCD_LCLK_MD (75 | GPIO_ALT_FN_2_OUT) ++#define GPIO76_LCD_PCLK_MD (76 | GPIO_ALT_FN_2_OUT) ++#define GPIO77_LCD_ACBIAS_MD (77 | GPIO_ALT_FN_2_OUT) ++#define GPIO78_nCS_2_MD (78 | GPIO_ALT_FN_2_OUT) ++#define GPIO79_nCS_3_MD (79 | GPIO_ALT_FN_2_OUT) ++#define GPIO80_nCS_4_MD (80 | GPIO_ALT_FN_2_OUT) ++ ++ ++/* ++ * Power Manager ++ */ ++ ++#define PMCR __REG(0x40F00000) /* Power Manager Control Register */ ++#define PSSR __REG(0x40F00004) /* Power Manager Sleep Status Register */ ++#define PSPR __REG(0x40F00008) /* Power Manager Scratch Pad Register */ ++#define PWER __REG(0x40F0000C) /* Power Manager Wake-up Enable Register */ ++#define PRER __REG(0x40F00010) /* Power Manager GPIO Rising-Edge Detect Enable Register */ ++#define PFER __REG(0x40F00014) /* Power Manager GPIO Falling-Edge Detect Enable Register */ ++#define PEDR __REG(0x40F00018) /* Power Manager GPIO Edge Detect Status Register */ ++#define PCFR __REG(0x40F0001C) /* Power Manager General Configuration Register */ ++#define PGSR0 __REG(0x40F00020) /* Power Manager GPIO Sleep State Register for GP[31-0] */ ++#define PGSR1 __REG(0x40F00024) /* Power Manager GPIO Sleep State Register for GP[63-32] */ ++#define PGSR2 __REG(0x40F00028) /* Power Manager GPIO Sleep State Register for GP[84-64] */ ++#define RCSR __REG(0x40F00030) /* Reset Controller Status Register */ ++ ++#define PSSR_RDH (1 << 5) /* Read Disable Hold */ ++#define PSSR_PH (1 << 4) /* Peripheral Control Hold */ ++#define PSSR_VFS (1 << 2) /* VDD Fault Status */ ++#define PSSR_BFS (1 << 1) /* Battery Fault Status */ ++#define PSSR_SSS (1 << 0) /* Software Sleep Status */ ++ ++#define PCFR_DS (1 << 3) /* Deep Sleep Mode */ ++#define PCFR_FS (1 << 2) /* Float Static Chip Selects */ ++#define PCFR_FP (1 << 1) /* Float PCMCIA controls */ ++#define PCFR_OPDE (1 << 0) /* 3.6864 MHz oscillator power-down enable */ ++ ++#define RCSR_GPR (1 << 3) /* GPIO Reset */ ++#define RCSR_SMR (1 << 2) /* Sleep Mode */ ++#define RCSR_WDR (1 << 1) /* Watchdog Reset */ ++#define RCSR_HWR (1 << 0) /* Hardware Reset */ ++ ++ ++/* ++ * SSP Serial Port Registers ++ */ ++ ++#define SSCR0 __REG(0x41000000) /* SSP Control Register 0 */ ++#define SSCR1 __REG(0x41000004) /* SSP Control Register 1 */ ++#define SSSR __REG(0x41000008) /* SSP Status Register */ ++#define SSITR __REG(0x4100000C) /* SSP Interrupt Test Register */ ++#define SSDR __REG(0x41000010) /* (Write / Read) SSP Data Write Register/SSP Data Read Register */ ++ ++ ++/* ++ * MultiMediaCard (MMC) controller ++ */ ++ ++#define MMC_STRPCL __REG(0x41100000) /* Control to start and stop MMC clock */ ++#define MMC_STAT __REG(0x41100004) /* MMC Status Register (read only) */ ++#define MMC_CLKRT __REG(0x41100008) /* MMC clock rate */ ++#define MMC_SPI __REG(0x4110000c) /* SPI mode control bits */ ++#define MMC_CMDAT __REG(0x41100010) /* Command/response/data sequence control */ ++#define MMC_RESTO __REG(0x41100014) /* Expected response time out */ ++#define MMC_RDTO __REG(0x41100018) /* Expected data read time out */ ++#define MMC_BLKLEN __REG(0x4110001c) /* Block length of data transaction */ ++#define MMC_NOB __REG(0x41100020) /* Number of blocks, for block mode */ ++#define MMC_PRTBUF __REG(0x41100024) /* Partial MMC_TXFIFO FIFO written */ ++#define MMC_I_MASK __REG(0x41100028) /* Interrupt Mask */ ++#define MMC_I_REG __REG(0x4110002c) /* Interrupt Register (read only) */ ++#define MMC_CMD __REG(0x41100030) /* Index of current command */ ++#define MMC_ARGH __REG(0x41100034) /* MSW part of the current command argument */ ++#define MMC_ARGL __REG(0x41100038) /* LSW part of the current command argument */ ++#define MMC_RES __REG(0x4110003c) /* Response FIFO (read only) */ ++#define MMC_RXFIFO __REG(0x41100040) /* Receive FIFO (read only) */ ++#define MMC_TXFIFO __REG(0x41100044) /* Transmit FIFO (write only) */ ++ ++ ++/* ++ * Core Clock ++ */ ++ ++#define CCCR __REG(0x41300000) /* Core Clock Configuration Register */ ++#define CKEN __REG(0x41300004) /* Clock Enable Register */ ++#define OSCC __REG(0x41300008) /* Oscillator Configuration Register */ ++ ++#define CCCR_N_MASK 0x0380 /* Run Mode Frequency to Turbo Mode Frequency Multiplier */ ++#define CCCR_M_MASK 0x0060 /* Memory Frequency to Run Mode Frequency Multiplier */ ++#define CCCR_L_MASK 0x001f /* Crystal Frequency to Memory Frequency Multiplier */ ++ ++#define CKEN16_LCD (1 << 16) /* LCD Unit Clock Enable */ ++#define CKEN14_I2C (1 << 14) /* I2C Unit Clock Enable */ ++#define CKEN13_FICP (1 << 13) /* FICP Unit Clock Enable */ ++#define CKEN12_MMC (1 << 12) /* MMC Unit Clock Enable */ ++#define CKEN11_USB (1 << 11) /* USB Unit Clock Enable */ ++#define CKEN8_I2S (1 << 8) /* I2S Unit Clock Enable */ ++#define CKEN7_BTUART (1 << 7) /* BTUART Unit Clock Enable */ ++#define CKEN6_FFUART (1 << 6) /* FFUART Unit Clock Enable */ ++#define CKEN5_STUART (1 << 5) /* STUART Unit Clock Enable */ ++#define CKEN3_SSP (1 << 3) /* SSP Unit Clock Enable */ ++#define CKEN2_AC97 (1 << 2) /* AC97 Unit Clock Enable */ ++#define CKEN1_PWM1 (1 << 1) /* PWM1 Clock Enable */ ++#define CKEN0_PWM0 (1 << 0) /* PWM0 Clock Enable */ ++ ++#define OSCC_OON (1 << 1) /* 32.768kHz OON (write-once only bit) */ ++#define OSCC_OOK (1 << 0) /* 32.768kHz OOK (read-only bit) */ ++ ++ ++/* ++ * LCD ++ */ ++ ++#define LCCR0 __REG(0x44000000) /* LCD Controller Control Register 0 */ ++#define LCCR1 __REG(0x44000004) /* LCD Controller Control Register 1 */ ++#define LCCR2 __REG(0x44000008) /* LCD Controller Control Register 2 */ ++#define LCCR3 __REG(0x4400000C) /* LCD Controller Control Register 3 */ ++#define DFBR0 __REG(0x44000020) /* DMA Channel 0 Frame Branch Register */ ++#define DFBR1 __REG(0x44000024) /* DMA Channel 1 Frame Branch Register */ ++#define LCSR __REG(0x44000038) /* LCD Controller Status Register */ ++#define LIIDR __REG(0x4400003C) /* LCD Controller Interrupt ID Register */ ++#define TMEDRGBR __REG(0x44000040) /* TMED RGB Seed Register */ ++#define TMEDCR __REG(0x44000044) /* TMED Control Register */ ++ ++#define FDADR0 __REG(0x44000200) /* DMA Channel 0 Frame Descriptor Address Register */ ++#define FSADR0 __REG(0x44000204) /* DMA Channel 0 Frame Source Address Register */ ++#define FIDR0 __REG(0x44000208) /* DMA Channel 0 Frame ID Register */ ++#define LDCMD0 __REG(0x4400020C) /* DMA Channel 0 Command Register */ ++#define FDADR1 __REG(0x44000210) /* DMA Channel 1 Frame Descriptor Address Register */ ++#define FSADR1 __REG(0x44000214) /* DMA Channel 1 Frame Source Address Register */ ++#define FIDR1 __REG(0x44000218) /* DMA Channel 1 Frame ID Register */ ++#define LDCMD1 __REG(0x4400021C) /* DMA Channel 1 Command Register */ ++ ++#define LCCR0_ENB (1 << 0) /* LCD Controller enable */ ++#define LCCR0_CMS (1 << 1) /* Color = 0, Monochrome = 1 */ ++#define LCCR0_SDS (1 << 2) /* Single Panel = 0, Dual Panel = 1 */ ++#define LCCR0_LDM (1 << 3) /* LCD Disable Done Mask */ ++#define LCCR0_SFM (1 << 4) /* Start of frame mask */ ++#define LCCR0_IUM (1 << 5) /* Input FIFO underrun mask */ ++#define LCCR0_EFM (1 << 6) /* End of Frame mask */ ++#define LCCR0_PAS (1 << 7) /* Passive = 0, Active = 1 */ ++#define LCCR0_BLE (1 << 8) /* Little Endian = 0, Big Endian = 1 */ ++#define LCCR0_DPD (1 << 9) /* Double Pixel mode, 4 pixel value = 0, 8 pixle values = 1 */ ++#define LCCR0_DIS (1 << 10) /* LCD Disable */ ++#define LCCR0_QDM (1 << 11) /* LCD Quick Disable mask */ ++#define LCCR0_PDD (0xff << 12) /* Palette DMA request delay */ ++#define LCCR0_PDD_S 12 ++#define LCCR0_BM (1 << 20) /* Branch mask */ ++#define LCCR0_OUM (1 << 21) /* Output FIFO underrun mask */ ++ ++#define LCCR1_PPL Fld (10, 0) /* Pixels Per Line - 1 */ ++#define LCCR1_DisWdth(Pixel) /* Display Width [1..800 pix.] */ \ ++ (((Pixel) - 1) << FShft (LCCR1_PPL)) ++ ++#define LCCR1_HSW Fld (6, 10) /* Horizontal Synchronization */ ++#define LCCR1_HorSnchWdth(Tpix) /* Horizontal Synchronization */ \ ++ /* pulse Width [1..64 Tpix] */ \ ++ (((Tpix) - 1) << FShft (LCCR1_HSW)) ++ ++#define LCCR1_ELW Fld (8, 16) /* End-of-Line pixel clock Wait */ ++ /* count - 1 [Tpix] */ ++#define LCCR1_EndLnDel(Tpix) /* End-of-Line Delay */ \ ++ /* [1..256 Tpix] */ \ ++ (((Tpix) - 1) << FShft (LCCR1_ELW)) ++ ++#define LCCR1_BLW Fld (8, 24) /* Beginning-of-Line pixel clock */ ++ /* Wait count - 1 [Tpix] */ ++#define LCCR1_BegLnDel(Tpix) /* Beginning-of-Line Delay */ \ ++ /* [1..256 Tpix] */ \ ++ (((Tpix) - 1) << FShft (LCCR1_BLW)) ++ ++ ++#define LCCR2_LPP Fld (10, 0) /* Line Per Panel - 1 */ ++#define LCCR2_DisHght(Line) /* Display Height [1..1024 lines] */ \ ++ (((Line) - 1) << FShft (LCCR2_LPP)) ++ ++#define LCCR2_VSW Fld (6, 10) /* Vertical Synchronization pulse */ ++ /* Width - 1 [Tln] (L_FCLK) */ ++#define LCCR2_VrtSnchWdth(Tln) /* Vertical Synchronization pulse */ \ ++ /* Width [1..64 Tln] */ \ ++ (((Tln) - 1) << FShft (LCCR2_VSW)) ++ ++#define LCCR2_EFW Fld (8, 16) /* End-of-Frame line clock Wait */ ++ /* count [Tln] */ ++#define LCCR2_EndFrmDel(Tln) /* End-of-Frame Delay */ \ ++ /* [0..255 Tln] */ \ ++ ((Tln) << FShft (LCCR2_EFW)) ++ ++#define LCCR2_BFW Fld (8, 24) /* Beginning-of-Frame line clock */ ++ /* Wait count [Tln] */ ++#define LCCR2_BegFrmDel(Tln) /* Beginning-of-Frame Delay */ \ ++ /* [0..255 Tln] */ \ ++ ((Tln) << FShft (LCCR2_BFW)) ++ ++#if 0 ++#define LCCR3_PCD (0xff) /* Pixel clock divisor */ ++#define LCCR3_ACB (0xff << 8) /* AC Bias pin frequency */ ++#define LCCR3_ACB_S 8 ++#endif ++ ++#define LCCR3_API (0xf << 16) /* AC Bias pin trasitions per interrupt */ ++#define LCCR3_API_S 16 ++#define LCCR3_VSP (1 << 20) /* vertical sync polarity */ ++#define LCCR3_HSP (1 << 21) /* horizontal sync polarity */ ++#define LCCR3_PCP (1 << 22) /* pixel clock polarity */ ++#define LCCR3_OEP (1 << 23) /* output enable polarity */ ++#if 0 ++#define LCCR3_BPP (7 << 24) /* bits per pixel */ ++#define LCCR3_BPP_S 24 ++#endif ++#define LCCR3_DPC (1 << 27) /* double pixel clock mode */ ++ ++ ++#define LCCR3_PCD Fld (8, 0) /* Pixel Clock Divisor */ ++#define LCCR3_PixClkDiv(Div) /* Pixel Clock Divisor */ \ ++ (((Div) << FShft (LCCR3_PCD))) ++ ++ ++#define LCCR3_BPP Fld (3, 24) /* Bit Per Pixel */ ++#define LCCR3_Bpp(Bpp) /* Bit Per Pixel */ \ ++ (((Bpp) << FShft (LCCR3_BPP))) ++ ++#define LCCR3_ACB Fld (8, 8) /* AC Bias */ ++#define LCCR3_Acb(Acb) /* BAC Bias */ \ ++ (((Acb) << FShft (LCCR3_ACB))) ++ ++#define LCCR3_HorSnchH (LCCR3_HSP*0) /* Horizontal Synchronization */ ++ /* pulse active High */ ++#define LCCR3_HorSnchL (LCCR3_HSP*1) /* Horizontal Synchronization */ ++ ++#define LCCR3_VrtSnchH (LCCR3_VSP*0) /* Vertical Synchronization pulse */ ++ /* active High */ ++#define LCCR3_VrtSnchL (LCCR3_VSP*1) /* Vertical Synchronization pulse */ ++ /* active Low */ ++ ++#define LCSR_LDD (1 << 0) /* LCD Disable Done */ ++#define LCSR_SOF (1 << 1) /* Start of frame */ ++#define LCSR_BER (1 << 2) /* Bus error */ ++#define LCSR_ABC (1 << 3) /* AC Bias count */ ++#define LCSR_IUL (1 << 4) /* input FIFO underrun Lower panel */ ++#define LCSR_IUU (1 << 5) /* input FIFO underrun Upper panel */ ++#define LCSR_OU (1 << 6) /* output FIFO underrun */ ++#define LCSR_QD (1 << 7) /* quick disable */ ++#define LCSR_EOF (1 << 8) /* end of frame */ ++#define LCSR_BS (1 << 9) /* branch status */ ++#define LCSR_SINT (1 << 10) /* subsequent interrupt */ ++ ++#define LDCMD_PAL (1 << 26) /* instructs DMA to load palette buffer */ ++ ++#define LCSR_LDD (1 << 0) /* LCD Disable Done */ ++#define LCSR_SOF (1 << 1) /* Start of frame */ ++#define LCSR_BER (1 << 2) /* Bus error */ ++#define LCSR_ABC (1 << 3) /* AC Bias count */ ++#define LCSR_IUL (1 << 4) /* input FIFO underrun Lower panel */ ++#define LCSR_IUU (1 << 5) /* input FIFO underrun Upper panel */ ++#define LCSR_OU (1 << 6) /* output FIFO underrun */ ++#define LCSR_QD (1 << 7) /* quick disable */ ++#define LCSR_EOF (1 << 8) /* end of frame */ ++#define LCSR_BS (1 << 9) /* branch status */ ++#define LCSR_SINT (1 << 10) /* subsequent interrupt */ ++ ++#define LDCMD_PAL (1 << 26) /* instructs DMA to load palette buffer */ ++ ++/* ++ * Memory controller ++ */ ++ ++#define MDCNFG __REG(0x48000000) /* SDRAM Configuration Register 0 */ ++#define MDREFR __REG(0x48000004) /* SDRAM Refresh Control Register */ ++#define MSC0 __REG(0x48000008) /* Static Memory Control Register 0 */ ++#define MSC1 __REG(0x4800000C) /* Static Memory Control Register 1 */ ++#define MSC2 __REG(0x48000010) /* Static Memory Control Register 2 */ ++#define MECR __REG(0x48000014) /* Expansion Memory (PCMCIA/Compact Flash) Bus Configuration */ ++#define SXLCR __REG(0x48000018) /* LCR value to be written to SDRAM-Timing Synchronous Flash */ ++#define SXCNFG __REG(0x4800001C) /* Synchronous Static Memory Control Register */ ++#define SXMRS __REG(0x48000024) /* MRS value to be written to Synchronous Flash or SMROM */ ++#define MCMEM0 __REG(0x48000028) /* Card interface Common Memory Space Socket 0 Timing */ ++#define MCMEM1 __REG(0x4800002C) /* Card interface Common Memory Space Socket 1 Timing */ ++#define MCATT0 __REG(0x48000030) /* Card interface Attribute Space Socket 0 Timing Configuration */ ++#define MCATT1 __REG(0x48000034) /* Card interface Attribute Space Socket 1 Timing Configuration */ ++#define MCIO0 __REG(0x48000038) /* Card interface I/O Space Socket 0 Timing Configuration */ ++#define MCIO1 __REG(0x4800003C) /* Card interface I/O Space Socket 1 Timing Configuration */ ++#define MDMRS __REG(0x48000040) /* MRS value to be written to SDRAM */ ++#define BOOT_DEF __REG(0x48000044) /* Read-Only Boot-Time Register. Contains BOOT_SEL and PKG_SEL */ ++ ++#define MDREFR_K2FREE (1 << 25) /* SDRAM Free-Running Control */ ++#define MDREFR_K1FREE (1 << 24) /* SDRAM Free-Running Control */ ++#define MDREFR_K0FREE (1 << 23) /* SDRAM Free-Running Control */ ++#define MDREFR_SLFRSH (1 << 22) /* SDRAM Self-Refresh Control/Status */ ++#define MDREFR_APD (1 << 20) /* SDRAM/SSRAM Auto-Power-Down Enable */ ++#define MDREFR_K2DB2 (1 << 19) /* SDCLK2 Divide by 2 Control/Status */ ++#define MDREFR_K2RUN (1 << 18) /* SDCLK2 Run Control/Status */ ++#define MDREFR_K1DB2 (1 << 17) /* SDCLK1 Divide by 2 Control/Status */ ++#define MDREFR_K1RUN (1 << 16) /* SDCLK1 Run Control/Status */ ++#define MDREFR_E1PIN (1 << 15) /* SDCKE1 Level Control/Status */ ++#define MDREFR_K0DB2 (1 << 14) /* SDCLK0 Divide by 2 Control/Status */ ++#define MDREFR_K0RUN (1 << 13) /* SDCLK0 Run Control/Status */ ++#define MDREFR_E0PIN (1 << 12) /* SDCKE0 Level Control/Status */ ++ ++#endif +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/serial.h +@@ -0,0 +1,51 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/serial.h ++ * ++ * Author: Nicolas Pitre ++ * Copyright: (C) 2001 MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++ ++#define BAUD_BASE 921600 ++ ++/* Standard COM flags */ ++#define STD_COM_FLAGS (ASYNC_SKIP_TEST) ++ ++#define STD_SERIAL_PORT_DEFNS \ ++ { \ ++ type: PORT_PXA, \ ++ xmit_fifo_size: 32, \ ++ baud_base: BAUD_BASE, \ ++ iomem_base: (void *)&FFUART,\ ++ iomem_reg_shift: 2, \ ++ io_type: SERIAL_IO_MEM32,\ ++ irq: IRQ_FFUART, \ ++ flags: STD_COM_FLAGS, \ ++ }, { \ ++ type: PORT_PXA, \ ++ xmit_fifo_size: 32, \ ++ baud_base: BAUD_BASE, \ ++ iomem_base: (void *)&BTUART,\ ++ iomem_reg_shift: 2, \ ++ io_type: SERIAL_IO_MEM32,\ ++ irq: IRQ_BTUART, \ ++ flags: STD_COM_FLAGS, \ ++ }, { \ ++ type: PORT_PXA, \ ++ xmit_fifo_size: 32, \ ++ baud_base: BAUD_BASE, \ ++ iomem_base: (void *)&STUART,\ ++ iomem_reg_shift: 2, \ ++ io_type: SERIAL_IO_MEM32,\ ++ irq: IRQ_STUART, \ ++ flags: STD_COM_FLAGS, \ ++ } ++ ++#define RS_TABLE_SIZE 8 ++ ++#define EXTRA_SERIAL_PORT_DEFNS ++ +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/system.h +@@ -0,0 +1,32 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/system.h ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include "hardware.h" ++ ++static inline void arch_idle(void) ++{ ++ cpu_do_idle(); ++} ++ ++static inline void arch_reset(char mode) ++{ ++ if (mode == 's') { ++ /* Jump into ROM at address 0 */ ++ cpu_reset(0); ++ } else { ++ /* Initialize the watchdog and let it fire */ ++ OWER = OWER_WME; ++ OSSR = OSSR_M3; ++ OSMR3 = OSCR + 368640; /* ... in 100 ms */ ++ } ++} ++ +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/time.h +@@ -0,0 +1,86 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/time.h ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++ ++static inline unsigned long pxa_get_rtc_time(void) ++{ ++ return RCNR; ++} ++ ++static int pxa_set_rtc(void) ++{ ++ unsigned long current_time = xtime.tv_sec; ++ ++ if (RTSR & RTSR_ALE) { ++ /* make sure not to forward the clock over an alarm */ ++ unsigned long alarm = RTAR; ++ if (current_time >= alarm && alarm >= RCNR) ++ return -ERESTARTSYS; ++ } ++ RCNR = current_time; ++ return 0; ++} ++ ++/* IRQs are disabled before entering here from do_gettimeofday() */ ++static unsigned long pxa_gettimeoffset (void) ++{ ++ unsigned long ticks_to_match, elapsed, usec; ++ ++ /* Get ticks before next timer match */ ++ ticks_to_match = OSMR0 - OSCR; ++ ++ /* We need elapsed ticks since last match */ ++ elapsed = LATCH - ticks_to_match; ++ ++ /* Now convert them to usec */ ++ usec = (unsigned long)(elapsed*tick)/LATCH; ++ ++ return usec; ++} ++ ++static void pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ long flags; ++ int next_match; ++ ++ do_profile(regs); ++ ++ /* Loop until we get ahead of the free running timer. ++ * This ensures an exact clock tick count and time acuracy. ++ * IRQs are disabled inside the loop to ensure coherence between ++ * lost_ticks (updated in do_timer()) and the match reg value, so we ++ * can use do_gettimeofday() from interrupt handlers. ++ */ ++ do { ++ do_leds(); ++ do_set_rtc(); ++ save_flags_cli( flags ); ++ do_timer(regs); ++ OSSR = OSSR_M0; /* Clear match on timer 0 */ ++ next_match = (OSMR0 += LATCH); ++ restore_flags( flags ); ++ } while( (signed long)(next_match - OSCR) <= 0 ); ++} ++ ++extern inline void setup_timer (void) ++{ ++ gettimeoffset = pxa_gettimeoffset; ++ set_rtc = pxa_set_rtc; ++ xtime.tv_sec = pxa_get_rtc_time(); ++ timer_irq.handler = pxa_timer_interrupt; ++ OSMR0 = 0; /* set initial match at 0 */ ++ OSSR = 0xf; /* clear status on all timers */ ++ setup_arm_irq(IRQ_OST0, &timer_irq); ++ OIER |= OIER_E0; /* enable match on timer 0 to cause interrupts */ ++ OSCR = 0; /* initialize free-running timer, force first match */ ++} ++ +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/timex.h +@@ -0,0 +1,17 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/timex.h ++ * ++ * Author: Nicolas Pitre ++ * Created: Jun 15, 2001 ++ * Copyright: MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++/* ++ * PXA250/210 timer ++ */ ++#define CLOCK_TICK_RATE 3686400 ++#define CLOCK_TICK_FACTOR 80 +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/trizeps2.h +@@ -0,0 +1,206 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/trizeps2.h ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Copyright (c) 2002 Luc De Cock, Teradyne DS, Ltd. ++ * ++ * 2002-10-10: Initial code started from idp.h ++ */ ++ ++ ++/* ++ * Note: this file must be safe to include in assembly files ++ */ ++ ++/* comment out following if you have a board with 32MB RAM */ ++//#define PXA_TRIZEPS2_64MB 1 ++#undef PXA_TRIZEPS2_64MB ++ ++#define TRIZEPS2_FLASH_PHYS (PXA_CS0_PHYS) ++#define TRIZEPS2_ALT_FLASH_PHYS (PXA_CS1_PHYS) ++#define TRIZEPS2_MEDIAQ_PHYS (PXA_CS3_PHYS) ++#define TRIZEPS2_IDE_PHYS (PXA_CS5_PHYS + 0x03000000) ++#define TRIZEPS2_ETH_PHYS (0x0C800000) ++#define TRIZEPS2_COREVOLT_PHYS (PXA_CS5_PHYS + 0x03800000) ++#define TRIZEPS2_BCR_PHYS (0x0E000000) ++#define TRIZEPS2_CPLD_PHYS (0x0C000000) ++ ++/* ++ * virtual memory map ++ */ ++ ++#define TRIZEPS2_IDE_BASE (0xf0000000) ++#define TRIZEPS2_IDE_SIZE (1*1024*1024) ++ ++#define TRIZEPS2_ETH_BASE (0xf1000000) ++#define TRIZEPS2_ETH_SIZE (1*1024*1024) ++#define ETH_BASE TRIZEPS2_ETH_BASE //smc9194 driver compatibility issue ++ ++#define TRIZEPS2_COREVOLT_BASE (TRIZEPS2_ETH_BASE + TRIZEPS2_ETH_SIZE) ++#define TRIZEPS2_COREVOLT_SIZE (1*1024*1024) ++ ++#define TRIZEPS2_BCR_BASE (0xf0000000) ++#define TRIZEPS2_BCR_SIZE (1*1024*1024) ++ ++#define BCR_P2V(x) ((x) - TRIZEPS2_BCR_PHYS + TRIZEPS2_BCR_BASE) ++#define BCR_V2P(x) ((x) - TRIZEPS2_BCR_BASE + TRIZEPS2_BCR_PHYS) ++ ++#ifndef __ASSEMBLY__ ++# define __BCR_REG(x) (*((volatile unsigned short *)BCR_P2V(x))) ++#else ++# define __BCR_REG(x) BCR_P2V(x) ++#endif ++ ++/* board level registers */ ++#define TRIZEPS2_CPLD_BASE (0xf0100000) ++#define CPLD_P2V(x) ((x) - TRIZEPS2_CPLD_PHYS + TRIZEPS2_CPLD_BASE) ++#define CPLD_V2P(x) ((x) - TRIZEPS2_CPLD_BASE + TRIZEPS2_CPLD_PHYS) ++ ++#ifndef __ASSEMBLY__ ++# define __CPLD_REG(x) (*((volatile unsigned short *)CPLD_P2V(x))) ++#else ++# define __CPLD_REG(x) CPLD_P2V(x) ++#endif ++ ++#define _TRIZEPS2_PCCARD_STATUS (0x0c000000) ++#define TRIZEPS2_PCCARD_STATUS __CPLD_REG(_TRIZEPS2_PCCARD_STATUS) ++ ++/* ++ * CS memory timing via Static Memory Control Register (MSC0-2) ++ */ ++ ++#define MSC_CS(cs,val) ((val)<<((cs&1)<<4)) ++ ++#define MSC_RBUFF_SHIFT 15 ++#define MSC_RBUFF(x) ((x)<<MSC_RBUFF_SHIFT) ++#define MSC_RBUFF_SLOW MSC_RBUFF(0) ++#define MSC_RBUFF_FAST MSC_RBUFF(1) ++ ++#define MSC_RRR_SHIFT 12 ++#define MSC_RRR(x) ((x)<<MSC_RRR_SHIFT) ++ ++#define MSC_RDN_SHIFT 8 ++#define MSC_RDN(x) ((x)<<MSC_RDN_SHIFT) ++ ++#define MSC_RDF_SHIFT 4 ++#define MSC_RDF(x) ((x)<<MSC_RDF_SHIFT) ++ ++#define MSC_RBW_SHIFT 3 ++#define MSC_RBW(x) ((x)<<MSC_RBW_SHIFT) ++#define MSC_RBW_16 MSC_RBW(1) ++#define MSC_RBW_32 MSC_RBW(0) ++ ++#define MSC_RT_SHIFT 0 ++#define MSC_RT(x) ((x)<<MSC_RT_SHIFT) ++ ++ ++/* ++ * Bit masks for various registers ++ */ ++// TRIZEPS2_BCR_PCCARD_PWR ++#define PCC_3V (1 << 0) ++#define PCC_5V (1 << 1) ++#define PCC_EN1 (1 << 2) ++#define PCC_EN0 (1 << 3) ++ ++// TRIZEPS2_BCR_PCCARD_EN ++#define PCC_RESET (1 << 6) ++#define PCC_ENABLE (1 << 0) ++ ++// TRIZEPS2_BSR_PCCARDx_STATUS ++#define _PCC_WRPROT (1 << 7) // 7-4 read as low true ++#define _PCC_RESET (1 << 6) ++#define _PCC_IRQ (1 << 5) ++#define _PCC_INPACK (1 << 4) ++#define PCC_BVD1 (1 << 0) ++#define PCC_BVD2 (1 << 1) ++#define PCC_VS1 (1 << 2) ++#define PCC_VS2 (1 << 3) ++ ++// TRIZEPS2_BCR_CONTROL bits ++#define BCR_LCD_ON (1 << 4) ++#define BCR_LCD_OFF (0) ++#define BCR_LCD_MASK (1 << 4) ++#define BCR_PCMCIA_RESET (1 << 7) ++#define BCR_PCMCIA_NORMAL (0) ++ ++#define PCC_DETECT (GPLR(24) & GPIO_bit(24)) ++#define PCC_READY (GPLR(1) & GPIO_bit(1)) ++ ++// Board Control Register ++#define _TRIZEPS2_BCR_CONTROL (TRIZEPS2_BCR_PHYS) ++#define TRIZEPS2_BCR_CONTROL __BCR_REG(_TRIZEPS2_BCR_CONTROL) ++ ++// Board TTL-IO register ++#define TRIZEPS2_TTLIO_PHYS (0x0d800000) ++#define TRIZEPS2_TTLIO_BASE (0xf2000000) ++// various ioctl cmds ++#define TTLIO_RESET 0 ++#define TTLIO_GET 1 ++#define TTLIO_SET 2 ++#define TTLIO_UNSET 3 ++ ++/* ++ * Macros for LCD Driver ++ */ ++ ++#ifdef CONFIG_FB_PXA ++ ++#define FB_BACKLIGHT_ON() ++#define FB_BACKLIGHT_OFF() ++ ++#define FB_PWR_ON() ++#define FB_PWR_OFF() ++ ++#define FB_VLCD_ON() WRITE_TRIZEPS2_BCR(BCR_LCD_ON,BCR_LCD_MASK); ++#define FB_VLCD_OFF() WRITE_TRIZEPS2_BCR(BCR_LCD_OFF,BCR_LCD_MASK); ++ ++#endif ++ ++/* A listing of interrupts used by external hardware devices */ ++ ++#define GPIO_TOUCH_PANEL_IRQ 2 ++#define TOUCH_PANEL_IRQ IRQ_GPIO(GPIO_TOUCH_PANEL_IRQ) ++#define GPIO_ETHERNET_IRQ 19 ++#define ETHERNET_IRQ IRQ_GPIO(GPIO_ETHERNET_IRQ) ++#define GPIO_TTLIO_IRQ 23 ++#define TTLIO_IRQ IRQ_GPIO(GPIO_TTLIO_IRQ) ++ ++#define TOUCH_PANEL_IRQ_EDGE GPIO_FALLING_EDGE ++#define IDE_IRQ_EDGE GPIO_RISING_EDGE ++#define ETHERNET_IRQ_EDGE GPIO_RISING_EDGE ++ ++#define PCMCIA_S_CD_VALID IRQ_GPIO(24) ++#define PCMCIA_S_CD_VALID_EDGE GPIO_BOTH_EDGES ++ ++#define PCMCIA_S_RDYINT IRQ_GPIO(1) ++#define PCMCIA_S_RDYINT_EDGE GPIO_FALLING_EDGE ++ ++/* ++ * macros for MTD driver ++ */ ++ ++#define FLASH_WRITE_PROTECT_DISABLE() // ((TRIZEPS2_CPLD_FLASH_WE) &= ~(0x1)) ++#define FLASH_WRITE_PROTECT_ENABLE() // ((TRIZEPS2_CPLD_FLASH_WE) |= (0x1)) ++ ++/* shadow registers for write only registers */ ++#ifndef __ASSEMBLY__ ++extern unsigned short trizeps2_bcr_shadow; ++#endif ++ ++/* ++ * macros to write to write only register ++ * ++ * none of these macros are protected from ++ * multiple drivers using them in interrupt context. ++ */ ++ ++#define WRITE_TRIZEPS2_BCR(value, mask) \ ++{\ ++ trizeps2_bcr_shadow = ((value & mask) | (trizeps2_bcr_shadow & ~mask));\ ++ TRIZEPS2_BCR_CONTROL = trizeps2_bcr_shadow;\ ++} ++ +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/uncompress.h +@@ -0,0 +1,42 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/uncompress.h ++ * ++ * Author: Nicolas Pitre ++ * Copyright: (C) 2001 MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#define FFUART ((volatile unsigned long *)0x40100000) ++#define BTUART ((volatile unsigned long *)0x40200000) ++#define STUART ((volatile unsigned long *)0x40700000) ++ ++#define UART FFUART ++ ++ ++static __inline__ void putc(char c) ++{ ++ while (!(UART[5] & 0x20)); ++ UART[0] = c; ++} ++ ++/* ++ * This does not append a newline ++ */ ++static void puts(const char *s) ++{ ++ while (*s) { ++ putc(*s); ++ if (*s == '\n') ++ putc('\r'); ++ s++; ++ } ++} ++ ++/* ++ * nothing to do ++ */ ++#define arch_decomp_setup() ++#define arch_decomp_wdog() +--- /dev/null ++++ linux-2.4.27/include/asm-arm/arch-pxa/vmalloc.h +@@ -0,0 +1,23 @@ ++/* ++ * linux/include/asm-arm/arch-pxa/vmalloc.h ++ * ++ * Author: Nicolas Pitre ++ * Copyright: (C) 2001 MontaVista Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++/* ++ * Just any arbitrary offset to the start of the vmalloc VM area: the ++ * current 8MB value just means that there will be a 8MB "hole" after the ++ * physical memory until the kernel virtual memory starts. That means that ++ * any out-of-bounds memory accesses will hopefully be caught. ++ * The vmalloc() routines leaves a hole of 4kB between each vmalloced ++ * area for the same reason. ;) ++ */ ++#define VMALLOC_OFFSET (8*1024*1024) ++#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) ++#define VMALLOC_VMADDR(x) ((unsigned long)(x)) ++#define VMALLOC_END (0xe8000000) +--- linux-2.4.27/include/asm-arm/assembler.h~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/include/asm-arm/assembler.h +@@ -13,3 +13,26 @@ + + #include <asm/proc/ptrace.h> + #include <asm/proc/assembler.h> ++ ++/* ++ * Endian independent macros for shifting bytes within registers. ++ */ ++#ifndef __ARMEB__ ++#define pull lsr ++#define push lsl ++#define byte(x) (x*8) ++#else ++#define pull lsl ++#define push lsr ++#define byte(x) ((3-x)*8) ++#endif ++ ++/* ++ * Data preload for architectures that support it ++ */ ++#if __LINUX_ARM_ARCH__ >= 5 ++#define PLD(code...) code ++#else ++#define PLD(code...) ++#endif ++ +--- linux-2.4.27/include/asm-arm/bitops.h~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/include/asm-arm/bitops.h +@@ -91,6 +91,8 @@ + return (((unsigned char *) addr)[nr >> 3] >> (nr & 7)) & 1; + } + ++#if __LINUX_ARM_ARCH__ < 5 ++ + /* + * ffz = Find First Zero in word. Undefined if no zero exists, + * so code should check against ~0UL first.. +@@ -117,6 +119,23 @@ + + #define ffs(x) generic_ffs(x) + ++#else ++ ++/* ++ * On ARMv5 and above those functions can be implemented around ++ * the clz instruction for much better code efficiency. ++ */ ++ ++extern __inline__ int generic_fls(int x); ++#define fls(x) \ ++ ( __builtin_constant_p(x) ? generic_fls(x) : \ ++ ({ int __r; asm("clz%?\t%0, %1" : "=r"(__r) : "r"(x)); 32-__r; }) ) ++#define ffs(x) ({ unsigned long __t = (x); fls(__t & -__t); }) ++#define __ffs(x) (ffs(x) - 1) ++#define ffz(x) __ffs( ~(x) ) ++ ++#endif ++ + /* + * hweightN: returns the hamming weight (i.e. the number + * of bits set) of a N-bit word +--- linux-2.4.27/include/asm-arm/io.h~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/include/asm-arm/io.h +@@ -168,7 +168,7 @@ + * devices. This is the "generic" version. The PCI specific version + * is in pci.h + */ +-extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle); ++extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle, unsigned long flags); + extern void consistent_free(void *vaddr, size_t size, dma_addr_t handle); + extern void consistent_sync(void *vaddr, size_t size, int rw); + +--- linux-2.4.27/include/asm-arm/memory.h~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/include/asm-arm/memory.h +@@ -123,6 +123,9 @@ + ((unsigned)((page) - NODE_MEM_MAP(node)) < NODE_DATA(node)->node_size)); \ + }) + ++/* We want large page mapping possible */ ++#define VMALLOC_ALIGN 0x10000 ++ + #endif + + /* +--- linux-2.4.27/include/asm-arm/proc-armv/pgtable.h~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/include/asm-arm/proc-armv/pgtable.h +@@ -15,9 +15,6 @@ + #ifndef __ASM_PROC_PGTABLE_H + #define __ASM_PROC_PGTABLE_H + +-#include <asm/proc/domain.h> +-#include <asm/arch/vmalloc.h> +- + /* + * entries per page directory level: they are two-level, so + * we don't really have any PMD directory. +@@ -26,27 +23,92 @@ + #define PTRS_PER_PMD 1 + #define PTRS_PER_PGD 4096 + +-/**************** +-* PMD functions * +-****************/ +- +-/* PMD types (actually level 1 descriptor) */ +-#define PMD_TYPE_MASK 0x0003 +-#define PMD_TYPE_FAULT 0x0000 +-#define PMD_TYPE_TABLE 0x0001 +-#define PMD_TYPE_SECT 0x0002 +-#define PMD_UPDATABLE 0x0010 +-#define PMD_SECT_CACHEABLE 0x0008 +-#define PMD_SECT_BUFFERABLE 0x0004 +-#define PMD_SECT_AP_WRITE 0x0400 +-#define PMD_SECT_AP_READ 0x0800 ++/* ++ * Hardware page table definitions. ++ * ++ * + Level 1 descriptor (PMD) ++ * - common ++ */ ++#define PMD_TYPE_MASK (3 << 0) ++#define PMD_TYPE_FAULT (0 << 0) ++#define PMD_TYPE_TABLE (1 << 0) ++#define PMD_TYPE_SECT (2 << 0) ++#define PMD_UPDATABLE (1 << 4) + #define PMD_DOMAIN(x) ((x) << 5) ++#define PMD_PROTECTION (1 << 9) /* v5 */ ++/* ++ * - section ++ */ ++#define PMD_SECT_BUFFERABLE (1 << 2) ++#define PMD_SECT_CACHEABLE (1 << 3) ++#define PMD_SECT_AP_WRITE (1 << 10) ++#define PMD_SECT_AP_READ (1 << 11) ++#define PMD_SECT_TEX(x) ((x) << 12) /* v5 */ ++/* ++ * - coarse table ++ */ ++ ++/* ++ * + Level 2 descriptor (PTE) ++ * - common ++ */ ++#define PTE_TYPE_MASK (3 << 0) ++#define PTE_TYPE_FAULT (0 << 0) ++#define PTE_TYPE_LARGE (1 << 0) ++#define PTE_TYPE_SMALL (2 << 0) ++#define PTE_TYPE_EXT (3 << 0) /* v5 */ ++#define PTE_BUFFERABLE (1 << 2) ++#define PTE_CACHEABLE (1 << 3) ++ ++/* ++ * - extended small page/tiny page ++ */ ++#define PTE_EXT_AP_UNO_SRO (0 << 4) ++#define PTE_EXT_AP_UNO_SRW (1 << 4) ++#define PTE_EXT_AP_URO_SRW (2 << 4) ++#define PTE_EXT_AP_URW_SRW (3 << 4) ++#define PTE_EXT_TEX(x) ((x) << 6) /* v5 */ ++ ++/* ++ * - small page ++ */ ++#define PTE_SMALL_AP_UNO_SRO (0x00 << 4) ++#define PTE_SMALL_AP_UNO_SRW (0x55 << 4) ++#define PTE_SMALL_AP_URO_SRW (0xaa << 4) ++#define PTE_SMALL_AP_URW_SRW (0xff << 4) ++#define PTE_AP_READ PTE_SMALL_AP_URO_SRW ++#define PTE_AP_WRITE PTE_SMALL_AP_UNO_SRW ++ ++/* ++ * "Linux" PTE definitions. ++ * ++ * We keep two sets of PTEs - the hardware and the linux version. ++ * This allows greater flexibility in the way we map the Linux bits ++ * onto the hardware tables, and allows us to have YOUNG and DIRTY ++ * bits. ++ * ++ * The PTE table pointer refers to the hardware entries; the "Linux" ++ * entries are stored 1024 bytes below. ++ */ ++#define L_PTE_PRESENT (1 << 0) ++#define L_PTE_YOUNG (1 << 1) ++#define L_PTE_BUFFERABLE (1 << 2) /* matches PTE */ ++#define L_PTE_CACHEABLE (1 << 3) /* matches PTE */ ++#define L_PTE_USER (1 << 4) ++#define L_PTE_WRITE (1 << 5) ++#define L_PTE_EXEC (1 << 6) ++#define L_PTE_DIRTY (1 << 7) ++ ++#ifndef __ASSEMBLY__ ++ ++#include <asm/proc/domain.h> ++#include <asm/arch/vmalloc.h> + + #define _PAGE_USER_TABLE (PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_USER)) + #define _PAGE_KERNEL_TABLE (PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL)) + + #define pmd_bad(pmd) (pmd_val(pmd) & 2) +-#define set_pmd(pmdp,pmd) cpu_set_pmd(pmdp,pmd) ++#define set_pmd(pmdp,pmd) cpu_set_pmd(pmdp, pmd) + + static inline pmd_t __mk_pmd(pte_t *ptep, unsigned long prot) + { +@@ -75,49 +137,8 @@ + return __phys_to_virt(ptr); + } + +-/**************** +-* PTE functions * +-****************/ +- +-/* PTE types (actually level 2 descriptor) */ +-#define PTE_TYPE_MASK 0x0003 +-#define PTE_TYPE_FAULT 0x0000 +-#define PTE_TYPE_LARGE 0x0001 +-#define PTE_TYPE_SMALL 0x0002 +-#define PTE_AP_READ 0x0aa0 +-#define PTE_AP_WRITE 0x0550 +-#define PTE_CACHEABLE 0x0008 +-#define PTE_BUFFERABLE 0x0004 +- + #define set_pte(ptep, pte) cpu_set_pte(ptep,pte) + +-/* We now keep two sets of ptes - the physical and the linux version. +- * This gives us many advantages, and allows us greater flexibility. +- * +- * The Linux pte's contain: +- * bit meaning +- * 0 page present +- * 1 young +- * 2 bufferable - matches physical pte +- * 3 cacheable - matches physical pte +- * 4 user +- * 5 write +- * 6 execute +- * 7 dirty +- * 8-11 unused +- * 12-31 virtual page address +- * +- * These are stored at the pte pointer; the physical PTE is at -1024bytes +- */ +-#define L_PTE_PRESENT (1 << 0) +-#define L_PTE_YOUNG (1 << 1) +-#define L_PTE_BUFFERABLE (1 << 2) +-#define L_PTE_CACHEABLE (1 << 3) +-#define L_PTE_USER (1 << 4) +-#define L_PTE_WRITE (1 << 5) +-#define L_PTE_EXEC (1 << 6) +-#define L_PTE_DIRTY (1 << 7) +- + /* + * The following macros handle the cache and bufferable bits... + */ +@@ -162,5 +183,8 @@ + * Mark the prot value as uncacheable and unbufferable. + */ + #define pgprot_noncached(prot) __pgprot(pgprot_val(prot) & ~(L_PTE_CACHEABLE | L_PTE_BUFFERABLE)) ++#define pgprot_writecombine(prot) __pgprot(pgprot_val(prot) & ~L_PTE_CACHEABLE) ++ ++#endif /* __ASSEMBLY__ */ + + #endif /* __ASM_PROC_PGTABLE_H */ +--- linux-2.4.27/include/asm-arm/proc-armv/processor.h~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/include/asm-arm/proc-armv/processor.h +@@ -23,6 +23,9 @@ + #define KERNEL_STACK_SIZE PAGE_SIZE + + struct context_save_struct { ++#ifdef CONFIG_CPU_XSCALE ++ long long acc0; ++#endif + unsigned long cpsr; + unsigned long r4; + unsigned long r5; +@@ -35,7 +38,11 @@ + unsigned long pc; + }; + ++#ifdef CONFIG_CPU_XSCALE ++#define INIT_CSS (struct context_save_struct){ 0, SVC_MODE, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ++#else + #define INIT_CSS (struct context_save_struct){ SVC_MODE, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ++#endif + + #define EXTRA_THREAD_STRUCT \ + unsigned int domain; +--- linux-2.4.27/include/asm-arm/proc-fns.h~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/include/asm-arm/proc-fns.h +@@ -124,6 +124,14 @@ + # define CPU_NAME sa1100 + # endif + # endif ++# ifdef CONFIG_CPU_XSCALE ++# ifdef CPU_NAME ++# undef MULTI_CPU ++# define MULTI_CPU ++# else ++# define CPU_NAME xscale ++# endif ++# endif + #endif + + #ifndef MULTI_CPU +--- linux-2.4.27/include/asm-arm/procinfo.h~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/include/asm-arm/procinfo.h +@@ -55,7 +55,8 @@ + #define HWCAP_FAST_MULT 16 + #define HWCAP_FPA 32 + #define HWCAP_VFP 64 +-#define HWCAP_EDSP 128 ++#define HWCAP_EDSP 128 /* El Segundo */ + #define HWCAP_JAVA 256 ++#define HWCAP_XSCALE 512 /* XScale DSP co-processor */ + + #endif +--- linux-2.4.27/include/asm-arm/uaccess.h~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/include/asm-arm/uaccess.h +@@ -86,7 +86,7 @@ + __get_user_x(__r1, __p, __e, 1, "lr"); \ + break; \ + case 2: \ +- __get_user_x(__r1, __p, __e, 2, "r2", "lr"); \ ++ __get_user_x(__r1, __p, __e, 2, "ip", "lr"); \ + break; \ + case 4: \ + __get_user_x(__r1, __p, __e, 4, "lr"); \ +--- linux-2.4.27/include/linux/cramfs_fs_sb.h~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/include/linux/cramfs_fs_sb.h +@@ -10,6 +10,10 @@ + unsigned long blocks; + unsigned long files; + unsigned long flags; ++#ifdef CONFIG_CRAMFS_LINEAR ++ unsigned long linear_phys_addr; ++ char * linear_virt_addr; ++#endif + }; + + #endif +--- linux-2.4.27/include/linux/i2c-id.h~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/include/linux/i2c-id.h +@@ -100,6 +100,10 @@ + #define I2C_DRIVERID_SAA7191 57 /* video decoder */ + #define I2C_DRIVERID_INDYCAM 58 /* SGI IndyCam */ + ++#define I2C_DRIVERID_DS1307 46 /* real time clock: DS1307 */ ++#define I2C_DRIVERID_24LC64 47 /* EEprom 24LC64 */ ++#define I2C_DRIVERID_FM24CLB4 48 /* EEprom FM24CLB4 */ ++ + #define I2C_DRIVERID_EXP0 0xF0 /* experimental use id's */ + #define I2C_DRIVERID_EXP1 0xF1 + #define I2C_DRIVERID_EXP2 0xF2 +@@ -172,6 +176,8 @@ + + #define I2C_ALGO_OCP 0x120000 /* IBM or otherwise On-chip I2C algorithm */ + ++#define I2C_ALGO_PXA 0x400000 /* Intel PXA I2C algorithm */ ++ + #define I2C_ALGO_EXP 0x800000 /* experimental */ + + #define I2C_ALGO_MASK 0xff0000 /* Mask for algorithms */ +--- linux-2.4.27/include/linux/serial.h~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/include/linux/serial.h +@@ -75,11 +75,13 @@ + #define PORT_16654 11 + #define PORT_16850 12 + #define PORT_RSA 13 /* RSA-DV II/S card */ +-#define PORT_MAX 13 ++#define PORT_PXA 14 ++#define PORT_MAX 14 + + #define SERIAL_IO_PORT 0 + #define SERIAL_IO_HUB6 1 + #define SERIAL_IO_MEM 2 ++#define SERIAL_IO_MEM32 3 + + struct serial_uart_config { + char *name; +--- linux-2.4.27/include/linux/serial_reg.h~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/include/linux/serial_reg.h +@@ -119,6 +119,14 @@ + #define UART_IERX_SLEEP 0x10 /* Enable sleep mode */ + + /* ++ * The Intel PXA250/210 chip defines those bits ++ */ ++#define UART_IER_DMAE 0x80 /* DMA Requests Enable */ ++#define UART_IER_UUE 0x40 /* UART Unit Enable */ ++#define UART_IER_NRZE 0x20 /* NRZ coding Enable */ ++#define UART_IER_RTOIE 0x10 /* Receiver Time Out Interrupt Enable */ ++ ++/* + * These are the definitions for the Modem Control Register + */ + #define UART_MCR_AFE 0x20 /* Enable auto-RTS/CTS (TI16C750) */ +--- /dev/null ++++ linux-2.4.27/include/mmc/ioctl.h +@@ -0,0 +1,25 @@ ++/* ++ * linux/include/linux/mmc/ioctl.h ++ * ++ * Author: Vladimir Shebordaev ++ * Copyright: MontaVista Software Inc. ++ * ++ * $Id: ioctl.h,v 0.2 2002/07/11 16:28:21 ted Exp ted $ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef __MMC_IOCTL_H__ ++#define __MMC_IOCTL_H__ ++ ++#include <asm/ioctl.h> ++ ++/* IOCTL commands provided by MMC subsystem */ ++#define IOCMMCSTRNSMODE _IOW('I',0x0f01,int) ++#define IOCMMCGTRNSMODE _IOR('I',0x0f02,int) ++#define IOCMMCGCARDESC _IOR('I',0x0f03,int) /* FIXME */ ++#define IOCMMCGBLKSZMAX _IOR('I',0x0f04,ssize_t) ++#define IOCMMCGNOBMAX _IOR('I',0x0f05,ssize_t) ++ ++#endif /* __MMC_IOCTL_H__ */ +--- /dev/null ++++ linux-2.4.27/include/mmc/mmc.h +@@ -0,0 +1,143 @@ ++/* ++ * linux/include/linux/mmc/mmc.h ++ * ++ * Author: Vladimir Shebordaev ++ * Copyright: MontaVista Software Inc. ++ * ++ * $Id: mmc.h,v 0.2.1.2 2002/07/25 16:29:47 ted Exp ted $ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef __MMC_H__ ++#define __MMC_H__ ++ ++#include <linux/types.h> ++#include <mmc/types.h> ++ ++/* ++ * MMC card type ++ */ ++enum _mmc_type { ++ MMC_CARD_TYPE_RO = 1, ++ MMC_CARD_TYPE_RW, ++ MMC_CARD_TYPE_IO ++}; ++ ++/* ++ * MMC card state ++ */ ++enum _mmc_state { ++ MMC_CARD_STATE_IDLE = 1, ++ MMC_CARD_STATE_READY, ++ MMC_CARD_STATE_IDENT, ++ MMC_CARD_STATE_STNBY, ++ MMC_CARD_STATE_TRAN, ++ MMC_CARD_STATE_DATA, ++ MMC_CARD_STATE_RCV, ++ MMC_CARD_STATE_DIS, ++ MMC_CARD_STATE_UNPLUGGED=0xff ++}; ++ ++/* ++ * Data transfer mode ++ */ ++enum _mmc_transfer_mode { ++ MMC_TRANSFER_MODE_STREAM = 1, ++ MMC_TRANSFER_MODE_BLOCK_SINGLE, ++ MMC_TRANSFER_MODE_BLOCK_MULTIPLE, ++ MMC_TRANSFER_MODE_UNDEFINED = -1 ++}; ++ ++struct _mmc_card_csd_rec { /* CSD register contents */ ++/* FIXME: BYTE_ORDER */ ++ u8 ecc:2, ++ file_format:2, ++ tmp_write_protect:1, ++ perm_write_protect:1, ++ copy:1, ++ file_format_grp:1; ++ u64 content_prot_app:1, ++ rsvd3:4, ++ write_bl_partial:1, ++ write_bl_len:4, ++ r2w_factor:3, ++ default_ecc:2, ++ wp_grp_enable:1, ++ wp_grp_size:5, ++ erase_grp_mult:5, ++ erase_grp_size:5, ++ c_size_mult:3, ++ vdd_w_curr_max:3, ++ vdd_w_curr_min:3, ++ vdd_r_curr_max:3, ++ vdd_r_curr_min:3, ++ c_size:12, ++ rsvd2:2, ++ dsr_imp:1, ++ read_blk_misalign:1, ++ write_blk_misalign:1, ++ read_bl_partial:1; ++ ++ u16 read_bl_len:4, ++ ccc:12; ++ u8 tran_speed; ++ u8 nsac; ++ u8 taac; ++ u8 rsvd1:2, ++ spec_vers:4, ++ csd_structure:2; ++}; ++ ++struct _mmc_card_cid_rec { /* CID register contents */ ++/* FIXME: BYTE_ORDER */ ++ u8 mdt_year:4, ++ mdt_mon:4; ++ u32 psn; ++ u8 prv_minor:4, ++ prv_major:4; ++ u8 pnm[6]; ++ u16 oid; ++ u8 mid; ++}; ++ ++/* ++ * Public card description ++ */ ++struct _mmc_card_info_rec { ++ mmc_type_t type; ++ mmc_transfer_mode_t transfer_mode; /* current data transfer mode */ ++ __u16 rca; /* card's RCA assigned during initialization */ ++ struct _mmc_card_csd_rec csd; ++ struct _mmc_card_cid_rec cid; ++ __u32 tran_speed; /* kbits */ ++ __u16 read_bl_len; ++ __u16 write_bl_len; ++ size_t capacity; /* card's capacity in bytes */ ++}; ++ ++/* ++ * Micsellaneous defines ++ */ ++#ifndef SEEK_SET ++#define SEEK_SET (0) ++#endif ++ ++#ifndef SEEK_CUR ++#define SEEK_CUR (1) ++#endif ++ ++#ifndef SEEK_END ++#define SEEK_END (2) ++#endif ++ ++#ifndef TRUE ++#define TRUE (1) ++#endif ++ ++#ifndef FALSE ++#define FALSE (0) ++#endif ++ ++#endif /* __MMC_H__ */ +--- /dev/null ++++ linux-2.4.27/include/mmc/types.h +@@ -0,0 +1,29 @@ ++/* ++ * linux/include/linux/mmc/types.h ++ * ++ * Author: Vladimir Shebordaev ++ * Copyright: MontaVista Software Inc. ++ * ++ * $Id: types.h,v 0.2 2002/07/11 16:28:21 ted Exp ted $ ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef __MMC_TYPES_H__ ++#define __MMC_TYPES_H__ ++ ++/* MMC card */ ++typedef enum _mmc_type mmc_type_t; ++typedef enum _mmc_state mmc_state_t; ++typedef enum _mmc_transfer_mode mmc_transfer_mode_t; ++ ++typedef struct _mmc_card_csd_rec mmc_card_csd_rec_t; ++typedef struct _mmc_card_cid_rec mmc_card_cid_rec_t; ++ ++typedef struct _mmc_card_info_rec mmc_card_info_rec_t; ++typedef struct _mmc_card_info_rec *mmc_card_info_t; ++ ++typedef enum _mmc_error mmc_error_t; ++ ++#endif /* __MMC_TYPES_H__ */ +--- /dev/null ++++ linux-2.4.27/include/video/lcdctrl.h +@@ -0,0 +1,61 @@ ++/* ++ * lcdctrl.h ++ * ++ * Generic LCD control for brightness, contrast, etc. ++ * Device specific drivers implement a lcdctrl_device and ++ * provides access to it via lcdctrl_device_get_ops(). ++ * ++ * Copyright (C) 2002 Intrinsyc Software Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * History: ++ * Mar 2002: Initial version [FB] ++ * ++ */ ++#ifndef __LCD_CONTROL_H ++#define __LCD_CONTROL_H ++ ++#define _LCDCTRL_IOCTL_ON 1 ++#define _LCDCTRL_IOCTL_OFF 2 ++#define _LCDCTRL_IOCTL_INTENSITY 3 ++#define _LCDCTRL_IOCTL_BRIGHTNESS 4 ++#define _LCDCTRL_IOCTL_CONTRAST 5 ++#define _LCDCTRL_IOCTL_GET_BRIGHTNESS 6 ++#define _LCDCTRL_IOCTL_GET_CONTRAST 7 ++#define _LCDCTRL_IOCTL_GET_INTENSITY 8 ++ ++#define _LCD_CONTROL_NAME "lcdctrl" ++ ++#define LCD_NO_SYNC 0 ++#define LCD_SYNC_NEEDED 1 ++ ++int lcdctrl_enable( void); ++int lcdctrl_disable( void); ++ ++/* intensity, contrast, and brightness take values ++ * between 0..100. ++ */ ++int lcdctrl_set_intensity( int intensity); ++int lcdctrl_set_contrast( int contrast, int sync); ++int lcdctrl_set_brightness( int brightness); ++ ++int lcdctrl_get_intensity( void); ++int lcdctrl_get_contrast( void); ++int lcdctrl_get_brightness( void); ++ ++struct lcdctrl_device ++{ ++ int (*init)( int*, int*, int*); ++ int (*enable)(void); ++ int (*disable)(void); ++ int (*set_intensity)( int i); ++ int (*set_brightness)( int b); ++ int (*set_contrast)( int c, int sync); ++}; ++ ++int lcdctrl_init( void); ++ ++#endif +--- linux-2.4.27/init/do_mounts.c~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/init/do_mounts.c +@@ -394,6 +394,16 @@ + } + #endif + ++#ifdef CONFIG_ROOT_CRAMFS_LINEAR ++static int __init mount_linear_cramfs_root(void) ++{ ++ void *data = root_mount_data; ++ if (sys_mount("/dev/root","/root","cramfs",root_mountflags,data) == 0) ++ return 1; ++ return 0; ++} ++#endif ++ + static int __init create_dev(char *name, kdev_t dev, char *devfs_name) + { + void *handle; +@@ -759,6 +769,16 @@ + + static void __init mount_root(void) + { ++#ifdef CONFIG_ROOT_CRAMFS_LINEAR ++ if (ROOT_DEV == MKDEV(0, 0)) { ++ if (mount_linear_cramfs_root()) { ++ sys_chdir("/root"); ++ ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev; ++ printk("VFS: Mounted root (linear cramfs filesystem).\n"); ++ return; ++ } ++ } ++#endif + #ifdef CONFIG_ROOT_NFS + if (MAJOR(ROOT_DEV) == NFS_MAJOR + && MINOR(ROOT_DEV) == NFS_MINOR) { +--- linux-2.4.27/mm/memory.c~2.4.27-vrs1-pxa1 ++++ linux-2.4.27/mm/memory.c +@@ -1018,6 +1018,41 @@ + return 1; /* Minor fault */ + + bad_wp_page: ++ if (pte_present(pte) && pte_read(pte)) { ++ /* ++ * Handle COW of XIP memory. ++ * Note that the source memory actually isn't a ram page so ++ * no struct page is associated to the source pte. ++ */ ++ char *dst; ++ int ret; ++ ++ spin_unlock(&mm->page_table_lock); ++ new_page = alloc_page(GFP_HIGHUSER); ++ if (!new_page) ++ return -1; ++ ++ /* copy XIP data to memory */ ++ dst = kmap_atomic(new_page, KM_USER0); ++ ret = copy_from_user(dst, (void*)address, PAGE_SIZE); ++ kunmap_atomic(dst, KM_USER0); ++ ++ /* make sure pte didn't change while we dropped the lock */ ++ spin_lock(&mm->page_table_lock); ++ if (!ret && pte_same(*page_table, pte)) { ++ ++mm->rss; ++ break_cow(vma, new_page, address, page_table); ++ lru_cache_add(new_page); ++ spin_unlock(&mm->page_table_lock); ++ return 1; /* Minor fault */ ++ } ++ ++ /* pte changed: back off */ ++ spin_unlock(&mm->page_table_lock); ++ page_cache_release(new_page); ++ return ret ? -1 : 1; ++ } ++ + spin_unlock(&mm->page_table_lock); + printk("do_wp_page: bogus page at address %08lx\n", address); + return -1; |