diff -Nru a/Documentation/arm/OMAP/README b/Documentation/arm/OMAP/README --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/Documentation/arm/OMAP/README 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,436 @@ + + README for ARM based OMAP processor from TI + =========================================== + +This is the README for Linux 2.6 on ARM based TI OMAP processors. + +In the first section it gives some general hints how to start with OMAP Linux. + +When successfully build a OMAP Linux kernel with help of first section and no +bootloader is already on the board, section 2 gives some tips how to use +commercial JTAG tools. + +In March 2004 the Linux Kernel 2.6 for ARM based TI OMAP processors was cleaned. +The goal was to send clean patches to RMK's official ARM tree and to make it +easier to add new OMAP processors or boards to the kernel tree. To keep the +kernel tree clean now, this document describes also some steps how +to add code for a new OMAP processor or OMAP based board to the OMAP Linux 2.6 +kernel tree. This is what the third section of this document is about. + +Section 4 of this README reports some rules to be followed to write +clean code to make it ready for easy inclusion into public OMAP Linux kernel. + +For more information also see TI's 'Linux Community for Texas Instruments OMAP +Processors' web page: + +http://linux.omap.com + +There, various downloads and resources can be found (e.g. documentation how +to build the kernel, how to use u-boot with OMAP Linux, pre-built tool chain +etc.). + +The mailing list for OMAP Linux is hosted there, too: + +http://linux.omap.com/mailman/listinfo + + +1. General hints how to start with OMAP Linux +-------------------------------------------------------------- + +The minimal setup is a arm-linux-gcc cross compiler, make, and some editor. +You will also most likely need a JTAG to flash the bootloader for the first +time. + +The first step is to get a bootloader for your board, u-boot is the +recommended one: + +http://sourceforge.net/projects/uboot/ + +Then you need to compile it with the same cross compiler as you would use +for the Linux kernel. Then you need to flash it to the board either via the +serial port, or by using a JTAG. + +Once you have the bootloader running, you can compile the kernel. + +You can get the OMAP sources either from the BitKeeper tree, or by +applying patches. The BitKeeper tree has the most up to date sources +and is the recommended one. + +- Using BitKeeper: + +You need to download the bk tool from: + +http://www.bitmover.com/ + +Download the dynamic one (x86-glibc22-linux) instead of the static +(x86-static-linux). Some users reported problems with the static version. + +After bk tool is installed, to learn more about bitkeeper you can follow the +tutorial at: + +http://www.bitkeeper.com/UG/ + +Then you can clone OMAP Linux by: + +bk clone http://linux-omap.bkbits.net/main + +Now, you have a copy (clone) of the reprository. To work with it and to +compile the kernel you have to check out the files from your local +repository by: + +bk -r get (or: bk -r edit) + +For kernel related BitKeeper information see also kernel documentation in: + +Documentation/BK-usage/bk-kernel-howto.txt + +Hint: If you are sitting behind a firewall and have to use a proxy for +internet access, you can access BitKeeper by http by setting the +http_proxy envirionment variable: + +http_proxy=http://proxy_username:proxy_password@proxy_name:proxy_port/ + +If you use bash shell, then this might look like: + +export http_proxy=http://foo:123@abc.host.com:8080/ + +with: + +foo: Your user name for the proxy +123: Your password for the proxy +abc.host.com: The name of your proxy you use for internet access +8080: The port used on to access the proxy + + +- Using Patches: + +If you don't want to use BitKeeper, then you can do the same thing with patch. + +Download the latest OMAP Linux patch from: + +http://www.muru.com/linux/omap/ + +Get a matching Linux kernel from: + +ftp://ftp.kernel.org/pub/linux/kernel/v2.6/ + +For example, if you download Linux-2.6.4-omap1 from muru.com, then you need +linux-2.6.4 kernel from kernel.org: + +$ wget ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.4.tar.bz2 +$ tar xjf linux-2.6.4.tar.bz2 +$ cd linux-2.6.4 +$ cat ../Linux-2.6.4-omap1 | patch -p1 + +Note: If OMAP patch from muru.com is against a kernel release candidate, +marked by -rcX, then kernel can be found on kernel.org under v2.6/testing/ + +Now, if you have a local kernel tree, either by BitKeeper or by patch, you +should look into arch/arm/config/ to see which of the various omap_xxx +configurations there you want to use. For example, if you have a OMAP1510 +based Innovator board, you select omap_innovator_1510_defconfig by + +$ make omap_innovator_1510_defconfig + +at top level directory (linux-2.6.4 in the example above). + +Then you can compile the kernel with + +$ make vmlinux + +Or make Image or make zImage or make uImage. + +Once you have the kernel compiled, you can upload it to the board via serial +port or JTAG (see below). + +Then you need a root file system either as initrd or on the flash. + +Once you have the system booting to Linux, you can use pretty much any Linux +applications cross compiled for ARM. + + +2. JTAG usage +-------------------------------------------------------------- + +If the flash of your board is really 'empty' and no bootloader is on the board +(e.g. u-boot) then you need a JTAG connection. With JTAG you can write +a bootloader to board's flash or download OMAP Linux kernel. For OMAP +commercial JTAG tools are available, so you have to pay for it. + +Examples are TI's Code Composer Studio (CCS) or Lauterbach's TRACE32 JTAG. + +- Linux kernel download with CCS + +You can use CCS to directly load an ELF file to your board. For example, use +arch/arm/boot/compressed/vmlinux. zImage isn't suited because it is not an ELF +file. CCS looks for .out files, so copy arch/arm/boot/compressed/vmlinux +to vmlinux.out and load it using CCS. Or use the filter *.* to select +vmlinux directly. Remember to run arm-linux-strip on ELF file first as CCS +get stroppy about unstripped ELF files. + +If you want vmlinux to be linked to run at a specific address, you can use +the CONFIG_ZBOOT options in the kernel build. But first try without +CONFIG_ZBOOT as the compressed image should be able to run from address +zero (if your CCS .gel files map address zero.) + +Otherwise, use something like this: + +CONFIG_ZBOOT_ROM=y +CONFIG_ZBOOT_ROM_TEXT=10408000 +CONFIG_ZBOOT_ROM_BSS=10800000 + +Also note that CCS is pretty useless for debugging Linux as it doesn't +properly handle virtual memory. In other words, once the MMU is +turned on and Linux is using virtual memory, CCS can no longer +properly disassemble, set breakpoints or read memory. + + +- Linux kernel download with Lauterbach TRACE32 + +To be done. + + +3. How to add new processor or board to OMAP Linux kernel tree +-------------------------------------------------------------- + +It is assumed that the OMAP processor to be added is based on an already +supported ARM core (e.g. ARM925 or ARM926). How to add support for new ARM +processor core that is not supported by ARM Linux is not scope of this document. + +1. If a new OMAP processor should be added, identify the ARM core of this +processor. E.g. at time of writing this document in March 2004 OMAP730 (ARM926 +core), OMAP1510 (ARM925 core) and OMAP1610 (ARM926 core) are supported. + +For a new board or device, identify the OMAP processor on the board. E.g. at +time of writing this document in March 2004 four boards are supported: +Innovator1510 (OMAP1510 processor), Innovator1610 (OMAP1610 processor), +Perseus2 (OMAP730 processor) and H2 (OMAP1610 processor). + +/* Discussion needed: How to handle the tons of compatible processors? +E.g. what to do if OMAP16xx is mainly identical with OMAP16yy? */ + +2. Start with arch/arm/mach-omap/Kconfig and add a new processor or board +option. + +To add a new processor add a new config option to the "OMAP Core Type" choice. +See examples for the syntax. The config option has to be called "ARCH_OMAPxxxx" +where xxxx is the number of OMAP processor. Don't forget to select a existing +clock frequency or to add a new one in "OMAP Feature Selections" section for +your new processor. + +To add a new board or device, add a new config option to the "OMAP Board Type" +choice. See examples for the syntax. The config option for boards has to be +called "MACH_OMAP_yyyy" where yyyy is the board name. Don't forget to add a +short help. + +Note: Kernel 2.6 Kconfig system will automatically expand the configuration +names with a leading "CONFIG_". So "ARCH_OMAPxxxx" will be expanded to +"CONFIG_ARCH_OMAPxxxx" and "MACH_OMAP_yyy" will expand to +"CONFIG_MACH_OMAP_yyyy". In code this can then be used by macros like +"#ifdef CONFIG_ARCH_OMAPxxxx" and "#ifdef CONFIG_MACH_OMAP_yyyy". + +Note: How to handle boards which are compatible or extensions of other boards? +See MACH_OMAP_H2 for example. The H2 depends on MACH_OMAP_INNOVATOR and expands +it. This is done by an additional select MACH_OMAP_INNOVATOR in MACH_OMAP_H2 +configuration option. With this the whole MACH_OMAP_INNOVATOR configuration is +selected and an additional symbol CONFIG_MACH_OMAP_H2 is available to +distinguish between INNOVATOR and H2 where necessary. + +3a. Only for new processors: Add the ARCH_OMAPxxxx to the correct ARM core in +arch/arm/mm/Kconfig. E.g. ARCH_OMAP730 in CPU_ARM926T configuration. + +3b. Only for new boards: Register the board within ARM Linux machine +registration system from RMK. For the CONFIG_ section use the same name like +in arch/arm/mach-omap/Kconfig. E.g. MACH_OMAP_yyyy. For MACH_TYPE_ section use +OMAP_yyyy where yyyy is the board name like above. + +Note: The elements of RMKs machine registration are used in +arch/arm/tools/mach-types. While kernel compilation +include/asm-arm/mach-types.h is generated automagically from this file. The +content of mach-types.h then is used for machine identification by kernel +bootcode and can be used for board identification. + +Note: The ARM Linux machine registration system from RMK can be found under: + +www.arm.linux.org.uk/developer/machines/ + +Note: Only OMAP based boards should be registered to RMKs registration +system. Not processors. + +4. Add a processor or board specific header file in include/asm-arm/arch-omap/. +Use board-yyyy.h with yyyy board name or omapxxxx.h with xxxx processor number. + +5. Add a processor or board specific section into include/asm-arm/arch-omap/ +hardware.h. Use examples for syntax and use CONFIG_ names as defined in +arch/arm/mach-omap/Kconfig. + +6. Add processor or board specific macros to board-yyyy.h or omapxxxx.h. The +macros to these specific files have to be named OMAPxxxx_ with xxxx processor +number to make them unique. + +7a. Only for new boards: Add a file board-yyyy.c with yyyy board name to +arch/arm/mach-omap/. Put board specific initialization code and resource +description into this file. The first element of MACHINE_START must be equal to +MACH_TYPE_ section of machine registration (see arch/arm/tools/mach-types after +machine registration at RMKs registration system). + +Put only code into this file that is board specific and not common. See other +board files for examples. + +7b. Only for new processors: Add processor specific IO description and +iotable_init() to arch/arm/mach-omap/common.c. See examples for the syntax. + +If you have introduced new clock definition in 2., add support for this new +clock in include/asm-arm/arch-omap/clocks.h and arch/arm/mach-omap/clocks.c. + +8. Only for new boards: Add "obj-$(CONFIG_MACH_OMAP_yyyy) += board-yyyy.o" with +yyyy board name to arch/arm/mach-omap/Makefile. This is used to compile your new +board specific initialization code from 7a. + +9. Check if other of the existing files have to be adjusted for the new +processor or board. Things to check: + +- Pin multiplexing +- GPIO configuration +- Powermanagement +- Clocking +- Interrupt controller and interrupt configuration +- Additional board specific things (e.g. FPGAs) + +If other existing files or device drivers have to be changed, use the following +mechanism for processor specific things: + +#ifdef CONFIG_ARCH_OMAPxxxx + if (cpu_is_omapxxxx()) { + /* Do the OMAPxxxx processor specific magic */ + } +#endif + +Note: cpu_is_omapxxxx() macro is defined in include/asm-arm/arch-omap/hardware.h +and uses OMAP_ID_REG for runtime processor identifcation. + +For board differentiation use board macro from include/asm-arm/mach-types.h: + +#ifdef CONFIG_MACH_OMAP_yyyy + if (machine_is_omap_yyyy()) { + /* Do the board specific magic */ + } +#endif + +Note: If technically possible and already implemented the OMAP Linux kernel +has support for a "one binary fits all" machanism. That is, the goal is to be +able to enable support for multiple OMAP processors and/or boards in Kconfig +system. Then it is decided by bootparameters and at runtime on which processor +and/or board the kernel is actually running on. With this machanism it is +possible to use the same kernel binary on different OMAP processors or boards +without recompiling. This is achived by the cpu_is_omapxxxx() and +machine_is_omap_yyyy() macros. + +On the other hand, for memory limited embedded systems it should be possible +to compile the kernel with support for only one processor/board combination. +For this a kernel binary is necessary which isn't bloated with code for all +other (unused) processors and boards. This is achived by using the preprocessor +CONFIG_ARCH_OMAPxxxx and CONFIG_MACH_OMAP_yyyy macros around the runtime +cpu_is_omapxxxx() and machine_is_omap_yyyy() selection. + +At the moment, the price for this flexibility is a increased number of #ifdef's +throughout the code. + +10. Configure the kernel by make menuconfig or make xconfig and select the new +processor or board. + +11. Compile the kernel by an appropriate cross compilation toolchain. Make this +until the code compiles error and warning free. The kernel should also be +compiled with the various debug checking thingies enabled (e.g. +CONFIG_DEBUG_SPINLOCK, CONFIG_DEBUG_PAGEALLOC etc.). + +/* ToDo: Anything to say about toolchain? */ + +12. Download the kernel image to the board and test it until it works ;-) + +It's not in the scope of this document how to do this (use a appropriate +bootloader or JTAG download). + +Note: The kernel initialization code expects some special values in the +registers R0, R1 and R2 of the ARM processor. These registers have to be +written by bootloader or debugger before starting the kernel. R0 has to be +zero, R1 has to contain the machine number from machine registration in +arch/arm/tools/mach-types. R2 points to the physical address of tagged list +in system RAM. For more information see Documentation/arm/Booting. + +While testing a new processor or board configuration, it is recommended to +enable low level debugging. This uses low level output functions to print kernel +messages on serial line before console is working. Enable it by + +Kernel hacking -> Kernel debugging -> Kernel low-level debugging functions + +in kernel configuration system. + +13. Check that no other processors or boards are broken by the new code. A first +test is to successful compile the other omap_xxx configurations from +arch/arm/configs/. Do this by e.g. + +cd linux +make omap_innovator_1510_defconfig +Compile the kernel + +Even better: Enable support for several processors and boards in Kconfig +system and compile kernel successfully. + +14. Only for new boards: Add a new default board configuration to +arch/arm/configs. Use omap_yyyy_xxxx_defconfig with yyyy boardname and xxxx +processornumber as filename. + +15. If the new code works, compiles without warnings and seems to break no other +configurations, post a patch to linux-omap-open-source@list.ti.com. + +With sending a patch to the community, it is reviewed, can be used and tested by +other users. It then can be included into the public OMAP kernel tree. + +16. Then adapt device drivers or write additional drivers for non-existing +processor peripherals or board devices. Improve and maintain the code for your +new processor or board. + + +4. General guidelines to write clean and OMAP Linux compatible code +------------------------------------------------------------------- + +- For register access use the __REG8/16/32() macros. At the moment, see first +example in include/asm-arm/arch-omap/hardware.h. + +Allegedly __REG() makes at least some versions of GCC emit tighter code +than the more direct wrappers. Presumably by making it easier to use certain +addressing modes. + +Make sure that the registers names are clearly marked as being registers +(and not addresses of registers). This has to be done by adding a '_REG' +suffix. E.g. + +#define OMAP_ID_REG (__REG32(0xfffed400)) +#define DPLL_CTL_REG (__REG16(0xfffecf00)) + +__raw_read[bwl] and __raw_write[bwl] are deprecated. They will converted to +__REG8/16/32() syntax, soon. Don't use anything else like own pointer +definitions or in[bwl]/out[bwl] etc., too. + +- Make read-modify-write register access preemption save. Use spin_lock() and +spin_unlock() where necessary. If an IRQ handler can access the registers, +use spin_lock_irqsave(), too. + +- Functions declared as __init shouldn't have any references after the kernel +initialization phase is complete. Usually they should be static as well. + +- Don't use return statements at end of void functions. + +- Use consistent indentation style. Don't use space indentations. Use tab +indentations. + +- In general use Linux formatting style. See Documentation/CodingStyle for more +information. If you use GNU emacs, see also chapter 8 of that document how to +add a linux-c-mode to emacs. + + +------------------------------------------------------------------ +Last modified 13. June 2004 +The OMAP Linux Kernel Team +Dirk Behme diff -Nru a/Makefile b/Makefile --- a/Makefile 2005-03-02 10:51:31 -08:00 +++ b/Makefile 2005-03-02 10:51:31 -08:00 @@ -10,6 +10,9 @@ # Comments in this file are targeted only to the developer, do not # expect to learn how to build the kernel reading this file. +# Add custom flags here to avoid conflict with updates +EXTRAVERSION := $(EXTRAVERSION)-omap1 + # Do not print "Entering directory ..." MAKEFLAGS += --no-print-directory @@ -166,9 +169,7 @@ # then ARCH is assigned, getting whatever value it gets normally, and # SUBARCH is subsequently ignored. -SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ - -e s/arm.*/arm/ -e s/sa110/arm/ \ - -e s/s390x/s390/ -e s/parisc64/parisc/ ) +SUBARCH := arm # Cross compiling and selecting different set of gcc/bin-utils # --------------------------------------------------------------------------- @@ -190,7 +191,7 @@ # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile ARCH ?= $(SUBARCH) -CROSS_COMPILE ?= +CROSS_COMPILE ?= arm-linux- # Architecture as present in compile.h UTS_MACHINE := $(ARCH) diff -Nru a/arch/arm/Kconfig b/arch/arm/Kconfig --- a/arch/arm/Kconfig 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/Kconfig 2005-03-02 10:51:31 -08:00 @@ -631,7 +631,7 @@ system, but the driver will do nothing. config LEDS_TIMER - bool "Timer LED" if LEDS && (ARCH_NETWINDER || ARCH_EBSA285 || ARCH_SHARK || MACH_MAINSTONE || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_P720T || ARCH_VERSATILE || ARCH_IMX || MACH_OMAP_H2 || MACH_OMAP_PERSEUS2) + bool "Timer LED" if LEDS && (ARCH_NETWINDER || ARCH_EBSA285 || ARCH_SHARK || MACH_MAINSTONE || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_P720T || ARCH_VERSATILE || ARCH_IMX || MACH_OMAP_H2 || MACH_OMAP_PERSEUS2 || MACH_OMAP_OSK) depends on ARCH_NETWINDER || ARCH_EBSA110 || ARCH_EBSA285 || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || MACH_MAINSTONE || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_CDB89712 || ARCH_P720T || ARCH_OMAP || ARCH_VERSATILE || ARCH_IMX default y if ARCH_EBSA110 help @@ -647,7 +647,7 @@ config LEDS_CPU bool "CPU usage LED" - depends on LEDS && (ARCH_NETWINDER || ARCH_EBSA285 || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || MACH_MAINSTONE || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_P720T || ARCH_VERSATILE || ARCH_IMX || MACH_OMAP_H2 || MACH_OMAP_PERSEUS2) + depends on LEDS && (ARCH_NETWINDER || ARCH_EBSA285 || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || MACH_MAINSTONE || ARCH_PXA_IDP || ARCH_INTEGRATOR || ARCH_P720T || ARCH_VERSATILE || ARCH_IMX || MACH_OMAP_H2 || MACH_OMAP_PERSEUS2 || MACH_OMAP_OSK) help If you say Y here, the red LED will be used to give a good real time indication of CPU usage, by lighting whenever the idle task @@ -688,7 +688,9 @@ source "net/Kconfig" -if ARCH_CLPS7500 || ARCH_IOP3XX || ARCH_IXP4XX || ARCH_L7200 || ARCH_LH7A40X || ARCH_PXA || ARCH_RPC || ARCH_S3C2410 || ARCH_SA1100 || ARCH_SHARK || FOOTBRIDGE +if ARCH_CLPS7500 || ARCH_IOP3XX || ARCH_IXP4XX || ARCH_L7200 \ + || ARCH_LH7A40X || ARCH_PXA || ARCH_RPC || ARCH_S3C2410 \ + || ARCH_SA1100 || ARCH_SHARK || FOOTBRIDGE || PCMCIA source "drivers/ide/Kconfig" endif @@ -726,6 +728,8 @@ source "drivers/misc/Kconfig" source "drivers/usb/Kconfig" + +source "drivers/ssi/Kconfig" source "drivers/mmc/Kconfig" diff -Nru a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile --- a/arch/arm/boot/compressed/Makefile 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/boot/compressed/Makefile 2005-03-02 10:51:31 -08:00 @@ -51,7 +51,11 @@ endif ifeq ($(CONFIG_DEBUG_ICEDCC),y) -OBJS += ice-dcc.o +OBJS += ice-dcc.o +endif + +ifeq ($(CONFIG_MACH_OMAP_PERSEUS2),y) +OBJS += head-omap.o endif ifeq ($(CONFIG_CPU_BIG_ENDIAN),y) diff -Nru a/arch/arm/boot/compressed/head-omap.S b/arch/arm/boot/compressed/head-omap.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/boot/compressed/head-omap.S 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,19 @@ +/* + * linux/arch/arm/boot/compressed/head-omap.S + * + * OMAP specific tweaks. This is merged into head.S by the linker. + * + */ + +#include +#include +#include + + .section ".start", "ax" + +__OMAP_start: +#ifdef CONFIG_MACH_OMAP_PERSEUS2 + /* support for booting without u-boot */ + mov r7, #(MACH_TYPE_OMAP_PERSEUS2 & ~0xf) + orr r7, r7, #(MACH_TYPE_OMAP_PERSEUS2 & 0xf) +#endif diff -Nru a/arch/arm/configs/omap_generic_1510_defconfig b/arch/arm/configs/omap_generic_1510_defconfig --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/configs/omap_generic_1510_defconfig 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,851 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ADIFCC is not set +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_PXA is not set +# 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_IOP3XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set +CONFIG_ARCH_OMAP=y + +# +# CLPS711X/EP721X Implementations +# + +# +# Epxa10db +# + +# +# Footbridge Implementations +# + +# +# IOP3xx Implementation Options +# +# CONFIG_ARCH_IOP310 is not set +# CONFIG_ARCH_IOP321 is not set + +# +# IOP3xx Chipset Features +# + +# +# Intel PXA250/210 Implementations +# + +# +# SA11x0 Implementations +# + +# +# TI OMAP Implementations +# +CONFIG_ARCH_OMAP1510=y +# CONFIG_ARCH_OMAP1610 is not set +# CONFIG_OMAP_INNOVATOR is not set +CONFIG_MACH_OMAP_GENERIC=y +# CONFIG_INNOVATOR_MISSED_IRQS is not set + +# +# OMAP Feature Selections +# +# CONFIG_OMAP1510_PM is not set +CONFIG_OMAP_ARM_168MHZ=y +# CONFIG_OMAP_ARM_120MHZ is not set +# CONFIG_OMAP_ARM_60MHZ is not set +# CONFIG_OMAP_ARM_30MHZ is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM925T=y +CONFIG_CPU_32v4=y +CONFIG_CPU_ABRT_EV4T=y +CONFIG_CPU_CACHE_V4WT=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WBI=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +CONFIG_CPU_DCACHE_WRITETHROUGH=y + +# +# General setup +# +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 + +# +# 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_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Generic Driver Options +# +CONFIG_PM=y +CONFIG_PREEMPT=y +# CONFIG_APM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="mem=64M console=ttyS2,115200 root=0803 ro init=/bin/sh" +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_DCSSBLK is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# 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 is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_IPV6 is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IPV6_SCTP__=y +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB 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 +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_NET_VENDOR_SMC=y +# CONFIG_SMC9194 is not set + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# +CONFIG_PPP=y +CONFIG_PPP_MULTILINK=y +# CONFIG_PPP_FILTER is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# 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 + +# +# Bluetooth support +# +# CONFIG_BT is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=y + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_REPORT_LUNS=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_KEYBOARD_OMAP=y +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +CONFIG_OMAP_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 +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=y +# CONFIG_I2C_ALGOPCF is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_ELV is not set +# CONFIG_I2C_ISA is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_VELLEMAN is not set +CONFIG_I2C_OMAP1610=y + +# +# I2C Hardware Sensors Chip support +# +# CONFIG_I2C_SENSOR is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# MMC/SD Card support +# +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_BROKEN_RFD=y +CONFIG_MMC_OMAP=y + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +# CONFIG_ROOT_NFS is not set +CONFIG_LOCKD=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_GSS is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS 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=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_NEC98_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +CONFIG_NLS=y +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 is not set +# 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 + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y + +# +# Misc devices +# + +# +# USB support +# +CONFIG_USB=y +CONFIG_USB_DEBUG=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811HS is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_BLUETOOTH_TTY is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_HP8200e=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT=y +# CONFIG_HID_FF is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_XPAD is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_DABUSB is not set + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +CONFIG_USB_RTL8150=y +CONFIG_USB_USBNET=y + +# +# USB Host-to-Host Cables +# +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_GENESYS=y +CONFIG_USB_NET1080=y +CONFIG_USB_PL2301=y + +# +# Intelligent USB Devices/Gadgets +# +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_ZAURUS=y +CONFIG_USB_CDCETHER=y + +# +# USB Network Adapters +# +CONFIG_USB_AX8817X=y + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_TIGL is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_BRLVGER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_TEST is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_INFO 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 is not set +# CONFIG_DEBUG_ERRORS is not set +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_CRC32=y diff -Nru a/arch/arm/configs/omap_generic_1610_defconfig b/arch/arm/configs/omap_generic_1610_defconfig --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/configs/omap_generic_1610_defconfig 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,883 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc3-omap1 +# Mon Oct 4 10:14:44 2004 +# +CONFIG_ARM=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_IOMAP=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# 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_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +CONFIG_ARCH_OMAP=y +# CONFIG_ARCH_VERSATILE_PB is not set +# CONFIG_ARCH_IMX is not set + +# +# TI OMAP Implementations +# + +# +# OMAP Core Type +# +# CONFIG_ARCH_OMAP730 is not set +# CONFIG_ARCH_OMAP1510 is not set +CONFIG_ARCH_OMAP16XX=y +CONFIG_ARCH_OMAP_OTG=y + +# +# OMAP Board Type +# +# CONFIG_MACH_OMAP_INNOVATOR is not set +# CONFIG_MACH_OMAP_H2 is not set +# CONFIG_MACH_OMAP_H3 is not set +# CONFIG_MACH_OMAP_H4 is not set +# CONFIG_MACH_OMAP_OSK is not set +CONFIG_MACH_OMAP_GENERIC=y + +# +# OMAP Feature Selections +# +# CONFIG_OMAP_BOOT_TAG is not set +CONFIG_OMAP_MUX=y +# CONFIG_OMAP_MUX_DEBUG is not set +CONFIG_OMAP_MUX_WARNINGS=y +CONFIG_OMAP_LL_DEBUG_UART1=y +# CONFIG_OMAP_LL_DEBUG_UART2 is not set +# CONFIG_OMAP_LL_DEBUG_UART3 is not set +CONFIG_OMAP_ARM_192MHZ=y +# CONFIG_OMAP_ARM_168MHZ is not set +# CONFIG_OMAP_ARM_120MHZ is not set +# CONFIG_OMAP_ARM_60MHZ is not set +# CONFIG_OMAP_ARM_30MHZ is not set +# CONFIG_OMAP_DSP is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM926T=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5TJ=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WBI=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +# CONFIG_CPU_CACHE_ROUND_ROBIN is not set + +# +# General setup +# +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 + +# +# 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_VFP is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_DEBUG_DRIVER is not set +CONFIG_PM=y +CONFIG_PREEMPT=y +# CONFIG_APM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="mem=64M console=ttyS2,115200 root=0803 ro init=/bin/sh" +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# 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 is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_NET_VENDOR_SMC=y +# CONFIG_SMC91X is not set +# CONFIG_SMC9194 is not set + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_PPP=y +CONFIG_PPP_MULTILINK=y +# CONFIG_PPP_FILTER is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# SCSI device support +# +CONFIG_SCSI=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=y + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_RAW is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_KEYBOARD_OMAP=y +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_8250_OMAP is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_OMAP_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=y +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_ISA is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_PCA_ISA is not set +# CONFIG_I2C_OMAP is not set + +# +# Hardware Sensors Chip support +# +# CONFIG_I2C_SENSOR is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set + +# +# Other I2C Chip support +# +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set +# CONFIG_ISP1301_OMAP is not set +# CONFIG_TPS65010 is not set +# CONFIG_GPIOEXPANDER_OMAP is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +# CONFIG_ROOT_NFS is not set +CONFIG_LOCKD=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS 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=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_EFI_PARTITION is not set + +# +# Native Language Support +# +CONFIG_NLS=y +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_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# 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 + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Misc devices +# + +# +# USB support +# +CONFIG_USB=y +CONFIG_USB_DEBUG=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_SUSPEND is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811HS is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_BLUETOOTH_TTY is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_RW_DETECT is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_HP8200e=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT=y +# CONFIG_HID_FF is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_MTOUCH is not set +# CONFIG_USB_EGALAX is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_DABUSB is not set + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +CONFIG_USB_RTL8150=y +CONFIG_USB_USBNET=y + +# +# USB Host-to-Host Cables +# +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_GENESYS=y +CONFIG_USB_NET1080=y +CONFIG_USB_PL2301=y + +# +# Intelligent USB Devices/Gadgets +# +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_ZAURUS=y +CONFIG_USB_CDCETHER=y + +# +# USB Network Adapters +# +CONFIG_USB_AX8817X=y + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_TIGL is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETSERVO is not set +# CONFIG_USB_TEST is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# Synchronous Serial Interfaces (SSI) +# +# CONFIG_OMAP_UWIRE is not set + +# +# MMC/SD Card support +# +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_BROKEN_RFD=y +CONFIG_MMC_OMAP=y +# CONFIG_MMC_OMAP16XX_BLOCK1 is not set +CONFIG_MMC_OMAP16XX_BLOCK2=y + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_INFO is not set +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_ERRORS is not set +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set diff -Nru a/arch/arm/configs/omap_generic_1710_defconfig b/arch/arm/configs/omap_generic_1710_defconfig --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/configs/omap_generic_1710_defconfig 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,853 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc3-omap1 +# Mon Oct 4 10:14:57 2004 +# +CONFIG_ARM=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_IOMAP=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_HOTPLUG=y +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# System Type +# +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# 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_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +CONFIG_ARCH_OMAP=y +# CONFIG_ARCH_VERSATILE_PB is not set +# CONFIG_ARCH_IMX is not set + +# +# TI OMAP Implementations +# + +# +# OMAP Core Type +# +# CONFIG_ARCH_OMAP730 is not set +# CONFIG_ARCH_OMAP1510 is not set +CONFIG_ARCH_OMAP16XX=y +CONFIG_ARCH_OMAP_OTG=y + +# +# OMAP Board Type +# +# CONFIG_MACH_OMAP_INNOVATOR is not set +# CONFIG_MACH_OMAP_H2 is not set +# CONFIG_MACH_OMAP_H3 is not set +# CONFIG_MACH_OMAP_H4 is not set +# CONFIG_MACH_OMAP_OSK is not set +CONFIG_MACH_OMAP_GENERIC=y + +# +# OMAP Feature Selections +# +CONFIG_OMAP_BOOT_TAG=y +# CONFIG_OMAP_BOOT_REASON is not set +# CONFIG_OMAP_MUX is not set +# CONFIG_OMAP_LL_DEBUG_UART1 is not set +# CONFIG_OMAP_LL_DEBUG_UART2 is not set +CONFIG_OMAP_LL_DEBUG_UART3=y +CONFIG_OMAP_ARM_192MHZ=y +# CONFIG_OMAP_ARM_168MHZ is not set +# CONFIG_OMAP_ARM_120MHZ is not set +# CONFIG_OMAP_ARM_60MHZ is not set +# CONFIG_OMAP_ARM_30MHZ is not set +# CONFIG_OMAP_DSP is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM926T=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5TJ=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WBI=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +# CONFIG_CPU_CACHE_ROUND_ROBIN is not set + +# +# General setup +# +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA 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_VFP is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_DEBUG_DRIVER is not set +CONFIG_PM=y +# CONFIG_PREEMPT is not set +# CONFIG_APM is not set +CONFIG_ARTHUR=y +CONFIG_CMDLINE="mem=64M console=tty0 console=ttyS2,115200 root=0801" +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# 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 is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_NET_VENDOR_SMC=y +# CONFIG_SMC91X is not set +# CONFIG_SMC9194 is not set + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y + +# +# Obsolete Wireless cards support (pre-802.11) +# +# CONFIG_STRIP is not set +# CONFIG_ATMEL is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_PPP=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# SCSI device support +# +CONFIG_SCSI=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_RAW is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_KEYBOARD_OMAP=y +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_8250_OMAP=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_OMAP_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V4=y +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +# CONFIG_ROOT_NFS is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS 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=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_EFI_PARTITION is not set + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# 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=y +# 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_ASCII 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=y +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Misc devices +# + +# +# USB support +# +CONFIG_USB=y +CONFIG_USB_DEBUG=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +CONFIG_USB_BANDWIDTH=y +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_SUSPEND is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811HS is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_BLUETOOTH_TTY is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_RW_DETECT is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM 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_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT=y +# CONFIG_HID_FF is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_MTOUCH is not set +# CONFIG_USB_EGALAX is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_DABUSB is not set + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +CONFIG_USB_USBNET=y + +# +# USB Host-to-Host Cables +# +CONFIG_USB_ALI_M5632=y +# CONFIG_USB_AN2720 is not set +# CONFIG_USB_BELKIN is not set +# CONFIG_USB_GENESYS is not set +# CONFIG_USB_NET1080 is not set +# CONFIG_USB_PL2301 is not set + +# +# Intelligent USB Devices/Gadgets +# +# CONFIG_USB_ARMLINUX is not set +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_ZAURUS is not set +# CONFIG_USB_CDCETHER is not set + +# +# USB Network Adapters +# +CONFIG_USB_AX8817X=y + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_TIGL is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETSERVO is not set +# CONFIG_USB_TEST is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# Synchronous Serial Interfaces (SSI) +# +# CONFIG_OMAP_UWIRE is not set + +# +# MMC/SD Card support +# +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_BLOCK=y +# CONFIG_MMC_BLOCK_BROKEN_RFD is not set +CONFIG_MMC_OMAP=y +# CONFIG_MMC_OMAP16XX_BLOCK1 is not set +CONFIG_MMC_OMAP16XX_BLOCK2=y + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_SLAB=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_INFO is not set +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +CONFIG_DEBUG_WAITQ=y +CONFIG_DEBUG_ERRORS=y +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +CONFIG_SECURITY=y +# CONFIG_SECURITY_NETWORK is not set +CONFIG_SECURITY_CAPABILITIES=y +# CONFIG_SECURITY_ROOTPLUG is not set +# CONFIG_SECURITY_SELINUX is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set diff -Nru a/arch/arm/configs/omap_h2_1610_defconfig b/arch/arm/configs/omap_h2_1610_defconfig --- a/arch/arm/configs/omap_h2_1610_defconfig 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/configs/omap_h2_1610_defconfig 2005-03-02 10:51:31 -08:00 @@ -1,13 +1,12 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.11-rc2 -# Tue Feb 1 14:01:46 2005 +# Linux kernel version: 2.6.9-rc3-omap1 +# Mon Oct 4 10:15:30 2004 # CONFIG_ARM=y CONFIG_MMU=y CONFIG_UID16=y CONFIG_RWSEM_GENERIC_SPINLOCK=y -CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_IOMAP=y # @@ -16,7 +15,6 @@ CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y -CONFIG_LOCK_KERNEL=y # # General setup @@ -30,7 +28,6 @@ # CONFIG_AUDIT is not set CONFIG_LOG_BUF_SHIFT=14 # CONFIG_HOTPLUG is not set -CONFIG_KOBJECT_UEVENT=y # CONFIG_IKCONFIG is not set # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y @@ -38,12 +35,12 @@ # CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_FUTEX=y CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_SHMEM=y -CONFIG_CC_ALIGN_FUNCTIONS=0 -CONFIG_CC_ALIGN_LABELS=0 -CONFIG_CC_ALIGN_LOOPS=0 -CONFIG_CC_ALIGN_JUMPS=0 # CONFIG_TINY_SHMEM is not set # @@ -54,7 +51,6 @@ # CONFIG_MODULE_FORCE_UNLOAD is not set CONFIG_OBSOLETE_MODPARM=y # CONFIG_MODVERSIONS is not set -# CONFIG_MODULE_SRCVERSION_ALL is not set # CONFIG_KMOD is not set # @@ -78,9 +74,8 @@ # CONFIG_ARCH_SHARK is not set # CONFIG_ARCH_LH7A40X is not set CONFIG_ARCH_OMAP=y -# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VERSATILE_PB is not set # CONFIG_ARCH_IMX is not set -# CONFIG_ARCH_H720X is not set # # TI OMAP Implementations @@ -107,17 +102,20 @@ # # OMAP Feature Selections # +CONFIG_OMAP_BOOT_TAG=y +# CONFIG_OMAP_BOOT_REASON is not set CONFIG_OMAP_MUX=y -# CONFIG_OMAP_MUX_DEBUG is not set +CONFIG_OMAP_MUX_DEBUG=y CONFIG_OMAP_MUX_WARNINGS=y CONFIG_OMAP_LL_DEBUG_UART1=y # CONFIG_OMAP_LL_DEBUG_UART2 is not set # CONFIG_OMAP_LL_DEBUG_UART3 is not set -CONFIG_OMAP_ARM_192MHZ=y +# CONFIG_OMAP_ARM_192MHZ is not set # CONFIG_OMAP_ARM_168MHZ is not set # CONFIG_OMAP_ARM_120MHZ is not set -# CONFIG_OMAP_ARM_60MHZ is not set +CONFIG_OMAP_ARM_60MHZ=y # CONFIG_OMAP_ARM_30MHZ is not set +# CONFIG_OMAP_DSP is not set # # Processor Type @@ -126,7 +124,6 @@ CONFIG_CPU_ARM926T=y CONFIG_CPU_32v5=y CONFIG_CPU_ABRT_EV5TJ=y -CONFIG_CPU_CACHE_VIVT=y CONFIG_CPU_COPY_V4WB=y CONFIG_CPU_TLB_V4WBI=y @@ -142,18 +139,9 @@ # # General setup # +# CONFIG_ZBOOT_ROM is not set CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 -# CONFIG_XIP_KERNEL is not set - -# -# PCCARD (PCMCIA/CardBus) support -# -# CONFIG_PCCARD is not set - -# -# PC-card bridges -# # # At least one math emulation must be selected @@ -171,14 +159,14 @@ # CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_FW_LOADER is not set CONFIG_DEBUG_DRIVER=y -CONFIG_PM=y -CONFIG_PREEMPT=y -# CONFIG_APM is not set +# CONFIG_PM is not set +# CONFIG_PREEMPT is not set # CONFIG_ARTHUR is not set -CONFIG_CMDLINE="mem=32M console=ttyS0,115200n8 root=0801 ro init=/bin/sh" -# CONFIG_LEDS is not set +CONFIG_CMDLINE="mem=32M console=ttyS0,115200n8 root=/dev/ram0 rw initrd=0x10600000,8M ramdisk_size=8192" +CONFIG_LEDS=y +# CONFIG_LEDS_TIMER is not set +# CONFIG_LEDS_CPU is not set CONFIG_ALIGNMENT_TRAP=y # @@ -231,7 +219,6 @@ # CONFIG_MTD_RAM is not set # CONFIG_MTD_ROM is not set # CONFIG_MTD_ABSENT is not set -# CONFIG_MTD_XIP is not set # # Mapping drivers for chip access @@ -240,15 +227,16 @@ # CONFIG_MTD_PHYSMAP is not set # CONFIG_MTD_ARM_INTEGRATOR is not set # CONFIG_MTD_EDB7312 is not set +# CONFIG_MTD_OMAP_NORv2 is not set # # Self-contained MTD device drivers # # CONFIG_MTD_SLRAM is not set # CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_OMAP_NOR is not set # CONFIG_MTD_MTDRAM is not set # CONFIG_MTD_BLKMTD is not set -# CONFIG_MTD_BLOCK2MTD is not set # # Disk-On-Chip Device Drivers @@ -270,25 +258,13 @@ # Block devices # # CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set # CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" -# CONFIG_CDROM_PKTCDVD is not set - -# -# IO Schedulers -# -CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -CONFIG_ATA_OVER_ETH=m # # Multi-device support (RAID and LVM) @@ -323,8 +299,6 @@ # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set # CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -# CONFIG_IP_TCPDIAG_IPV6 is not set # CONFIG_IPV6 is not set # CONFIG_NETFILTER is not set @@ -344,6 +318,7 @@ # CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set # # QoS and/or fair queueing @@ -369,9 +344,7 @@ # # Ethernet (10 or 100Mbit) # -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -CONFIG_SMC91X=y +# CONFIG_NET_ETHERNET is not set # # Ethernet (1000 Mbit) @@ -412,37 +385,7 @@ # # SCSI device support # -CONFIG_SCSI=y -CONFIG_SCSI_PROC_FS=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -# CONFIG_BLK_DEV_SD is not set -# CONFIG_CHR_DEV_ST is not set -# CONFIG_CHR_DEV_OSST is not set -# CONFIG_BLK_DEV_SR is not set -# CONFIG_CHR_DEV_SG is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_MULTI_LUN is not set -# CONFIG_SCSI_CONSTANTS is not set -# CONFIG_SCSI_LOGGING is not set - -# -# SCSI Transport Attributes -# -# CONFIG_SCSI_SPI_ATTRS is not set -# CONFIG_SCSI_FC_ATTRS is not set -# CONFIG_SCSI_ISCSI_ATTRS is not set - -# -# SCSI low-level drivers -# -# CONFIG_SCSI_SATA is not set -# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI is not set # # Fusion MPT device support @@ -517,6 +460,7 @@ # # Non-8250 serial port support # +CONFIG_SERIAL_8250_OMAP=y CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y @@ -537,8 +481,15 @@ # Watchdog Device Drivers # # CONFIG_SOFT_WATCHDOG is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +# CONFIG_OMAP16XX_WATCHDOG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set +CONFIG_OMAP_RTC=y # CONFIG_DTLK is not set # CONFIG_R3964 is not set @@ -552,7 +503,7 @@ # I2C support # CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_CHARDEV is not set # # I2C Algorithms @@ -564,10 +515,13 @@ # # I2C Hardware Bus support # +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set # CONFIG_I2C_ISA is not set # CONFIG_I2C_PARPORT_LIGHT is not set -# CONFIG_I2C_STUB is not set +# CONFIG_SCx200_ACB is not set # CONFIG_I2C_PCA_ISA is not set +CONFIG_I2C_OMAP=y # # Hardware Sensors Chip support @@ -575,25 +529,20 @@ # CONFIG_I2C_SENSOR is not set # CONFIG_SENSORS_ADM1021 is not set # CONFIG_SENSORS_ADM1025 is not set -# CONFIG_SENSORS_ADM1026 is not set # CONFIG_SENSORS_ADM1031 is not set # CONFIG_SENSORS_ASB100 is not set # CONFIG_SENSORS_DS1621 is not set # CONFIG_SENSORS_FSCHER is not set # CONFIG_SENSORS_GL518SM is not set # CONFIG_SENSORS_IT87 is not set -# CONFIG_SENSORS_LM63 is not set # CONFIG_SENSORS_LM75 is not set # CONFIG_SENSORS_LM77 is not set # CONFIG_SENSORS_LM78 is not set # CONFIG_SENSORS_LM80 is not set # CONFIG_SENSORS_LM83 is not set # CONFIG_SENSORS_LM85 is not set -# CONFIG_SENSORS_LM87 is not set # CONFIG_SENSORS_LM90 is not set # CONFIG_SENSORS_MAX1619 is not set -# CONFIG_SENSORS_PC87360 is not set -# CONFIG_SENSORS_SMSC47B397 is not set # CONFIG_SENSORS_SMSC47M1 is not set # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83L785TS is not set @@ -607,6 +556,9 @@ # CONFIG_SENSORS_PCF8591 is not set # CONFIG_SENSORS_RTC8564 is not set CONFIG_ISP1301_OMAP=y +# CONFIG_TPS65010 is not set +# CONFIG_SENSORS_TLV320AIC23 is not set +# CONFIG_GPIOEXPANDER_OMAP is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set @@ -635,7 +587,6 @@ # CONFIG_MINIX_FS is not set CONFIG_ROMFS_FS=y # CONFIG_QUOTA is not set -CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set @@ -679,7 +630,6 @@ CONFIG_JFFS2_FS=y CONFIG_JFFS2_FS_DEBUG=2 # CONFIG_JFFS2_FS_NAND is not set -# CONFIG_JFFS2_FS_NOR_ECC is not set # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set CONFIG_JFFS2_ZLIB=y CONFIG_JFFS2_RTIME=y @@ -695,17 +645,15 @@ # Network File Systems # CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_NFS_V4=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set # CONFIG_NFS_DIRECTIO is not set # CONFIG_NFSD is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y -CONFIG_LOCKD_V4=y # CONFIG_EXPORTFS is not set CONFIG_SUNRPC=y -CONFIG_SUNRPC_GSS=y -CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set # CONFIG_SMB_FS is not set # CONFIG_CIFS is not set @@ -717,7 +665,6 @@ # Partition Types # # CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y # # Native Language Support @@ -773,7 +720,10 @@ # CONFIG_FB=y CONFIG_FB_MODE_HELPERS=y -# CONFIG_FB_TILEBLITTING is not set +CONFIG_FB_OMAP=y +CONFIG_FB_OMAP_INTERNAL_LCDC=y +# CONFIG_FB_OMAP_EXTERNAL_LCDC is not set +# CONFIG_FB_OMAP_DMA_TUNE is not set # CONFIG_FB_VIRTUAL is not set # @@ -782,15 +732,9 @@ # CONFIG_VGA_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_FONTS=y +# CONFIG_FONTS is not set CONFIG_FONT_8x8=y CONFIG_FONT_8x16=y -# CONFIG_FONT_6x11 is not set -# CONFIG_FONT_PEARL_8x8 is not set -# CONFIG_FONT_ACORN_8x8 is not set -# CONFIG_FONT_MINI_4x6 is not set -# CONFIG_FONT_SUN8x16 is not set -# CONFIG_FONT_SUN12x22 is not set # # Logo configuration @@ -799,53 +743,118 @@ # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set CONFIG_LOGO_LINUX_CLUT224=y -# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound # -CONFIG_SOUND=y +# CONFIG_SOUND is not set # -# Advanced Linux Sound Architecture +# Misc devices # -# CONFIG_SND is not set # -# Open Sound System +# USB support # -CONFIG_SOUND_PRIME=y -# CONFIG_SOUND_BT878 is not set -# CONFIG_SOUND_FUSION is not set -# CONFIG_SOUND_CS4281 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_OSS is not set -# CONFIG_SOUND_TVMIXER is not set -# CONFIG_SOUND_AD1980 is not set +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set # -# Misc devices +# Miscellaneous USB options # +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y +CONFIG_USB_OTG=y +CONFIG_USB_OTG_WHITELIST=y # -# USB support +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811HS is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_BLUETOOTH_TTY is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_STORAGE is not set + +# +# USB Human Interface Devices (HID) +# +# CONFIG_USB_HID is not set + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_MTOUCH is not set +# CONFIG_USB_EGALAX is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_DABUSB is not set + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors # -# CONFIG_USB is not set -CONFIG_USB_ARCH_HAS_HCD=y -CONFIG_USB_ARCH_HAS_OHCI=y +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set # -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# USB port drivers # # +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_TIGL is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETSERVO is not set +CONFIG_USB_TEST=y + +# # USB Gadget Support # CONFIG_USB_GADGET=y -# CONFIG_USB_GADGET_DEBUG_FILES is not set # CONFIG_USB_GADGET_NET2280 is not set # CONFIG_USB_GADGET_PXA2XX is not set # CONFIG_USB_GADGET_GOKU is not set @@ -854,6 +863,7 @@ # CONFIG_USB_GADGET_DUMMY_HCD is not set CONFIG_USB_GADGET_OMAP=y CONFIG_USB_OMAP=y +# CONFIG_USB_OMAP_PROC is not set # CONFIG_USB_GADGET_DUALSPEED is not set # CONFIG_USB_ZERO is not set CONFIG_USB_ETH=y @@ -863,6 +873,11 @@ # CONFIG_USB_G_SERIAL is not set # +# Synchronous Serial Interfaces (SSI) +# +CONFIG_OMAP_UWIRE=y + +# # MMC/SD Card support # # CONFIG_MMC is not set @@ -872,58 +887,25 @@ # CONFIG_DEBUG_KERNEL=y # CONFIG_MAGIC_SYSRQ is not set -# CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set -CONFIG_DEBUG_PREEMPT=y # CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_DEBUG_KOBJECT is not set CONFIG_DEBUG_BUGVERBOSE=y CONFIG_DEBUG_INFO=y -# CONFIG_DEBUG_FS is not set CONFIG_FRAME_POINTER=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_WAITQ is not set CONFIG_DEBUG_ERRORS=y -CONFIG_DEBUG_LL=y -# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_LL is not set # # Security options # -# CONFIG_KEYS is not set # CONFIG_SECURITY is not set # # Cryptographic options # -CONFIG_CRYPTO=y -# CONFIG_CRYPTO_HMAC is not set -# CONFIG_CRYPTO_NULL is not set -# CONFIG_CRYPTO_MD4 is not set -CONFIG_CRYPTO_MD5=y -# CONFIG_CRYPTO_SHA1 is not set -# CONFIG_CRYPTO_SHA256 is not set -# CONFIG_CRYPTO_SHA512 is not set -# CONFIG_CRYPTO_WP512 is not set -CONFIG_CRYPTO_DES=y -# CONFIG_CRYPTO_BLOWFISH is not set -# CONFIG_CRYPTO_TWOFISH is not set -# CONFIG_CRYPTO_SERPENT is not set -# CONFIG_CRYPTO_AES is not set -# CONFIG_CRYPTO_CAST5 is not set -# CONFIG_CRYPTO_CAST6 is not set -# CONFIG_CRYPTO_TEA is not set -# CONFIG_CRYPTO_ARC4 is not set -# CONFIG_CRYPTO_KHAZAD is not set -# CONFIG_CRYPTO_ANUBIS is not set -# CONFIG_CRYPTO_DEFLATE is not set -# CONFIG_CRYPTO_MICHAEL_MIC is not set -# CONFIG_CRYPTO_CRC32C is not set -# CONFIG_CRYPTO_TEST is not set - -# -# Hardware crypto devices -# +# CONFIG_CRYPTO is not set # # Library routines diff -Nru a/arch/arm/configs/omap_h3_1710_defconfig b/arch/arm/configs/omap_h3_1710_defconfig --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/configs/omap_h3_1710_defconfig 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,883 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc3-omap1 +# Mon Oct 4 10:15:35 2004 +# +CONFIG_ARM=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_IOMAP=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# 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_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +CONFIG_ARCH_OMAP=y +# CONFIG_ARCH_VERSATILE_PB is not set +# CONFIG_ARCH_IMX is not set + +# +# TI OMAP Implementations +# + +# +# OMAP Core Type +# +# CONFIG_ARCH_OMAP730 is not set +# CONFIG_ARCH_OMAP1510 is not set +CONFIG_ARCH_OMAP16XX=y +CONFIG_ARCH_OMAP_OTG=y + +# +# OMAP Board Type +# +# CONFIG_MACH_OMAP_INNOVATOR is not set +# CONFIG_MACH_OMAP_H2 is not set +CONFIG_MACH_OMAP_H3=y +# CONFIG_MACH_OMAP_H4 is not set +# CONFIG_MACH_OMAP_OSK is not set +# CONFIG_MACH_OMAP_GENERIC is not set + +# +# OMAP Feature Selections +# +# CONFIG_OMAP_BOOT_TAG is not set +CONFIG_OMAP_MUX=y +# CONFIG_OMAP_MUX_DEBUG is not set +CONFIG_OMAP_MUX_WARNINGS=y +CONFIG_OMAP_LL_DEBUG_UART1=y +# CONFIG_OMAP_LL_DEBUG_UART2 is not set +# CONFIG_OMAP_LL_DEBUG_UART3 is not set +# CONFIG_OMAP_ARM_192MHZ is not set +CONFIG_OMAP_ARM_168MHZ=y +# CONFIG_OMAP_ARM_120MHZ is not set +# CONFIG_OMAP_ARM_60MHZ is not set +# CONFIG_OMAP_ARM_30MHZ is not set +# CONFIG_OMAP_DSP is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM926T=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5TJ=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WBI=y + +# +# Processor Features +# +CONFIG_ARM_THUMB=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +# CONFIG_CPU_CACHE_ROUND_ROBIN is not set + +# +# General setup +# +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0x10C08000 +CONFIG_ZBOOT_ROM_BSS=0x10200000 + +# +# 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_VFP is not set +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_AOUT=y +# CONFIG_BINFMT_MISC is not set + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_PM is not set +# CONFIG_PREEMPT is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="mem=32M console=ttyS0,115200n8 initrd=0x10A00000,8M root=/dev/ram0 rw ip=dhcp devfs=mount" +CONFIG_LEDS=y +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB 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 + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# 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 is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +CONFIG_IRDA=y + +# +# IrDA protocols +# +# CONFIG_IRLAN is not set +# CONFIG_IRNET is not set +# CONFIG_IRCOMM is not set +# CONFIG_IRDA_ULTRA is not set + +# +# IrDA options +# +# CONFIG_IRDA_CACHE_LAST_LSAP is not set +# CONFIG_IRDA_FAST_RR is not set +# CONFIG_IRDA_DEBUG is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +# CONFIG_IRTTY_SIR is not set + +# +# Dongle support +# + +# +# Old SIR device drivers +# +# CONFIG_IRPORT_SIR is not set + +# +# Old Serial dongle support +# + +# +# FIR device drivers +# +# CONFIG_USB_IRDA is not set +# CONFIG_SIGMATEL_FIR is not set +CONFIG_OMAP1610_IR=y +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_NET_VENDOR_SMC=y +CONFIG_SMC91X=y +# CONFIG_SMC9194 is not set + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_PPP=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPPOE is not set +CONFIG_SLIP=y +CONFIG_SLIP_COMPRESSED=y +# CONFIG_SLIP_SMART is not set +# CONFIG_SLIP_MODE_SLIP6 is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_RAW is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_KEYBOARD_OMAP=y +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_8250_OMAP=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_NOWAYOUT=y + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +# CONFIG_OMAP16XX_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_OMAP_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +CONFIG_I2C=y +# CONFIG_I2C_CHARDEV is not set + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_ISA is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_PCA_ISA is not set +CONFIG_I2C_OMAP=y + +# +# Hardware Sensors Chip support +# +# CONFIG_I2C_SENSOR is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set + +# +# Other I2C Chip support +# +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set +# CONFIG_ISP1301_OMAP is not set +CONFIG_TPS65010=y +# CONFIG_SENSORS_TLV320AIC23 is not set +CONFIG_GPIOEXPANDER_OMAP=y +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Multimedia devices +# +CONFIG_VIDEO_DEV=y + +# +# Video For Linux +# + +# +# Video Adapters +# +# CONFIG_VIDEO_CPIA is not set +# CONFIG_VIDEO_SAA5246A is not set +# CONFIG_VIDEO_SAA5249 is not set +# CONFIG_TUNER_3036 is not set +# CONFIG_VIDEO_OVCAMCHIP is not set + +# +# Radio Adapters +# +# CONFIG_RADIO_MAESTRO is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +CONFIG_ROMFS_FS=y +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +CONFIG_DEVFS_FS=y +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS_XATTR is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Graphics support +# +CONFIG_FB=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_OMAP=y +CONFIG_FB_OMAP_INTERNAL_LCDC=y +# CONFIG_FB_OMAP_EXTERNAL_LCDC is not set +# CONFIG_FB_OMAP_DMA_TUNE is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y + +# +# Sound +# +CONFIG_SOUND=y + +# +# Advanced Linux Sound Architecture +# +# CONFIG_SND is not set + +# +# Open Sound System +# +CONFIG_SOUND_PRIME=y +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 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_OSS is not set +# CONFIG_SOUND_TVMIXER is not set +# CONFIG_SOUND_AD1980 is not set + +# +# Misc devices +# + +# +# USB support +# +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_OHCI_HCD=m +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811HS is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH_TTY is not set +# CONFIG_USB_MIDI is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_STORAGE is not set + +# +# USB Human Interface Devices (HID) +# +# CONFIG_USB_HID is not set + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_MTOUCH is not set +# CONFIG_USB_EGALAX is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_DABUSB is not set +# CONFIG_USB_VICAM is not set +# CONFIG_USB_DSBR is not set +# CONFIG_USB_IBMCAM is not set +# CONFIG_USB_KONICAWC is not set +# CONFIG_USB_OV511 is not set +# CONFIG_USB_SE401 is not set +# CONFIG_USB_SN9C102 is not set +# CONFIG_USB_STV680 is not set + +# +# USB Network adaptors +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_TIGL is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETSERVO is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# Synchronous Serial Interfaces (SSI) +# +CONFIG_OMAP_UWIRE=y + +# +# MMC/SD Card support +# +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_BLOCK=y +# CONFIG_MMC_BLOCK_BROKEN_RFD is not set +CONFIG_MMC_OMAP=y +CONFIG_MMC_OMAP16XX_BLOCK1=y +# CONFIG_MMC_OMAP16XX_BLOCK2 is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_ICEDCC is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +CONFIG_CRC_CCITT=y +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set diff -Nru a/arch/arm/configs/omap_innovator_1510_defconfig b/arch/arm/configs/omap_innovator_1510_defconfig --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/configs/omap_innovator_1510_defconfig 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,921 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc1-omap1 +# Wed Sep 8 14:14:10 2004 +# +CONFIG_ARM=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# 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_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +CONFIG_ARCH_OMAP=y +# CONFIG_ARCH_VERSATILE_PB is not set +# CONFIG_ARCH_IMX is not set + +# +# TI OMAP Implementations +# + +# +# OMAP Core Type +# +# CONFIG_ARCH_OMAP730 is not set +CONFIG_ARCH_OMAP1510=y +# CONFIG_ARCH_OMAP1610 is not set +# CONFIG_ARCH_OMAP1710 is not set +# CONFIG_ARCH_OMAP5912 is not set + +# +# OMAP Board Type +# +CONFIG_MACH_OMAP_INNOVATOR=y +# CONFIG_MACH_OMAP_GENERIC is not set + +# +# OMAP Feature Selections +# +# CONFIG_OMAP_BOOT_TAG is not set +CONFIG_OMAP_MUX=y +# CONFIG_OMAP_MUX_DEBUG is not set +CONFIG_OMAP_LL_DEBUG_UART1=y +# CONFIG_OMAP_LL_DEBUG_UART2 is not set +# CONFIG_OMAP_LL_DEBUG_UART3 is not set +CONFIG_OMAP_ARM_168MHZ=y +# CONFIG_OMAP_ARM_120MHZ is not set +# CONFIG_OMAP_ARM_60MHZ is not set +# CONFIG_OMAP_ARM_30MHZ is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM925T=y +CONFIG_CPU_32v4=y +CONFIG_CPU_ABRT_EV4T=y +CONFIG_CPU_CACHE_V4WT=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WBI=y + +# +# Processor Features +# +CONFIG_ARM_THUMB=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +CONFIG_CPU_DCACHE_WRITETHROUGH=y + +# +# General setup +# +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 + +# +# 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_VFP is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_DEBUG_DRIVER is not set +CONFIG_PM=y +CONFIG_PREEMPT=y +# CONFIG_APM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="console=ttyS0,115200n8 root=/dev/nfs ip=bootp noinitrd" +CONFIG_LEDS=y +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# 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 is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_SMC91X=y +# CONFIG_NET_VENDOR_SMC is not set + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_PPP=y +CONFIG_PPP_MULTILINK=y +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_ASYNC=y +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=y +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# SCSI device support +# +CONFIG_SCSI=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=y +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=y + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=240 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=320 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_KEYBOARD_OMAP=y +CONFIG_OMAP_PS2=m +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_8250_OMAP=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_GEN_RTC is not set +CONFIG_OMAP_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +CONFIG_I2C=y +# CONFIG_I2C_CHARDEV is not set + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_ISA is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_PCA_ISA is not set +# CONFIG_I2C_OMAP is not set + +# +# Hardware Sensors Chip support +# +# CONFIG_I2C_SENSOR is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set + +# +# Other I2C Chip support +# +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set +# CONFIG_TPS65010 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V4=y +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS 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=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_EFI_PARTITION is not set + +# +# Native Language Support +# +CONFIG_NLS=y +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_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# 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 + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Graphics support +# +CONFIG_FB=y +# CONFIG_FB_MODE_HELPERS is not set +CONFIG_FB_OMAP=y +CONFIG_FB_OMAP_DMA_TUNE=y +# CONFIG_FB_OMAP_OLD is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set + +# +# Logo configuration +# +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_MONO=y +CONFIG_LOGO_LINUX_VGA16=y +CONFIG_LOGO_LINUX_CLUT224=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Misc devices +# + +# +# USB support +# +CONFIG_USB=y +CONFIG_USB_DEBUG=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_SUSPEND=y + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811HS is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_BLUETOOTH_TTY is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_RW_DETECT is not set +CONFIG_USB_STORAGE_DATAFAB=y +CONFIG_USB_STORAGE_FREECOM=y +CONFIG_USB_STORAGE_DPCM=y +CONFIG_USB_STORAGE_HP8200e=y +CONFIG_USB_STORAGE_SDDR09=y +CONFIG_USB_STORAGE_SDDR55=y +CONFIG_USB_STORAGE_JUMPSHOT=y + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT=y +# CONFIG_HID_FF is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_MTOUCH is not set +# CONFIG_USB_EGALAX is not set +# CONFIG_USB_XPAD is not set +# CONFIG_USB_ATI_REMOTE is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_DABUSB is not set + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +CONFIG_USB_RTL8150=y +CONFIG_USB_USBNET=y + +# +# USB Host-to-Host Cables +# +CONFIG_USB_ALI_M5632=y +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_GENESYS=y +CONFIG_USB_NET1080=y +CONFIG_USB_PL2301=y + +# +# Intelligent USB Devices/Gadgets +# +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +CONFIG_USB_ZAURUS=y +CONFIG_USB_CDCETHER=y + +# +# USB Network Adapters +# +CONFIG_USB_AX8817X=y + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_TIGL is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGETSERVO is not set +# CONFIG_USB_TEST is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# Synchronous Serial Interfaces (SSI) +# +# CONFIG_OMAP_UWIRE is not set + +# +# MMC/SD Card support +# +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_BROKEN_RFD=y +CONFIG_MMC_OMAP=y + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_INFO is not set +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_WAITQ is not set +# CONFIG_DEBUG_ERRORS is not set +# CONFIG_DEBUG_LL is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Library routines +# +CONFIG_CRC_CCITT=y +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff -Nru a/arch/arm/configs/omap_innovator_1610_defconfig b/arch/arm/configs/omap_innovator_1610_defconfig --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/configs/omap_innovator_1610_defconfig 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,617 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.9-rc3-omap1 +# Mon Oct 4 10:15:49 2004 +# +CONFIG_ARM=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_IOMAP=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SHMEM=y +# CONFIG_TINY_SHMEM is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# 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_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +CONFIG_ARCH_OMAP=y +# CONFIG_ARCH_VERSATILE_PB is not set +# CONFIG_ARCH_IMX is not set + +# +# TI OMAP Implementations +# + +# +# OMAP Core Type +# +# CONFIG_ARCH_OMAP730 is not set +# CONFIG_ARCH_OMAP1510 is not set +CONFIG_ARCH_OMAP16XX=y +CONFIG_ARCH_OMAP_OTG=y + +# +# OMAP Board Type +# +CONFIG_MACH_OMAP_INNOVATOR=y +# CONFIG_MACH_OMAP_H2 is not set +# CONFIG_MACH_OMAP_H3 is not set +# CONFIG_MACH_OMAP_H4 is not set +# CONFIG_MACH_OMAP_OSK is not set +# CONFIG_MACH_OMAP_GENERIC is not set + +# +# OMAP Feature Selections +# +# CONFIG_OMAP_BOOT_TAG is not set +CONFIG_OMAP_MUX=y +# CONFIG_OMAP_MUX_DEBUG is not set +CONFIG_OMAP_MUX_WARNINGS=y +CONFIG_OMAP_LL_DEBUG_UART1=y +# CONFIG_OMAP_LL_DEBUG_UART2 is not set +# CONFIG_OMAP_LL_DEBUG_UART3 is not set +CONFIG_OMAP_ARM_192MHZ=y +# CONFIG_OMAP_ARM_168MHZ is not set +# CONFIG_OMAP_ARM_120MHZ is not set +# CONFIG_OMAP_ARM_60MHZ is not set +# CONFIG_OMAP_ARM_30MHZ is not set +# CONFIG_OMAP_DSP is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM926T=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5TJ=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WBI=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +CONFIG_CPU_DCACHE_WRITETHROUGH=y +# CONFIG_CPU_CACHE_ROUND_ROBIN is not set + +# +# General setup +# +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 + +# +# 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_VFP is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_PM is not set +# CONFIG_PREEMPT is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="mem=32M console=tty0 console=ttyS0,115200 initrd=0x10200000,8M root=/dev/ram0 rw" +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=m +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# 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 is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_NET_VENDOR_SMC is not set +CONFIG_SMC91X=y + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_PPP=y +CONFIG_PPP_MULTILINK=y +# CONFIG_PPP_FILTER is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_RAW is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_KEYBOARD_OMAP=y +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_8250_OMAP=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_OMAP_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +CONFIG_DEVFS_FS=y +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS_XATTR is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +# CONFIG_ROOT_NFS is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Graphics support +# +CONFIG_FB=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_OMAP=y +CONFIG_FB_OMAP_INTERNAL_LCDC=y +# CONFIG_FB_OMAP_EXTERNAL_LCDC is not set +# CONFIG_FB_OMAP_DMA_TUNE is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set + +# +# Logo configuration +# +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_MONO=y +CONFIG_LOGO_LINUX_VGA16=y +CONFIG_LOGO_LINUX_CLUT224=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Misc devices +# + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# Synchronous Serial Interfaces (SSI) +# +# CONFIG_OMAP_UWIRE is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_INFO is not set +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set diff -Nru a/arch/arm/configs/omap_osk_5912_defconfig b/arch/arm/configs/omap_osk_5912_defconfig --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/configs/omap_osk_5912_defconfig 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,789 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.10-rc3-omap1 +# Fri Dec 10 12:22:22 2004 +# +CONFIG_ARM=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_IOMAP=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_HOTPLUG is not set +CONFIG_KOBJECT_UEVENT=y +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_TINY_SHMEM is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# 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_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +CONFIG_ARCH_OMAP=y +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_H720X is not set + +# +# TI OMAP Implementations +# + +# +# OMAP Core Type +# +# CONFIG_ARCH_OMAP730 is not set +# CONFIG_ARCH_OMAP1510 is not set +CONFIG_ARCH_OMAP16XX=y +CONFIG_ARCH_OMAP_OTG=y + +# +# OMAP Board Type +# +# CONFIG_MACH_OMAP_INNOVATOR is not set +# CONFIG_MACH_OMAP_H2 is not set +# CONFIG_MACH_OMAP_H3 is not set +# CONFIG_MACH_OMAP_H4 is not set +CONFIG_MACH_OMAP_OSK=y +# CONFIG_MACH_OMAP_GENERIC is not set + +# +# OMAP Feature Selections +# +# CONFIG_OMAP_BOOT_TAG is not set +CONFIG_OMAP_MUX=y +# CONFIG_OMAP_MUX_DEBUG is not set +CONFIG_OMAP_MUX_WARNINGS=y +CONFIG_OMAP_MPU_TIMER=y +# CONFIG_OMAP_32K_TIMER is not set +CONFIG_OMAP_LL_DEBUG_UART1=y +# CONFIG_OMAP_LL_DEBUG_UART2 is not set +# CONFIG_OMAP_LL_DEBUG_UART3 is not set +# CONFIG_OMAP_ARM_216MHZ is not set +CONFIG_OMAP_ARM_192MHZ=y +# CONFIG_OMAP_ARM_168MHZ is not set +# CONFIG_OMAP_ARM_120MHZ is not set +# CONFIG_OMAP_ARM_60MHZ is not set +# CONFIG_OMAP_ARM_30MHZ is not set +# CONFIG_OMAP_DSP is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM926T=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5TJ=y +CONFIG_CPU_CACHE_VIVT=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WBI=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +CONFIG_CPU_DCACHE_WRITETHROUGH=y +# CONFIG_CPU_CACHE_ROUND_ROBIN is not set + +# +# General setup +# +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +# 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_VFP is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_PM=y +# CONFIG_PREEMPT is not set +# CONFIG_APM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="mem=32M console=ttyS0,115200 initrd=0x10400000,8M root=/dev/ram0 rw" +# CONFIG_LEDS is not set +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=y +# 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 +# CONFIG_INFTL 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_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 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_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_EDB7312 is not set +CONFIG_MTD_OMAP_NORv2=y + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_OMAP_NOR is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=m +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# 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 is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_IP_TCPDIAG=y +# CONFIG_IP_TCPDIAG_IPV6 is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_SMC91X=y + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +CONFIG_PPP=y +CONFIG_PPP_MULTILINK=y +# CONFIG_PPP_FILTER is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPPOE is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_RAW is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +CONFIG_KEYBOARD_OMAP=y +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_GUNZE is not set +CONFIG_TOUCHSCREEN_OMAP=y +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_OMAP_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ISA is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_PCA_ISA is not set +CONFIG_I2C_OMAP=y + +# +# Hardware Sensors Chip support +# +# CONFIG_I2C_SENSOR is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set + +# +# Other I2C Chip support +# +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set +# CONFIG_ISP1301_OMAP is not set +CONFIG_TPS65010=y +# CONFIG_SENSORS_TLV320AIC23 is not set +# CONFIG_GPIOEXPANDER_OMAP is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +CONFIG_AUTOFS_FS=y +CONFIG_AUTOFS4_FS=y + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_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_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +# CONFIG_ROOT_NFS is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Graphics support +# +CONFIG_FB=y +CONFIG_FB_MODE_HELPERS=y +# CONFIG_FB_TILEBLITTING is not set +CONFIG_FB_OMAP=y +CONFIG_FB_OMAP_INTERNAL_LCDC=y +# CONFIG_FB_OMAP_EXTERNAL_LCDC is not set +CONFIG_FB_OMAP_DMA_TUNE=y +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set + +# +# Logo configuration +# +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Misc devices +# + +# +# USB support +# +# CONFIG_USB is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# Synchronous Serial Interfaces (SSI) +# +CONFIG_OMAP_UWIRE=y +# CONFIG_OMAP_TSC2101 is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_INFO is not set +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff -Nru a/arch/arm/configs/omap_perseus2_730_defconfig b/arch/arm/configs/omap_perseus2_730_defconfig --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/configs/omap_perseus2_730_defconfig 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,605 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.10-rc3-omap1 +# Tue Dec 7 11:36:21 2004 +# +CONFIG_ARM=y +CONFIG_MMU=y +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_IOMAP=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_HOTPLUG is not set +CONFIG_KOBJECT_UEVENT=y +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_TINY_SHMEM is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CO285 is not set +# 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_IOP3XX is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +CONFIG_ARCH_OMAP=y +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_H720X is not set + +# +# TI OMAP Implementations +# + +# +# OMAP Core Type +# +CONFIG_ARCH_OMAP730=y +# CONFIG_ARCH_OMAP1510 is not set +# CONFIG_ARCH_OMAP16XX is not set +CONFIG_ARCH_OMAP_OTG=y + +# +# OMAP Board Type +# +CONFIG_MACH_OMAP_PERSEUS2=y + +# +# OMAP Feature Selections +# +# CONFIG_OMAP_BOOT_TAG is not set +# CONFIG_OMAP_MUX is not set +CONFIG_OMAP_MPU_TIMER=y +# CONFIG_OMAP_32K_TIMER is not set +CONFIG_OMAP_LL_DEBUG_UART1=y +# CONFIG_OMAP_LL_DEBUG_UART2 is not set +# CONFIG_OMAP_LL_DEBUG_UART3 is not set +# CONFIG_OMAP_ARM_195MHZ is not set +CONFIG_OMAP_ARM_182MHZ=y +# CONFIG_OMAP_ARM_168MHZ is not set +# CONFIG_OMAP_ARM_120MHZ is not set +# CONFIG_OMAP_ARM_60MHZ is not set +# CONFIG_OMAP_ARM_30MHZ is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM926T=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5TJ=y +CONFIG_CPU_CACHE_VIVT=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WBI=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +# CONFIG_CPU_CACHE_ROUND_ROBIN is not set + +# +# General setup +# +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +# 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_VFP is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_PM is not set +CONFIG_PREEMPT=y +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="mem=32M console=ttyS0,115200 ip=dhcp" +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 is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# 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 is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_IP_TCPDIAG=y +# CONFIG_IP_TCPDIAG_IPV6 is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +CONFIG_SMC91X=y + +# +# Ethernet (1000 Mbit) +# + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_RAW is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_OMAP_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_SYSFS=y +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS_XATTR is not set +# CONFIG_TMPFS is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +# CONFIG_EXPORTFS is not set +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Graphics support +# +CONFIG_FB=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_OMAP=y +CONFIG_FB_OMAP_INTERNAL_LCDC=y +CONFIG_FB_VIRTUAL=y + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Misc devices +# + +# +# USB support +# +# CONFIG_USB is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# Synchronous Serial Interfaces (SSI) +# +CONFIG_OMAP_UWIRE=y +# CONFIG_OMAP_TSC2101 is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_INFO is not set +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_USER is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set diff -Nru a/arch/arm/kernel/arch.c b/arch/arm/kernel/arch.c --- a/arch/arm/kernel/arch.c 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/kernel/arch.c 2005-03-02 10:51:31 -08:00 @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -42,5 +43,28 @@ } __tagtable(ATAG_ACORN, parse_tag_acorn); + +#endif + +#ifdef CONFIG_OMAP_BOOT_TAG + +unsigned char omap_bootloader_tag[512]; +int omap_bootloader_tag_len = 0; + +static int __init parse_tag_omap(const struct tag *tag) +{ + u32 size = tag->hdr.size - (sizeof(tag->hdr) >> 2); + + size <<= 2; + if (size > sizeof(omap_bootloader_tag)) + return -1; + + memcpy(omap_bootloader_tag, tag->u.omap.data, size); + omap_bootloader_tag_len = size; + + return 0; +} + +__tagtable(ATAG_OMAP, parse_tag_omap); #endif diff -Nru a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c --- a/arch/arm/kernel/irq.c 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/kernel/irq.c 2005-03-02 10:51:31 -08:00 @@ -37,6 +37,8 @@ #include #include #include +#include +#include /* * Maximum IRQ count. Currently, this is arbitary. However, it should @@ -336,6 +338,13 @@ if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); + +#ifdef CONFIG_NO_IDLE_HZ + if ((system_timer->dyn_tick_int->state & DYN_TICK_INT_ENABLED) + && system_timer->dyn_tick_int->handler + && (irq != system_timer->dyn_tick_int->skip)) + system_timer->dyn_tick_int->handler(irq, 0, regs); +#endif spin_lock_irq(&irq_controller_lock); diff -Nru a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c --- a/arch/arm/kernel/time.c 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/kernel/time.c 2005-03-02 10:51:31 -08:00 @@ -35,6 +35,7 @@ #include #include #include +#include u64 jiffies_64 = INITIAL_JIFFIES; @@ -350,6 +351,53 @@ #endif } +#ifdef CONFIG_NO_IDLE_HZ +int timer_dyn_tick_enable(void) +{ + unsigned long flags; + int ret = -ENODEV; + + write_seqlock_irqsave(&xtime_lock, flags); + if (!system_timer->dyn_tick->enable) + goto out_err; + + ret = system_timer->dyn_tick->enable(); + if (ret != 0) + goto out_err; + + if (system_timer->dyn_tick_int->handler + && system_timer->dyn_tick_int->skip) + system_timer->dyn_tick_int->state = DYN_TICK_INT_ENABLED; + + system_timer->dyn_tick->state |= DYN_TICK_ENABLED; + write_sequnlock_irqrestore(&xtime_lock, flags); + + return ret; + +out_err: + system_timer->dyn_tick_int->state &= ~DYN_TICK_INT_ENABLED; + system_timer->dyn_tick->state &= ~DYN_TICK_ENABLED; + write_sequnlock_irqrestore(&xtime_lock, flags); + return ret; +} + +int timer_dyn_tick_disable(void) +{ + unsigned long flags; + int ret = 0; + + write_seqlock_irqsave(&xtime_lock, flags); + if (system_timer->dyn_tick->disable) + ret = system_timer->dyn_tick->disable(); + + system_timer->dyn_tick_int->state &= ~DYN_TICK_INT_ENABLED; + system_timer->dyn_tick->state &= ~DYN_TICK_ENABLED; + write_sequnlock_irqrestore(&xtime_lock, flags); + + return ret; +} +#endif + #ifdef CONFIG_PM static int timer_suspend(struct sys_device *dev, u32 state) { @@ -381,6 +429,29 @@ .resume = timer_resume, }; +#ifdef CONFIG_NO_IDLE_HZ +static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf) +{ + return sprintf(buf, "%i\n", + system_timer->dyn_tick->state & DYN_TICK_ENABLED); +} + +static ssize_t timer_set_dyn_tick(struct sys_device *dev, const char *buf, + size_t count) +{ + int ret = 0; + unsigned int enable = simple_strtoul(buf, NULL, 2); + + if (enable) + ret = timer_dyn_tick_enable(); + else + ret = timer_dyn_tick_disable(); + + return count; +} +static SYSDEV_ATTR(dyn_tick, 0644, timer_show_dyn_tick, timer_set_dyn_tick); +#endif + static int __init timer_init_sysfs(void) { int ret = sysdev_class_register(&timer_sysclass); @@ -388,6 +459,15 @@ system_timer->dev.cls = &timer_sysclass; ret = sysdev_register(&system_timer->dev); } + +#ifdef CONFIG_NO_IDLE_HZ + ret = sysdev_create_file(&system_timer->dev, &attr_dyn_tick); +#if defined(CONFIG_NO_IDLE_HZ_ENABLED) + /* Turn on dynamic tick after calibrate delay for correct bogomips */ + ret = timer_dyn_tick_enable(); +#endif +#endif + return ret; } diff -Nru a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig --- a/arch/arm/mach-omap/Kconfig 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/mach-omap/Kconfig 2005-03-02 10:51:31 -08:00 @@ -66,6 +66,19 @@ Support for TI OMAP 730 Perseus2 board. Say Y here if you have such a board. +config MACH_VOICEBLUE + bool "Voiceblue" + depends on ARCH_OMAP1510 + help + Support for Voiceblue GSM/VoIP gateway. Say Y here if you have such + board. + +config MACH_NETSTAR + bool "NetStar" + depends on ARCH_OMAP1510 + help + Support for NetStar PBX. Say Y here if you have such a board. + config MACH_OMAP_GENERIC bool "Generic OMAP board" depends on ARCH_OMAP1510 || ARCH_OMAP16XX @@ -77,13 +90,31 @@ comment "OMAP Feature Selections" -#config OMAP_BOOT_TAG -# bool "OMAP bootloader information passing" -# depends on ARCH_OMAP -# default n -# help -# Say Y, if you have a bootloader which passes information -# about your board and its peripheral configuration. +config OMAP_BOOT_TAG + bool "OMAP bootloader information passing" + depends on ARCH_OMAP + default n + help + Say Y, if you have a bootloader which passes information + about your board and its peripheral configuration. + +config OMAP_BOOT_REASON + bool "Support for boot reason" + depends on OMAP_BOOT_TAG + default n + help + Say Y, if you want to have a procfs entry for reading the boot + reason in user-space. + +config OMAP_GPIO_SWITCH + bool "GPIO switch support" + depends on OMAP_BOOT_TAG + default n + help + Say Y, if you want to have support for input layer reporting + of GPIO switches (e.g. cover switches). Your bootloader has to + provide information about the switches to the kernel via the + ATAG_OMAP mechanism. config OMAP_MUX bool "OMAP multiplexing support" @@ -113,6 +144,65 @@ printed, it's safe to deselect OMAP_MUX for your product. choice + prompt "System timer" + default OMAP_MPU_TIMER + +config OMAP_MPU_TIMER + bool "Use mpu timer" + help + Select this option if you want to use the OMAP mpu timer. This + timer provides more intra-tick resolution than the 32KHz timer, + but consumes more power. + +config OMAP_32K_TIMER + bool "Use 32KHz timer" + depends on ARCH_OMAP16XX + help + Select this option if you want to enable the OMAP 32KHz timer. + This timer saves power compared to the OMAP_MPU_TIMER, and has + support for no tick during idle. The 32KHz timer provides less + intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is + currently only available for OMAP-16xx. + +endchoice + +config OMAP_32K_TIMER_HZ + int "Kernel internal timer frequency for 32KHz timer" + range 32 1024 + depends on OMAP_32K_TIMER + default "128" + help + Kernel internal timer frequency should be a divisor of 32768, + such as 64 or 128. If ARM Linux default HZ=100 is used, the system + will still work, but the timer interrupt will use less efficient + modulo code. + +config NO_IDLE_HZ + bool "Dynamic Tick Timer" + depends on OMAP_32K_TIMER + help + Select this option if you want to disable continuous timer ticks + and have them programmed one at a time from the idle loop. This + option saves power as the system does not need to exit idle state + because of a timer interrupt. If you have this option selected, + you still need to enable dynamic tick using the sysfs interface. + By default dynamic tick is disabled during the boot, and can be + manually enabled with: + + echo 1 > /sys/devices/platform/timer0/dyn_tick + + If you want dynamic tick automatically enabled during boot, select + also NO_IDLE_HZ_ENABLED below. + +config NO_IDLE_HZ_ENABLED + bool "Enable Dynamic Tick Timer by default" + depends on NO_IDLE_HZ + default n + help + Select this option if you want dynamic tick turned on by default + at startup. + +choice prompt "Low-level debug console UART" depends on ARCH_OMAP default OMAP_LL_DEBUG_UART1 @@ -128,6 +218,19 @@ endchoice +config OMAP_DM_TIMER + bool "Use dual-mode timer" + default n + depends on ARCH_OMAP16XX + help + Select this option if you want to use OMAP Dual-Mode timers. + +config OMAP_ARM_216MHZ + bool "OMAP ARM 216 MHz CPU (1710 only)" + depends on ARCH_OMAP16XX + help + Enable 216 MHz clock for OMAP1710 CPU. If unsure, say N. + config OMAP_ARM_195MHZ bool "OMAP ARM 195 MHz CPU" depends on ARCH_OMAP730 @@ -152,6 +255,12 @@ help Enable 168MHz clock for OMAP CPU. If unsure, say N. +config OMAP_ARM_150MHZ + bool "OMAP ARM 150 MHz CPU" + depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730 + help + Enable 150MHz clock for OMAP CPU. If unsure, say N. + config OMAP_ARM_120MHZ bool "OMAP ARM 120 MHz CPU" depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730 @@ -170,6 +279,8 @@ depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730 help Enable 30MHz clock for OMAP CPU. If unsure, say N. + +source "arch/arm/mach-omap/dsp/Kconfig" endmenu diff -Nru a/arch/arm/mach-omap/Makefile b/arch/arm/mach-omap/Makefile --- a/arch/arm/mach-omap/Makefile 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/mach-omap/Makefile 2005-03-02 10:51:31 -08:00 @@ -16,6 +16,8 @@ obj-$(CONFIG_MACH_OMAP_PERSEUS2) += board-perseus2.o obj-$(CONFIG_MACH_OMAP_OSK) += board-osk.o obj-$(CONFIG_MACH_OMAP_H3) += board-h3.o +obj-$(CONFIG_MACH_VOICEBLUE) += board-voiceblue.o +obj-$(CONFIG_MACH_NETSTAR) += board-netstar.o # OCPI interconnect support for 1710, 1610 and 5912 obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o @@ -24,11 +26,16 @@ led-$(CONFIG_MACH_OMAP_H2) += leds-h2p2-debug.o led-$(CONFIG_MACH_OMAP_INNOVATOR) += leds-innovator.o led-$(CONFIG_MACH_OMAP_PERSEUS2) += leds-h2p2-debug.o +led-$(CONFIG_MACH_OMAP_OSK) += leds-osk.o obj-$(CONFIG_LEDS) += $(led-y) # Power Management obj-$(CONFIG_PM) += pm.o sleep.o +obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o +obj-$(CONFIG_OMAP_BOOT_REASON) += bootreason.o +obj-$(CONFIG_OMAP_GPIO_SWITCH) += gpio-switch.o + ifeq ($(CONFIG_ARCH_OMAP1510),y) # Innovator-1510 FPGA obj-$(CONFIG_MACH_OMAP_INNOVATOR) += fpga.o @@ -36,3 +43,6 @@ # kgdb support obj-$(CONFIG_KGDB_SERIAL) += kgdb-serial.o + +# DSP subsystem +obj-y += dsp/ diff -Nru a/arch/arm/mach-omap/board-generic.c b/arch/arm/mach-omap/board-generic.c --- a/arch/arm/mach-omap/board-generic.c 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/mach-omap/board-generic.c 2005-03-02 10:51:31 -08:00 @@ -26,7 +26,6 @@ #include #include #include -#include #include "common.h" diff -Nru a/arch/arm/mach-omap/board-h2.c b/arch/arm/mach-omap/board-h2.c --- a/arch/arm/mach-omap/board-h2.c 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/mach-omap/board-h2.c 2005-03-02 10:51:31 -08:00 @@ -29,7 +29,6 @@ #include #include -#include #include #include @@ -42,7 +41,7 @@ static struct resource h2_smc91x_resources[] = { [0] = { .start = OMAP1610_ETHR_START, /* Physical */ - .end = OMAP1610_ETHR_START + SZ_4K, + .end = OMAP1610_ETHR_START + 0xf, .flags = IORESOURCE_MEM, }, [1] = { diff -Nru a/arch/arm/mach-omap/board-h3.c b/arch/arm/mach-omap/board-h3.c --- a/arch/arm/mach-omap/board-h3.c 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/mach-omap/board-h3.c 2005-03-02 10:51:31 -08:00 @@ -31,6 +31,7 @@ #include #include #include +#include #include "common.h" @@ -41,7 +42,7 @@ static struct resource smc91x_resources[] = { [0] = { .start = OMAP1710_ETHR_START, /* Physical */ - .end = OMAP1710_ETHR_START + OMAP1710_ETHR_SIZE, + .end = OMAP1710_ETHR_START + 0xf, .flags = IORESOURCE_MEM, }, [1] = { @@ -58,8 +59,51 @@ .resource = smc91x_resources, }; +#define GPTIMER_BASE 0xFFFB1400 +#define GPTIMER_REGS(x) (0xFFFB1400 + (x * 0x800)) +#define GPTIMER_REGS_SIZE 0x46 + +static struct resource intlat_resources[] = { + [0] = { + .start = GPTIMER_REGS(0), /* Physical */ + .end = GPTIMER_REGS(0) + GPTIMER_REGS_SIZE, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = INT_1610_GPTIMER1, + .end = INT_1610_GPTIMER1, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device intlat_device = { + .name = "omap_intlat", + .id = 0, + .num_resources = ARRAY_SIZE(intlat_resources), + .resource = intlat_resources, +}; + static struct platform_device *devices[] __initdata = { &smc91x_device, + &intlat_device, +}; + +static struct omap_usb_config h3_usb_config __initdata = { + /* usb1 has a Mini-AB port and external isp1301 transceiver */ + .otg = 2, + +#ifdef CONFIG_USB_GADGET_OMAP + .hmc_mode = 19, /* 0:host(off) 1:dev|otg 2:disabled */ +#elif defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) + /* NONSTANDARD CABLE NEEDED (B-to-Mini-B) */ + .hmc_mode = 20, /* 1:dev|otg(off) 1:host 2:disabled */ +#endif + + .pins[1] = 3, +}; + +static struct omap_board_config_kernel h3_config[] = { + { OMAP_TAG_USB, &h3_usb_config }, }; static void __init h3_init(void) diff -Nru a/arch/arm/mach-omap/board-innovator.c b/arch/arm/mach-omap/board-innovator.c --- a/arch/arm/mach-omap/board-innovator.c 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/mach-omap/board-innovator.c 2005-03-02 10:51:31 -08:00 @@ -26,7 +26,6 @@ #include #include -#include #include #include #include @@ -46,7 +45,7 @@ static struct resource innovator1510_smc91x_resources[] = { [0] = { .start = OMAP1510_FPGA_ETHR_START, /* Physical */ - .end = OMAP1510_FPGA_ETHR_START + 16, + .end = OMAP1510_FPGA_ETHR_START + 0xf, .flags = IORESOURCE_MEM, }, [1] = { @@ -74,7 +73,7 @@ static struct resource innovator1610_smc91x_resources[] = { [0] = { .start = INNOVATOR1610_ETHR_START, /* Physical */ - .end = INNOVATOR1610_ETHR_START + SZ_4K, + .end = INNOVATOR1610_ETHR_START + 0xf, .flags = IORESOURCE_MEM, }, [1] = { diff -Nru a/arch/arm/mach-omap/board-netstar.c b/arch/arm/mach-omap/board-netstar.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/board-netstar.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,151 @@ +/* + * Modified from board-generic.c + * + * Copyright (C) 2004 2N Telekomunikace, Ladislav Michl + * + * Code for Netstar OMAP board. + * + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "common.h" + +extern void __init omap_init_time(void); +extern int omap_gpio_init(void); + +static struct resource netstar_smc91x_resources[] = { + [0] = { + .start = OMAP_CS1_PHYS + 0x300, + .end = OMAP_CS1_PHYS + 0x300 + 16, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = OMAP_GPIO_IRQ(8), + .end = OMAP_GPIO_IRQ(8), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device netstar_smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(netstar_smc91x_resources), + .resource = netstar_smc91x_resources, +}; + +static struct platform_device *netstar_devices[] __initdata = { + &netstar_smc91x_device, +}; + +static void __init netstar_init_irq(void) +{ + omap_init_irq(); + omap_gpio_init(); +} + +static void __init netstar_init(void) +{ + /* green LED */ + omap_request_gpio(4); + omap_set_gpio_direction(4, 0); + /* smc91x reset */ + omap_request_gpio(7); + omap_set_gpio_direction(7, 0); + omap_set_gpio_dataout(7, 1); + udelay(2); /* wait at least 100ns */ + omap_set_gpio_dataout(7, 0); + mdelay(50); /* 50ms until PHY ready */ + /* smc91x interrupt pin */ + omap_request_gpio(8); + omap_set_gpio_edge_ctrl(8, OMAP_GPIO_RISING_EDGE); + + omap_request_gpio(12); + omap_request_gpio(13); + omap_request_gpio(14); + omap_request_gpio(15); + omap_set_gpio_edge_ctrl(12, OMAP_GPIO_FALLING_EDGE); + omap_set_gpio_edge_ctrl(13, OMAP_GPIO_FALLING_EDGE); + omap_set_gpio_edge_ctrl(14, OMAP_GPIO_FALLING_EDGE); + omap_set_gpio_edge_ctrl(15, OMAP_GPIO_FALLING_EDGE); + + platform_add_devices(netstar_devices, ARRAY_SIZE(netstar_devices)); + + /* Switch on green LED */ + omap_set_gpio_dataout(4, 0); + /* Switch off red LED */ + omap_writeb(0x00, OMAP_LPG1_PMR); /* Disable clock */ + omap_writeb(0x80, OMAP_LPG1_LCR); +} + +static int __initdata omap_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1}; + +static void __init netstar_map_io(void) +{ + omap_map_io(); + omap_serial_init(omap_serial_ports); +} + +#define MACHINE_PANICED 1 +#define MACHINE_REBOOTING 2 +#define MACHINE_REBOOT 4 +static unsigned long machine_state; + +static int panic_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ + if (test_and_set_bit(MACHINE_PANICED, &machine_state)) + return NOTIFY_DONE; + + /* Switch off green LED */ + omap_set_gpio_dataout(4, 1); + /* Flash red LED */ + omap_writeb(0x78, OMAP_LPG1_LCR); + omap_writeb(0x01, OMAP_LPG1_PMR); /* Enable clock */ + + return NOTIFY_DONE; +} + +static struct notifier_block panic_block = { + .notifier_call = panic_event, +}; + +static int __init netstar_late_init(void) +{ + /* TODO: Setup front panel switch here */ + + /* Setup panic notifier */ + notifier_chain_register(&panic_notifier_list, &panic_block); + + return 0; +} + +postcore_initcall(netstar_late_init); + +MACHINE_START(NETSTAR, "NetStar OMAP5910") + MAINTAINER("Ladislav Michl ") + BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000) + BOOT_PARAMS(0x10000100) + MAPIO(netstar_map_io) + INITIRQ(netstar_init_irq) + INIT_MACHINE(netstar_init) + .timer = &omap_timer, +MACHINE_END diff -Nru a/arch/arm/mach-omap/board-osk.c b/arch/arm/mach-omap/board-osk.c --- a/arch/arm/mach-omap/board-osk.c 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/mach-omap/board-osk.c 2005-03-02 10:51:31 -08:00 @@ -35,10 +35,10 @@ #include #include -#include #include -#include #include +#include +#include #include "common.h" @@ -52,7 +52,7 @@ static struct resource osk5912_smc91x_resources[] = { [0] = { .start = OMAP_OSK_ETHR_START, /* Physical */ - .end = OMAP_OSK_ETHR_START + SZ_4K, + .end = OMAP_OSK_ETHR_START + 0xf, .flags = IORESOURCE_MEM, }, [1] = { @@ -64,13 +64,32 @@ static struct platform_device osk5912_smc91x_device = { .name = "smc91x", - .id = 0, + .id = -1, .num_resources = ARRAY_SIZE(osk5912_smc91x_resources), .resource = osk5912_smc91x_resources, }; +static struct resource osk5912_cf_resources[] = { + [0] = { + .start = OMAP_GPIO_IRQ(62), + .end = OMAP_GPIO_IRQ(62), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device osk5912_cf_device = { + .name = "omap_cf", + .id = -1, + .dev = { + .platform_data = (void *) 2 /* CS2 */, + }, + .num_resources = ARRAY_SIZE(osk5912_cf_resources), + .resource = osk5912_cf_resources, +}; + static struct platform_device *osk5912_devices[] __initdata = { &osk5912_smc91x_device, + &osk5912_cf_device, }; static void __init osk_init_smc91x(void) @@ -80,6 +99,20 @@ return; } omap_set_gpio_edge_ctrl(0, OMAP_GPIO_RISING_EDGE); + + /* Check EMIFS wait states to fix errors with SMC_GET_PKT_HDR */ + EMIFS_CCS(1) |= 0x2; +} + +static void __init osk_init_cf(void) +{ + omap_cfg_reg(M7_1610_GPIO62); + if ((omap_request_gpio(62)) < 0) { + printk("Error requesting gpio 62 for CF irq\n"); + return; + } + /* it's really active-low */ + omap_set_gpio_edge_ctrl(62, OMAP_GPIO_FALLING_EDGE); } void osk_init_irq(void) @@ -87,12 +120,22 @@ omap_init_irq(); omap_gpio_init(); osk_init_smc91x(); + osk_init_cf(); } static struct omap_usb_config osk_usb_config __initdata = { - /* has usb host and device, but no Mini-AB port */ + /* has usb host connector (A) ... for development it can also + * be used, with a NONSTANDARD gender-bending cable/dongle, as + * a peripheral. + */ +#ifdef CONFIG_USB_GADGET_OMAP + .register_dev = 1, + .hmc_mode = 0, +#else .register_host = 1, .hmc_mode = 16, + .rwc = 1, +#endif .pins[0] = 2, }; @@ -102,9 +145,10 @@ static void __init osk_init(void) { - platform_add_devices(osk5912_devices, ARRAY_SIZE(osk5912_devices)); + platform_add_devices(osk5912_devices, ARRAY_SIZE(osk5912_devices)); omap_board_config = osk_config; omap_board_config_size = ARRAY_SIZE(osk_config); + USB_TRANSCEIVER_CTRL_REG |= (3 << 1); } static void __init osk_map_io(void) diff -Nru a/arch/arm/mach-omap/board-perseus2.c b/arch/arm/mach-omap/board-perseus2.c --- a/arch/arm/mach-omap/board-perseus2.c 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/mach-omap/board-perseus2.c 2005-03-02 10:51:31 -08:00 @@ -21,18 +21,16 @@ #include #include -#include #include #include #include -#include #include "common.h" static struct resource smc91x_resources[] = { [0] = { .start = H2P2_DBG_FPGA_ETHR_START, /* Physical */ - .end = H2P2_DBG_FPGA_ETHR_START + SZ_4K, + .end = H2P2_DBG_FPGA_ETHR_START + 0xf, .flags = IORESOURCE_MEM, }, [1] = { diff -Nru a/arch/arm/mach-omap/board-voiceblue.c b/arch/arm/mach-omap/board-voiceblue.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/board-voiceblue.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,256 @@ +/* + * linux/arch/arm/mach-omap/board-voiceblue.c + * + * Modified from board-generic.c + * + * Copyright (C) 2004 2N Telekomunikace, Ladislav Michl + * + * Code for OMAP5910 based VoiceBlue board (VoIP to GSM gateway). + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "common.h" + +extern void omap_init_time(void); +extern int omap_gpio_init(void); + +static struct plat_serial8250_port voiceblue_ports[] = { + { + .mapbase = (unsigned long)(OMAP_CS1_PHYS + 0x40000), + .irq = OMAP_GPIO_IRQ(12), + .flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP, + .iotype = UPIO_MEM, + .regshift = 1, + .uartclk = 3686400, + }, + { + .mapbase = (unsigned long)(OMAP_CS1_PHYS + 0x50000), + .irq = OMAP_GPIO_IRQ(13), + .flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP, + .iotype = UPIO_MEM, + .regshift = 1, + .uartclk = 3686400, + }, + { + .mapbase = (unsigned long)(OMAP_CS1_PHYS + 0x60000), + .irq = OMAP_GPIO_IRQ(14), + .flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP, + .iotype = UPIO_MEM, + .regshift = 1, + .uartclk = 3686400, + }, + { + .mapbase = (unsigned long)(OMAP_CS1_PHYS + 0x70000), + .irq = OMAP_GPIO_IRQ(15), + .flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP, + .iotype = UPIO_MEM, + .regshift = 1, + .uartclk = 3686400, + }, + { }, +}; + +static struct platform_device serial_device = { + .name = "serial8250", + .id = 1, + .dev = { + .platform_data = voiceblue_ports, + }, +}; + +static int __init ext_uart_init(void) +{ + return platform_device_register(&serial_device); +} +arch_initcall(ext_uart_init); + +static struct resource voiceblue_smc91x_resources[] = { + [0] = { + .start = OMAP_CS2_PHYS + 0x300, + .end = OMAP_CS2_PHYS + 0x300 + 16, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = OMAP_GPIO_IRQ(8), + .end = OMAP_GPIO_IRQ(8), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device voiceblue_smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(voiceblue_smc91x_resources), + .resource = voiceblue_smc91x_resources, +}; + +static struct platform_device *voiceblue_devices[] __initdata = { + &voiceblue_smc91x_device, +}; + +static struct omap_usb_config voiceblue_usb_config __initdata = { + .hmc_mode = 3, + .register_host = 1, + .register_dev = 1, + .pins[0] = 2, + .pins[1] = 6, + .pins[2] = 6, +}; + +static struct omap_board_config_kernel voiceblue_config[] = { + { OMAP_TAG_USB, &voiceblue_usb_config }, +}; + +static void __init voiceblue_init_irq(void) +{ + omap_init_irq(); + omap_gpio_init(); +} + +static void __init voiceblue_init(void) +{ + /* There is a good chance board is going up, so enable Power LED + * (it is connected through invertor) */ + omap_writeb(0x00, OMAP_LPG1_LCR); + /* Watchdog */ + omap_request_gpio(0); + /* smc91x reset */ + omap_request_gpio(7); + omap_set_gpio_direction(7, 0); + omap_set_gpio_dataout(7, 1); + udelay(2); /* wait at least 100ns */ + omap_set_gpio_dataout(7, 0); + mdelay(50); /* 50ms until PHY ready */ + /* smc91x interrupt pin */ + omap_request_gpio(8); + omap_set_gpio_edge_ctrl(8, OMAP_GPIO_RISING_EDGE); + /* 16C554 reset*/ + omap_request_gpio(6); + omap_set_gpio_direction(6, 0); + omap_set_gpio_dataout(6, 0); + /* 16C554 interrupt pins */ + omap_request_gpio(12); + omap_request_gpio(13); + omap_request_gpio(14); + omap_request_gpio(15); + omap_set_gpio_edge_ctrl(12, OMAP_GPIO_RISING_EDGE); + omap_set_gpio_edge_ctrl(13, OMAP_GPIO_RISING_EDGE); + omap_set_gpio_edge_ctrl(14, OMAP_GPIO_RISING_EDGE); + omap_set_gpio_edge_ctrl(15, OMAP_GPIO_RISING_EDGE); + + platform_add_devices(voiceblue_devices, ARRAY_SIZE(voiceblue_devices)); + omap_board_config = voiceblue_config; + omap_board_config_size = ARRAY_SIZE(voiceblue_config); +} + +static int __initdata omap_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1}; + +static void __init voiceblue_map_io(void) +{ + omap_map_io(); + omap_serial_init(omap_serial_ports); +} + +#define MACHINE_PANICED 1 +#define MACHINE_REBOOTING 2 +#define MACHINE_REBOOT 4 +static unsigned long machine_state; + +static int panic_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ + if (test_and_set_bit(MACHINE_PANICED, &machine_state)) + return NOTIFY_DONE; + + /* Flash Power LED + * (TODO: Enable clock right way (enabled in bootloader already)) */ + omap_writeb(0x78, OMAP_LPG1_LCR); + + return NOTIFY_DONE; +} + +static struct notifier_block panic_block = { + .notifier_call = panic_event, +}; + +static int __init setup_notifier(void) +{ + /* Setup panic notifier */ + notifier_chain_register(&panic_notifier_list, &panic_block); + + return 0; +} + +postcore_initcall(setup_notifier); + +static int wdt_gpio_state; + +void voiceblue_wdt_enable(void) +{ + omap_set_gpio_direction(0, 0); + omap_set_gpio_dataout(0, 0); + omap_set_gpio_dataout(0, 1); + omap_set_gpio_dataout(0, 0); + wdt_gpio_state = 0; +} + +void voiceblue_wdt_disable(void) +{ + omap_set_gpio_dataout(0, 0); + omap_set_gpio_dataout(0, 1); + omap_set_gpio_dataout(0, 0); + omap_set_gpio_direction(0, 1); +} + +void voiceblue_wdt_ping(void) +{ + if (test_bit(MACHINE_REBOOT, &machine_state)) + return; + + wdt_gpio_state = !wdt_gpio_state; + omap_set_gpio_dataout(0, wdt_gpio_state); +} + +void voiceblue_reset(void) +{ + set_bit(MACHINE_REBOOT, &machine_state); + voiceblue_wdt_enable(); + while (1) ; +} + +EXPORT_SYMBOL(voiceblue_wdt_enable); +EXPORT_SYMBOL(voiceblue_wdt_disable); +EXPORT_SYMBOL(voiceblue_wdt_ping); + +MACHINE_START(VOICEBLUE, "VoiceBlue OMAP5910") + MAINTAINER("Ladislav Michl ") + BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000) + BOOT_PARAMS(0x10000100) + MAPIO(voiceblue_map_io) + INITIRQ(voiceblue_init_irq) + INIT_MACHINE(voiceblue_init) + .timer = &omap_timer, +MACHINE_END diff -Nru a/arch/arm/mach-omap/bootreason.c b/arch/arm/mach-omap/bootreason.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/bootreason.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,80 @@ +/* + * linux/arch/arm/mach-omap/bootreason.c + * + * OMAP Bootreason passing + * + * Copyright (c) 2004 Nokia + * + * Written by David Weinehall + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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. + */ +#include +#include +#include +#include + +static char boot_reason[16]; + +static int omap_bootreason_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len += sprintf(page + len, "%s\n", boot_reason); + + *start = page + off; + + if (len > off) + len -= off; + else + len = 0; + + return len < count ? len : count; +} + +static int __init bootreason_init(void) +{ + const struct omap_boot_reason_config *cfg; + int reason_valid = 0; + + cfg = omap_get_config(OMAP_TAG_BOOT_REASON, struct omap_boot_reason_config); + if (cfg != NULL) { + strncpy(boot_reason, cfg->reason_str, sizeof(cfg->reason_str)); + boot_reason[sizeof(cfg->reason_str)] = 0; + reason_valid = 1; + } else { + /* Read the boot reason from the OMAP registers */ + } + + if (!reason_valid) + return -ENOENT; + + printk(KERN_INFO "Bootup reason: %s\n", boot_reason); + + if (!create_proc_read_entry("bootreason", S_IRUGO, NULL, + omap_bootreason_read_proc, NULL)) + return -ENOMEM; + + return 0; +} + +late_initcall(bootreason_init); diff -Nru a/arch/arm/mach-omap/clock.c b/arch/arm/mach-omap/clock.c --- a/arch/arm/mach-omap/clock.c 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/mach-omap/clock.c 2005-03-02 10:51:31 -08:00 @@ -22,36 +22,43 @@ static LIST_HEAD(clocks); static DECLARE_MUTEX(clocks_sem); -static DEFINE_SPINLOCK(clockfw_lock); +static spinlock_t clockfw_lock = SPIN_LOCK_UNLOCKED; static void propagate_rate(struct clk * clk); +/* External clock (MCLK & BCLK) functions */ +static int set_ext_clk_rate(struct clk * clk, unsigned long rate); +static long round_ext_clk_rate(struct clk * clk, unsigned long rate); +static void init_ext_clk(struct clk * clk); /* MPU virtual clock functions */ -static int select_table_rate(unsigned long rate); -static long round_to_table_rate(unsigned long rate); +static int select_table_rate(struct clk * clk, unsigned long rate); +static long round_to_table_rate(struct clk * clk, unsigned long rate); void clk_setdpll(__u16, __u16); struct mpu_rate rate_table[] = { /* MPU MHz, xtal MHz, dpll1 MHz, CKCTL, DPLL_CTL * armdiv, dspdiv, dspmmu, tcdiv, perdiv, lcddiv */ -#if defined(CONFIG_OMAP_ARM_216MHZ) && defined(CONFIG_ARCH_OMAP16XX) +#if defined(CONFIG_OMAP_ARM_216MHZ) { 216000000, 12000000, 216000000, 0x050d, 0x2910 }, /* 1/1/2/2/2/8 */ #endif -#if defined(CONFIG_OMAP_ARM_195MHZ) && defined(CONFIG_ARCH_OMAP730) +#if defined(CONFIG_OMAP_ARM_195MHZ) { 195000000, 13000000, 195000000, 0x050e, 0x2790 }, /* 1/1/2/2/4/8 */ #endif -#if defined(CONFIG_OMAP_ARM_192MHZ) && defined(CONFIG_ARCH_OMAP16XX) +#if defined(CONFIG_OMAP_ARM_192MHZ) { 192000000, 19200000, 192000000, 0x050f, 0x2510 }, /* 1/1/2/2/8/8 */ { 192000000, 12000000, 192000000, 0x050f, 0x2810 }, /* 1/1/2/2/8/8 */ { 96000000, 12000000, 192000000, 0x055f, 0x2810 }, /* 2/2/2/2/8/8 */ { 48000000, 12000000, 192000000, 0x0ccf, 0x2810 }, /* 4/4/4/4/8/8 */ { 24000000, 12000000, 192000000, 0x0fff, 0x2810 }, /* 8/8/8/8/8/8 */ #endif -#if defined(CONFIG_OMAP_ARM_182MHZ) && defined(CONFIG_ARCH_OMAP730) +#if defined(CONFIG_OMAP_ARM_182MHZ) { 182000000, 13000000, 182000000, 0x050e, 0x2710 }, /* 1/1/2/2/4/8 */ #endif #if defined(CONFIG_OMAP_ARM_168MHZ) { 168000000, 12000000, 168000000, 0x010f, 0x2710 }, /* 1/1/1/2/8/8 */ #endif +#if defined(CONFIG_OMAP_ARM_150MHZ) + { 150000000, 12000000, 150000000, 0x150a, 0x2cb0 }, /* 0/0/1/1/2/2 */ +#endif #if defined(CONFIG_OMAP_ARM_120MHZ) { 120000000, 12000000, 120000000, 0x010a, 0x2510 }, /* 1/1/1/2/4/4 */ #endif @@ -174,12 +181,12 @@ .recalc = &watchdog_recalc, }; -static struct clk arminth_ck1610 = { +static struct clk arminth_ck16xx = { .name = "arminth_ck", .parent = &arm_ck, .flags = CLOCK_IN_OMAP16XX, .recalc = &followparent_recalc, - /* Note: On 1610/1710 frequency can be divided by 2 by programming + /* Note: On 16xx the frequency can be divided by 2 by programming * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1 * * 1510 version is in TC clocks. @@ -209,7 +216,7 @@ static struct clk tc_ck = { .name = "tc_ck", .parent = &ck_dpll1, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730 | RATE_CKCTL | RATE_PROPAGATES | ALWAYS_ENABLED, .rate_offset = CKCTL_TCDIV_OFFSET, .recalc = &ckctl_recalc, @@ -220,9 +227,9 @@ .parent = &tc_ck, .flags = CLOCK_IN_OMAP1510, .recalc = &followparent_recalc, - /* Note: On 1510 frequency follows TC_CK + /* Note: On 1510 the frequency follows TC_CK * - * 1610/1710 version is in MPU clocks. + * 16xx version is in MPU clocks. */ }; @@ -309,7 +316,7 @@ static struct clk lcd_ck = { .name = "lcd_ck", .parent = &ck_dpll1, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730 | RATE_CKCTL, .enable_reg = ARM_IDLECT2, .enable_bit = EN_LCDCK, @@ -338,7 +345,7 @@ RATE_FIXED | ENABLE_REG_32BIT, .enable_reg = MOD_CONF_CTRL_0, .enable_bit = 30, - /* (1510/1610/1710) + /* (for both 1510 and 16xx) * The "enable bit" actually chooses between 48MHz and 12MHz/32kHz. */ }; @@ -356,7 +363,7 @@ */ }; -static struct clk usb_ck1610 = { +static struct clk usb_ck16xx = { .name = "usb_ck", /* Direct from ULPD, no parent */ .rate = 48000000, @@ -383,15 +390,41 @@ .enable_bit = USB_HOST_HHC_UHOST_EN, }; -/* To be done -- -static struct clk mclk = { +static struct clk mclk_1510 = { + .name = "mclk", + /* Direct from ULPD, no parent. May be enabled by ext hardware. */ + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510 | RATE_FIXED, +}; + +static struct clk mclk_16xx = { .name = "mclk", + /* Direct from ULPD, no parent. May be enabled by ext hardware. */ + .flags = CLOCK_IN_OMAP16XX, + .enable_reg = COM_CLK_DIV_CTRL_SEL, + .enable_bit = COM_ULPD_PLL_CLK_REQ, + .set_rate = &set_ext_clk_rate, + .round_rate = &round_ext_clk_rate, + .init = &init_ext_clk, +}; + +static struct clk bclk_1510 = { + .name = "bclk", + /* Direct from ULPD, no parent. May be enabled by ext hardware. */ + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510 | RATE_FIXED, }; -static struct clk bclk = { +static struct clk bclk_16xx = { .name = "bclk", + /* Direct from ULPD, no parent. May be enabled by ext hardware. */ + .flags = CLOCK_IN_OMAP16XX, + .enable_reg = SWD_CLK_DIV_CTRL_SEL, + .enable_bit = SWD_ULPD_PLL_CLK_REQ, + .set_rate = &set_ext_clk_rate, + .round_rate = &round_ext_clk_rate, + .init = &init_ext_clk, }; --- to be done */ static struct clk mmc1_ck = { .name = "mmc1_ck", @@ -438,8 +471,7 @@ &armxor_ck, &armtim_ck, &armwdt_ck, - &arminth_ck1510, - &arminth_ck1610, + &arminth_ck1510, &arminth_ck16xx, /* CK_GEN2 clocks */ &dsp_ck, &dspmmu_ck, @@ -460,13 +492,10 @@ &uart1_ck, &uart2_ck, &uart3_ck, - &usb_ck1510, - &usb_ck1610, + &usb_ck1510, &usb_ck16xx, &usb_hhc_ck, - /* To be done -- - &mclk, - &bclk, - -- to be done */ + &mclk_1510, &mclk_16xx, + &bclk_1510, &bclk_16xx, &mmc1_ck, &mmc2_ck, /* Virtual clocks */ @@ -629,6 +658,13 @@ EXPORT_SYMBOL(clk_unuse); +int clk_get_usecount(struct clk *clk) +{ + return clk->usecount; +} +EXPORT_SYMBOL(clk_get_usecount); + + unsigned long clk_get_rate(struct clk *clk) { return clk->rate; @@ -742,7 +778,7 @@ } if(clk->round_rate != 0) - return clk->round_rate(rate); + return clk->round_rate(clk, rate); return clk->rate; } @@ -761,11 +797,14 @@ } -static int select_table_rate(unsigned long rate) +static int select_table_rate(struct clk * clk, unsigned long rate) { /* Find the highest supported frequency <= rate and switch to it */ struct mpu_rate * ptr; + if (clk != &virtual_ck_mpu) + return -EINVAL; + for (ptr = rate_table; ptr->rate; ptr++) { if (ptr->xtal != ck_ref.rate) continue; @@ -792,12 +831,15 @@ } -static long round_to_table_rate(unsigned long rate) +static long round_to_table_rate(struct clk * clk, unsigned long rate) { /* Find the highest supported frequency <= rate */ struct mpu_rate * ptr; long highest_rate; + if (clk != &virtual_ck_mpu) + return -EINVAL; + highest_rate = -EINVAL; for (ptr = rate_table; ptr->rate; ptr++) { @@ -840,7 +882,7 @@ ret = 0; } else if(clk->set_rate != 0) { spin_lock_irqsave(&clockfw_lock, flags); - ret = clk->set_rate(rate); + ret = clk->set_rate(clk, rate); spin_unlock_irqrestore(&clockfw_lock, flags); } @@ -852,10 +894,79 @@ EXPORT_SYMBOL(clk_set_rate); +static unsigned calc_ext_dsor(unsigned long rate) +{ + unsigned dsor; + + /* MCLK and BCLK divisor selection is not linear: + * freq = 96MHz / dsor + * + * RATIO_SEL range: dsor <-> RATIO_SEL + * 0..6: (RATIO_SEL+2) <-> (dsor-2) + * 6..48: (8+(RATIO_SEL-6)*2) <-> ((dsor-8)/2+6) + * Minimum dsor is 2 and maximum is 96. Odd divisors starting from 9 + * can not be used. + */ + for (dsor = 2; dsor < 96; ++dsor) { + if ((dsor & 1) && dsor > 8) + continue; + if (rate >= 96000000 / dsor) + break; + } + return dsor; +} + + +static int set_ext_clk_rate(struct clk * clk, unsigned long rate) +{ + unsigned dsor; + __u16 ratio_bits; + + dsor = calc_ext_dsor(rate); + clk->rate = 96000000 / dsor; + if (dsor > 8) + ratio_bits = ((dsor - 8) / 2 + 6) << 2; + else + ratio_bits = (dsor - 2) << 2; + + ratio_bits |= omap_readw(clk->enable_reg) & ~0xfd; + omap_writew(ratio_bits, clk->enable_reg); + + return 0; +} + + +static long round_ext_clk_rate(struct clk * clk, unsigned long rate) +{ + return 96000000 / calc_ext_dsor(rate); +} + + +static void init_ext_clk(struct clk * clk) +{ + unsigned dsor; + __u16 ratio_bits; + + /* Determine current rate and ensure clock is based on 96MHz APLL */ + ratio_bits = omap_readw(clk->enable_reg) & ~1; + omap_writew(ratio_bits, clk->enable_reg); + + ratio_bits = (ratio_bits & 0xfc) >> 2; + if (ratio_bits > 6) + dsor = (ratio_bits - 6) * 2 + 8; + else + dsor = ratio_bits + 2; + + clk-> rate = 96000000 / dsor; +} + + int clk_register(struct clk *clk) { down(&clocks_sem); list_add(&clk->node, &clocks); + if (clk->init) + clk->init(clk); up(&clocks_sem); return 0; } @@ -887,6 +998,11 @@ clk_register(*clkp); continue; } + + if (((*clkp)->flags &CLOCK_IN_OMAP730) && cpu_is_omap730()) { + clk_register(*clkp); + continue; + } } info = omap_get_config(OMAP_TAG_CLOCK, struct omap_clock_config); @@ -906,7 +1022,7 @@ omap_writew(0x1000, ARM_SYSST); /* Find the highest supported frequency and enable it */ - if (select_table_rate(~0)) { + if (select_table_rate(&virtual_ck_mpu, ~0)) { printk(KERN_ERR "System frequencies not set. Check your config.\n"); /* Guess sane values (60MHz) */ omap_writew(0x2290, DPLL_CTL); diff -Nru a/arch/arm/mach-omap/clock.h b/arch/arm/mach-omap/clock.h --- a/arch/arm/mach-omap/clock.h 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/mach-omap/clock.h 2005-03-02 10:51:31 -08:00 @@ -22,13 +22,14 @@ struct clk *parent; unsigned long rate; __s8 usecount; - __u8 flags; + __u16 flags; __u32 enable_reg; __u8 enable_bit; __u8 rate_offset; void (*recalc)(struct clk *); - int (*set_rate)(unsigned long); - long (*round_rate)(unsigned long); + int (*set_rate)(struct clk *, unsigned long); + long (*round_rate)(struct clk *, unsigned long); + void (*init)(struct clk *); }; @@ -50,6 +51,7 @@ #define ENABLE_REG_32BIT 32 #define CLOCK_IN_OMAP16XX 64 #define CLOCK_IN_OMAP1510 128 +#define CLOCK_IN_OMAP730 256 /* ARM_CKCTL bit shifts */ #define CKCTL_PERDIV_OFFSET 0 @@ -97,6 +99,10 @@ /* Various register defines for clock controls scattered around OMAP chip */ #define USB_MCLK_EN 4 /* In ULPD_CLKC_CTRL */ #define USB_HOST_HHC_UHOST_EN 9 /* In MOD_CONF_CTRL_0 */ +#define SWD_ULPD_PLL_CLK_REQ 1 /* In SWD_CLK_DIV_CTRL_SEL */ +#define COM_ULPD_PLL_CLK_REQ 1 /* In COM_CLK_DIV_CTRL_SEL */ +#define SWD_CLK_DIV_CTRL_SEL 0xfffe0874 +#define COM_CLK_DIV_CTRL_SEL 0xfffe0878 int clk_register(struct clk *clk); diff -Nru a/arch/arm/mach-omap/common.c b/arch/arm/mach-omap/common.c --- a/arch/arm/mach-omap/common.c 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/mach-omap/common.c 2005-03-02 10:51:31 -08:00 @@ -263,9 +263,6 @@ iotable_init(omap_io_desc, ARRAY_SIZE(omap_io_desc)); omap_check_revision(); - /* clear BM to canonicalize CS0 (not CS3) at 0000:0000 */ - omap_writel(omap_readl(EMIFS_CONFIG) & 0x0d, EMIFS_CONFIG); - #ifdef CONFIG_ARCH_OMAP730 if (cpu_is_omap730()) { iotable_init(omap730_io_desc, ARRAY_SIZE(omap730_io_desc)); @@ -435,6 +432,9 @@ if (cpu_is_omap1510()) { omap_cfg_reg(UART3_TX); omap_cfg_reg(UART3_RX); + } + if (cpu_is_omap1710()) { + clk_enable(clk_get(0, "uart3_ck")); } break; } diff -Nru a/arch/arm/mach-omap/dma.c b/arch/arm/mach-omap/dma.c --- a/arch/arm/mach-omap/dma.c 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/mach-omap/dma.c 2005-03-02 10:51:31 -08:00 @@ -494,7 +494,7 @@ chan->data = data; chan->enabled_irqs = OMAP_DMA_TOUT_IRQ | OMAP_DMA_DROP_IRQ | OMAP_DMA_BLOCK_IRQ; - if (cpu_is_omap16xx() || cpu_is_omap730()) { + if (cpu_is_omap16xx()) { /* If the sync device is set, configure it dynamically. */ if (dev_id != 0) { set_gdma_dev(free_ch + 1, dev_id); diff -Nru a/arch/arm/mach-omap/dmtimer.c b/arch/arm/mach-omap/dmtimer.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/dmtimer.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,249 @@ +/* + * linux/arch/arm/mach-omap/dmtimer.c + * + * OMAP Dual-Mode Timers + * + * Copyright (C) 2005 Nokia Corporation + * Author: Lauri Leukkunen + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define OMAP_TIMER_COUNT 8 + +#define OMAP_TIMER_ID_REG 0x00 +#define OMAP_TIMER_OCP_CFG_REG 0x10 +#define OMAP_TIMER_SYS_STAT_REG 0x14 +#define OMAP_TIMER_STAT_REG 0x18 +#define OMAP_TIMER_INT_EN_REG 0x1c +#define OMAP_TIMER_WAKEUP_EN_REG 0x20 +#define OMAP_TIMER_CTRL_REG 0x24 +#define OMAP_TIMER_COUNTER_REG 0x28 +#define OMAP_TIMER_LOAD_REG 0x2c +#define OMAP_TIMER_TRIGGER_REG 0x30 +#define OMAP_TIMER_WRITE_PEND_REG 0x34 +#define OMAP_TIMER_MATCH_REG 0x38 +#define OMAP_TIMER_CAPTURE_REG 0x3c +#define OMAP_TIMER_IF_CTRL_REG 0x40 + + +static struct dmtimer_info_struct { + struct list_head unused_timers; + struct list_head reserved_timers; +} dm_timer_info; + +static struct omap_dm_timer dm_timers[] = { + { .base=0xfffb1400, .irq=INT_1610_GPTIMER1 }, + { .base=0xfffb1c00, .irq=INT_1610_GPTIMER2 }, + { .base=0xfffb2400, .irq=INT_1610_GPTIMER3 }, + { .base=0xfffb2c00, .irq=INT_1610_GPTIMER4 }, + { .base=0xfffb3400, .irq=INT_1610_GPTIMER5 }, + { .base=0xfffb3c00, .irq=INT_1610_GPTIMER6 }, + { .base=0xfffb4400, .irq=INT_1610_GPTIMER7 }, + { .base=0xfffb4c00, .irq=INT_1610_GPTIMER8 }, + { .base=0x0 }, +}; + + +static spinlock_t dm_timer_lock; + + +inline void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value) +{ + omap_writel(value, timer->base + reg); + while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG)) + ; +} + +inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg) +{ + return omap_readl(timer->base + reg); +} + +void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) +{ + int n = (timer - dm_timers) << 1; + u32 l; + + l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n); + l |= source << n; + omap_writel(l, MOD_CONF_CTRL_1); +} + + +void omap_dm_timer_reset(struct omap_dm_timer *timer) +{ + /* Reset and set posted mode */ + omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); + omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, 0x02); + + omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_ARMXOR); +} + + + +struct omap_dm_timer * omap_dm_timer_request(void) +{ + struct omap_dm_timer *timer; + unsigned long flags; + + spin_lock_irqsave(&dm_timer_lock, flags); + + if (list_empty(&dm_timer_info.unused_timers)) + return NULL; + + timer = (struct omap_dm_timer *)dm_timer_info.unused_timers.next; + + list_move_tail((struct list_head *)timer, &dm_timer_info.reserved_timers); + + spin_unlock_irqrestore(&dm_timer_lock, flags); + + return timer; +} + + +void omap_dm_timer_free(struct omap_dm_timer *timer) +{ + unsigned long flags; + + omap_dm_timer_reset(timer); + + spin_lock_irqsave(&dm_timer_lock, flags); + list_move_tail((struct list_head *)timer, &dm_timer_info.unused_timers); + spin_unlock_irqrestore(&dm_timer_lock, flags); +} + +void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, + unsigned int value) +{ + omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value); +} + +unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) +{ + return omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG); +} + +void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) +{ + omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value); +} + +void omap_dm_timer_enable_autoreload(struct omap_dm_timer *timer) +{ + u32 l; + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); + l |= OMAP_TIMER_CTRL_AR; + omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); +} + +void omap_dm_timer_trigger(struct omap_dm_timer *timer) +{ + omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 1); +} + +void omap_dm_timer_set_trigger(struct omap_dm_timer *timer, unsigned int value) +{ + u32 l; + + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); + l |= value & 0x3; + omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); +} + +void omap_dm_timer_start(struct omap_dm_timer *timer) +{ + u32 l; + + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); + l |= OMAP_TIMER_CTRL_ST; + omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); +} + +void omap_dm_timer_stop(struct omap_dm_timer *timer) +{ + u32 l; + + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); + l &= ~0x1; + omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); +} + +unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) +{ + return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG); +} + +void omap_dm_timer_reset_counter(struct omap_dm_timer *timer) +{ + omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, 0); +} + +void omap_dm_timer_set_load(struct omap_dm_timer *timer, unsigned int load) +{ + omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); +} + +void omap_dm_timer_set_match(struct omap_dm_timer *timer, unsigned int match) +{ + omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); +} + +void omap_dm_timer_enable_compare(struct omap_dm_timer *timer) +{ + u32 l; + + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); + l |= OMAP_TIMER_CTRL_CE; + omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); +} + + +static inline void __dm_timer_init(void) +{ + struct omap_dm_timer *timer; + + spin_lock_init(&dm_timer_lock); + INIT_LIST_HEAD(&dm_timer_info.unused_timers); + INIT_LIST_HEAD(&dm_timer_info.reserved_timers); + + timer = &dm_timers[0]; + while (timer->base) { + list_add_tail((struct list_head *)timer, &dm_timer_info.unused_timers); + omap_dm_timer_reset(timer); + timer++; + } +} + +static int __init omap_dm_timer_init(void) +{ + __dm_timer_init(); + return 0; +} + +arch_initcall(omap_dm_timer_init); + diff -Nru a/arch/arm/mach-omap/dsp/Kconfig b/arch/arm/mach-omap/dsp/Kconfig --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/dsp/Kconfig 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,29 @@ + +config OMAP_DSP + tristate "OMAP DSP driver (DSP Gateway)" + depends on ARCH_OMAP1510 || ARCH_OMAP16XX + help + This enables OMAP DSP driver, DSP Gateway. + +config OMAP_DSP_MBCMD_VERBOSE + bool "Mailbox Command Verbose LOG" + depends on OMAP_DSP + help + This enables kernel log output in the Mailbox command exchanges + in the DSP Gateway driver. + +config OMAP_DSP_TASK_MULTIOPEN + bool "DSP Task Multiopen Capability" + depends on OMAP_DSP + help + This enables DSP tasks to be opened by multiple times at a time. + Otherwise, they can be opened only once at a time. + +config OMAP_DSP_FBEXPORT + bool "Framebuffer export to DSP" + depends on OMAP_DSP + help + This enables to map the frame buffer to DSP. + By doing this, DSP can access the frame buffer directly without + bothering ARM. + diff -Nru a/arch/arm/mach-omap/dsp/Makefile b/arch/arm/mach-omap/dsp/Makefile --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/dsp/Makefile 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,15 @@ +# +# Makefile for the OMAP DSP driver. +# + +# The target object and module list name. + +obj-y := dsp_common.o + +obj-$(CONFIG_OMAP_DSP) += dsp.o + +# Declare multi-part drivers + +dsp-objs := dsp_core.o ipbuf.o mblog.o task.o \ + dsp_ctl_core.o dsp_ctl.o taskwatch.o error.o dsp_mem.o \ + uaccess_dsp.o diff -Nru a/arch/arm/mach-omap/dsp/dsp.h b/arch/arm/mach-omap/dsp/dsp.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/dsp/dsp.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,203 @@ +/* + * linux/arch/arm/mach-omap/dsp/dsp.h + * + * Header for OMAP DSP driver + * + * Copyright (C) 2002-2004 Nokia Corporation + * + * Written by Toshihiro Kobayashi + * + * 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 + * + * 2004/12/03: DSP Gateway version 3.1 + */ + +#include "hardware_dsp.h" +#include "dsp_common.h" + +#define DSP_DRIVER_VERSION "3.1" + +#define OLD_BINARY_SUPPORT y + +#ifdef OLD_BINARY_SUPPORT +#define MBREV_3_0 0x0017 +#endif + +#define DSP_INIT_PAGE 0xfff000 +/* idle program will be placed at IDLEPG_BASE. */ +#define IDLEPG_BASE 0xfffe00 +#define IDLEPG_SIZE 0x100 + +/* + * INT_D2A_MB value definition + * INT_DSP_MAILBOX1: use Mailbox 1 (INT 10) for DSP->ARM mailbox + * INT_DSP_MAILBOX2: use Mailbox 2 (INT 11) for DSP->ARM mailbox + */ +#define INT_D2A_MB1 INT_DSP_MAILBOX1 + +/* keep 2 entries for OMAP_DSP_TID_FREE and OMAP_DSP_TID_ANON */ +#define TASKDEV_MAX 254 + +#define MKLONG(uw,lw) (((unsigned long)(uw)) << 16 | (lw)) +#define MBCMD(nm) OMAP_DSP_MBCMD_##nm + +extern void dsp_cur_users_add(struct task_struct *tsk); +extern void dsp_cur_users_del(struct task_struct *tsk); +extern void dsp_cur_users_map_update(void); + +enum mbsend_type { + MBSEND_TYPE_NOWAIT, /* never wait */ + MBSEND_TYPE_NORMAL, /* waits */ + MBSEND_TYPE_RECOVERY, /* used for mmu err recovery comand */ +}; + +/* struct mbcmd and struct mbcmd_hw must be compatible */ +struct mbcmd { + unsigned short cmd_l:8; + unsigned short cmd_h:7; + unsigned short seq:1; + unsigned short data; +}; + +struct mbcmd_hw { + unsigned short cmd; + unsigned short data; +}; + +#define mbcmd_set(mb, h, l, d) \ + do { \ + (mb).cmd_h = (h); \ + (mb).cmd_l = (l); \ + (mb).data = (d); \ + } while(0) + +struct mb_exarg { + unsigned char tid; + int argc; + unsigned short *argv; +}; + +extern void dsp_mb_start(void); +extern void dsp_mb_stop(void); +extern void dsp_mb_config(void *sync_seq_adr); +extern int sync_with_dsp(unsigned short *syncwd, unsigned short tid, + int try_cnt); +extern int __dsp_mbsend(struct mbcmd *mb, struct mb_exarg *arg, + enum mbsend_type send_type); +#define dsp_mbsend(mb) \ + __dsp_mbsend(mb, NULL, MBSEND_TYPE_NORMAL) +#define dsp_mbsend_recovery(mb) \ + __dsp_mbsend(mb, NULL, MBSEND_TYPE_RECOVERY) +#define dsp_mbsend_exarg(mb, arg) \ + __dsp_mbsend(mb, arg, MBSEND_TYPE_NORMAL) +extern int __dsp_mbsend_and_wait(struct mbcmd *mb, struct mb_exarg *arg, + wait_queue_head_t *q); +#define dsp_mbsend_and_wait(mb, q) \ + __dsp_mbsend_and_wait(mb, NULL, q) +#define dsp_mbsend_and_wait_exarg(mb, arg, q) \ + __dsp_mbsend_and_wait(mb, arg, q) + +extern void ipbuf_start(void); +extern void ipbuf_stop(void); +extern int ipbuf_config(unsigned short ln, unsigned short lsz, + unsigned long adr); +extern int is_ipbuf_internal_mem(void); +extern unsigned short get_free_ipbuf(unsigned char tid); +extern void __unuse_ipbuf(unsigned short bid, enum mbsend_type send_type); +#define unuse_ipbuf(bid) __unuse_ipbuf(bid, MBSEND_TYPE_NORMAL) +#define unuse_ipbuf_nowait(bid) __unuse_ipbuf(bid, MBSEND_TYPE_NOWAIT) +extern void release_ipbuf(unsigned short bid); +extern void balance_ipbuf(enum mbsend_type send_type); + +#define release_ipbuf_pvt(ipbuf_pvt) \ + do { \ + (ipbuf_pvt)->s = OMAP_DSP_TID_FREE; \ + } while(0) + +extern int dsp_is_ready(void); +extern int dspuncfg(void); +extern void dsp_runlevel(unsigned char level); +extern int dsp_suspend(void); +extern int dsp_resume(void); + +extern int dsp_task_config_all(unsigned char n); +extern void dsp_task_unconfig_all(void); +extern unsigned char dsp_task_count(void); +extern int dsp_taskmod_busy(void); +extern int dsp_mkdev(char *name); +extern int dsp_rmdev(char *name); +extern int dsp_tadd(unsigned char minor, unsigned long adr); +extern int dsp_tdel(unsigned char minor); +extern int dsp_tkill(unsigned char minor); +extern long taskdev_state(unsigned char minor); + +#ifdef CONFIG_PROC_FS +extern int ipbuf_is_held(unsigned char tid, unsigned short bid); +#endif /* CONFIG_PROC_FS */ + +extern int dsp_mem_enable(void); +extern int dsp_mem_disable(void); +extern void dsp_map_update(struct task_struct *tsk); +extern unsigned long dsp_virt_to_phys(void *vadr, size_t *len); +extern void dsp_mem_start(void); + +extern void dsp_twch_start(void); +extern void dsp_twch_stop(void); +extern void dsp_twch_touch(void); + +extern void dsp_err_start(void); +extern void dsp_err_stop(void); +extern void dsp_err_mmu_set(unsigned long adr); +extern void dsp_err_mmu_clear(void); +extern int dsp_err_mmu_isset(void); +extern void dsp_err_wdt_clear(void); +extern int dsp_err_wdt_isset(void); + +enum cmd_l_type { + CMD_L_TYPE_NULL, + CMD_L_TYPE_TID, + CMD_L_TYPE_SUBCMD, +}; + +struct cmdinfo { + char *name; + enum cmd_l_type cmd_l_type; + void (*handler)(struct mbcmd *mb); +}; + +extern const struct cmdinfo *cmdinfo[]; + +#define cmd_name(mb) (cmdinfo[(mb).cmd_h]->name) +extern char *subcmd_name(struct mbcmd *mb); + +enum mblog_dir { + MBLOG_DIR_AD, + MBLOG_DIR_DA, +}; + +extern void mblog_add(struct mbcmd *mb, enum mblog_dir dir); +#ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE +extern void mblog_printcmd(struct mbcmd *mb, enum mblog_dir dir); +#else /* CONFIG_OMAP_DSP_MBCMD_VERBOSE */ +#define mblog_printcmd(mb, dir) do {} while(0) +#endif /* CONFIG_OMAP_DSP_MBCMD_VERBOSE */ + +extern struct ipbuf **ipbuf; +extern struct ipbcfg ipbcfg; +extern struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad; + +#ifdef CONFIG_PROC_FS +extern struct proc_dir_entry *procdir_dsp; +#endif /* CONFIG_PROC_FS */ diff -Nru a/arch/arm/mach-omap/dsp/dsp_common.c b/arch/arm/mach-omap/dsp/dsp_common.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/dsp/dsp_common.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,233 @@ +/* + * linux/arch/arm/mach-omap/dsp/dsp_common.c + * + * OMAP DSP driver static part + * + * Copyright (C) 2002-2004 Nokia Corporation + * + * Written by Toshihiro Kobayashi + * + * 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 + * + * 2004/11/19: DSP Gateway version 3.1 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dsp_common.h" + +struct clk *dsp_ck_handle; +struct clk *api_ck_handle; +unsigned long dspmem_base, dspmem_size; +int dsp_runstat = RUNSTAT_RESET; +unsigned short dsp_icrmask = DSPREG_ICR_EMIF_IDLE_DOMAIN | + DSPREG_ICR_DPLL_IDLE_DOMAIN | + DSPREG_ICR_PER_IDLE_DOMAIN | + DSPREG_ICR_CACHE_IDLE_DOMAIN | + DSPREG_ICR_DMA_IDLE_DOMAIN | + DSPREG_ICR_CPU_IDLE_DOMAIN; + +int dsp_set_rstvect(unsigned long adr) +{ + unsigned long *dst_adr; + + if (adr >= DSPSPACE_SIZE) + return -EINVAL; + + dst_adr = dspbyte_to_virt(DSP_BOOT_ADR_DIRECT); + /* word swap */ + *dst_adr = ((adr & 0xffff) << 16) | (adr >> 16); + /* fill 8 bytes! */ + *(dst_adr+1) = 0; + /* direct boot */ + omap_writew(MPUI_DSP_BOOT_CONFIG_DIRECT, MPUI_DSP_BOOT_CONFIG); + + return 0; +} + +static void simple_load_code(unsigned char *src_c, unsigned short *dst, int len) +{ + int i; + unsigned short *src = (unsigned short *)src_c; + int len_w; + + /* len must be multiple of 2. */ + if (len & 1) + BUG(); + + len_w = len / 2; + for (i = 0; i < len_w; i++) { + /* byte swap copy */ + *dst = ((*src & 0x00ff) << 8) | + ((*src & 0xff00) >> 8); + src++; + dst++; + } +} + +/* program size must be multiple of 2 */ +#define IDLE_TEXT_SIZE 28 +#define IDLE_TEXT(icr) { \ + /* disable WDT */ \ + 0x76, 0x34, 0x04, 0xb8, /* 0x763404b8: mov AR3 0x3404 */ \ + 0xfb, 0x61, 0x00, 0xf5, /* 0xfb6100f5: mov *AR3 0x00f5 */ \ + 0x9a, /* 0x9a: port */ \ + 0xfb, 0x61, 0x00, 0xa0, /* 0xfb6100a0: mov *AR3 0x00a0 */ \ + 0x9a, /* 0x9a: port */ \ + /* set ICR = icr */ \ + 0x3c, 0x1b, /* 0x3c1b: mov AR3 0x1 */ \ + 0xe6, 0x61, (icr), /* 0xe661**: mov *AR3, icr */ \ + 0x9a, /* 0x9a: port */ \ + /* idle and loop forever */ \ + 0x7a, 0x00, 0x00, 0x0c, /* 0x7a00000c: idle */ \ + 0x4a, 0x7a, /* 0x4a7a: b -6 (infinite loop) */ \ + 0x20, 0x20 /* 0x20: nop */ \ +} + +/* + * idle_boot base: + * Initialized with DSP_BOOT_ADR_MPUI (=0x010000). + * This value is used before DSP Gateway driver is initialized. + * DSP Gateway driver will overwrite this value with other value, + * to avoid confliction with the user program. + */ +static unsigned long idle_boot_base = DSP_BOOT_ADR_MPUI; + +void dsp_idle(void) +{ + unsigned char icr; + + disable_irq(INT_DSP_MMU); + preempt_disable(); + __dsp_reset(); + clk_use(api_ck_handle); + + /* + * icr settings: + * DMA should not sleep for DARAM/SARAM access + * DPLL should not sleep for DMA. + */ + icr = dsp_icrmask & + ~(DSPREG_ICR_DMA_IDLE_DOMAIN | DSPREG_ICR_DPLL_IDLE_DOMAIN) & + 0xff; + { + unsigned char idle_text[IDLE_TEXT_SIZE] = IDLE_TEXT(icr); + simple_load_code(idle_text, dspbyte_to_virt(idle_boot_base), + IDLE_TEXT_SIZE); + } + if (idle_boot_base == DSP_BOOT_ADR_MPUI) + omap_writew(MPUI_DSP_BOOT_CONFIG_MPUI, MPUI_DSP_BOOT_CONFIG); + else + dsp_set_rstvect(idle_boot_base); + clk_unuse(api_ck_handle); + udelay(10); /* to make things stable */ + __dsp_run(); + dsp_runstat = RUNSTAT_IDLE; + preempt_enable(); + enable_irq(INT_DSP_MMU); +} + +void dsp_set_idle_boot_base(unsigned long adr, size_t size) +{ + if (adr == idle_boot_base) + return; + idle_boot_base = adr; + if (size < IDLE_TEXT_SIZE) { + printk(KERN_ERR + "omapdsp: size for idle program is not enough!\n"); + BUG(); + } + if (dsp_runstat == RUNSTAT_IDLE) + dsp_idle(); +} + +static int init_done; + +static int __init omap_dsp_init(void) +{ + dspmem_size = 0; +#ifdef CONFIG_ARCH_OMAP1510 + if (cpu_is_omap1510()) { + dspmem_base = OMAP1510_DSP_BASE; + dspmem_size = OMAP1510_DSP_SIZE; + } +#endif +#ifdef CONFIG_ARCH_OMAP16XX + if (cpu_is_omap16xx()) { + dspmem_base = OMAP16XX_DSP_BASE; + dspmem_size = OMAP16XX_DSP_SIZE; + } +#endif + if (dspmem_size == 0) { + printk(KERN_ERR "omapdsp: unsupported omap architecture.\n"); + return -ENODEV; + } + + dsp_ck_handle = clk_get(0, "dsp_ck"); + if (IS_ERR(dsp_ck_handle)) { + printk(KERN_ERR "omapdsp: could not acquire dsp_ck handle.\n"); + return PTR_ERR(dsp_ck_handle); + } + + api_ck_handle = clk_get(0, "api_ck"); + if (IS_ERR(api_ck_handle)) { + printk(KERN_ERR "omapdsp: could not acquire api_ck handle.\n"); + return PTR_ERR(api_ck_handle); + } + + __dsp_enable(); + mpui_byteswap_off(); + mpui_wordswap_on(); + tc_wordswap(); + + init_done = 1; + return 0; +} + +void omap_dsp_request_idle(void) +{ + if (dsp_runstat == RUNSTAT_RESET) { + if (!init_done) + omap_dsp_init(); + dsp_idle(); + } +} + +arch_initcall(omap_dsp_init); + +EXPORT_SYMBOL(omap_dsp_request_idle); + +#ifdef CONFIG_OMAP_DSP_MODULE +EXPORT_SYMBOL(dsp_ck_handle); +EXPORT_SYMBOL(api_ck_handle); +EXPORT_SYMBOL(dspmem_base); +EXPORT_SYMBOL(dspmem_size); +EXPORT_SYMBOL(dsp_runstat); +EXPORT_SYMBOL(dsp_icrmask); +EXPORT_SYMBOL(dsp_set_rstvect); +EXPORT_SYMBOL(dsp_idle); +EXPORT_SYMBOL(dsp_set_idle_boot_base); + +EXPORT_SYMBOL(__cpu_flush_kern_tlb_range); +#endif diff -Nru a/arch/arm/mach-omap/dsp/dsp_common.h b/arch/arm/mach-omap/dsp/dsp_common.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/dsp/dsp_common.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,117 @@ +/* + * linux/arch/arm/mach-omap/dsp/dsp_common.h + * + * Header for OMAP DSP driver static part + * + * Copyright (C) 2002-2004 Nokia Corporation + * + * Written by Toshihiro Kobayashi + * + * 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 + * + * 2004/11/16: DSP Gateway version 3.1 + */ + +#include "hardware_dsp.h" + +#define DSPSPACE_SIZE 0x1000000 + +#define omap_set_bit_regw(b,r) \ + do { omap_writew(omap_readw(r) | (b), (r)); } while(0) +#define omap_clr_bit_regw(b,r) \ + do { omap_writew(omap_readw(r) & ~(b), (r)); } while(0) +#define omap_set_bit_regl(b,r) \ + do { omap_writel(omap_readl(r) | (b), (r)); } while(0) +#define omap_clr_bit_regl(b,r) \ + do { omap_writel(omap_readl(r) & ~(b), (r)); } while(0) + +#define dspword_to_virt(dw) ((void *)(dspmem_base + ((dw) << 1))) +#define dspbyte_to_virt(db) ((void *)(dspmem_base + (db))) +#define virt_to_dspword(va) (((unsigned long)(va) - dspmem_base) >> 1) +#define virt_to_dspbyte(va) ((unsigned long)(va) - dspmem_base) +#define is_dsp_internal_mem(va) \ + (((unsigned long)(va) >= dspmem_base) && \ + ((unsigned long)(va) < dspmem_base + dspmem_size)) +#define is_dspbyte_internal_mem(db) ((db) < dspmem_size) +#define is_dspword_internal_mem(dw) (((dw) << 1) < dspmem_size) + +/* + * MPUI byteswap/wordswap on/off + * default setting: wordswap = all, byteswap = APIMEM only + */ +#define mpui_wordswap_on() \ + { \ + omap_writel( \ + (omap_readl(MPUI_CTRL) & ~MPUI_CTRL_WORDSWAP_MASK) | \ + MPUI_CTRL_WORDSWAP_ALL, MPUI_CTRL); \ + } while(0) + +#define mpui_wordswap_off() \ + { \ + omap_writel( \ + (omap_readl(MPUI_CTRL) & ~MPUI_CTRL_WORDSWAP_MASK) | \ + MPUI_CTRL_WORDSWAP_NONE, MPUI_CTRL); \ + } while(0) + +#define mpui_byteswap_on() \ + { \ + omap_writel( \ + (omap_readl(MPUI_CTRL) & ~MPUI_CTRL_BYTESWAP_MASK) | \ + MPUI_CTRL_BYTESWAP_API, MPUI_CTRL); \ + } while(0) + +#define mpui_byteswap_off() \ + { \ + omap_writel( \ + (omap_readl(MPUI_CTRL) & ~MPUI_CTRL_BYTESWAP_MASK) | \ + MPUI_CTRL_BYTESWAP_NONE, MPUI_CTRL); \ + } while(0) + +/* + * TC wordswap on / off + */ +#define tc_wordswap() \ + { \ + omap_writel(TC_ENDIANISM_SWAP_WORD | TC_ENDIANISM_EN, \ + TC_ENDIANISM); \ + } while(0) + +#define tc_noswap() \ + { \ + omap_writel(omap_inl(TC_ENDIANISM) & ~TC_ENDIANISM_EN, \ + TC_ENDIANISM); \ + } while(0) + +/* + * enable priority registers, EMIF, MPUI control logic + */ +#define __dsp_enable() omap_set_bit_regw(ARM_RSTCT1_DSP_RST, ARM_RSTCT1) +#define __dsp_disable() omap_clr_bit_regw(ARM_RSTCT1_DSP_RST, ARM_RSTCT1) +#define __dsp_run() omap_set_bit_regw(ARM_RSTCT1_DSP_EN, ARM_RSTCT1) +#define __dsp_reset() omap_clr_bit_regw(ARM_RSTCT1_DSP_EN, ARM_RSTCT1) + +#define RUNSTAT_RESET 0 +#define RUNSTAT_IDLE 1 +#define RUNSTAT_RUN 2 + +extern struct clk *dsp_ck_handle; +extern struct clk *api_ck_handle; +extern unsigned long dspmem_base, dspmem_size; +extern int dsp_runstat; +extern unsigned short dsp_icrmask; + +int dsp_set_rstvect(unsigned long adr); +void dsp_idle(void); +void dsp_set_idle_boot_base(unsigned long adr, size_t size); diff -Nru a/arch/arm/mach-omap/dsp/dsp_core.c b/arch/arm/mach-omap/dsp/dsp_core.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/dsp/dsp_core.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,787 @@ +/* + * linux/arch/arm/mach-omap/dsp/dsp_core.c + * + * OMAP DSP driver + * + * Copyright (C) 2002-2004 Nokia Corporation + * + * Written by Toshihiro Kobayashi + * + * 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 + * + * 2004/11/22: DSP Gateway version 3.1 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hardware_dsp.h" +#include "dsp.h" +#include "ipbuf.h" +#include "proclist.h" + + +MODULE_AUTHOR("Toshihiro Kobayashi "); +MODULE_DESCRIPTION("OMAP DSP driver module"); +MODULE_LICENSE("GPL"); + +enum mbseq_check_level { + MBSEQ_CHECK_NONE, /* no check */ + MBSEQ_CHECK_VERBOSE, /* discard the illegal command and + error report */ + MBSEQ_CHECK_SILENT, /* discard the illegal command */ +}; + +static enum mbseq_check_level mbseq_check_level = MBSEQ_CHECK_VERBOSE; +static unsigned short mbseq_send; +static unsigned short mbseq_expect; + +struct sync_seq { + unsigned short da_dsp; + unsigned short da_arm; + unsigned short ad_dsp; + unsigned short ad_arm; +}; + +static struct sync_seq *sync_seq; + +/* + * DSP module user process list + */ +static LIST_HEAD(cur_users_list); + +void dsp_cur_users_add(struct task_struct *tsk) +{ + preempt_disable(); + proc_list_add(&cur_users_list, tsk); + preempt_enable(); +} + +void dsp_cur_users_del(struct task_struct *tsk) +{ + preempt_disable(); + proc_list_del(&cur_users_list, tsk); + preempt_enable(); +} + +void dsp_cur_users_map_update(void) +{ + struct list_head *ptr; + struct proc_list *pl; + struct task_struct *tsk; + + preempt_disable(); + list_for_each(ptr, &cur_users_list) { + pl = list_entry(ptr, struct proc_list, list_head); + tsk = pl->tsk; + + /* + * excluding ZOMBIE, STOPPED processes + */ + if ((tsk->state == TASK_RUNNING) || + (tsk->state == TASK_INTERRUPTIBLE) || + (tsk->state == TASK_UNINTERRUPTIBLE)) { + dsp_map_update(tsk); + } + } + preempt_enable(); +} + +#ifdef CONFIG_PROC_FS +static int cur_users_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + char *out; + int len; + struct list_head *ptr; + struct proc_list *pl; + + out = page; + preempt_disable(); + list_for_each(ptr, &cur_users_list) { + pl = list_entry(ptr, struct proc_list, list_head); + out += sprintf(out, "%d\n", pl->tsk->pid); + } + preempt_enable(); + + len = out - (page + off); + if (len < count) { + *eof = 1; + if (len <= 0) + return 0; + } else + len = count; + *start = page + off; + + return len; +} + +static void dsp_create_cur_users_proc(void) +{ + struct proc_dir_entry *ent; + + ent = create_proc_read_entry("cur_users", 0, procdir_dsp, + cur_users_read_proc, NULL); + if (ent == NULL) { + printk(KERN_ERR + "omapdsp: failed to register proc device: cur_users\n"); + } +} + +static void dsp_remove_cur_users_proc(void) +{ + remove_proc_entry("cur_users", procdir_dsp); +} +#endif /* CONFIG_PROC_FS */ + +static void __init dsp_cur_users_init(void) +{ +#ifdef CONFIG_PROC_FS + dsp_create_cur_users_proc(); +#endif +} + +static void dsp_cur_users_exit(void) +{ + preempt_disable(); + proc_list_flush(&cur_users_list); + preempt_enable(); +#ifdef CONFIG_PROC_FS + dsp_remove_cur_users_proc(); +#endif +} + +/* + * mailbox commands + */ +extern void mbx1_wdsnd(struct mbcmd *mb); +extern void mbx1_wdreq(struct mbcmd *mb); +extern void mbx1_bksnd(struct mbcmd *mb); +extern void mbx1_bkreq(struct mbcmd *mb); +extern void mbx1_bkyld(struct mbcmd *mb); +extern void mbx1_bksndp(struct mbcmd *mb); +extern void mbx1_bkreqp(struct mbcmd *mb); +extern void mbx1_tctl(struct mbcmd *mb); +extern void mbx1_wdt(struct mbcmd *mb); +extern void mbx1_suspend(struct mbcmd *mb); +extern void mbx1_tcfg(struct mbcmd *mb); +extern void mbx1_tadd(struct mbcmd *mb); +extern void mbx1_tdel(struct mbcmd *mb); +extern void mbx1_dspcfg(struct mbcmd *mb); +extern void mbx1_regrw(struct mbcmd *mb); +extern void mbx1_getvar(struct mbcmd *mb); +extern void mbx1_err(struct mbcmd *mb); +extern void mbx1_dbg(struct mbcmd *mb); + +static const struct cmdinfo + cif_null = { "Unknown", CMD_L_TYPE_NULL, NULL }, + cif_wdsnd = { "WDSND", CMD_L_TYPE_TID, mbx1_wdsnd }, + cif_wdreq = { "WDREQ", CMD_L_TYPE_TID, mbx1_wdreq }, + cif_bksnd = { "BKSND", CMD_L_TYPE_TID, mbx1_bksnd }, + cif_bkreq = { "BKREQ", CMD_L_TYPE_TID, mbx1_bkreq }, + cif_bkyld = { "BKYLD", CMD_L_TYPE_NULL, mbx1_bkyld }, + cif_bksndp = { "BKSNDP", CMD_L_TYPE_TID, mbx1_bksndp }, + cif_bkreqp = { "BKREQP", CMD_L_TYPE_TID, mbx1_bkreqp }, + cif_tctl = { "TCTL", CMD_L_TYPE_TID, mbx1_tctl }, + cif_wdt = { "WDT", CMD_L_TYPE_NULL, mbx1_wdt }, + cif_runlevel = { "RUNLEVEL", CMD_L_TYPE_SUBCMD, NULL }, + cif_pm = { "PM", CMD_L_TYPE_SUBCMD, NULL }, + cif_suspend = { "SUSPEND", CMD_L_TYPE_NULL, mbx1_suspend }, + cif_tcfg = { "TCFG", CMD_L_TYPE_TID, mbx1_tcfg }, + cif_tadd = { "TADD", CMD_L_TYPE_TID, mbx1_tadd }, + cif_tdel = { "TDEL", CMD_L_TYPE_TID, mbx1_tdel }, + cif_tstop = { "TSTOP", CMD_L_TYPE_TID, NULL }, + cif_dspcfg = { "DSPCFG", CMD_L_TYPE_SUBCMD, mbx1_dspcfg }, + cif_regrw = { "REGRW", CMD_L_TYPE_SUBCMD, mbx1_regrw }, + cif_getvar = { "GETVAR", CMD_L_TYPE_SUBCMD, mbx1_getvar }, + cif_setvar = { "SETVAR", CMD_L_TYPE_SUBCMD, NULL }, + cif_err = { "ERR", CMD_L_TYPE_SUBCMD, mbx1_err }, + cif_dbg = { "DBG", CMD_L_TYPE_NULL, mbx1_dbg }; + +const struct cmdinfo *cmdinfo[128] = { +/*00*/ &cif_null, &cif_null, &cif_null, &cif_null, + &cif_null, &cif_null, &cif_null, &cif_null, + &cif_null, &cif_null, &cif_null, &cif_null, + &cif_null, &cif_null, &cif_null, &cif_null, +/*10*/ &cif_wdsnd, &cif_wdreq, &cif_null, &cif_null, + &cif_null, &cif_null, &cif_null, &cif_null, + &cif_null, &cif_null, &cif_null, &cif_null, + &cif_null, &cif_null, &cif_null, &cif_null, +/*20*/ &cif_bksnd, &cif_bkreq, &cif_null, &cif_bkyld, + &cif_bksndp, &cif_bkreqp, &cif_null, &cif_null, + &cif_null, &cif_null, &cif_null, &cif_null, + &cif_null, &cif_null, &cif_null, &cif_null, +/*30*/ &cif_tctl, &cif_null, &cif_null, &cif_null, + &cif_null, &cif_null, &cif_null, &cif_null, + &cif_null, &cif_null, &cif_null, &cif_null, + &cif_null, &cif_null, &cif_null, &cif_null, +/*40*/ &cif_null, &cif_null, &cif_null, &cif_null, + &cif_null, &cif_null, &cif_null, &cif_null, + &cif_null, &cif_null, &cif_null, &cif_null, + &cif_null, &cif_null, &cif_null, &cif_null, +/*50*/ &cif_wdt, &cif_runlevel, &cif_pm, &cif_suspend, + &cif_null, &cif_null, &cif_null, &cif_null, + &cif_null, &cif_null, &cif_null, &cif_null, + &cif_null, &cif_null, &cif_null, &cif_null, +/*60*/ &cif_tcfg, &cif_null, &cif_tadd, &cif_tdel, + &cif_null, &cif_tstop, &cif_null, &cif_null, + &cif_null, &cif_null, &cif_null, &cif_null, + &cif_null, &cif_null, &cif_null, &cif_null, +/*70*/ &cif_dspcfg, &cif_null, &cif_regrw, &cif_null, + &cif_getvar, &cif_setvar, &cif_null, &cif_null, + &cif_err, &cif_dbg, &cif_null, &cif_null, + &cif_null, &cif_null, &cif_null, &cif_null +}; + +int sync_with_dsp(unsigned short *syncwd, unsigned short tid, int try_cnt) +{ + int try; + + if (*(volatile unsigned short *)syncwd == tid) + return 0; + + for (try = 0; try < try_cnt; try++) { + udelay(1); + if (*(volatile unsigned short *)syncwd == tid) { + /* success! */ + printk(KERN_INFO + "omapdsp: sync_with_dsp(): try = %d\n", try); + return 0; + } + } + + /* fail! */ + return -1; +} + +static __inline__ int mbsync_irq_save(unsigned long *flags, int try_cnt) +{ + int cnt; + + local_irq_save(*flags); + if (omap_readw(MAILBOX_ARM2DSP1_Flag) == 0) + return 0; + /* + * mailbox is busy. wait for some usecs... + */ + local_irq_restore(*flags); + for (cnt = 0; cnt < try_cnt; cnt++) { + udelay(1); + local_irq_save(*flags); + if (omap_readw(MAILBOX_ARM2DSP1_Flag) == 0) /* success! */ + return 0; + local_irq_restore(*flags); + } + + /* fail! */ + return -1; +} + +#ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE +#define print_mb_busy_abort(mb) \ + printk(KERN_DEBUG \ + "mbx: mailbox is busy. %s is aborting.\n", cmd_name(*mb)) +#define print_mb_lock_abort(mb) \ + printk(KERN_DEBUG \ + "mbx: mailbox is locked. %s is aborting.\n", cmd_name(*mb)) +#else /* CONFIG_OMAP_DSP_MBCMD_VERBOSE */ +#define print_mb_busy_abort(mb) do {} while(0) +#define print_mb_lock_abort(mb) do {} while(0) +#endif /* !CONFIG_OMAP_DSP_MBCMD_VERBOSE */ + +static int __mbsend(struct mbcmd *mb) +{ + struct mbcmd_hw *mb_hw = (struct mbcmd_hw *)mb; + unsigned long flags; + + /* + * DSP mailbox interrupt latency must be less than 1ms. + * + * FIXME: use task queue! + */ + if (mbsync_irq_save(&flags, 1000) < 0) { + print_mb_busy_abort(mb); + return -1; + } + + mb->seq = mbseq_send & 1; + mbseq_send++; + if (sync_seq) + sync_seq->ad_arm = mbseq_send; + mblog_add(mb, MBLOG_DIR_AD); + mblog_printcmd(mb, MBLOG_DIR_AD); + + omap_writew(mb_hw->data, MAILBOX_ARM2DSP1); + omap_writew(mb_hw->cmd, MAILBOX_ARM2DSP1b); + + local_irq_restore(flags); + return 0; +} + +/* + * __dsp_mbsend(): mailbox dispatcher + * interrupt routine should call this function with + * send_type = MBSEND_TYPE_NOWAIT + */ +int __dsp_mbsend(struct mbcmd *mb, struct mb_exarg *arg, + enum mbsend_type send_type) +{ + static DECLARE_MUTEX(mbsend_sem); + int ret = 0; + + /* + * while MMU fault is set, + * only recovery command can be executed + */ + if (dsp_err_mmu_isset() && (send_type != MBSEND_TYPE_RECOVERY)) { + print_mb_busy_abort(mb); + return -1; + } + + /* + * fast lane for interrupt context: + * no need to get semaphore + */ + if (send_type == MBSEND_TYPE_NOWAIT) + return __mbsend(mb); + + /* + * process context + */ + if (down_interruptible(&mbsend_sem) < 0) + return -1; + + if (arg) { /* we have extra argument */ + struct mbcmd mb_pm; + int dspmem_access; + int i; + + if ((dspmem_access = is_dsp_internal_mem(ipbuf_sys_ad)) != 0) { + mbcmd_set(mb_pm, MBCMD(PM), OMAP_DSP_MBCMD_PM_ENABLE, + DSPREG_ICR_DMA_IDLE_DOMAIN); + if (__mbsend(&mb_pm) < 0) + goto out; + } + if (sync_with_dsp(&ipbuf_sys_ad->s, OMAP_DSP_TID_FREE, 10) < 0) { + printk(KERN_ERR "omapdsp: ipbuf_sys_ad is busy.\n"); + ret = -EBUSY; + goto out; + } + for (i = 0; i < arg->argc; i++) { + ipbuf_sys_ad->d[i] = arg->argv[i]; + } + ipbuf_sys_ad->s = arg->tid; + if (dspmem_access) + mbcmd_set(mb_pm, MBCMD(PM), OMAP_DSP_MBCMD_PM_DISABLE, + DSPREG_ICR_DMA_IDLE_DOMAIN); + if (__mbsend(&mb_pm) < 0) + goto out; + } + + ret = __mbsend(mb); + +out: + up(&mbsend_sem); + return ret; +} + +int __dsp_mbsend_and_wait(struct mbcmd *mb, struct mb_exarg *arg, + wait_queue_head_t *q) +{ + long current_state; + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(q, &wait); + current_state = current->state; + set_current_state(TASK_INTERRUPTIBLE); + if (dsp_mbsend_exarg(mb, arg) < 0) { + set_current_state(current_state); + remove_wait_queue(q, &wait); + return -1; + } + schedule(); + set_current_state(current_state); + remove_wait_queue(q, &wait); + + return 0; +} + +void dsp_mb_start(void) +{ + mbseq_send = 0; + mbseq_expect = 0; +} + +void dsp_mb_stop(void) +{ + sync_seq = NULL; +} + +/* + * dsp_mb_config() is called in interrupt context. + */ +void dsp_mb_config(void *sync_seq_adr) +{ + sync_seq = sync_seq_adr; + sync_seq->da_arm = mbseq_expect; +} + +/* + * mailbox interrupt handler + */ +static irqreturn_t mbx1_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + union { + struct mbcmd sw; + struct mbcmd_hw hw; + } mb; + +#if (INT_D2A_MB1 == INT_DSP_MAILBOX1) + mb.hw.data = omap_readw(MAILBOX_DSP2ARM1); + mb.hw.cmd = omap_readw(MAILBOX_DSP2ARM1b); +#elif (INT_D2A_MB1 == INT_DSP_MAILBOX2) + mb.hw.data = omap_readw(MAILBOX_DSP2ARM2); + mb.hw.cmd = omap_readw(MAILBOX_DSP2ARM2b); +#endif + + if (mb.sw.seq != (mbseq_expect & 1)) { + switch (mbseq_check_level) { + case MBSEQ_CHECK_NONE: + break; + case MBSEQ_CHECK_VERBOSE: + printk(KERN_INFO + "mbx: illegal seq bit!!! ignoring this command." + " (%04x:%04x)\n", mb.hw.cmd, mb.hw.data); + return IRQ_HANDLED; + case MBSEQ_CHECK_SILENT: + return IRQ_HANDLED; + } + } + + mblog_add(&mb.sw, MBLOG_DIR_DA); + mblog_printcmd(&mb.sw, MBLOG_DIR_DA); + + /* + * call handler for each command + */ + if (cmdinfo[mb.sw.cmd_h]->handler) + cmdinfo[mb.sw.cmd_h]->handler(&mb.sw); + else if (cmdinfo[mb.sw.cmd_h] != &cif_null) + printk(KERN_ERR "mbx: %s is not allowed from DSP.\n", + cmd_name(mb.sw)); + else + printk(KERN_ERR + "mbx: Unrecognized command: cmd=0x%04x, data=0x%04x\n", + mb.hw.cmd & 0x7fff, mb.hw.data); + + mbseq_expect++; + if (sync_seq) + sync_seq->da_arm = mbseq_expect; + return IRQ_HANDLED; +} + +static irqreturn_t mbx2_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned short cmd, data; + +#if (INT_D2A_MB1 == INT_DSP_MAILBOX1) + data = omap_readw(MAILBOX_DSP2ARM2); + cmd = omap_readw(MAILBOX_DSP2ARM2b); +#elif (INT_D2A_MB1 == INT_DSP_MAILBOX2) + data = omap_readw(MAILBOX_DSP2ARM1); + cmd = omap_readw(MAILBOX_DSP2ARM1b); +#endif + printk(KERN_DEBUG + "mailbox2 interrupt! cmd=%04x, data=%04x\n", cmd, data); + + return IRQ_HANDLED; +} + +#if 0 +static void mpuio_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + printk(KERN_INFO "MPUIO interrupt!\n"); +} +#endif + +#ifdef CONFIG_PROC_FS +struct proc_dir_entry *procdir_dsp = NULL; + +static void dsp_create_procdir_dsp(void) +{ + procdir_dsp = proc_mkdir("dsp", 0); + if (procdir_dsp == NULL) { + printk(KERN_ERR + "omapdsp: failed to register proc directory: dsp\n"); + } +} + +static void dsp_remove_procdir_dsp(void) +{ + procdir_dsp = NULL; + remove_proc_entry("dsp", 0); +} +#endif /* CONFIG_PROC_FS */ + +extern irqreturn_t dsp_mmu_interrupt(int irq, void *dev_id, + struct pt_regs *regs); + +extern int dsp_ctl_core_init(void); +extern void dsp_ctl_core_exit(void); +extern void dsp_ctl_init(void); +extern void dsp_ctl_exit(void); +extern int dsp_mem_init(void); +extern void dsp_mem_exit(void); +extern void mblog_init(void); +extern void mblog_exit(void); +extern int dsp_taskmod_init(void); +extern void dsp_taskmod_exit(void); + +/* + * device functions + */ +static void dsp_dev_release(struct device *dev) +{ +} + +/* + * driver functions + */ +#if (INT_D2A_MB1 == INT_DSP_MAILBOX1) +# define INT_D2A_MB2 INT_DSP_MAILBOX2 +#elif(INT_D2A_MB1 == INT_DSP_MAILBOX2) /* swap MB1 and MB2 */ +# define INT_D2A_MB2 INT_DSP_MAILBOX1 +#endif + +static int __init dsp_drv_probe(struct device *dev) +{ + int ret; + + printk(KERN_INFO "OMAP DSP driver initialization\n"); + + //__dsp_enable(); // XXX + +#ifdef CONFIG_PROC_FS + dsp_create_procdir_dsp(); +#endif /* CONFIG_PROC_FS */ + + if ((ret = dsp_ctl_core_init()) < 0) + goto fail1; + if ((ret = dsp_mem_init()) < 0) + goto fail2; + dsp_cur_users_init(); + dsp_ctl_init(); + mblog_init(); + if ((ret = dsp_taskmod_init()) < 0) + goto fail3; + + /* + * mailbox interrupt handlers registration + */ + ret = request_irq(INT_D2A_MB1, mbx1_interrupt, SA_INTERRUPT, "dsp", + dev); + if (ret) { + printk(KERN_ERR + "failed to register mailbox1 interrupt: %d\n", ret); + goto fail4; + } + + ret = request_irq(INT_D2A_MB2, mbx2_interrupt, SA_INTERRUPT, "dsp", + dev); + if (ret) { + printk(KERN_ERR + "failed to register mailbox2 interrupt: %d\n", ret); + goto fail5; + } + + ret = request_irq(INT_DSP_MMU, dsp_mmu_interrupt, SA_INTERRUPT, "dsp", + dev); + if (ret) { + printk(KERN_ERR + "failed to register DSP MMU interrupt: %d\n", ret); + goto fail6; + } + +#if 0 + ret = request_irq(INT_MPUIO, mpuio_interrupt, SA_INTERRUPT, "dsp", dev); + if (ret) { + printk(KERN_ERR + "failed to register MPUIO interrupt: %d\n", ret); + goto fail7; + } +#endif + + return 0; + +fail6: + free_irq(INT_D2A_MB2, dev); +fail5: + free_irq(INT_D2A_MB1, dev); +fail4: + dsp_taskmod_exit(); +fail3: + mblog_exit(); + dsp_ctl_exit(); + dsp_cur_users_exit(); + dsp_mem_exit(); +fail2: + dsp_ctl_core_exit(); +fail1: +#ifdef CONFIG_PROC_FS + dsp_remove_procdir_dsp(); +#endif /* CONFIG_PROC_FS */ + + //__dsp_disable(); // XXX + return ret; +} + +static int dsp_drv_remove(struct device *dev) +{ + __dsp_reset(); + +#if 0 + free_irq(INT_MPUIO, dev); +#endif + free_irq(INT_DSP_MMU, dev); + free_irq(INT_D2A_MB2, dev); + free_irq(INT_D2A_MB1, dev); + + dspuncfg(); + dsp_taskmod_exit(); + mblog_exit(); + dsp_ctl_exit(); + dsp_cur_users_exit(); + dsp_mem_exit(); + + dsp_ctl_core_exit(); +#ifdef CONFIG_PROC_FS + dsp_remove_procdir_dsp(); +#endif /* CONFIG_PROC_FS */ + + //__dsp_disable(); // XXX + + return 0; +} + +#ifdef CONFIG_PM +static int dsp_drv_suspend(struct device *dev, u32 state, u32 level) +{ + switch(level) { + case SUSPEND_NOTIFY: + case SUSPEND_DISABLE: + case SUSPEND_SAVE_STATE: + break; + case SUSPEND_POWER_DOWN: + dsp_suspend(); + break; + } + + return 0; +} + +static int dsp_drv_resume(struct device *dev, u32 level) +{ + switch(level) { + case RESUME_POWER_ON: + dsp_resume(); + break; + case RESUME_RESTORE_STATE: + case RESUME_ENABLE: + break; + } + + return 0; +} +#endif /* CONFIG_PM */ + +static struct resource dsp_resources[] = { + { + .start = INT_DSP_MAILBOX1, + .flags = IORESOURCE_IRQ, + }, + { + .start = INT_DSP_MAILBOX2, + .flags = IORESOURCE_IRQ, + }, + { + .start = INT_DSP_MMU, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device dsp_device = { + .name = "dsp", + .id = 0, + .dev = { + .release = dsp_dev_release, + }, + .num_resources = ARRAY_SIZE(&dsp_resources), + .resource = dsp_resources, +}; + +static struct device_driver dsp_driver = { + .name = "dsp", + .bus = &platform_bus_type, + .probe = dsp_drv_probe, + .remove = dsp_drv_remove, +#ifdef CONFIG_PM + .suspend = dsp_drv_suspend, + .resume = dsp_drv_resume, +#endif +}; + +static int __init omap_dsp_mod_init(void) +{ + int ret; + + ret = platform_device_register(&dsp_device); + if (ret) { + printk(KERN_ERR "failed to register the DSP device: %d\n", ret); + goto fail1; + } + + ret = driver_register(&dsp_driver); + if (ret) { + printk(KERN_ERR "failed to register the DSP driver: %d\n", ret); + goto fail2; + } + + return 0; + +fail2: + platform_device_unregister(&dsp_device); +fail1: + return -ENODEV; +} + +static void __exit omap_dsp_mod_exit(void) +{ + driver_unregister(&dsp_driver); + platform_device_unregister(&dsp_device); +} + +module_init(omap_dsp_mod_init); +module_exit(omap_dsp_mod_exit); diff -Nru a/arch/arm/mach-omap/dsp/dsp_ctl.c b/arch/arm/mach-omap/dsp/dsp_ctl.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/dsp/dsp_ctl.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,893 @@ +/* + * linux/arch/arm/mach-omap/dsp/dsp_ctl.c + * + * OMAP DSP control device driver + * + * Copyright (C) 2002-2004 Nokia Corporation + * + * Written by Toshihiro Kobayashi + * + * 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 + * + * 2004/12/03: DSP Gateway version 3.1 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hardware_dsp.h" +#include "dsp.h" +#include "ipbuf.h" + +void dsp_create_runtime_procs(void); +void dsp_remove_runtime_procs(void); + +static enum { + CFG_ERR, + CFG_READY, + CFG_SUSPEND +} cfgstat; +static int mbx_revision; +static DECLARE_WAIT_QUEUE_HEAD(ioctl_wait_q); +static unsigned short ioctl_wait_cmd; +static DECLARE_MUTEX(ioctl_sem); + +static unsigned char n_stask; + +/* + * control functions + */ +static void dsp_run(void) +{ + disable_irq(INT_DSP_MMU); + preempt_disable(); + if (dsp_runstat == RUNSTAT_RESET) { + clk_use(api_ck_handle); + __dsp_run(); + dsp_runstat = RUNSTAT_RUN; + } + preempt_enable(); + enable_irq(INT_DSP_MMU); +} + +static void dsp_reset(void) +{ + disable_irq(INT_DSP_MMU); + preempt_disable(); + if (dsp_runstat > RUNSTAT_RESET) { + __dsp_reset(); + if (dsp_runstat == RUNSTAT_RUN) + clk_unuse(api_ck_handle); + dsp_runstat = RUNSTAT_RESET; + } + preempt_enable(); + enable_irq(INT_DSP_MMU); +} + +static short varread_val[5]; /* maximum */ + +static int dsp_regread(unsigned short cmd_l, unsigned short adr, + unsigned short *val) +{ + struct mbcmd mb; + int ret = 0; + + if (down_interruptible(&ioctl_sem)) + return -ERESTARTSYS; + + ioctl_wait_cmd = MBCMD(REGRW); + mbcmd_set(mb, MBCMD(REGRW), cmd_l, adr); + dsp_mbsend_and_wait(&mb, &ioctl_wait_q); + + if (ioctl_wait_cmd != 0) { + printk(KERN_ERR "omapdsp: register read error!\n"); + ret = -EINVAL; + goto up_out; + } + + *val = varread_val[0]; + +up_out: + up(&ioctl_sem); + return ret; +} + +static int dsp_regwrite(unsigned short cmd_l, unsigned short adr, + unsigned short val) +{ + struct mbcmd mb; + struct mb_exarg arg = { + .tid = OMAP_DSP_TID_ANON, + .argc = 1, + .argv = &val, + }; + + mbcmd_set(mb, MBCMD(REGRW), cmd_l, adr); + dsp_mbsend_exarg(&mb, &arg); + return 0; +} + +static int dsp_getvar(unsigned char varid, unsigned short *val, int sz) +{ + struct mbcmd mb; + int ret = 0; + + if (down_interruptible(&ioctl_sem)) + return -ERESTARTSYS; + + ioctl_wait_cmd = MBCMD(GETVAR); + mbcmd_set(mb, MBCMD(GETVAR), varid, 0); + dsp_mbsend_and_wait(&mb, &ioctl_wait_q); + + if (ioctl_wait_cmd != 0) { + printk(KERN_ERR "omapdsp: variable read error!\n"); + ret = -EINVAL; + goto up_out; + } + + memcpy(val, varread_val, sz * sizeof(short)); + +up_out: + up(&ioctl_sem); + return ret; +} + +static int dsp_setvar(unsigned char varid, unsigned short val) +{ + struct mbcmd mb; + + mbcmd_set(mb, MBCMD(SETVAR), varid, val); + dsp_mbsend(&mb); + return 0; +} + +static int dspcfg(void) +{ + struct mbcmd mb; + int ret = 0; + + if (down_interruptible(&ioctl_sem)) + return -ERESTARTSYS; + + if (cfgstat != CFG_ERR) { + printk(KERN_ERR + "omapdsp: DSP has been already configured. " + "do unconfig!\n"); + ret = -EBUSY; + goto up_out; + } + + dsp_mb_start(); + dsp_twch_start(); + dsp_mem_start(); + dsp_err_start(); + + mbx_revision = -1; + ioctl_wait_cmd = MBCMD(DSPCFG); + mbcmd_set(mb, MBCMD(DSPCFG), OMAP_DSP_MBCMD_DSPCFG_REQ, 0); + dsp_mbsend_and_wait(&mb, &ioctl_wait_q); + + if (ioctl_wait_cmd != 0) { + printk(KERN_ERR "omapdsp: configuration error!\n"); + ret = -EINVAL; + cfgstat = CFG_ERR; + goto up_out; + } + + if ((ret = dsp_task_config_all(n_stask)) < 0) { + up(&ioctl_sem); + dspuncfg(); + return -EINVAL; + } + + cfgstat = CFG_READY; + + /* send parameter */ + if ((ret = dsp_setvar(OMAP_DSP_MBCMD_VARID_ICRMASK, dsp_icrmask)) < 0) + goto up_out; +#ifdef CONFIG_PROC_FS + dsp_create_runtime_procs(); +#endif + +up_out: + up(&ioctl_sem); + return ret; +} + +int dspuncfg(void) +{ + if (dsp_taskmod_busy()) { + printk(KERN_WARNING "omapdsp: tasks are busy.\n"); + return -EBUSY; + } + + if (down_interruptible(&ioctl_sem)) + return -ERESTARTSYS; + + /* FIXME: lock task module */ + +#ifdef CONFIG_PROC_FS + dsp_remove_runtime_procs(); +#endif + + dsp_mb_stop(); + dsp_twch_stop(); + dsp_err_stop(); + dsp_task_unconfig_all(); + ipbuf_stop(); + cfgstat = CFG_ERR; + + up(&ioctl_sem); + return 0; +} + +int dsp_is_ready(void) +{ + return (cfgstat == CFG_READY) ? 1 : 0; +} + +void dsp_runlevel(unsigned char level) +{ + struct mbcmd mb; + + mbcmd_set(mb, MBCMD(RUNLEVEL), level, 0); + if (level == OMAP_DSP_MBCMD_RUNLEVEL_RECOVERY) + dsp_mbsend_recovery(&mb); + else + dsp_mbsend(&mb); +} + +int dsp_suspend(void) +{ + struct mbcmd mb; + int ret = 0; + + if (down_interruptible(&ioctl_sem)) + return -ERESTARTSYS; + + if (!dsp_is_ready()) { + printk(KERN_WARNING + "omapdsp: DSP is not ready. suspend failed.\n"); + ret = -EINVAL; + goto up_out; + } + + ioctl_wait_cmd = MBCMD(SUSPEND); + mbcmd_set(mb, MBCMD(SUSPEND), 0, 0); + dsp_mbsend_and_wait(&mb, &ioctl_wait_q); + + if (ioctl_wait_cmd != 0) { + printk(KERN_ERR "omapdsp: DSP suspend error!\n"); + ret = -EINVAL; + goto up_out; + } + + udelay(100); + dsp_reset(); + cfgstat = CFG_SUSPEND; +up_out: + up(&ioctl_sem); + return ret; +} + +int dsp_resume(void) +{ + if (cfgstat != CFG_SUSPEND) + return 0; + + cfgstat = CFG_READY; + dsp_run(); + return 0; +} + +/* + * DSP control device file operations + */ +static int dsp_ctl_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + + switch (cmd) { + /* + * command level 1: commands which don't need lock + */ + case OMAP_DSP_IOCTL_RUN: + dsp_run(); + break; + + case OMAP_DSP_IOCTL_RESET: + dsp_reset(); + break; + + case OMAP_DSP_IOCTL_SETRSTVECT: + ret = dsp_set_rstvect((unsigned long)arg); + break; + + case OMAP_DSP_IOCTL_IDLE: + dsp_idle(); + break; + + case OMAP_DSP_IOCTL_MPUI_WORDSWAP_ON: + mpui_wordswap_on(); + break; + + case OMAP_DSP_IOCTL_MPUI_WORDSWAP_OFF: + mpui_wordswap_off(); + break; + + case OMAP_DSP_IOCTL_MPUI_BYTESWAP_ON: + mpui_byteswap_on(); + break; + + case OMAP_DSP_IOCTL_MPUI_BYTESWAP_OFF: + mpui_byteswap_off(); + break; + + case OMAP_DSP_IOCTL_MBSEND: + { + struct omap_dsp_mailbox_cmd u_cmd; + struct mbcmd_hw mb; + if (copy_from_user(&u_cmd, (void *)arg, sizeof(u_cmd))) + return -EFAULT; + mb.cmd = u_cmd.cmd; + mb.data = u_cmd.data; + ret = dsp_mbsend((struct mbcmd *)&mb); + break; + } + + case OMAP_DSP_IOCTL_SETVAR: + { + struct omap_dsp_varinfo var; + if (copy_from_user(&var, (void *)arg, sizeof(var))) + return -EFAULT; + ret = dsp_setvar(var.varid, var.val[0]); + break; + } + + case OMAP_DSP_IOCTL_RUNLEVEL: + dsp_runlevel(arg); + break; + + /* + * command level 2: commands which need lock + */ + case OMAP_DSP_IOCTL_DSPCFG: + ret = dspcfg(); + break; + + case OMAP_DSP_IOCTL_DSPUNCFG: + ret = dspuncfg(); + break; + + case OMAP_DSP_IOCTL_TASKCNT: + ret = dsp_task_count(); + break; + + case OMAP_DSP_IOCTL_SUSPEND: + ret = dsp_suspend(); + break; + + case OMAP_DSP_IOCTL_RESUME: + ret = dsp_resume(); + break; + + case OMAP_DSP_IOCTL_REGMEMR: + { + struct omap_dsp_reginfo *u_reg = (void *)arg; + unsigned short adr, val; + + if (copy_from_user(&adr, &u_reg->adr, sizeof(short))) + return -EFAULT; + if ((ret = dsp_regread(OMAP_DSP_MBCMD_REGRW_MEMR, + adr, &val)) < 0) + return ret; + if (copy_to_user(&u_reg->val, &val, sizeof(short))) + return -EFAULT; + break; + } + + case OMAP_DSP_IOCTL_REGMEMW: + { + struct omap_dsp_reginfo reg; + + if (copy_from_user(®, (void *)arg, sizeof(reg))) + return -EFAULT; + ret = dsp_regwrite(OMAP_DSP_MBCMD_REGRW_MEMW, + reg.adr, reg.val); + break; + } + + case OMAP_DSP_IOCTL_REGIOR: + { + struct omap_dsp_reginfo *u_reg = (void *)arg; + unsigned short adr, val; + + if (copy_from_user(&adr, &u_reg->adr, sizeof(short))) + return -EFAULT; + if ((ret = dsp_regread(OMAP_DSP_MBCMD_REGRW_IOR, + adr, &val)) < 0) + return ret; + if (copy_to_user(&u_reg->val, &val, sizeof(short))) + return -EFAULT; + break; + } + + case OMAP_DSP_IOCTL_REGIOW: + { + struct omap_dsp_reginfo reg; + + if (copy_from_user(®, (void *)arg, sizeof(reg))) + return -EFAULT; + ret = dsp_regwrite(OMAP_DSP_MBCMD_REGRW_IOW, + reg.adr, reg.val); + break; + } + + case OMAP_DSP_IOCTL_GETVAR: + { + struct omap_dsp_varinfo *u_var = (void *)arg; + unsigned char varid; + unsigned short val[5]; /* maximum */ + int argc; + + if (copy_from_user(&varid, &u_var->varid, sizeof(char))) + return -EFAULT; + switch (varid) { + case OMAP_DSP_MBCMD_VARID_ICRMASK: + argc = 1; + break; + case OMAP_DSP_MBCMD_VARID_LOADINFO: + argc = 5; + break; + default: + return -EINVAL; + } + if ((ret = dsp_getvar(varid, val, argc)) < 0) + return ret; + if (copy_to_user(&u_var->val, val, sizeof(short) * argc)) + return -EFAULT; + break; + } + + default: + return -ENOIOCTLCMD; + } + + return ret; +} + +static int dsp_ctl_open(struct inode *inode, struct file *file) +{ + dsp_map_update(current); + dsp_cur_users_add(current); + return 0; +} + +static int dsp_ctl_release(struct inode *inode, struct file *file) +{ + dsp_cur_users_del(current); + return 0; +} + +/* + * functions called from mailbox1 interrupt routine + */ +void mbx1_suspend(struct mbcmd *mb) +{ + if (!waitqueue_active(&ioctl_wait_q) || + (ioctl_wait_cmd != MBCMD(SUSPEND))) { + printk(KERN_WARNING + "mbx: SUSPEND command received, " + "but nobody is waiting for it...\n"); + return; + } + + ioctl_wait_cmd = 0; + wake_up_interruptible(&ioctl_wait_q); +} + +void mbx1_dspcfg(struct mbcmd *mb) +{ + unsigned char last = mb->cmd_l & 0x80; + unsigned char cfgcmd = mb->cmd_l & 0x7f; + static unsigned long tmp_ipbuf_sys_da; + + /* mailbox protocol check */ + if (cfgcmd == OMAP_DSP_MBCMD_DSPCFG_PROTREV) { + if (!waitqueue_active(&ioctl_wait_q) || + (ioctl_wait_cmd != MBCMD(DSPCFG))) { + printk(KERN_WARNING + "mbx: DSPCFG command received, " + "but nobody is waiting for it...\n"); + return; + } + + mbx_revision = mb->data; + if (mbx_revision == OMAP_DSP_MBPROT_REVISION) + return; +#ifdef OLD_BINARY_SUPPORT + else if (mbx_revision == MBREV_3_0) { + printk(KERN_WARNING + "mbx: ***** old DSP binary *****\n" + " Please update your DSP application.\n"); + return; + } +#endif + else { + printk(KERN_ERR + "mbx: protocol revision check error!\n" + " expected=0x%04x, received=0x%04x\n", + OMAP_DSP_MBPROT_REVISION, mb->data); + mbx_revision = -1; + goto abort; + } + } + + /* + * following commands are accepted only after + * revision check has been passed. + */ + if (!mbx_revision < 0) { + printk(KERN_INFO + "mbx: DSPCFG command received, " + "but revision check has not been passed.\n"); + return; + } + + if (!waitqueue_active(&ioctl_wait_q) || + (ioctl_wait_cmd != MBCMD(DSPCFG))) { + printk(KERN_WARNING + "mbx: DSPCFG command received, " + "but nobody is waiting for it...\n"); + return; + } + + switch (cfgcmd) { + case OMAP_DSP_MBCMD_DSPCFG_SYSADRH: + tmp_ipbuf_sys_da = (unsigned long)mb->data << 16; + break; + + case OMAP_DSP_MBCMD_DSPCFG_SYSADRL: + tmp_ipbuf_sys_da |= mb->data; + break; + + case OMAP_DSP_MBCMD_DSPCFG_ABORT: + goto abort; + + default: + printk(KERN_ERR + "mbx: Unknown CFG command: cmd_l=0x%02x, data=0x%04x\n", + mb->cmd_l, mb->data); + return; + } + + if (last) { + unsigned long badr; + unsigned short bln; + unsigned short bsz; + volatile unsigned short *buf; + void *sync_seq; + + /* system IPBUF initialization */ + if (tmp_ipbuf_sys_da & 0x1) { + printk(KERN_ERR + "mbx: system ipbuf address (0x%lx) " + "is odd number!\n", tmp_ipbuf_sys_da); + goto abort; + } + ipbuf_sys_da = dspword_to_virt(tmp_ipbuf_sys_da); + + if (sync_with_dsp(&ipbuf_sys_da->s, OMAP_DSP_TID_ANON, 10) < 0) { + printk(KERN_ERR "mbx: DSPCFG - IPBUF sync failed!\n"); + return; + } + /* + * read configuration data on system IPBUF + * we must read with 16bit-access + */ +#ifdef OLD_BINARY_SUPPORT + if (mbx_revision == OMAP_DSP_MBPROT_REVISION) { +#endif + buf = ipbuf_sys_da->d; + n_stask = buf[0]; + bln = buf[1]; + bsz = buf[2]; + badr = MKLONG(buf[3], buf[4]); + /*ipbuf_sys_da = dspword_to_virt(MKLONG(buf[5], buf[6])); */ + ipbuf_sys_ad = dspword_to_virt(MKLONG(buf[7], buf[8])); + sync_seq = dspword_to_virt(MKLONG(buf[9], buf[10])); +#ifdef OLD_BINARY_SUPPORT + } else if (mbx_revision == MBREV_3_0) { + buf = ipbuf_sys_da->d; + n_stask = buf[0]; + bln = buf[1]; + bsz = buf[2]; + badr = MKLONG(buf[3], buf[4]); + /* bkeep = buf[5]; */ + /*ipbuf_sys_da = dspword_to_virt(MKLONG(buf[6], buf[67)); */ + ipbuf_sys_ad = dspword_to_virt(MKLONG(buf[8], buf[9])); + sync_seq = dspword_to_virt(MKLONG(buf[10], buf[11])); + } else /* should not occur */ + goto abort; +#endif + + /* ipbuf_config() should be done in interrupt routine. */ + if (ipbuf_config(bln, bsz, badr) < 0) + goto abort; + + ipbuf_sys_da->s = OMAP_DSP_TID_FREE; + + /* mb_config() should be done in interrupt routine. */ + dsp_mb_config(sync_seq); + + ioctl_wait_cmd = 0; + wake_up_interruptible(&ioctl_wait_q); + } + return; + +abort: + wake_up_interruptible(&ioctl_wait_q); + return; +} + +void mbx1_regrw(struct mbcmd *mb) +{ + if (!waitqueue_active(&ioctl_wait_q) || + (ioctl_wait_cmd != MBCMD(REGRW))) { + printk(KERN_WARNING + "mbx: REGRW command received, " + "but nobody is waiting for it...\n"); + return; + } + + switch (mb->cmd_l) { + case OMAP_DSP_MBCMD_REGRW_DATA: + ioctl_wait_cmd = 0; + varread_val[0] = mb->data; + wake_up_interruptible(&ioctl_wait_q); + return; + + default: + printk(KERN_ERR + "mbx: Illegal REGRW command: " + "cmd_l=0x%02x, data=0x%04x\n", mb->cmd_l, mb->data); + return; + } +} + +void mbx1_getvar(struct mbcmd *mb) +{ + unsigned char varid = mb->cmd_l; + int i; + volatile unsigned short *buf; + + if (!waitqueue_active(&ioctl_wait_q) || + (ioctl_wait_cmd != MBCMD(GETVAR))) { + printk(KERN_WARNING + "mbx: GETVAR command received, " + "but nobody is waiting for it...\n"); + return; + } + + ioctl_wait_cmd = 0; + switch (varid) { + case OMAP_DSP_MBCMD_VARID_ICRMASK: + varread_val[0] = mb->data; + break; + case OMAP_DSP_MBCMD_VARID_LOADINFO: + { + if (sync_with_dsp(&ipbuf_sys_da->s, OMAP_DSP_TID_ANON, 10) < 0) { + printk(KERN_ERR + "mbx: GETVAR - IPBUF sync failed!\n"); + return; + } + /* need word access. do not use memcpy. */ + buf = ipbuf_sys_da->d; + for (i = 0; i < 5; i++) { + varread_val[i] = buf[i]; + } + ipbuf_sys_da->s = OMAP_DSP_TID_FREE; + break; + } + } + wake_up_interruptible(&ioctl_wait_q); + + return; +} + +#ifdef CONFIG_PROC_FS +/* + * proc entry + */ +static int version_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int len; + + len = sprintf(page, "%s\n", DSP_DRIVER_VERSION); + return len; +} + +static int icrmask_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int len; + +#if 0 + if (dsp_is_ready()) { + int ret; + unsigned short val; + + if ((ret = dsp_getvar(OMAP_DSP_MBCMD_VARID_ICRMASK, &val, 1)) < 0) + return ret; + if (val != dsp_icrmask) + printk(KERN_WARNING + "omapdsp: icrmask value is inconsistent!\n"); + } +#endif + len = sprintf(page, "%04x (hex)\n", dsp_icrmask); + + return len; +} + +static int icrmask_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int len; + char tmp[16]; + int ret; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + len = (count > 15) ? 15 : count; + if (copy_from_user(tmp, buffer, len)) + return -EFAULT; + tmp[len] = '\0'; + dsp_icrmask = simple_strtol(tmp, NULL, 16); + + if (dsp_is_ready()) { + ret = dsp_setvar(OMAP_DSP_MBCMD_VARID_ICRMASK, dsp_icrmask); + if (ret < 0) + return ret; + } + + return len; +} + +static int loadinfo_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int len; + int ret; + static unsigned short val[5]; + static unsigned long last_jiffies = 0; + + /* + * read_proc function seems to be called some times by one read: + * we won't issue new request within same jiffies. + */ + if (jiffies != last_jiffies) { + if ((ret = dsp_getvar(OMAP_DSP_MBCMD_VARID_LOADINFO, val, 5)) < 0) + return ret; + last_jiffies = jiffies; + } + /* load info value range is 0(free) - 10000(busy) */ + len = sprintf(page, + "DSP load info:\n" + " 10ms average = %3d.%02d%%\n" + " 1sec average = %3d.%02d%% busiest 10ms = %3d.%02d%%\n" + " 1min average = %3d.%02d%% busiest 1s = %3d.%02d%%\n", + val[0]/100, val[0]%100, + val[1]/100, val[1]%100, val[2]/100, val[2]%100, + val[3]/100, val[3]%100, val[4]/100, val[4]%100); + len -= off; + if (len < count) { + *eof = 1; + if (len <= 0) + return 0; + } else + len = count; + *start = page + off; + return len; +} + +extern void dsp_create_ipbuf_proc(void); +extern void dsp_remove_ipbuf_proc(void); + +void dsp_create_runtime_procs(void) +{ + struct proc_dir_entry *ent; + + ent = create_proc_read_entry("loadinfo", 0, procdir_dsp, + loadinfo_read_proc, NULL); + if (ent == NULL) { + printk(KERN_ERR + "omapdsp: failed to register proc device: loadinfo\n"); + } + + /* other modules */ + dsp_create_ipbuf_proc(); +} + +void dsp_remove_runtime_procs(void) +{ + remove_proc_entry("loadinfo", procdir_dsp); + /* other modules */ + dsp_remove_ipbuf_proc(); +} + +static void __init dsp_ctl_create_proc(void) +{ + struct proc_dir_entry *ent; + + /* version */ + ent = create_proc_read_entry("version", 0, procdir_dsp, + version_read_proc, NULL); + if (ent == NULL) { + printk(KERN_ERR + "omapdsp: failed to register proc device: version\n"); + } + + /* icrmask */ + ent = create_proc_entry("icrmask", S_IFREG | S_IWUSR | S_IRUGO, + procdir_dsp); + if (ent == NULL) { + printk(KERN_ERR + "omapdsp: failed to register proc device: icrmask\n"); + } + ent->read_proc = icrmask_read_proc; + ent->write_proc = icrmask_write_proc; +} + +static void dsp_ctl_remove_proc(void) +{ + remove_proc_entry("version", procdir_dsp); + remove_proc_entry("icrmask", procdir_dsp); +} + +#endif /* CONFIG_PROC_FS */ + +struct file_operations dsp_ctl_fops = { + .owner = THIS_MODULE, + .ioctl = dsp_ctl_ioctl, + .open = dsp_ctl_open, + .release = dsp_ctl_release, +}; + +void __init dsp_ctl_init(void) +{ +#ifdef CONFIG_PROC_FS + dsp_ctl_create_proc(); +#endif +} + +void dsp_ctl_exit(void) +{ +#ifdef CONFIG_PROC_FS + dsp_ctl_remove_proc(); +#endif +} diff -Nru a/arch/arm/mach-omap/dsp/dsp_ctl_core.c b/arch/arm/mach-omap/dsp/dsp_ctl_core.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/dsp/dsp_ctl_core.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,106 @@ +/* + * linux/arch/arm/mach-omap/dsp/dsp_ctl_core.c + * + * OMAP DSP control devices core driver + * + * Copyright (C) 2004 Nokia Corporation + * + * Written by Toshihiro Kobayashi + * + * 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 + * + * 2004/10/04: DSP Gateway version 3.1 + */ + +#include +#include +#include +#include +#include +#include +#include "hardware_dsp.h" + +#define CTL_MINOR 0 +#define MEM_MINOR 1 +#define TWCH_MINOR 2 +#define ERR_MINOR 3 + +extern struct file_operations dsp_ctl_fops, + dsp_mem_fops, + dsp_twch_fops, + dsp_err_fops; + +static int dsp_ctl_core_open(struct inode *inode, struct file *file) +{ + switch (iminor(inode)) { + case CTL_MINOR: + file->f_op = &dsp_ctl_fops; + break; + case MEM_MINOR: + file->f_op = &dsp_mem_fops; + break; + case TWCH_MINOR: + file->f_op = &dsp_twch_fops; + break; + case ERR_MINOR: + file->f_op = &dsp_err_fops; + break; + default: + return -ENXIO; + } + if (file->f_op && file->f_op->open) + return file->f_op->open(inode, file); + return 0; +} + +static struct file_operations dsp_ctl_core_fops = { + .owner = THIS_MODULE, + .open = dsp_ctl_core_open, +}; + +int __init dsp_ctl_core_init(void) +{ + int retval; + + retval = register_chrdev(OMAP_DSP_CTL_MAJOR, "dspctl", + &dsp_ctl_core_fops); + if (retval < 0) { + printk(KERN_ERR + "omapdsp: failed to register dspctl device: %d\n", + retval); + return retval; + } + devfs_mk_dir("dspctl"); + devfs_mk_cdev(MKDEV(OMAP_DSP_CTL_MAJOR, CTL_MINOR), + S_IFCHR | S_IRUSR | S_IWUSR, "dspctl/ctl"); + devfs_mk_cdev(MKDEV(OMAP_DSP_CTL_MAJOR, MEM_MINOR), + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, "dspctl/mem"); + devfs_mk_cdev(MKDEV(OMAP_DSP_CTL_MAJOR, TWCH_MINOR), + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, "dspctl/twch"); + devfs_mk_cdev(MKDEV(OMAP_DSP_CTL_MAJOR, ERR_MINOR), + S_IFCHR | S_IRUSR | S_IRGRP, "dspctl/err"); + + return 0; +} + +void dsp_ctl_core_exit(void) +{ + devfs_remove("dspctl/err"); + devfs_remove("dspctl/twch"); + devfs_remove("dspctl/mem"); + devfs_remove("dspctl/ctl"); + devfs_remove("dspctl"); + unregister_chrdev(OMAP_DSP_CTL_MAJOR, "dspctl"); +} diff -Nru a/arch/arm/mach-omap/dsp/dsp_mem.c b/arch/arm/mach-omap/dsp/dsp_mem.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/dsp/dsp_mem.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,1438 @@ +/* + * linux/arch/arm/mach-omap/dsp/dsp_mem.c + * + * OMAP DSP memory driver + * + * Copyright (C) 2002-2004 Nokia Corporation + * + * Written by Toshihiro Kobayashi + * + * 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 + * + * Toshihiro Kobayashi + * 2004/11/24: DSP Gateway version 3.1 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "uaccess_dsp.h" +#include "dsp.h" + +#define SZ_1MB 0x100000 +#define SZ_64KB 0x10000 +#define SZ_4KB 0x1000 +#define SZ_1KB 0x400 +#define is_aligned(adr,align) (!((adr)&((align)-1))) + +#define PGDIR_MASK (~(PGDIR_SIZE-1)) +#define PGDIR_ALIGN(addr) (((addr)+PGDIR_SIZE-1)&(PGDIR_MASK)) + +#define dsp_mmu_enable() \ + do { \ + omap_writew(DSPMMU_CNTL_MMU_EN | DSPMMU_CNTL_RESET_SW, \ + DSPMMU_CNTL); \ + } while(0) +#define dsp_mmu_disable() \ + do { omap_writew(0, DSPMMU_CNTL); } while(0) +#define dsp_mmu_flush() \ + do { \ + omap_writew(DSPMMU_FLUSH_ENTRY_FLUSH_ENTRY, \ + DSPMMU_FLUSH_ENTRY); \ + } while(0) +#define __dsp_mmu_gflush() \ + do { omap_writew(DSPMMU_GFLUSH_GFLUSH, DSPMMU_GFLUSH); } while(0) +#define __dsp_mmu_itack() \ + do { omap_writew(DSPMMU_IT_ACK_IT_ACK, DSPMMU_IT_ACK); } while(0) + +#define EMIF_PRIO_LB_MASK 0x0000f000 +#define EMIF_PRIO_LB_SHIFT 12 +#define EMIF_PRIO_DMA_MASK 0x00000f00 +#define EMIF_PRIO_DMA_SHIFT 8 +#define EMIF_PRIO_DSP_MASK 0x00000070 +#define EMIF_PRIO_DSP_SHIFT 4 +#define EMIF_PRIO_MPU_MASK 0x00000007 +#define EMIF_PRIO_MPU_SHIFT 0 +#define set_emiff_dma_prio(prio) \ + do { \ + omap_writel((omap_readl(OMAP_TC_OCPT1_PRIOR) & \ + ~EMIF_PRIO_DMA_MASK) | \ + ((prio) << EMIF_PRIO_DMA_SHIFT), \ + OMAP_TC_OCPT1_PRIOR); \ + } while(0) + +enum exmap_type { + EXMAP_TYPE_MEM, + EXMAP_TYPE_FB +}; + +struct exmap_tbl { + unsigned int valid:1; + unsigned int cntnu:1; /* grouping */ + enum exmap_type type; + void *buf; + void *vadr; + unsigned int order; +}; +#define DSPMMU_TLB_LINES 32 +static struct exmap_tbl exmap_tbl[DSPMMU_TLB_LINES]; + +static int dsp_exunmap(unsigned long dspadr); + +static void *dspvect_page; +static unsigned long dsp_fault_adr; + +static __inline__ unsigned long lineup_offset(unsigned long adr, + unsigned long ref, + unsigned long mask) +{ + unsigned long newadr; + + newadr = (adr & ~mask) | (ref & mask); + if (newadr < adr) + newadr += mask + 1; + return newadr; +} + +/* + * ARM MMU operations + */ +static int exmap_set_armmmu(unsigned long virt, unsigned long phys, + unsigned long size) +{ + long off; + unsigned long sz_left; + pmd_t *pmdp; + pte_t *ptep; + int prot_pmd, prot_pte; + + printk(KERN_DEBUG + "omapdsp: mapping in ARM MMU, v=0x%08lx, p=0x%08lx, sz=0x%lx\n", + virt, phys, size); + + prot_pmd = PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_IO); + prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_WRITE; + + pmdp = pmd_offset(pgd_offset_k(virt), virt); + if (pmd_none(*pmdp)) { + ptep = pte_alloc_one_kernel(&init_mm, 0); + if (ptep == NULL) + return -ENOMEM; + /* note: two PMDs will be set */ + pmd_populate_kernel(&init_mm, pmdp, ptep); + } + + off = phys - virt; + for (sz_left = size; + sz_left >= PAGE_SIZE; + sz_left -= PAGE_SIZE, virt += PAGE_SIZE) { + ptep = pte_offset_kernel(pmdp, virt); + set_pte(ptep, __pte((virt + off) | prot_pte)); + } + if (sz_left) + BUG(); + + return 0; +} + +static void exmap_clear_armmmu(unsigned long virt, unsigned long size) +{ + unsigned long sz_left; + pmd_t *pmdp; + pte_t *ptep; + + printk(KERN_DEBUG + "omapdsp: unmapping in ARM MMU, v=0x%08lx, sz=0x%lx\n", + virt, size); + + for (sz_left = size; + sz_left >= PAGE_SIZE; + sz_left -= PAGE_SIZE, virt += PAGE_SIZE) { + pmdp = pmd_offset(pgd_offset_k(virt), virt); + ptep = pte_offset_kernel(pmdp, virt); + pte_clear(ptep); + } + if (sz_left) + BUG(); +} + +void dsp_map_update(struct task_struct *tsk) +{ + unsigned long virt; + pmd_t *pmdp; + + printk(KERN_DEBUG + "omapdsp: updating memory mapping for DSP space. (pid=%d)\n", + tsk->pid); + + for (virt = dspmem_base; + virt < dspmem_base + DSPSPACE_SIZE; + virt += PGDIR_SIZE) { + pmdp = pmd_offset(pgd_offset(tsk->mm, virt), virt); + pmd_clear(pmdp); + } +} + +static int exmap_valid(void *vadr, size_t len) +{ + int i; + +start: + for (i = 0; i < DSPMMU_TLB_LINES; i++) { + void *mapadr; + unsigned long mapsize; + struct exmap_tbl *ent = &exmap_tbl[i]; + + if (!ent->valid) + continue; + mapadr = (void *)ent->vadr; + mapsize = 1 << (ent->order + PAGE_SHIFT); + if ((vadr >= mapadr) && (vadr < mapadr + mapsize)) { + if (vadr + len <= mapadr + mapsize) { + /* this map covers whole address. */ + return 1; + } else { + /* + * this map covers partially. + * check rest portion. + */ + len -= mapadr + mapsize - vadr; + vadr = mapadr + mapsize; + goto start; + } + } + } + + return 0; +} + +/* + * dsp_virt_to_phys() + * returns physical address, and sets len to valid length + */ +unsigned long dsp_virt_to_phys(void *vadr, size_t *len) +{ + int i; + + if (is_dsp_internal_mem(vadr)) { + /* DSRAM or SARAM */ + *len = dspmem_base + dspmem_size - (unsigned long)vadr; + return (unsigned long)vadr; + } + + /* EXRAM */ + for (i = 0; i < DSPMMU_TLB_LINES; i++) { + void *mapadr; + unsigned long mapsize; + struct exmap_tbl *ent = &exmap_tbl[i]; + + if (!ent->valid) + continue; + mapadr = (void *)ent->vadr; + mapsize = 1 << (ent->order + PAGE_SHIFT); + if ((vadr >= mapadr) && (vadr < mapadr + mapsize)) { + *len = mapadr + mapsize - vadr; + return __pa(ent->buf) + vadr - mapadr; + } + } + + /* valid mapping not found */ + return 0; +} + +/* + * DSP MMU operations + */ +static __inline__ unsigned short get_cam_l_va_mask(unsigned short slst) +{ + switch (slst) { + case DSPMMU_CAM_L_SLST_1MB: + return DSPMMU_CAM_L_VA_TAG_L1_MASK | + DSPMMU_CAM_L_VA_TAG_L2_MASK_1MB; + case DSPMMU_CAM_L_SLST_64KB: + return DSPMMU_CAM_L_VA_TAG_L1_MASK | + DSPMMU_CAM_L_VA_TAG_L2_MASK_64KB; + case DSPMMU_CAM_L_SLST_4KB: + return DSPMMU_CAM_L_VA_TAG_L1_MASK | + DSPMMU_CAM_L_VA_TAG_L2_MASK_4KB; + case DSPMMU_CAM_L_SLST_1KB: + return DSPMMU_CAM_L_VA_TAG_L1_MASK | + DSPMMU_CAM_L_VA_TAG_L2_MASK_1KB; + } + return 0; +} + +static __inline__ void get_tlb_lock(int *base, int *victim) +{ + unsigned short lock = omap_readw(DSPMMU_LOCK); + if (base != NULL) + *base = (lock & DSPMMU_LOCK_BASE_MASK) + >> DSPMMU_LOCK_BASE_SHIFT; + if (victim != NULL) + *victim = (lock & DSPMMU_LOCK_VICTIM_MASK) + >> DSPMMU_LOCK_VICTIM_SHIFT; +} + +static __inline__ void set_tlb_lock(int base, int victim) +{ + omap_writew((base << DSPMMU_LOCK_BASE_SHIFT) | + (victim << DSPMMU_LOCK_VICTIM_SHIFT), DSPMMU_LOCK); +} + +static __inline__ void __read_tlb(unsigned short lbase, unsigned short victim, + unsigned short *cam_h, unsigned short *cam_l, + unsigned short *ram_h, unsigned short *ram_l) +{ + /* set victim */ + set_tlb_lock(lbase, victim); + + /* read a TLB entry */ + omap_writew(DSPMMU_LD_TLB_RD, DSPMMU_LD_TLB); + + if (cam_h != NULL) + *cam_h = omap_readw(DSPMMU_READ_CAM_H); + if (cam_l != NULL) + *cam_l = omap_readw(DSPMMU_READ_CAM_L); + if (ram_h != NULL) + *ram_h = omap_readw(DSPMMU_READ_RAM_H); + if (ram_l != NULL) + *ram_l = omap_readw(DSPMMU_READ_RAM_L); +} + +static __inline__ void __load_tlb(unsigned short cam_h, unsigned short cam_l, + unsigned short ram_h, unsigned short ram_l) +{ + omap_writew(cam_h, DSPMMU_CAM_H); + omap_writew(cam_l, DSPMMU_CAM_L); + omap_writew(ram_h, DSPMMU_RAM_H); + omap_writew(ram_l, DSPMMU_RAM_L); + + /* flush the entry */ + dsp_mmu_flush(); + + /* load a TLB entry */ + omap_writew(DSPMMU_LD_TLB_LD, DSPMMU_LD_TLB); +} + +static int dsp_mmu_load_tlb(unsigned long vadr, unsigned long padr, + unsigned short slst, unsigned short prsvd, + unsigned short ap) +{ + int lbase, victim; + unsigned short cam_l_va_mask; + + clk_use(dsp_ck_handle); + + get_tlb_lock(&lbase, NULL); + for (victim = 0; victim < lbase; victim++) { + unsigned short cam_l; + + /* read a TLB entry */ + __read_tlb(lbase, victim, NULL, &cam_l, NULL, NULL); + if (!(cam_l & DSPMMU_CAM_L_V)) + goto found_victim; + } + set_tlb_lock(lbase, victim); + +found_victim: + /* The last (31st) entry cannot be locked? */ + if (victim == 31) { + printk(KERN_ERR "omapdsp: TLB is full.\n"); + return -EBUSY; + } + + cam_l_va_mask = get_cam_l_va_mask(slst); + if (vadr & + ~(DSPMMU_CAM_H_VA_TAG_H_MASK << 22 | + (unsigned long)cam_l_va_mask << 6)) { + printk(KERN_ERR + "omapdsp: mapping vadr (0x%06lx) is not " + "aligned boundary\n", vadr); + return -EINVAL; + } + + __load_tlb(vadr >> 22, (vadr >> 6 & cam_l_va_mask) | prsvd | slst, + padr >> 16, (padr & DSPMMU_RAM_L_RAM_LSB_MASK) | ap); + + /* update lock base */ + if (victim == lbase) + lbase++; + set_tlb_lock(lbase, lbase); + + clk_unuse(dsp_ck_handle); + return 0; +} + +static int dsp_mmu_clear_tlb(unsigned long vadr) +{ + int lbase; + int i; + int max_valid = 0; + + clk_use(dsp_ck_handle); + + get_tlb_lock(&lbase, NULL); + for (i = 0; i < lbase; i++) { + unsigned short cam_h, cam_l; + unsigned short cam_l_va_mask, cam_vld, slst; + unsigned long cam_va; + + /* read a TLB entry */ + __read_tlb(lbase, i, &cam_h, &cam_l, NULL, NULL); + + cam_vld = cam_l & DSPMMU_CAM_L_V; + if (!cam_vld) + continue; + + slst = cam_l & DSPMMU_CAM_L_SLST_MASK; + cam_l_va_mask = get_cam_l_va_mask(slst); + cam_va = (unsigned long)(cam_h & DSPMMU_CAM_H_VA_TAG_H_MASK) << 22 | + (unsigned long)(cam_l & cam_l_va_mask) << 6; + + if (cam_va == vadr) + /* flush the entry */ + dsp_mmu_flush(); + else + max_valid = i; + } + + /* set new lock base */ + set_tlb_lock(max_valid+1, max_valid+1); + + clk_unuse(dsp_ck_handle); + return 0; +} + +static void dsp_mmu_gflush(void) +{ + clk_use(dsp_ck_handle); + + __dsp_mmu_gflush(); + set_tlb_lock(1, 1); + + clk_unuse(dsp_ck_handle); +} + +/* + * dsp_exmap() + * + * OMAP_DSP_MEM_IOCTL_EXMAP ioctl calls this function with padr=0. + * In this case, the buffer for DSP is allocated in this routine, + * then it is mapped. + * On the other hand, for example - frame buffer sharing, calls + * this function with padr set. It means some known address space + * pointed with padr is going to be shared with DSP. + */ +static int dsp_exmap(unsigned long dspadr, unsigned long padr, + unsigned long size, enum exmap_type type) +{ + unsigned short slst; + void *buf; + unsigned int order = 0; + unsigned long unit; + unsigned int cntnu = 0; + unsigned long _dspadr = dspadr; + unsigned long _padr = padr; + void *_vadr = dspbyte_to_virt(dspadr); + unsigned long _size = size; + struct exmap_tbl *exmap_ent; + int status; + int i; + +#define MINIMUM_PAGESZ SZ_4KB + /* + * alignment check + */ + if (!is_aligned(size, MINIMUM_PAGESZ)) { + printk(KERN_ERR + "omapdsp: size(0x%lx) is not multiple of 4KB.\n", size); + return -EINVAL; + } + if (!is_aligned(dspadr, MINIMUM_PAGESZ)) { + printk(KERN_ERR + "omapdsp: DSP address(0x%lx) is not aligned.\n", dspadr); + return -EINVAL; + } + if (!is_aligned(padr, MINIMUM_PAGESZ)) { + printk(KERN_ERR + "omapdsp: physical address(0x%lx) is not aligned.\n", + padr); + return -EINVAL; + } + + /* address validity check */ + if ((dspadr < dspmem_size) || + (dspadr >= DSPSPACE_SIZE) || + ((dspadr + size > DSP_INIT_PAGE) && + (dspadr < DSP_INIT_PAGE + PAGE_SIZE))) { + printk(KERN_ERR + "omapdsp: illegal address/size for dsp_exmap().\n"); + return -EINVAL; + } + + /* overlap check */ + for (i = 0; i < DSPMMU_TLB_LINES; i++) { + unsigned long mapsize; + struct exmap_tbl *tmp_ent = &exmap_tbl[i]; + + if (!tmp_ent->valid) + continue; + mapsize = 1 << (tmp_ent->order + PAGE_SHIFT); + if ((_vadr + size > tmp_ent->vadr) && + (_vadr < tmp_ent->vadr + mapsize)) { + printk(KERN_ERR "omapdsp: exmap page overlap!\n"); + return -EINVAL; + } + } + +start: + buf = NULL; + /* Are there any free TLB lines? */ + for (i = 0; i < DSPMMU_TLB_LINES; i++) { + if (!exmap_tbl[i].valid) + goto found_free; + } + printk(KERN_ERR "omapdsp: DSP TLB is full.\n"); + status = -EBUSY; + goto fail; + +found_free: + exmap_ent = &exmap_tbl[i]; + + if ((_size >= SZ_1MB) && + (is_aligned(_padr, SZ_1MB) || (padr == 0)) && + is_aligned(_dspadr, SZ_1MB)) { + unit = SZ_1MB; + slst = DSPMMU_CAM_L_SLST_1MB; + order = 20 - PAGE_SHIFT; + } else if ((_size >= SZ_64KB) && + (is_aligned(_padr, SZ_64KB) || (padr == 0)) && + is_aligned(_dspadr, SZ_64KB)) { + unit = SZ_64KB; + slst = DSPMMU_CAM_L_SLST_64KB; + order = 16 - PAGE_SHIFT; + } else /* if (_size >= SZ_4KB) */ { + unit = SZ_4KB; + slst = DSPMMU_CAM_L_SLST_4KB; + order = 12 - PAGE_SHIFT; + } +#if 0 /* 1KB is not enabled */ + else if (_size >= SZ_1KB) { + unit = SZ_1KB; + slst = DSPMMU_CAM_L_SLST_1KB; + order = 10 - PAGE_SHIFT; + } +#endif + + /* buffer allocation */ + if (type == EXMAP_TYPE_MEM) { + struct page *page, *ps, *pe; + + buf = (void *)__get_free_pages(GFP_KERNEL, order); + if (buf == NULL) { + status = -ENOMEM; + goto fail; + } + /* mark the pages as reserved; this is needed for mmap */ + ps = virt_to_page(buf); + pe = virt_to_page(buf + unit); + for (page = ps; page < pe; page++) { + SetPageReserved(page); + } + _padr = __pa(buf); + } + + /* + * mapping for ARM MMU: + * we should not access to the allocated memory through 'buf' + * since this area should not be cashed. + */ + status = exmap_set_armmmu((unsigned long)_vadr, _padr, unit); + if (status < 0) + goto fail; + + /* loading DSP TLB entry */ + status = dsp_mmu_load_tlb(_dspadr, _padr, slst, 0, DSPMMU_RAM_L_AP_FA); + if (status < 0) { + exmap_clear_armmmu((unsigned long)_vadr, unit); + goto fail; + } + + exmap_ent->buf = buf; + exmap_ent->vadr = _vadr; + exmap_ent->order = order; + exmap_ent->valid = 1; + exmap_ent->cntnu = cntnu; + exmap_ent->type = type; + + if ((_size -= unit) == 0) + return size; + + _dspadr += unit; + _vadr += unit; + _padr = padr ? _padr + unit : 0; + cntnu = 1; + goto start; + +fail: + if (buf) + free_pages((unsigned long)buf, order); + dsp_exunmap(dspadr); + return status; +} + +static unsigned long unmap_free_arm(struct exmap_tbl *ent) +{ + unsigned long size; + + /* clearing ARM MMU */ + size = 1 << (ent->order + PAGE_SHIFT); + exmap_clear_armmmu((unsigned long)ent->vadr, size); + + /* freeing allocated memory */ + if (ent->type == EXMAP_TYPE_MEM) { + free_pages((unsigned long)ent->buf, ent->order); + printk(KERN_DEBUG + "omapdsp: freeing 0x%lx bytes @ adr 0x%8p\n", + size, ent->buf); + } + + return size; +} + +static int dsp_exunmap(unsigned long dspadr) +{ + void *vadr; + unsigned long size, total = 0; + struct exmap_tbl *ent; + int idx; + + vadr = dspbyte_to_virt(dspadr); + for (idx = 0; idx < DSPMMU_TLB_LINES; idx++) { + ent = &exmap_tbl[idx]; + if (!ent->valid) + continue; + if (ent->vadr == vadr) + goto found_map; + } + printk(KERN_WARNING + "omapdsp: address %06lx not found in exmap_tbl.\n", dspadr); + return -EINVAL; + +found_map: + preempt_disable(); + + /* clearing DSP TLB entry */ + dsp_mmu_clear_tlb(dspadr); + + /* clear ARM MMU and free buffer */ + size = unmap_free_arm(ent); + ent->valid = 0; + total += size; + + /* we don't free PTEs */ + + /* flush TLB */ + flush_tlb_kernel_range((unsigned long)vadr, (unsigned long)vadr + size); + /* + * we should clear processes' mm as well, + * because processes might have old map. + */ + dsp_cur_users_map_update(); + preempt_enable(); + + /* check if next mapping is in same group */ + if (++idx == DSPMMU_TLB_LINES) + return total; + ent = &exmap_tbl[idx]; + if (!ent->valid || !ent->cntnu) + return total; + + dspadr += size; + vadr += size; + if (ent->vadr == vadr) /* OK */ + goto found_map; + + printk(KERN_ERR + "omapdsp: illegal exmap_tbl grouping!\n" + "expected vadr = %p, exmap_tbl[%d].vadr = %p\n", + vadr, idx, ent->vadr); + return -EINVAL; +} + +static void exmap_flush(void) +{ + pmd_t *pmdp, *initcode_pmd; + struct exmap_tbl *ent; + unsigned long virt; + int i; + + preempt_disable(); + + /* clearing DSP TLB entry */ + dsp_mmu_gflush(); + + /* exmap_tbl[0] should be preserved */ + for (i = 1; i < DSPMMU_TLB_LINES; i++) { + ent = &exmap_tbl[i]; + if (ent->valid) { + unmap_free_arm(ent); + ent->valid = 0; + } + } + + /* freeing PTE */ + virt = (unsigned long)dspbyte_to_virt(DSP_INIT_PAGE); + initcode_pmd = pmd_offset(pgd_offset_k(virt), virt); /* 0xe0e00000 */ + + for (virt = PGDIR_ALIGN(dspmem_base + dspmem_size); + virt < dspmem_base + DSPSPACE_SIZE; + virt += PGDIR_SIZE) { + pmdp = pmd_offset(pgd_offset_k(virt), virt); + + /* do not free the PTE for DSP vector table */ + if (pmdp == initcode_pmd) + continue; + + pmd_clear(pmdp); + if (!pmd_none(*pmdp)) { + pte_t *pte = pte_offset_kernel(pmdp, 0); + /* note: clears two PMDs */ + pmd_clear(pmdp); + pte_free_kernel(pte); + } + } + + /* flush TLB */ + flush_tlb_kernel_range(dspmem_base + dspmem_size, + dspmem_base + DSPSPACE_SIZE); + /* + * we should clear processes' mm as well, + * because processes might had accessed to those spaces + * with old table in the past. + */ + dsp_cur_users_map_update(); + preempt_enable(); +} + +#ifdef CONFIG_OMAP_DSP_FBEXPORT +#ifndef CONFIG_FB +#error You configured OMAP_DSP_FBEXPORT, but FB was not configured! +#endif /* CONFIG_FB */ + +static int dsp_fbexport(unsigned long *dspadr) +{ + unsigned long dspadr_actual; + unsigned long padr_sys, padr, fbsz_sys, fbsz; + int cnt; + + printk(KERN_DEBUG "omapdsp: frame buffer export\n"); + + if (num_registered_fb == 0) { + printk(KERN_INFO "omapdsp: frame buffer not registered.\n"); + return -EINVAL; + } + if (num_registered_fb != 1) { + printk(KERN_INFO + "omapdsp: %d frame buffers found. we use first one.\n", + num_registered_fb); + } + padr_sys = registered_fb[0]->fix.smem_start; + fbsz_sys = registered_fb[0]->fix.smem_len; + if (fbsz_sys == 0) { + printk(KERN_ERR + "omapdsp: framebuffer doesn't seem to be configured " + "correctly! (size=0)\n"); + return -EINVAL; + } + + /* + * align padr and fbsz to 4kB boundary + * (should be noted to the user afterwards!) + */ + padr = padr_sys & ~(SZ_4KB-1); + fbsz = (fbsz_sys + padr_sys - padr + SZ_4KB-1) & ~(SZ_4KB-1); + + /* line up dspadr offset with padr */ + dspadr_actual = + (fbsz > SZ_1MB) ? lineup_offset(*dspadr, padr, SZ_1MB-1) : + (fbsz > SZ_64KB) ? lineup_offset(*dspadr, padr, SZ_64KB-1) : + /* (fbsz > SZ_4KB) ? */ *dspadr; + if (dspadr_actual != *dspadr) + printk(KERN_DEBUG + "omapdsp: actual dspadr for FBEXPORT = %08lx\n", + dspadr_actual); + *dspadr = dspadr_actual; + + cnt = dsp_exmap(dspadr_actual, padr, fbsz, EXMAP_TYPE_FB); + if (cnt < 0) { + printk(KERN_ERR "omapdsp: exmap failure.\n"); + return cnt; + } + + if ((padr != padr_sys) || (fbsz != fbsz_sys)) { + printk(KERN_WARNING +" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" +" !! screen base address or size is not aligned in 4kB: !!\n" +" !! actual screen adr = %08lx, size = %08lx !!\n" +" !! exporting adr = %08lx, size = %08lx !!\n" +" !! Make sure that the framebuffer is allocated with 4kB-order! !!\n" +" !! Otherwise DSP can corrupt the kernel memory. !!\n" +" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", + padr_sys, fbsz_sys, padr, fbsz); + } + + /* increase the DMA priority */ + set_emiff_dma_prio(15); + + return cnt; +} + +#else /* CONFIG_OMAP_DSP_FBEXPORT */ + +static int dsp_fbexport(unsigned long *dspadr) +{ + printk(KERN_ERR "omapdsp: FBEXPORT function is not enabled.\n"); + return -EINVAL; +} + +#endif /* CONFIG_OMAP_DSP_FBEXPORT */ + +static int dsp_mmu_itack(void) +{ + unsigned long dspadr; + + printk(KERN_INFO "omapdsp: sending DSP MMU interrupt ack.\n"); + if (!dsp_err_mmu_isset()) { + printk(KERN_ERR "omapdsp: DSP MMU error has not been set.\n"); + return -EINVAL; + } + dspadr = dsp_fault_adr & ~(SZ_4K-1); + dsp_exmap(dspadr, 0, SZ_4K, EXMAP_TYPE_MEM); /* FIXME: reserve TLB entry for this */ + printk(KERN_INFO "omapdsp: falling into recovery runlevel...\n"); + dsp_runlevel(OMAP_DSP_MBCMD_RUNLEVEL_RECOVERY); + __dsp_mmu_itack(); + udelay(100); + dsp_exunmap(dspadr); + dsp_err_mmu_clear(); + return 0; +} + +static void dsp_mmu_init(void) +{ + unsigned long phys; + void *virt; + + clk_use(dsp_ck_handle); + + dsp_mmu_disable(); /* clear all */ + udelay(10); + dsp_mmu_enable(); + + /* mapping for ARM MMU */ + phys = __pa(dspvect_page); + virt = dspbyte_to_virt(DSP_INIT_PAGE); /* 0xe0fff000 */ + exmap_set_armmmu((unsigned long)virt, phys, PAGE_SIZE); + exmap_tbl[0].buf = dspvect_page; + exmap_tbl[0].vadr = virt; + exmap_tbl[0].order = 0; + exmap_tbl[0].valid = 1; + exmap_tbl[0].cntnu = 0; + + /* DSP TLB initialization */ + set_tlb_lock(0, 0); + /* preserved, full access */ + dsp_mmu_load_tlb(DSP_INIT_PAGE, phys, DSPMMU_CAM_L_SLST_4KB, + DSPMMU_CAM_L_P, DSPMMU_RAM_L_AP_FA); + clk_unuse(dsp_ck_handle); +} + +static void dsp_mmu_shutdown(void) +{ + exmap_flush(); + dsp_mmu_disable(); /* clear all */ +} + +/* + * + */ +static int dsp_mem_en_flag; + +int dsp_mem_enable(void) +{ + struct mbcmd mb; + int ret = 0; + + if (dsp_is_ready() && (!dsp_mem_en_flag) && + (dsp_icrmask & DSPREG_ICR_DMA_IDLE_DOMAIN)) { + mbcmd_set(mb, MBCMD(PM), OMAP_DSP_MBCMD_PM_ENABLE, + DSPREG_ICR_DMA_IDLE_DOMAIN); + if ((ret = dsp_mbsend(&mb)) < 0) + return ret; + dsp_mem_en_flag = 1; + } + return ret; +} + +int dsp_mem_disable(void) +{ + struct mbcmd mb; + int ret = 0; + + if (dsp_is_ready() && dsp_mem_en_flag) { + mbcmd_set(mb, MBCMD(PM), OMAP_DSP_MBCMD_PM_DISABLE, + DSPREG_ICR_DMA_IDLE_DOMAIN); + if ((ret = dsp_mbsend(&mb)) < 0) + return ret; + dsp_mem_en_flag = 0; + } + return ret; +} + +/* + * dsp_mem file operations + */ +static loff_t dsp_mem_lseek(struct file *file, loff_t offset, int orig) +{ + loff_t ret; + + down(&file->f_dentry->d_inode->i_sem); + switch (orig) { + case 0: + file->f_pos = offset; + ret = file->f_pos; + break; + case 1: + file->f_pos += offset; + ret = file->f_pos; + break; + default: + ret = -EINVAL; + } + up(&file->f_dentry->d_inode->i_sem); + return ret; +} + +static ssize_t intmem_read(struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + unsigned long p = *ppos; + void *vadr = dspbyte_to_virt(p); + ssize_t size = dspmem_size; + ssize_t read; + + if (p >= size) + return 0; + clk_use(api_ck_handle); + read = count; + if (count > size - p) + read = size - p; + if (copy_to_user(buf, vadr, read)) { + read = -EFAULT; + goto finish; + } + *ppos += read; +finish: + clk_unuse(api_ck_handle); + return read; +} + +static ssize_t exmem_read(struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + unsigned long p = *ppos; + void *vadr = dspbyte_to_virt(p); + + if (!exmap_valid(vadr, count)) { + printk(KERN_ERR + "omapdsp: DSP address %08lx / size %08x " + "is not valid!\n", p, count); + return -EFAULT; + } + if (count > DSPSPACE_SIZE - p) + count = DSPSPACE_SIZE - p; + if (copy_to_user(buf, vadr, count)) + return -EFAULT; + *ppos += count; + + return count; +} + +static ssize_t dsp_mem_read(struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + if (is_dspbyte_internal_mem(*ppos)) + return intmem_read(file, buf, count, ppos); + else + return exmem_read(file, buf, count, ppos); +} + +static ssize_t intmem_write(struct file *file, const char *buf, size_t count, + loff_t *ppos) +{ + unsigned long p = *ppos; + void *vadr = dspbyte_to_virt(p); + ssize_t size = dspmem_size; + ssize_t written; + + if (p >= size) + return 0; + clk_use(api_ck_handle); + written = count; + if (count > size - p) + written = size - p; + if (copy_from_user(vadr, buf, written)) { + written = -EFAULT; + goto finish; + } + *ppos += written; +finish: + clk_unuse(api_ck_handle); + return written; +} + +static ssize_t exmem_write(struct file *file, const char *buf, size_t count, + loff_t *ppos) +{ + unsigned long p = *ppos; + void *vadr = dspbyte_to_virt(p); + + if (!exmap_valid(vadr, count)) { + printk(KERN_ERR + "omapdsp: DSP address %08lx / size %08x " + "is not valid!\n", p, count); + return -EFAULT; + } + if (count > DSPSPACE_SIZE - p) + count = DSPSPACE_SIZE - p; + if (copy_from_user(vadr, buf, count)) + return -EFAULT; + *ppos += count; + + return count; +} + +static ssize_t dsp_mem_write(struct file *file, const char *buf, size_t count, + loff_t *ppos) +{ + if (is_dspbyte_internal_mem(*ppos)) + return intmem_write(file, buf, count, ppos); + else + return exmem_write(file, buf, count, ppos); +} + +static int dsp_mem_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case OMAP_DSP_MEM_IOCTL_MMUINIT: + dsp_mmu_init(); + return 0; + + case OMAP_DSP_MEM_IOCTL_EXMAP: + { + struct omap_dsp_mapinfo mapinfo; + if (copy_from_user(&mapinfo, (void *)arg, + sizeof(mapinfo))) + return -EFAULT; + return dsp_exmap(mapinfo.dspadr, 0, mapinfo.size, + EXMAP_TYPE_MEM); + } + + case OMAP_DSP_MEM_IOCTL_EXUNMAP: + return dsp_exunmap((unsigned long)arg); + + case OMAP_DSP_MEM_IOCTL_EXMAP_FLUSH: + exmap_flush(); + return 0; + + case OMAP_DSP_MEM_IOCTL_FBEXPORT: + { + unsigned long dspadr; + int ret; + if (copy_from_user(&dspadr, (void *)arg, sizeof(long))) + return -EFAULT; + ret = dsp_fbexport(&dspadr); + if (copy_to_user((void *)arg, &dspadr, sizeof(long))) + return -EFAULT; + return ret; + } + + case OMAP_DSP_MEM_IOCTL_MMUITACK: + return dsp_mmu_itack(); + + default: + return -ENOIOCTLCMD; + } +} + +static int dsp_mem_mmap(struct file *file, struct vm_area_struct *vma) +{ + /* + * FIXME + */ + return -ENOSYS; +} + +static int dsp_mem_open(struct inode *inode, struct file *file) +{ + dsp_map_update(current); + dsp_cur_users_add(current); + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + if (dsp_mem_enable() < 0) + return -EBUSY; + + return 0; +} + +static int dsp_mem_release(struct inode *inode, struct file *file) +{ + dsp_mem_disable(); + dsp_cur_users_del(current); + return 0; +} + +#ifdef CONFIG_PROC_FS +/* + * proc entry + */ +static int dsp_mmu_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int len = 0; + off_t begin = 0; + int lbase, victim; + int i; + + clk_use(dsp_ck_handle); + + get_tlb_lock(&lbase, &victim); + + len += sprintf(page, "p: preserved, v: valid\n" + "ety cam_va ram_pa sz ap\n"); + /* 00: p v 0x300000 0x10171800 64KB FA */ + for (i = 0; i < 32; i++) { + unsigned short cam_h, cam_l, ram_h, ram_l; + unsigned short cam_l_va_mask, prsvd, cam_vld, slst; + unsigned long cam_va; + unsigned short ram_l_ap; + unsigned long ram_pa; + char *pgsz_str, *ap_str; + + /* read a TLB entry */ + __read_tlb(lbase, i, &cam_h, &cam_l, &ram_h, &ram_l); + + slst = cam_l & DSPMMU_CAM_L_SLST_MASK; + cam_l_va_mask = get_cam_l_va_mask(slst); + pgsz_str = (slst == DSPMMU_CAM_L_SLST_1MB) ? " 1MB": + (slst == DSPMMU_CAM_L_SLST_64KB)? "64KB": + (slst == DSPMMU_CAM_L_SLST_4KB) ? " 4KB": + " 1KB"; + prsvd = cam_l & DSPMMU_CAM_L_P; + cam_vld = cam_l & DSPMMU_CAM_L_V; + ram_l_ap = ram_l & DSPMMU_RAM_L_AP_MASK; + ap_str = (ram_l_ap == DSPMMU_RAM_L_AP_RO) ? "RO": + (ram_l_ap == DSPMMU_RAM_L_AP_FA) ? "FA": + "NA"; + cam_va = (unsigned long)(cam_h & DSPMMU_CAM_H_VA_TAG_H_MASK) << 22 | + (unsigned long)(cam_l & cam_l_va_mask) << 6; + ram_pa = (unsigned long)ram_h << 16 | + (ram_l & DSPMMU_RAM_L_RAM_LSB_MASK); + + if (i == lbase) + len += sprintf(page + len, "lock base = %d\n", lbase); + if (i == victim) + len += sprintf(page + len, "victim = %d\n", victim); + /* 00: p v 0x300000 0x10171800 64KB FA */ + len += sprintf(page + len, + "%02d: %c %c 0x%06lx 0x%08lx %s %s\n", + i, + prsvd ? 'p' : ' ', + cam_vld ? 'v' : ' ', + cam_va, ram_pa, pgsz_str, ap_str); + + if (len + begin > off + count) + break; + if (len + begin < off) { + begin += len; + len = 0; + } + } + + /* restore victim entry */ + set_tlb_lock(lbase, victim); + + len -= off - begin; + if (len < count) { + *eof = 1; + if (len <= 0) { + len = 0; + goto finish; + } + } else + len = count; + *start = page + off; + *start = page + (off - begin); + +finish: + clk_unuse(dsp_ck_handle); + return len; +} + +static int exmap_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int len = 0; + off_t begin = 0; + int i; + + len += sprintf(page, "v: valid, c: cntnu\n" + "ety vadr buf od\n"); + /* 00: v c 0xe0300000 0xc0171800 0 */ + for (i = 0; i < DSPMMU_TLB_LINES; i++) { + struct exmap_tbl *ent = &exmap_tbl[i]; + /* 00: v c 0xe0300000 0xc0171800 0 */ + len += sprintf(page + len, "%02d: %c %c 0x%8p 0x%8p %2d\n", + i, + ent->valid ? 'v' : ' ', + ent->cntnu ? 'c' : ' ', + ent->vadr, ent->buf, ent->order); + if (len + begin > off + count) + break; + if (len + begin < off) { + begin += len; + len = 0; + } + } + + len -= off - begin; + if (len < count) { + *eof = 1; + if (len <= 0) + return 0; + } else + len = count; + *start = page + (off - begin); + + return len; +} + +static void __init dsp_mem_create_proc(void) +{ + struct proc_dir_entry *ent; + + /* mmu */ + ent = create_proc_read_entry("mmu", 0, procdir_dsp, dsp_mmu_read_proc, + NULL); + if (ent == NULL) { + printk(KERN_ERR + "omapdsp: failed to register proc device: mmu\n"); + } + + /* exmap */ + ent = create_proc_read_entry("exmap", 0, procdir_dsp, exmap_read_proc, + NULL); + if (ent == NULL) { + printk(KERN_ERR + "omapdsp: failed to register proc device: exmap\n"); + } +} + +static void dsp_mem_remove_proc(void) +{ + remove_proc_entry("mmu", procdir_dsp); + remove_proc_entry("exmap", procdir_dsp); +} + +#endif /* CONFIG_PROC_FS */ + +/* + * DSP MMU interrupt handler + */ + +/* + * MMU fault mask: + * We ignore prefetch err. + */ +#define MMUFAULT_MASK \ + (DSPMMU_FAULT_ST_PERM |\ + DSPMMU_FAULT_ST_TLB_MISS |\ + DSPMMU_FAULT_ST_TRANS) +irqreturn_t dsp_mmu_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned short status; + unsigned short adh, adl; + unsigned short dp; + + status = omap_readw(DSPMMU_FAULT_ST); + adh = omap_readw(DSPMMU_FAULT_AD_H); + adl = omap_readw(DSPMMU_FAULT_AD_L); + dp = adh & DSPMMU_FAULT_AD_H_DP; + dsp_fault_adr = MKLONG(adh & DSPMMU_FAULT_AD_H_ADR_MASK, adl); + /* if the fault is masked, nothing to do */ + if ((status & MMUFAULT_MASK) == 0) { + printk(KERN_DEBUG "DSP MMU interrupt, but ignoring.\n"); + /* + * note: in OMAP1710, + * when CACHE + DMA domain gets out of idle in DSP, + * MMU interrupt occurs but DSPMMU_FAULT_ST is not set. + * in this case, we just ignore the interrupt. + */ + if (status) { + printk(KERN_DEBUG "%s%s%s%s\n", + (status & DSPMMU_FAULT_ST_PREF)? + " (prefetch err)" : "", + (status & DSPMMU_FAULT_ST_PERM)? + " (permission fault)" : "", + (status & DSPMMU_FAULT_ST_TLB_MISS)? + " (TLB miss)" : "", + (status & DSPMMU_FAULT_ST_TRANS) ? + " (translation fault)": ""); + printk(KERN_DEBUG + "fault address = %s: 0x%06lx\n", + dp ? "DATA" : "PROGRAM", + dsp_fault_adr); + } + return IRQ_HANDLED; + } + + printk(KERN_INFO "DSP MMU interrupt!\n"); + printk(KERN_INFO "%s%s%s%s\n", + (status & DSPMMU_FAULT_ST_PREF)? + (MMUFAULT_MASK & DSPMMU_FAULT_ST_PREF)? + " prefetch err": + " (prefetch err)": + "", + (status & DSPMMU_FAULT_ST_PERM)? + (MMUFAULT_MASK & DSPMMU_FAULT_ST_PERM)? + " permission fault": + " (permission fault)": + "", + (status & DSPMMU_FAULT_ST_TLB_MISS)? + (MMUFAULT_MASK & DSPMMU_FAULT_ST_TLB_MISS)? + " TLB miss": + " (TLB miss)": + "", + (status & DSPMMU_FAULT_ST_TRANS)? + (MMUFAULT_MASK & DSPMMU_FAULT_ST_TRANS)? + " translation fault": + " (translation fault)": + ""); + printk(KERN_INFO "fault address = %s: 0x%06lx\n", + dp ? "DATA" : "PROGRAM", + dsp_fault_adr); + + if (dsp_is_ready()) { + /* + * If we call dsp_exmap() here, + * "kernel BUG at slab.c" occurs. + */ + /* FIXME */ + dsp_err_mmu_set(dsp_fault_adr); + } else { + printk(KERN_INFO "Resetting DSP...\n"); + __dsp_reset(); + clk_unuse(api_ck_handle); + printk(KERN_INFO "Flushing DSP MMU...\n"); + exmap_flush(); + dsp_mmu_init(); + } + + return IRQ_HANDLED; +} + +/* + * + */ +struct file_operations dsp_mem_fops = { + .owner = THIS_MODULE, + .llseek = dsp_mem_lseek, + .read = dsp_mem_read, + .write = dsp_mem_write, + .ioctl = dsp_mem_ioctl, + .mmap = dsp_mem_mmap, + .open = dsp_mem_open, + .release = dsp_mem_release, +}; + +void dsp_mem_start(void) +{ + dsp_mem_en_flag = 0; +} + +int __init dsp_mem_init(void) +{ + int i; + + for (i = 0; i < DSPMMU_TLB_LINES; i++) { + exmap_tbl[i].valid = 0; + } + + dspvect_page = (void *)__get_free_page(GFP_KERNEL); + if (dspvect_page == NULL) { + printk(KERN_ERR + "omapdsp: failed to allocate memory " + "for dsp vector table\n"); + return -ENOMEM; + } + dsp_mmu_init(); + dsp_set_idle_boot_base(IDLEPG_BASE, IDLEPG_SIZE); + +#ifdef CONFIG_PROC_FS + dsp_mem_create_proc(); +#endif + + return 0; +} + +void dsp_mem_exit(void) +{ + dsp_mmu_shutdown(); + + if (dspvect_page != NULL) { + unsigned long virt; + pmd_t *pmdp; + pte_t *ptep; + + free_page((unsigned long)dspvect_page); + dspvect_page = NULL; + + virt = (unsigned long)dspbyte_to_virt(DSP_INIT_PAGE); + pmdp = pmd_offset(pgd_offset_k(virt), virt); + ptep = pte_offset_kernel(pmdp, 0); + pmd_clear(pmdp); + pte_free_kernel(ptep); + } + +#ifdef CONFIG_PROC_FS + dsp_mem_remove_proc(); +#endif +} diff -Nru a/arch/arm/mach-omap/dsp/error.c b/arch/arm/mach-omap/dsp/error.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/dsp/error.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,195 @@ +/* + * linux/arch/arm/mach-omap/dsp/error.c + * + * OMAP DSP error detection I/F device driver + * + * Copyright (C) 2002-2004 Nokia Corporation + * + * Written by Toshihiro Kobayashi + * + * 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 + * + * 2004/11/22: DSP Gateway version 3.1 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dsp.h" + +static DECLARE_WAIT_QUEUE_HEAD(err_wait_q); +static unsigned long errcode; +static int errcnt; +static unsigned short wdtval; /* FIXME: read through ioctl */ +static unsigned long mmu_fadr; /* FIXME: read through ioctl */ + +/* + * DSP error detection device file operations + */ +static ssize_t dsp_err_read(struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + unsigned long flags; + int status; + + if (count < 4) + return 0; + + if (errcnt == 0) { + long current_state; + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&err_wait_q, &wait); + current_state = current->state; + set_current_state(TASK_INTERRUPTIBLE); + if (errcnt == 0) /* last check */ + schedule(); + set_current_state(current_state); + remove_wait_queue(&err_wait_q, &wait); + if (signal_pending(current)) + return -EINTR; + } + + local_irq_save(flags); + status = copy_to_user(buf, &errcode, 4); + if (status) { + local_irq_restore(flags); + return -EFAULT; + } + errcnt = 0; + local_irq_restore(flags); + + return 4; +} + +static unsigned int dsp_err_poll(struct file *file, poll_table *wait) +{ + unsigned int mask = 0; + + poll_wait(file, &err_wait_q, wait); + if (errcnt != 0) + mask |= POLLIN | POLLRDNORM; + + return mask; +} + +struct file_operations dsp_err_fops = { + .owner = THIS_MODULE, + .poll = dsp_err_poll, + .read = dsp_err_read, +}; + +/* + * DSP MMU + */ +void dsp_err_mmu_set(unsigned long adr) +{ + disable_irq(INT_DSP_MMU); + errcode |= OMAP_DSP_ERRDT_MMU; + errcnt++; + mmu_fadr = adr; + wake_up_interruptible(&err_wait_q); +} + +void dsp_err_mmu_clear(void) +{ + errcode &= ~OMAP_DSP_ERRDT_MMU; + enable_irq(INT_DSP_MMU); +} + +int dsp_err_mmu_isset(void) +{ + return (errcode & OMAP_DSP_ERRDT_MMU) ? 1 : 0; +} + +/* + * WDT + */ +void dsp_err_wdt_clear(void) +{ + errcode &= ~OMAP_DSP_ERRDT_WDT; +} + +int dsp_err_wdt_isset(void) +{ + return (errcode & OMAP_DSP_ERRDT_WDT) ? 1 : 0; +} + +/* + * functions called from mailbox1 interrupt routine + */ +void mbx1_wdt(struct mbcmd *mb) +{ + printk(KERN_WARNING "omapdsp: DSP WDT expired!\n"); + errcode |= OMAP_DSP_ERRDT_WDT; + errcnt++; + wdtval = mb->data; + wake_up_interruptible(&err_wait_q); +} + +extern void mbx1_err_ipbfull(void); +extern void mbx1_err_fatal(unsigned char tid); + +void mbx1_err(struct mbcmd *mb) +{ + unsigned char eid = mb->cmd_l; + char *eidnm = subcmd_name(mb); + unsigned char tid; + + if (eidnm) { + printk(KERN_WARNING + "mbx: ERR from DSP (%s): 0x%04x\n", eidnm, mb->data); + } else { + printk(KERN_WARNING + "mbx: ERR from DSP (unknown EID=%02x): %04x\n", + eid, mb->data); + } + + switch (eid) { + case OMAP_DSP_EID_IPBFULL: + mbx1_err_ipbfull(); + break; + + case OMAP_DSP_EID_FATAL: + tid = mb->data & 0x00ff; + mbx1_err_fatal(tid); + break; + } +} + +/* + * + */ +void dsp_err_start(void) +{ + errcnt = 0; + if (dsp_err_wdt_isset()) + dsp_err_wdt_clear(); + if (dsp_err_mmu_isset()) + dsp_err_mmu_clear(); +} + +void dsp_err_stop(void) +{ + wake_up_interruptible(&err_wait_q); +} diff -Nru a/arch/arm/mach-omap/dsp/fifo.h b/arch/arm/mach-omap/dsp/fifo.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/dsp/fifo.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,122 @@ +/* + * linux/arch/arm/mach-omap/dsp/fifo.h + * + * FIFO buffer operators + * + * Copyright (C) 2002-2004 Nokia Corporation + * + * Written by Toshihiro Kobayashi + * + * 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 + * + * 2004/06/29: DSP Gateway version 3.1 + */ + +struct fifo_struct { + char *buf; + size_t sz; + size_t cnt; + unsigned int wp; +}; + +static inline int alloc_fifo(struct fifo_struct *fifo, size_t sz) +{ + if ((fifo->buf = kmalloc(sz, GFP_KERNEL)) == NULL) + return -ENOMEM; + fifo->sz = sz; + fifo->cnt = 0; + fifo->wp = 0; + return 0; +} + +static inline void free_fifo(struct fifo_struct *fifo) +{ + if (fifo->buf == NULL) + return; + + kfree(fifo->buf); + fifo->buf = NULL; + fifo->sz = 0; +} + +static inline void flush_fifo(struct fifo_struct *fifo) +{ + fifo->cnt = 0; + fifo->wp = 0; +} + +#define fifo_empty(fifo) ((fifo)->cnt == 0) + +static inline void write_word_to_fifo(struct fifo_struct *fifo, + unsigned short word) +{ + *(unsigned short *)&fifo->buf[fifo->wp] = word; + if ((fifo->wp += 2) == fifo->sz) + fifo->wp = 0; + if ((fifo->cnt += 2) > fifo->sz) + fifo->cnt = fifo->sz; +} + +/* + * (before) + * + * [*******----------*************] + * ^wp + * <----------------------------> sz = 30 + * <-----> <-----------> cnt = 20 + * + * (read: count=16) + * <-> <-----------> count = 16 + * <-----------> cnt1 = 13 + * ^rp + * + * (after) + * [---****-----------------------] + * ^wp + */ +static inline size_t copy_to_user_fm_fifo(char *dst, struct fifo_struct *fifo, + size_t count) +{ + int rp; + + /* fifo size can be zero */ + if (fifo->sz == 0) + return 0; + + if (count > fifo->cnt) + count = fifo->cnt; + + if ((rp = fifo->wp - fifo->cnt) >= 0) { + /* valid area is straight */ + if (copy_to_user(dst, &fifo->buf[rp], count)) + return -EFAULT; + } else { + int cnt1 = -rp; + rp += fifo->sz; + if (cnt1 >= count) { + /* requested area is straight */ + if (copy_to_user(dst, &fifo->buf[rp], count)) + return -EFAULT; + } else { + if (copy_to_user(dst, &fifo->buf[rp], cnt1)) + return -EFAULT; + if (copy_to_user(dst+cnt1, fifo->buf, count-cnt1)) + return -EFAULT; + } + } + fifo->cnt -= count; + + return count; +} diff -Nru a/arch/arm/mach-omap/dsp/hardware_dsp.h b/arch/arm/mach-omap/dsp/hardware_dsp.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/dsp/hardware_dsp.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,196 @@ +/* + * linux/arch/arm/mach-omap/dsp/hardware_dsp.h + * + * Register bit definitions for DSP driver + * + * Copyright (C) 2002-2004 Nokia Corporation + * + * Written by Toshihiro Kobayashi + * + * 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 + * + * 2004/09/30: DSP Gateway version 3.1 + */ + +#ifndef __OMAP_DSP_HARDWARE_DSP_H +#define __OMAP_DSP_HARDWARE_DSP_H + +/* + * MAJOR device number: !! allocated arbitrary !! + */ +#define OMAP_DSP_CTL_MAJOR 96 +#define OMAP_DSP_TASK_MAJOR 97 + +/* + * Reset Control + */ +#define ARM_RSTCT1_SW_RST 0x0008 +#define ARM_RSTCT1_DSP_RST 0x0004 +#define ARM_RSTCT1_DSP_EN 0x0002 +#define ARM_RSTCT1_ARM_RST 0x0001 + +/* + * MPUI + */ +#define MPUI_CTRL_WORDSWAP_MASK 0x00600000 +#define MPUI_CTRL_WORDSWAP_ALL 0x00000000 +#define MPUI_CTRL_WORDSWAP_NONAPI 0x00200000 +#define MPUI_CTRL_WORDSWAP_API 0x00400000 +#define MPUI_CTRL_WORDSWAP_NONE 0x00600000 +#define MPUI_CTRL_AP_MASK 0x001c0000 +#define MPUI_CTRL_AP_MDH 0x00000000 +#define MPUI_CTRL_AP_MHD 0x00040000 +#define MPUI_CTRL_AP_DMH 0x00080000 +#define MPUI_CTRL_AP_HMD 0x000c0000 +#define MPUI_CTRL_AP_DHM 0x00100000 +#define MPUI_CTRL_AP_HDM 0x00140000 +#define MPUI_CTRL_BYTESWAP_MASK 0x00030000 +#define MPUI_CTRL_BYTESWAP_NONE 0x00000000 +#define MPUI_CTRL_BYTESWAP_NONAPI 0x00010000 +#define MPUI_CTRL_BYTESWAP_ALL 0x00020000 +#define MPUI_CTRL_BYTESWAP_API 0x00030000 +#define MPUI_CTRL_TIMEOUT_MASK 0x0000ff00 +#define MPUI_CTRL_APIF_HNSTB_DIV_MASK 0x000000f0 +#define MPUI_CTRL_S_NABORT_GL 0x00000008 +#define MPUI_CTRL_S_NABORT_32BIT 0x00000004 +#define MPUI_CTRL_EN_TIMEOUT 0x00000002 +#define MPUI_CTRL_HF_MCUCLK 0x00000001 +#define MPUI_DSP_BOOT_CONFIG_DIRECT 0x00000000 +#define MPUI_DSP_BOOT_CONFIG_PSD_DIRECT 0x00000001 +#define MPUI_DSP_BOOT_CONFIG_IDLE 0x00000002 +#define MPUI_DSP_BOOT_CONFIG_DL16 0x00000003 +#define MPUI_DSP_BOOT_CONFIG_DL32 0x00000004 +#define MPUI_DSP_BOOT_CONFIG_MPUI 0x00000005 +#define MPUI_DSP_BOOT_CONFIG_INTERNAL 0x00000006 + +/* + * DSP boot mode + * direct: 0xffff00 + * pseudo direct: 0x080000 + * MPUI: branch 0x010000 + * internel: branch 0x024000 + */ +#define DSP_BOOT_ADR_DIRECT 0xffff00 +#define DSP_BOOT_ADR_PSD_DIRECT 0x080000 +#define DSP_BOOT_ADR_MPUI 0x010000 +#define DSP_BOOT_ADR_INTERNAL 0x024000 + +/* + * TC + */ +#define TC_ENDIANISM_SWAP 0x00000002 +#define TC_ENDIANISM_SWAP_WORD 0x00000002 +#define TC_ENDIANISM_SWAP_BYTE 0x00000000 +#define TC_ENDIANISM_EN 0x00000001 + +/* + * DSP MMU + */ +#define DSPMMU_BASE (0xfffed200) +#define DSPMMU_PREFETCH (DSPMMU_BASE + 0x00) +#define DSPMMU_WALKING_ST (DSPMMU_BASE + 0x04) +#define DSPMMU_CNTL (DSPMMU_BASE + 0x08) +#define DSPMMU_FAULT_AD_H (DSPMMU_BASE + 0x0c) +#define DSPMMU_FAULT_AD_L (DSPMMU_BASE + 0x10) +#define DSPMMU_FAULT_ST (DSPMMU_BASE + 0x14) +#define DSPMMU_IT_ACK (DSPMMU_BASE + 0x18) +#define DSPMMU_TTB_H (DSPMMU_BASE + 0x1c) +#define DSPMMU_TTB_L (DSPMMU_BASE + 0x20) +#define DSPMMU_LOCK (DSPMMU_BASE + 0x24) +#define DSPMMU_LD_TLB (DSPMMU_BASE + 0x28) +#define DSPMMU_CAM_H (DSPMMU_BASE + 0x2c) +#define DSPMMU_CAM_L (DSPMMU_BASE + 0x30) +#define DSPMMU_RAM_H (DSPMMU_BASE + 0x34) +#define DSPMMU_RAM_L (DSPMMU_BASE + 0x38) +#define DSPMMU_GFLUSH (DSPMMU_BASE + 0x3c) +#define DSPMMU_FLUSH_ENTRY (DSPMMU_BASE + 0x40) +#define DSPMMU_READ_CAM_H (DSPMMU_BASE + 0x44) +#define DSPMMU_READ_CAM_L (DSPMMU_BASE + 0x48) +#define DSPMMU_READ_RAM_H (DSPMMU_BASE + 0x4c) +#define DSPMMU_READ_RAM_L (DSPMMU_BASE + 0x50) + +#define DSPMMU_CNTL_BURST_16MNGT_EN 0x0020 +#define DSPMMU_CNTL_WTL_EN 0x0004 +#define DSPMMU_CNTL_MMU_EN 0x0002 +#define DSPMMU_CNTL_RESET_SW 0x0001 + +#define DSPMMU_FAULT_AD_H_DP 0x0100 +#define DSPMMU_FAULT_AD_H_ADR_MASK 0x00ff + +#define DSPMMU_FAULT_ST_PREF 0x0008 +#define DSPMMU_FAULT_ST_PERM 0x0004 +#define DSPMMU_FAULT_ST_TLB_MISS 0x0002 +#define DSPMMU_FAULT_ST_TRANS 0x0001 + +#define DSPMMU_IT_ACK_IT_ACK 0x0001 + +#define DSPMMU_LOCK_BASE_MASK 0xfc00 +#define DSPMMU_LOCK_BASE_SHIFT 10 +#define DSPMMU_LOCK_VICTIM_MASK 0x03f0 +#define DSPMMU_LOCK_VICTIM_SHIFT 4 + +#define DSPMMU_CAM_H_VA_TAG_H_MASK 0x0003 + +#define DSPMMU_CAM_L_VA_TAG_L1_MASK 0xc000 +#define DSPMMU_CAM_L_VA_TAG_L2_MASK_1MB 0x0000 +#define DSPMMU_CAM_L_VA_TAG_L2_MASK_64KB 0x3c00 +#define DSPMMU_CAM_L_VA_TAG_L2_MASK_4KB 0x3fc0 +#define DSPMMU_CAM_L_VA_TAG_L2_MASK_1KB 0x3ff0 +#define DSPMMU_CAM_L_P 0x0008 +#define DSPMMU_CAM_L_V 0x0004 +#define DSPMMU_CAM_L_SLST_MASK 0x0003 +#define DSPMMU_CAM_L_SLST_1MB 0x0000 +#define DSPMMU_CAM_L_SLST_64KB 0x0001 +#define DSPMMU_CAM_L_SLST_4KB 0x0002 +#define DSPMMU_CAM_L_SLST_1KB 0x0003 + +#define DSPMMU_RAM_L_RAM_LSB_MASK 0xfc00 +#define DSPMMU_RAM_L_AP_MASK 0x0300 +#define DSPMMU_RAM_L_AP_NA 0x0000 +#define DSPMMU_RAM_L_AP_RO 0x0200 +#define DSPMMU_RAM_L_AP_FA 0x0300 + +#define DSPMMU_GFLUSH_GFLUSH 0x0001 + +#define DSPMMU_FLUSH_ENTRY_FLUSH_ENTRY 0x0001 + +#define DSPMMU_LD_TLB_RD 0x0002 +#define DSPMMU_LD_TLB_LD 0x0001 + +/* + * Mailbox + */ +#define MAILBOX_BASE (0xfffcf000) +#define MAILBOX_ARM2DSP1 (MAILBOX_BASE + 0x00) +#define MAILBOX_ARM2DSP1b (MAILBOX_BASE + 0x04) +#define MAILBOX_DSP2ARM1 (MAILBOX_BASE + 0x08) +#define MAILBOX_DSP2ARM1b (MAILBOX_BASE + 0x0c) +#define MAILBOX_DSP2ARM2 (MAILBOX_BASE + 0x10) +#define MAILBOX_DSP2ARM2b (MAILBOX_BASE + 0x14) +#define MAILBOX_ARM2DSP1_Flag (MAILBOX_BASE + 0x18) +#define MAILBOX_DSP2ARM1_Flag (MAILBOX_BASE + 0x1c) +#define MAILBOX_DSP2ARM2_Flag (MAILBOX_BASE + 0x20) + +/* + * DSP ICR + */ +#define DSPREG_ICR_EMIF_IDLE_DOMAIN 0x0020 +#define DSPREG_ICR_DPLL_IDLE_DOMAIN 0x0010 +#define DSPREG_ICR_PER_IDLE_DOMAIN 0x0008 +#define DSPREG_ICR_CACHE_IDLE_DOMAIN 0x0004 +#define DSPREG_ICR_DMA_IDLE_DOMAIN 0x0002 +#define DSPREG_ICR_CPU_IDLE_DOMAIN 0x0001 + +#endif /* __OMAP_DSP_HARDWARE_DSP_H */ diff -Nru a/arch/arm/mach-omap/dsp/ipbuf.c b/arch/arm/mach-omap/dsp/ipbuf.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/dsp/ipbuf.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,324 @@ +/* + * linux/arch/arm/mach-omap/dsp/ipbuf.c + * + * IPBUF handler + * + * Copyright (C) 2002-2004 Nokia Corporation + * + * Written by Toshihiro Kobayashi + * + * 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 + * + * 2004/11/22: DSP Gateway version 3.1 + */ + +#include +#include +#include +#include +#include +#include +#include "dsp.h" +#include "ipbuf.h" + +struct ipbuf **ipbuf; +struct ipbcfg ipbcfg; +struct ipbuf_sys *ipbuf_sys_da, *ipbuf_sys_ad; +static struct ipblink ipb_free; + +void ipbuf_stop(void) +{ + ipbcfg.ln = 0; + if (ipbuf) { + kfree(ipbuf); + ipbuf = NULL; + } +} + +/* + * ipbuf_config() is called in interrupt context + */ +int ipbuf_config(unsigned short ln, unsigned short lsz, unsigned long adr) +{ + void *base; + unsigned long lsz_byte = ((unsigned long)lsz) << 1; + size_t size; + int ret = 0; + int i; + + INIT_IPBLINK(&ipb_free); + + /* + * global IPBUF + */ + if (adr & 0x1) { + printk(KERN_ERR + "mbx: global ipbuf address (0x%08lx) is odd number!\n", + adr); + return -EINVAL; + } + size = lsz_byte * ln; + if (adr + size > DSPSPACE_SIZE) { + printk(KERN_ERR + "mbx: ipbuf address (0x%08lx) and size (0x%08x) is " + "illegal!\n", adr, size); + return -EINVAL; + } + base = dspword_to_virt(adr); + ipbuf = kmalloc(sizeof(void *) * ln, GFP_KERNEL); + if (ipbuf == NULL) { + printk(KERN_ERR "mbx: memory allocation for ipbuf failed.\n"); + return -ENOMEM; + } + for (i = 0; i < ln; i++) { + void *top, *btm; + + top = base + (sizeof(struct ipbuf) + lsz_byte) * i; + btm = base + (sizeof(struct ipbuf) + lsz_byte) * (i+1) - 1; + ipbuf[i] = (struct ipbuf *)top; + if (((unsigned long)top & 0xfffe0000) != + ((unsigned long)btm & 0xfffe0000)) { + /* + * an ipbuf line should not cross + * 64k-word boundary. + */ + printk(KERN_ERR + "omapdsp: ipbuf[%d] crosses 64k-word boundary!\n" + " @0x%p, size=0x%08lx\n", i, top, lsz_byte); + ret = -EINVAL; + } + } + ipbcfg.ln = ln; + ipbcfg.lsz = lsz; + ipbcfg.adr = adr; + ipbcfg.bsycnt = ln; /* DSP holds all ipbufs initially. */ + ipbcfg.cnt_full = 0; + + printk(KERN_INFO + "omapdsp: IPBUF configuration\n" + " %d words * %d lines at 0x%p.\n", + ipbcfg.lsz, ipbcfg.ln, dspword_to_virt(ipbcfg.adr)); + + return ret; +} + +int is_ipbuf_internal_mem(void) +{ + return is_dspword_internal_mem(ipbcfg.adr); +} + +/* + * Global IPBUF operations + */ +unsigned short get_free_ipbuf(unsigned char tid) +{ + unsigned short bid; + + if (ipblink_empty(&ipb_free)) { + /* + * FIXME: wait on queue when not available, + * but note that balance_ipbuf() also uses this routine + * and in that case we should return immediately. + */ + return OMAP_DSP_BID_NULL; + } + + /* + * FIXME: dsp_enable_dspmem! + */ + preempt_disable(); + disable_irq(INT_D2A_MB1); + bid = ipb_free.top; + ipbuf[bid]->la = tid; /* lock */ + ipblink_del_top(&ipb_free, ipbuf); + enable_irq(INT_D2A_MB1); + preempt_enable(); + + return bid; +} + +void release_ipbuf(unsigned short bid) +{ + if (ipbuf[bid]->la == OMAP_DSP_TID_FREE) { + printk(KERN_WARNING + "omapdsp: attempt to release unlocked IPBUF[%d].\n", + bid); + /* + * FIXME: re-calc bsycnt + */ + return; + } + ipbuf[bid]->la = OMAP_DSP_TID_FREE; + ipbuf[bid]->sa = OMAP_DSP_TID_FREE; + preempt_disable(); + disable_irq(INT_D2A_MB1); + ipblink_add_tail(&ipb_free, bid, ipbuf); + enable_irq(INT_D2A_MB1); + preempt_enable(); +} + +static int try_yld(unsigned short bid, enum mbsend_type send_type) +{ + struct mbcmd mb; + int status; + + ipbuf[bid]->sa = OMAP_DSP_TID_ANON; + mbcmd_set(mb, MBCMD(BKYLD), 0, bid); + status = __dsp_mbsend(&mb, NULL, send_type); + if (status < 0) { + /* DSP is busy and ARM keeps this line. */ + release_ipbuf(bid); + return status; + } + + ipb_bsycnt_inc(&ipbcfg); + return 0; +} + +/* + * balancing ipbuf lines with DSP + */ +void balance_ipbuf(enum mbsend_type send_type) +{ + while (ipbcfg.bsycnt <= ipbcfg.ln / 4) { + unsigned short bid; + + bid = get_free_ipbuf(OMAP_DSP_TID_ANON); + if (bid == OMAP_DSP_BID_NULL) + return; + if (try_yld(bid, send_type) < 0) + return; + } +} + +/* + * interrupt routine should call this function with + * send_type = MBSEND_TYPE_NOWAIT + */ +void __unuse_ipbuf(unsigned short bid, enum mbsend_type send_type) +{ + if (ipbcfg.bsycnt > ipbcfg.ln / 4) { + release_ipbuf(bid); + return; + } + + /* try to return this line */ + ipbuf[bid]->la = OMAP_DSP_TID_ANON; + if (try_yld(bid, send_type) < 0) + return; + + if (send_type != MBSEND_TYPE_NOWAIT) + balance_ipbuf(send_type); +} + +/* + * functions called from mailbox1 interrupt routine + */ + +void mbx1_err_ipbfull(void) +{ + ipbcfg.cnt_full++; +} + +#ifdef CONFIG_PROC_FS +/* + * proc file entry + */ + +static int ipbuf_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + char *out; + int len; + unsigned short bid; + + /* + * disable process's old pmd entry + */ + dsp_map_update(current); + dsp_cur_users_add(current); + + out = page; + for (bid = 0; bid < ipbcfg.ln; bid++) { + unsigned short la = ipbuf[bid]->la; + unsigned short ld = ipbuf[bid]->ld; + unsigned short c = ipbuf[bid]->c; + + out += sprintf(out, "ipbuf[%d]: adr = 0x%p\n", bid, ipbuf[bid]); + if (la == OMAP_DSP_TID_FREE) { + out += sprintf(out, + " DSPtask[%d]->Linux " + "(already read and now free for Linux)\n", + ld); + } else if (ld == OMAP_DSP_TID_FREE) { + out += sprintf(out, + " Linux->DSPtask[%d] " + "(already read and now free for DSP)\n", + la); + } else if (ipbuf_is_held(ld, bid)) { + out += sprintf(out, + " DSPtask[%d]->Linux " + "(waiting to be read)\n" + " count = %d\n", ld, c); + } else { + out += sprintf(out, + " Linux->DSPtask[%d] " + "(waiting to be read)\n" + " count = %d\n", la, c); + } + } + + out += sprintf(out, "\nFree IPBUF link: "); + preempt_disable(); + ipblink_for_each(bid, &ipb_free, ipbuf) { + out += sprintf(out, "%d ", bid); + } + preempt_enable(); + out += sprintf(out, "\n"); + out += sprintf(out, "IPBFULL error count: %ld\n", ipbcfg.cnt_full); + + len = out - page - off; + if (len < count) { + *eof = 1; + if (len <= 0) { + len = 0; + goto finish; + } + } else + len = count; + *start = page + off; + +finish: + dsp_cur_users_del(current); + return len; +} + +void dsp_create_ipbuf_proc(void) +{ + struct proc_dir_entry *ent; + + ent = create_proc_read_entry("ipbuf", 0, procdir_dsp, ipbuf_read_proc, + NULL); + if (ent == NULL) { + printk(KERN_ERR + "omapdsp: failed to register proc device: ipbuf\n"); + } +} + +void dsp_remove_ipbuf_proc(void) +{ + remove_proc_entry("ipbuf", procdir_dsp); +} +#endif /* CONFIG_PROC_FS */ diff -Nru a/arch/arm/mach-omap/dsp/ipbuf.h b/arch/arm/mach-omap/dsp/ipbuf.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/dsp/ipbuf.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,119 @@ +/* + * linux/arch/arm/mach-omap/dsp/ipbuf.h + * + * Header for IPBUF + * + * Copyright (C) 2002-2004 Nokia Corporation + * + * Written by Toshihiro Kobayashi + * + * 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 + * + * 2004/06/29: DSP Gateway version 3.1 + */ + +struct ipbuf { + unsigned short c; /* count */ + unsigned short next; /* link */ + unsigned short la; /* lock owner (ARM side) */ + unsigned short sa; /* sync word (ARM->DSP) */ + unsigned short ld; /* lock owner (DSP side) */ + unsigned short sd; /* sync word (DSP->ARM) */ + unsigned char d[0]; /* data */ +}; + +struct ipbuf_p { + unsigned short c; /* count */ + unsigned short s; /* sync word */ + unsigned short al; /* data address lower */ + unsigned short ah; /* data address upper */ +}; + +struct ipbuf_sys { + unsigned short s; /* sync word */ + unsigned short d[15]; /* data */ +}; + +struct ipbcfg { + unsigned short ln; + unsigned short lsz; + unsigned long adr; + unsigned short bsycnt; + unsigned long cnt_full; /* count of IPBFULL error */ +}; + +#define ipb_bsycnt_inc(ipbcfg) \ + do { \ + disable_irq(INT_D2A_MB1); \ + (ipbcfg)->bsycnt++; \ + enable_irq(INT_D2A_MB1); \ + } while(0) + +#define ipb_bsycnt_dec(ipbcfg) \ + do { \ + disable_irq(INT_D2A_MB1); \ + (ipbcfg)->bsycnt--; \ + enable_irq(INT_D2A_MB1); \ + } while(0) + +struct ipblink { + unsigned short top; + unsigned short tail; +}; + +#define INIT_IPBLINK(link) \ + do { \ + (link)->top = OMAP_DSP_BID_NULL; \ + (link)->tail = OMAP_DSP_BID_NULL; \ + } while(0) + +#define ipblink_empty(link) ((link)->top == OMAP_DSP_BID_NULL) + +static __inline__ void ipblink_del_top(struct ipblink *link, + struct ipbuf **ipbuf) +{ + struct ipbuf *bufp = ipbuf[link->top]; + + if ((link->top = bufp->next) == OMAP_DSP_BID_NULL) + link->tail = OMAP_DSP_BID_NULL; + else + bufp->next = OMAP_DSP_BID_NULL; +} + +static __inline__ void ipblink_add_tail(struct ipblink *link, + unsigned short bid, + struct ipbuf **ipbuf) +{ + if (ipblink_empty(link)) + link->top = bid; + else + ipbuf[link->tail]->next = bid; + link->tail = bid; +} + +static __inline__ void ipblink_add_pvt(struct ipblink *link) +{ + link->top = OMAP_DSP_BID_PVT; + link->tail = OMAP_DSP_BID_PVT; +} + +static __inline__ void ipblink_del_pvt(struct ipblink *link) +{ + link->top = OMAP_DSP_BID_NULL; + link->tail = OMAP_DSP_BID_NULL; +} + +#define ipblink_for_each(bid, link, ipbuf) \ + for (bid = (link)->top; bid != OMAP_DSP_BID_NULL; bid = ipbuf[bid]->next) diff -Nru a/arch/arm/mach-omap/dsp/mblog.c b/arch/arm/mach-omap/dsp/mblog.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/dsp/mblog.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,300 @@ +/* + * linux/arch/arm/mach-omap/dsp/mblog.c + * + * OMAP DSP driver Mailbox log module + * + * Copyright (C) 2003,2004 Nokia Corporation + * + * Written by Toshihiro Kobayashi + * + * 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 + * + * 2004/11/18: DSP Gateway version 3.1 + */ + +#include +#include +#include +#include +#include +#include +#include "dsp.h" + +#define RLCMD(nm) OMAP_DSP_MBCMD_RUNLEVEL_##nm +#define PMCMD(nm) OMAP_DSP_MBCMD_PM_##nm +#define CFGCMD(nm) OMAP_DSP_MBCMD_DSPCFG_##nm +#define REGCMD(nm) OMAP_DSP_MBCMD_REGRW_##nm +#define VICMD(nm) OMAP_DSP_MBCMD_VARID_##nm +#define EID(nm) OMAP_DSP_EID_##nm + +char *subcmd_name(struct mbcmd *mb) +{ + unsigned char cmd_h = mb->cmd_h; + unsigned char cmd_l = mb->cmd_l; + char *s; + + switch (cmd_h) { + case MBCMD(RUNLEVEL): + s = (cmd_l == RLCMD(USER)) ? "USER": + (cmd_l == RLCMD(SUPER)) ? "SUPER": + (cmd_l == RLCMD(RECOVERY)) ? "RECOVERY": + NULL; + break; + case MBCMD(PM): + s = (cmd_l == PMCMD(DISABLE)) ? "DISABLE": + (cmd_l == PMCMD(ENABLE)) ? "ENABLE": + NULL; + break; + case MBCMD(DSPCFG): + { + unsigned char cfgc = cmd_l & 0x7f; + s = (cfgc == CFGCMD(REQ)) ? "REQ": + (cfgc == CFGCMD(SYSADRH)) ? "SYSADRH": + (cfgc == CFGCMD(SYSADRL)) ? "SYSADRL": + (cfgc == CFGCMD(ABORT)) ? "ABORT": + (cfgc == CFGCMD(PROTREV)) ? "PROTREV": + NULL; + break; + } + case MBCMD(REGRW): + s = (cmd_l == REGCMD(MEMR)) ? "MEMR": + (cmd_l == REGCMD(MEMW)) ? "MEMW": + (cmd_l == REGCMD(IOR)) ? "IOR": + (cmd_l == REGCMD(IOW)) ? "IOW": + (cmd_l == REGCMD(DATA)) ? "DATA": + NULL; + break; + case MBCMD(GETVAR): + case MBCMD(SETVAR): + s = (cmd_l == VICMD(ICRMASK)) ? "ICRMASK": + (cmd_l == VICMD(LOADINFO)) ? "LOADINFO": + NULL; + break; + case MBCMD(ERR): + s = (cmd_l == EID(BADTID)) ? "BADTID": + (cmd_l == EID(BADTCN)) ? "BADTCN": + (cmd_l == EID(BADBID)) ? "BADBID": + (cmd_l == EID(BADCNT)) ? "BADCNT": + (cmd_l == EID(NOTLOCKED)) ? "NOTLOCKED": + (cmd_l == EID(STVBUF)) ? "STVBUF": + (cmd_l == EID(BADADR)) ? "BADADR": + (cmd_l == EID(BADTCTL)) ? "BADTCTL": + (cmd_l == EID(BADPARAM)) ? "BADPARAM": + (cmd_l == EID(FATAL)) ? "FATAL": + (cmd_l == EID(NOMEM)) ? "NOMEM": + (cmd_l == EID(NORES)) ? "NORES": + (cmd_l == EID(IPBFULL)) ? "IPBFULL": + (cmd_l == EID(TASKNOTRDY)) ? "TASKNOTRDY": + (cmd_l == EID(TASKBSY)) ? "TASKBSY": + (cmd_l == EID(TASKERR)) ? "TASKERR": + (cmd_l == EID(BADCFGTYP)) ? "BADCFGTYP": + (cmd_l == EID(DEBUG)) ? "DEBUG": + (cmd_l == EID(BADSEQ)) ? "BADSEQ": + (cmd_l == EID(BADCMD)) ? "BADCMD": + NULL; + break; + default: + s = NULL; + } + + return s; +} + +#define MBLOG_DEPTH 256 + +struct mblogent { + unsigned long jiffies; + unsigned short cmd; + unsigned short data; + enum mblog_dir dir; +}; + +static struct { + int wp; + unsigned long cnt, cnt_ad, cnt_da; + struct mblogent ent[MBLOG_DEPTH]; +} mblog; + +void mblog_add(struct mbcmd *mb, enum mblog_dir dir) +{ + struct mbcmd_hw *mb_hw = (struct mbcmd_hw *)mb; + struct mblogent *ent; + + disable_irq(INT_D2A_MB1); + ent = &mblog.ent[mblog.wp]; + ent->jiffies = jiffies; + ent->cmd = mb_hw->cmd; + ent->data = mb_hw->data; + ent->dir = dir; + if (mblog.cnt < 0xffffffff) + mblog.cnt++; + switch (dir) { + case MBLOG_DIR_AD: + if (mblog.cnt_ad < 0xffffffff) + mblog.cnt_ad++; + break; + case MBLOG_DIR_DA: + if (mblog.cnt_da < 0xffffffff) + mblog.cnt_da++; + break; + } + if (++mblog.wp == MBLOG_DEPTH) + mblog.wp = 0; + enable_irq(INT_D2A_MB1); +} + +#ifdef CONFIG_PROC_FS +static int mblog_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int len = 0; + off_t begin = 0; + int wp; + int i; + + disable_irq(INT_D2A_MB1); + + wp = mblog.wp; + len += sprintf(page, + "log count:%ld / ARM->DSP:%ld, DSP->ARM:%ld\n", + mblog.cnt, mblog.cnt_ad, mblog.cnt_da); + if (mblog.cnt == 0) + goto done; + + len += sprintf(page + len, " ARM->DSP ARM<-DSP\n"); + len += sprintf(page + len, "jiffies cmd data cmd data\n"); + i = (mblog.cnt >= MBLOG_DEPTH) ? wp : 0; + do { + struct mblogent *ent = &mblog.ent[i]; + union { + struct mbcmd sw; + struct mbcmd_hw hw; + } mb = { + .hw.cmd = ent->cmd, + .hw.data = ent->data + }; + char *subname; + const struct cmdinfo *ci = cmdinfo[mb.sw.cmd_h]; + + len += sprintf(page + len, + (ent->dir == MBLOG_DIR_AD) ? + "%08lx %04x %04x seq=%d": + "%08lx %04x %04x seq=%d", + ent->jiffies, ent->cmd, ent->data, mb.sw.seq); + switch (ci->cmd_l_type) { + case CMD_L_TYPE_SUBCMD: + if ((subname = subcmd_name(&mb.sw)) == NULL) + subname = "Unknown"; + len += sprintf(page + len, " %s:%s\n", + ci->name, subname); + break; + case CMD_L_TYPE_TID: + len += sprintf(page + len, " %s:task %d\n", + ci->name, mb.sw.cmd_l); + break; + case CMD_L_TYPE_NULL: + len += sprintf(page + len, " %s\n", ci->name); + break; + } + + if (len + begin > off + count) + break; + if (len + begin < off) { + begin += len; + len = 0; + } + + if (++i == MBLOG_DEPTH) + i = 0; + } while (i != wp); + +done: + enable_irq(INT_D2A_MB1); + len -= off - begin; + if (len < count) { + *eof = 1; + if (len <= 0) + return 0; + } else + len = count; + *start = page + (off - begin); + + return len; +} + +static void __init mblog_create_proc(void) +{ + struct proc_dir_entry *ent; + + ent = create_proc_read_entry("mblog", 0, procdir_dsp, mblog_read_proc, + NULL); + if (ent == NULL) { + printk(KERN_ERR + "omapdsp: failed to register proc device: mblog\n"); + } +} + +static void mblog_remove_proc(void) +{ + remove_proc_entry("mblog", procdir_dsp); +} +#endif /* CONFIG_PROC_FS */ + +#ifdef CONFIG_OMAP_DSP_MBCMD_VERBOSE +void mblog_printcmd(struct mbcmd *mb, enum mblog_dir dir) +{ + const struct cmdinfo *ci = cmdinfo[mb->cmd_h]; + char *dir_str; + char *subname; + + dir_str = (dir == MBLOG_DIR_AD) ? "sending" : "receiving"; + switch (ci->cmd_l_type) { + case CMD_L_TYPE_SUBCMD: + if ((subname = subcmd_name(mb)) == NULL) + subname = "Unknown"; + printk(KERN_DEBUG + "mbx: %s seq=%d, cmd=%02x:%02x(%s:%s), data=%04x\n", + dir_str, mb->seq, mb->cmd_h, mb->cmd_l, + ci->name, subname, mb->data); + break; + case CMD_L_TYPE_TID: + printk(KERN_DEBUG + "mbx: %s seq=%d, cmd=%02x:%02x(%s:task %d), data=%04x\n", + dir_str, mb->seq, mb->cmd_h, mb->cmd_l, + ci->name, mb->cmd_l, mb->data); + break; + case CMD_L_TYPE_NULL: + printk(KERN_DEBUG + "mbx: %s seq=%d, cmd=%02x:%02x(%s), data=%04x\n", + dir_str, mb->seq, mb->cmd_h, mb->cmd_l, + ci->name, mb->data); + break; + } +} +#endif /* CONFIG_OMAP_DSP_MBCMD_VERBOSE */ + +void __init mblog_init(void) +{ +#ifdef CONFIG_PROC_FS + mblog_create_proc(); +#endif +} + +void mblog_exit(void) +{ +#ifdef CONFIG_PROC_FS + mblog_remove_proc(); +#endif +} diff -Nru a/arch/arm/mach-omap/dsp/proclist.h b/arch/arm/mach-omap/dsp/proclist.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/dsp/proclist.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,84 @@ +/* + * linux/arch/arm/mach-omap/dsp/proclist.h + * + * Linux task list handler + * + * Copyright (C) 2004 Nokia Corporation + * + * Written by Toshihiro Kobayashi + * + * 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 + * + * 2004/11/22: DSP Gateway version 3.1 + */ + +struct proc_list { + struct list_head list_head; + struct task_struct *tsk; + unsigned int cnt; +}; + +static __inline__ void proc_list_add(struct list_head *list, + struct task_struct *tsk) +{ + struct list_head *ptr; + struct proc_list *pl; + struct proc_list *new; + + list_for_each(ptr, list) { + pl = list_entry(ptr, struct proc_list, list_head); + if (pl->tsk == tsk) { + /* + * this process has opened DSP devices multi time + */ + pl->cnt++; + return; + } + } + + new = kmalloc(sizeof(struct proc_list), GFP_KERNEL); + new->tsk = tsk; + new->cnt = 1; + list_add_tail(&new->list_head, list); +} + +static __inline__ void proc_list_del(struct list_head *list, + struct task_struct *tsk) +{ + struct list_head *ptr; + struct proc_list *pl; + + list_for_each(ptr, list) { + pl = list_entry(ptr, struct proc_list, list_head); + if (pl->tsk == tsk) { + if (--pl->cnt == 0) { + list_del(&pl->list_head); + kfree(pl); + } + return; + } + } +} + +static __inline__ void proc_list_flush(struct list_head *list) +{ + struct proc_list *pl; + + while (!list_empty(list)) { + pl = list_entry(list->next, struct proc_list, list_head); + list_del(&pl->list_head); + kfree(pl); + } +} diff -Nru a/arch/arm/mach-omap/dsp/task.c b/arch/arm/mach-omap/dsp/task.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/dsp/task.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,2658 @@ +/* + * linux/arch/arm/mach-omap/dsp/task.c + * + * OMAP DSP task device driver + * + * Copyright (C) 2002-2004 Nokia Corporation + * + * Written by Toshihiro Kobayashi + * mmap function by Hiroo Ishikawa + * + * 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 + * + * 2005/02/08: DSP Gateway version 3.1 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "uaccess_dsp.h" +#include "dsp.h" +#include "ipbuf.h" +#include "fifo.h" +#include "proclist.h" + +/* + * device state machine + * NOTASK: task is not attached. + * ATTACHED: task is attached. + * GARBAGE: task is detached. waiting for all processes to close this device. + * ADDREQ: requesting for tadd + * DELREQ: requesting for tdel. no process is opening this device. + * KILLREQ: requesting for tkill. + * ADDFAIL: tadd failed. + */ + +struct taskdev { + long state; + spinlock_t state_lock; + wait_queue_head_t state_wait_q; + unsigned int usecount; + char name[OMAP_DSP_TNM_LEN]; + struct file_operations fops; + struct list_head proc_list; + struct dsptask *task; + struct proc_dir_entry *procent_dir; + + /* read stuff */ + wait_queue_head_t read_wait_q; + struct semaphore read_sem; + + /* write stuff */ + wait_queue_head_t write_wait_q; + struct semaphore write_sem; + + /* ioctl stuff */ + wait_queue_head_t ioctl_wait_q; + struct semaphore ioctl_sem; + + /* device lock */ + struct semaphore lock_sem; + pid_t lock_pid; +}; + +struct rcvdt_bk_struct { + struct ipblink link; + unsigned int rp; + struct ipbuf_p *ipbuf_pvt_r; +}; + +struct dsptask { + enum { + TASK_STATE_ERR = 0, + TASK_STATE_READY, + TASK_STATE_CFGREQ + } state; + unsigned char tid; + char name[OMAP_DSP_TNM_LEN]; + unsigned short ttyp; + struct taskdev *dev; + + /* read stuff */ + union { + struct fifo_struct fifo; /* for active word */ + struct rcvdt_bk_struct bk; + } rcvdt; + + /* write stuff */ + size_t wsz; + struct ipbuf_p *ipbuf_pvt_w; /* for private block */ + + /* tctl stuff */ + int tctl_stat; + + /* mmap stuff */ + void *map_base; + size_t map_length; +}; + +#define sndtyp_acv(ttyp) ((ttyp) & OMAP_DSP_TTYP_ASND) +#define sndtyp_psv(ttyp) (!((ttyp) & OMAP_DSP_TTYP_ASND)) +#define sndtyp_bk(ttyp) ((ttyp) & OMAP_DSP_TTYP_BKDM) +#define sndtyp_wd(ttyp) (!((ttyp) & OMAP_DSP_TTYP_BKDM)) +#define sndtyp_pvt(ttyp) ((ttyp) & OMAP_DSP_TTYP_PVDM) +#define sndtyp_gbl(ttyp) (!((ttyp) & OMAP_DSP_TTYP_PVDM)) +#define rcvtyp_acv(ttyp) ((ttyp) & OMAP_DSP_TTYP_ARCV) +#define rcvtyp_psv(ttyp) (!((ttyp) & OMAP_DSP_TTYP_ARCV)) +#define rcvtyp_bk(ttyp) ((ttyp) & OMAP_DSP_TTYP_BKMD) +#define rcvtyp_wd(ttyp) (!((ttyp) & OMAP_DSP_TTYP_BKMD)) +#define rcvtyp_pvt(ttyp) ((ttyp) & OMAP_DSP_TTYP_PVMD) +#define rcvtyp_gbl(ttyp) (!((ttyp) & OMAP_DSP_TTYP_PVMD)) + +static int dsp_rmdev_minor(unsigned char minor); +static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor); +static void taskdev_delete(unsigned char minor); +static void taskdev_attach_task(struct taskdev *dev, struct dsptask *task); +static void taskdev_detach_task(struct taskdev *dev); + +#ifdef CONFIG_PROC_FS +static void taskdev_create_proc(struct taskdev *dev); +static void taskdev_remove_proc(struct taskdev *dev); +#endif + +static struct taskdev *taskdev[TASKDEV_MAX]; +static struct dsptask *dsptask[TASKDEV_MAX]; +static DECLARE_MUTEX(cfg_sem); +static unsigned short cfg_cmd; +static unsigned char cfg_tid; +static DECLARE_WAIT_QUEUE_HEAD(cfg_wait_q); +static unsigned char n_task; +static void *heap; +#ifdef CONFIG_PROC_FS +struct proc_dir_entry *procdir_dsp_task; +#endif + +#define devstate_lock(dev, devstate) devstate_lock_timeout(dev, devstate, 0) + +/* + * devstate_lock_timeout(): + * when called with timeout > 0, dev->state can be diffeent from what you want. + */ +static int devstate_lock_timeout(struct taskdev *dev, long devstate, + int timeout) +{ + DECLARE_WAITQUEUE(wait, current); + long current_state = current->state; + int ret = 0; + + spin_lock(&dev->state_lock); + add_wait_queue(&dev->state_wait_q, &wait); + while (!(dev->state & devstate)) { + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock(&dev->state_lock); + if (timeout) { + if ((timeout = schedule_timeout(timeout)) == 0) { + /* timeout */ + spin_lock(&dev->state_lock); + break; + } + } + else + schedule(); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + spin_lock(&dev->state_lock); + } + remove_wait_queue(&dev->state_wait_q, &wait); + set_current_state(current_state); + return ret; +} + +static __inline__ void devstate_unlock(struct taskdev *dev) +{ + spin_unlock(&dev->state_lock); +} + +static __inline__ int down_tasksem_interruptible(struct taskdev *dev, + struct semaphore *sem) +{ + int ret; + + if (dev->lock_pid == current->pid) { + /* this process has lock */ + ret = down_interruptible(sem); + } else { + if ((ret = down_interruptible(&dev->lock_sem)) != 0) + return ret; + ret = down_interruptible(sem); + up(&dev->lock_sem); + } + return ret; +} + +static int dsp_task_flush_buf(struct dsptask *task) +{ + unsigned short ttyp = task->ttyp; + + preempt_disable(); + if (sndtyp_wd(ttyp)) { + /* word receiving */ + flush_fifo(&task->rcvdt.fifo); + } else { + /* block receiving */ + struct rcvdt_bk_struct *rcvdt = &task->rcvdt.bk; + + if (sndtyp_gbl(ttyp)) { + /* global IPBUF */ + while (!ipblink_empty(&rcvdt->link)) { + unsigned short bid = rcvdt->link.top; + disable_irq(INT_D2A_MB1); + ipblink_del_top(&rcvdt->link, ipbuf); + enable_irq(INT_D2A_MB1); + unuse_ipbuf(bid); + } + } else { + /* private IPBUF */ + if (!ipblink_empty(&rcvdt->link)) { + ipblink_del_pvt(&rcvdt->link); + release_ipbuf_pvt(rcvdt->ipbuf_pvt_r); + } + } + } + preempt_enable(); + + return 0; +} + +static int dsp_task_set_fifosz(struct dsptask *task, unsigned long sz) +{ + unsigned short ttyp = task->ttyp; + struct fifo_struct *fifo = &task->rcvdt.fifo; + int stat; + + if (!(sndtyp_wd(ttyp) && sndtyp_acv(ttyp))) { + printk(KERN_ERR + "omapdsp: buffer size can be changed only for " + "active word sending task.\n"); + return -EINVAL; + } + if (sz == 0) { + printk(KERN_ERR "omapdsp: buffer size shouldn't be zero!\n"); + return -EINVAL; + } + preempt_disable(); + if (!fifo_empty(fifo)) { + printk(KERN_ERR "omapdsp: buffer is not empty!\n"); + preempt_enable(); + return -EINVAL; + } + if (sz & 0x1) { + /* force even value */ + sz++; + } + + free_fifo(fifo); + stat = alloc_fifo(fifo, sz); + preempt_enable(); + if (stat < 0) { + printk(KERN_ERR + "omapdsp: unable to change receive buffer size. " + "(%ld bytes for %s)\n", sz, task->name); + return -ENOMEM; + } + + return 0; +} + +static int taskdev_lock(struct taskdev *dev) +{ + if (down_interruptible(&dev->lock_sem)) + return -ERESTARTSYS; + dev->lock_pid = current->pid; + return 0; +} + +static int taskdev_unlock(struct taskdev *dev) +{ + if (dev->lock_pid != current->pid) { + printk(KERN_ERR + "omapdsp: an illegal process attempted to " + "unlock the dsptask lock!\n"); + return -EINVAL; + } + dev->lock_pid = 0; + up(&dev->lock_sem); + return 0; +} + +static int dsp_task_config(struct dsptask *task, unsigned char tid) +{ + unsigned short ttyp; + struct mbcmd mb; + + dsptask[tid] = task; + task->tid = tid; + + /* TCFG request */ + task->state = TASK_STATE_CFGREQ; + if (down_interruptible(&cfg_sem)) + return -ERESTARTSYS; + cfg_cmd = MBCMD(TCFG); + mbcmd_set(mb, MBCMD(TCFG), tid, 0); + dsp_mbsend_and_wait(&mb, &cfg_wait_q); + cfg_cmd = 0; + up(&cfg_sem); + + if (task->state != TASK_STATE_READY) { + printk(KERN_ERR "omapdsp: task %d configuration error!\n", tid); + return -EINVAL; + } + + if (strlen(task->name) <= 1) + sprintf(task->name, "%d", tid); + printk(KERN_INFO "omapdsp: task %d: name %s\n", tid, task->name); + + ttyp = task->ttyp; + + /* task type check */ + if (rcvtyp_psv(ttyp) && rcvtyp_pvt(ttyp)) { + printk(KERN_ERR "mbx: illegal task type(0x%04x), tid=%d\n", + tid, ttyp); + } + + /* private buffer address check */ + if (sndtyp_pvt(ttyp)) { + void *p = task->rcvdt.bk.ipbuf_pvt_r; + + if ((unsigned long)p & 0x1) { + printk(KERN_ERR + "mbx: private ipbuf (DSP->ARM) address (0x%p) " + "is odd number!\n", p); + return -EINVAL; + } + } + + if (rcvtyp_pvt(ttyp)) { + void *p = task->ipbuf_pvt_w; + + if ((unsigned long)p & 0x1) { + printk(KERN_ERR + "mbx: private ipbuf (ARM->DSP) address (0x%p) " + "is odd number!\n", p); + return -EINVAL; + } + } + + /* read initialization */ + if (sndtyp_wd(ttyp)) { + /* word */ + size_t fifosz; + + fifosz = sndtyp_psv(ttyp) ? 2 : /* passive */ + 32; /* active */ + if (alloc_fifo(&task->rcvdt.fifo, fifosz) < 0) { + printk(KERN_ERR + "omapdsp: unable to allocate receive buffer. " + "(%d bytes for %s)\n", fifosz, task->name); + return -ENOMEM; + } + } else { + /* block */ + INIT_IPBLINK(&task->rcvdt.bk.link); + task->rcvdt.bk.rp = 0; + } + + /* write initialization */ + task->wsz = rcvtyp_acv(ttyp) ? 0 : /* active */ + rcvtyp_wd(ttyp) ? 2 : /* passive word */ + ipbcfg.lsz*2; /* passive block */ + + return 0; +} + +static void dsp_task_init(struct dsptask *task) +{ + struct mbcmd mb; + + mbcmd_set(mb, MBCMD(TCTL), task->tid, OMAP_DSP_MBCMD_TCTL_TINIT); + dsp_mbsend(&mb); +} + +int dsp_task_config_all(unsigned char n) +{ + int i, ret; + struct taskdev *devheap; + struct dsptask *taskheap; + size_t devheapsz, taskheapsz; + + memset(taskdev, 0, sizeof(void *) * TASKDEV_MAX); + memset(dsptask, 0, sizeof(void *) * TASKDEV_MAX); + + n_task = n; + printk(KERN_INFO "omapdsp: found %d task(s)\n", n_task); + if (n_task == 0) + return 0; + + /* + * reducing kmalloc! + */ + devheapsz = sizeof(struct taskdev) * n_task; + taskheapsz = sizeof(struct dsptask) * n_task; + heap = kmalloc(devheapsz + taskheapsz, GFP_KERNEL); + if (heap == NULL) { + n_task = 0; + return -ENOMEM; + } + memset(heap, 0, devheapsz + taskheapsz); + devheap = heap; + taskheap = heap + devheapsz; + + for (i = 0; i < n_task; i++) { + struct taskdev *dev = &devheap[i]; + struct dsptask *task = &taskheap[i]; + + if ((ret = dsp_task_config(task, i)) < 0) + return ret; + if ((ret = taskdev_init(dev, task->name, i)) < 0) + return ret; + taskdev_attach_task(dev, task); + dsp_task_init(task); + printk(KERN_INFO "omapdsp: taskdev %s enabled.\n", dev->name); + } + + return 0; +} + +static void dsp_task_unconfig(struct dsptask *task) +{ + unsigned char tid = task->tid; + + preempt_disable(); + dsp_task_flush_buf(task); + if (sndtyp_wd(task->ttyp) && (task->state == TASK_STATE_READY)) + free_fifo(&task->rcvdt.fifo); + dsptask[tid] = NULL; + preempt_enable(); +} + +void dsp_task_unconfig_all(void) +{ + unsigned char minor; + unsigned char tid; + struct dsptask *task; + + for (minor = 0; minor < n_task; minor++) { + /* + * taskdev[minor] can be NULL in case of + * configuration failure + */ + if (taskdev[minor]) + taskdev_delete(minor); + } + for (; minor < TASKDEV_MAX; minor++) { + if (taskdev[minor]) + dsp_rmdev_minor(minor); + } + + for (tid = 0; tid < n_task; tid++) { + /* + * dsptask[tid] can be NULL in case of + * configuration failure + */ + task = dsptask[tid]; + if (task) + dsp_task_unconfig(task); + } + for (; tid < TASKDEV_MAX; tid++) { + task = dsptask[tid]; + if (task) { + /* + * on-demand tasks should be deleted in + * rmdev_minor(), but just in case. + */ + dsp_task_unconfig(task); + kfree(task); + } + } + + if (heap) { + kfree(heap); + heap = NULL; + } + + n_task = 0; +} + +unsigned char dsp_task_count(void) +{ + return n_task; +} + +int dsp_taskmod_busy(void) +{ + struct taskdev *dev; + unsigned char minor; + + for (minor = 0; minor < TASKDEV_MAX; minor++) { + dev = taskdev[minor]; + if (dev && + ((dev->usecount > 0) || + (dev->state == OMAP_DSP_DEVSTATE_ADDREQ) || + (dev->state == OMAP_DSP_DEVSTATE_DELREQ))) + return 1; + } + return 0; +} + +/* + * DSP task device file operations + */ +static ssize_t dsp_task_read_wd_acv(struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); + struct taskdev *dev = taskdev[minor]; + int have_devstate_lock = 0; + int ret = 0; + + if (count == 0) { + return 0; + } else if (count == 1) { + printk(KERN_ERR + "omapdsp: count=1 is illegal for dsp_task_read().\n"); + return -EINVAL; + } else if (count & 0x1) { + /* force even value */ + count--; + } + + if (down_tasksem_interruptible(dev, &dev->read_sem)) + return -ERESTARTSYS; + if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { + ret = -ERESTARTSYS; + goto up_out; + } + have_devstate_lock = 1; + + if (fifo_empty(&dev->task->rcvdt.fifo)) { + long current_state = current->state; + DECLARE_WAITQUEUE(wait, current); + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&dev->read_wait_q, &wait); + if (fifo_empty(&dev->task->rcvdt.fifo)) { /* last check */ + devstate_unlock(dev); + have_devstate_lock = 0; + schedule(); + } + set_current_state(current_state); + remove_wait_queue(&dev->read_wait_q, &wait); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + goto up_out; + } + if (!have_devstate_lock) { + if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { + ret = -ERESTARTSYS; + goto up_out; + } + have_devstate_lock = 1; + } + if (fifo_empty(&dev->task->rcvdt.fifo)) /* should not occur */ + goto up_out; + } + + /* data protection while copying */ + disable_irq(INT_D2A_MB1); + ret = copy_to_user_fm_fifo(buf, &dev->task->rcvdt.fifo, count); + enable_irq(INT_D2A_MB1); + +up_out: + if (have_devstate_lock) + devstate_unlock(dev); + up(&dev->read_sem); + return ret; +} + +static ssize_t dsp_task_read_bk_acv(struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); + struct taskdev *dev = taskdev[minor]; + struct rcvdt_bk_struct *rcvdt; + int dspmem_access = 0; + int have_devstate_lock = 0; + ssize_t ret = 0; + + if (count == 0) { + return 0; + } else if (count == 1) { + printk(KERN_ERR + "omapdsp: count=1 is illegal for dsp_task_read().\n"); + return -EINVAL; + } else if ((int)buf & 0x1) { + printk(KERN_ERR + "omapdsp: buf should be word aligned for " + "dsp_task_read().\n"); + return -EINVAL; + } else if (count & 0x1) { + /* force even value */ + count--; + } + + if (down_tasksem_interruptible(dev, &dev->read_sem)) + return -ERESTARTSYS; + if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { + ret = -ERESTARTSYS; + goto up_out; + } + have_devstate_lock = 1; + + if (ipblink_empty(&dev->task->rcvdt.bk.link)) { + long current_state; + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&dev->read_wait_q, &wait); + current_state = current->state; + set_current_state(TASK_INTERRUPTIBLE); + if (ipblink_empty(&dev->task->rcvdt.bk.link)) { /* last check */ + devstate_unlock(dev); + have_devstate_lock = 0; + schedule(); + } + set_current_state(current_state); + remove_wait_queue(&dev->read_wait_q, &wait); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + goto up_out; + } + if (!have_devstate_lock) { + if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { + ret = -ERESTARTSYS; + goto up_out; + } + have_devstate_lock = 1; + } + /* signal or 0-byte send from DSP */ + if (ipblink_empty(&dev->task->rcvdt.bk.link)) + goto up_out; + } + + /* data protection while copying */ + disable_irq(INT_D2A_MB1); + + rcvdt = &dev->task->rcvdt.bk; + /* copy from delayed IPBUF */ + if (sndtyp_pvt(dev->task->ttyp)) { + /* private */ + if (!ipblink_empty(&rcvdt->link)) { + struct ipbuf_p *ipbp = rcvdt->ipbuf_pvt_r; + unsigned long dspadr; + unsigned char *src; + size_t bkcnt; + + if ((dspmem_access = is_dsp_internal_mem(ipbp)) != 0) + dsp_mem_enable(); + dspadr = MKLONG(ipbp->ah, ipbp->al); + if (!dspmem_access && + ((dspmem_access = is_dspword_internal_mem(dspadr)) != 0)) + dsp_mem_enable(); + src = dspword_to_virt(dspadr) + rcvdt->rp; + bkcnt = ((unsigned long)ipbp->c) * 2 - rcvdt->rp; + if (bkcnt > count) { + if (copy_to_user_dsp(buf, src, count)) { + ret = -EFAULT; + goto enirq_out; + } + ret = count; + rcvdt->rp += count; + } else { + if (copy_to_user_dsp(buf, src, bkcnt)) { + ret = -EFAULT; + goto enirq_out; + } + ret = bkcnt; + ipblink_del_pvt(&rcvdt->link); + release_ipbuf_pvt(ipbp); + rcvdt->rp = 0; + } + } + } else { + /* global */ + if ((dspmem_access = is_ipbuf_internal_mem()) != 0) + dsp_mem_enable(); + while (!ipblink_empty(&rcvdt->link)) { + unsigned char *src; + size_t bkcnt; + unsigned short bid = rcvdt->link.top; + struct ipbuf *ipbp = ipbuf[bid]; + + src = ipbp->d + rcvdt->rp; + bkcnt = ((unsigned long)ipbp->c) * 2 - rcvdt->rp; + if (bkcnt > count) { + if (copy_to_user_dsp(buf, src, count)) { + ret = -EFAULT; + goto enirq_out; + } + ret += count; + rcvdt->rp += count; + break; + } else { + if (copy_to_user_dsp(buf, src, bkcnt)) { + ret = -EFAULT; + goto enirq_out; + } + ret += bkcnt; + buf += bkcnt; + count -= bkcnt; + ipblink_del_top(&rcvdt->link, ipbuf); + unuse_ipbuf(bid); + rcvdt->rp = 0; + } + } + } + +enirq_out: + if (dspmem_access) + dsp_mem_disable(); + enable_irq(INT_D2A_MB1); +up_out: + if (have_devstate_lock) + devstate_unlock(dev); + up(&dev->read_sem); + return ret; +} + +static ssize_t dsp_task_read_wd_psv(struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); + struct taskdev *dev = taskdev[minor]; + struct mbcmd mb; + unsigned char tid; + int ret = 0; + + if (count == 0) { + return 0; + } else if (count == 1) { + printk(KERN_ERR + "omapdsp: count=1 is illegal for dsp_task_read().\n"); + return -EINVAL; + } else { + /* force! */ + count = 2; + } + + if (down_tasksem_interruptible(dev, &dev->read_sem)) + return -ERESTARTSYS; + if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { + ret = -ERESTARTSYS; + goto up_out; + } + tid = dev->task->tid; + devstate_unlock(dev); + + mbcmd_set(mb, MBCMD(WDREQ), tid, 0); + dsp_mbsend_and_wait(&mb, &dev->read_wait_q); + + if (signal_pending(current)) { + ret = -ERESTARTSYS; + goto up_out; + } + if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { + ret = -ERESTARTSYS; + goto up_out; + } + if (fifo_empty(&dev->task->rcvdt.fifo)) /* should not occur */ + goto unlock_out; + ret = copy_to_user_fm_fifo(buf, &dev->task->rcvdt.fifo, count); + +unlock_out: + devstate_unlock(dev); +up_out: + up(&dev->read_sem); + return ret; +} + +static ssize_t dsp_task_read_bk_psv(struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); + struct taskdev *dev = taskdev[minor]; + struct rcvdt_bk_struct *rcvdt; + struct mbcmd mb; + unsigned char tid; + int dspmem_access = 0; + int ret = 0; + + if (count == 0) { + return 0; + } else if (count == 1) { + printk(KERN_ERR + "omapdsp: count=1 is illegal for dsp_task_read().\n"); + return -EINVAL; + } else if ((int)buf & 0x1) { + printk(KERN_ERR + "omapdsp: buf should be word aligned for dsp_task_read().\n"); + return -EINVAL; + } else if (count & 0x1) { + /* force even value */ + count--; + } + + if (down_tasksem_interruptible(dev, &dev->read_sem)) + return -ERESTARTSYS; + if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { + ret = -ERESTARTSYS; + goto up_out; + } + tid = dev->task->tid; + devstate_unlock(dev); + + mbcmd_set(mb, MBCMD(BKREQ), tid, count/2); + dsp_mbsend_and_wait(&mb, &dev->read_wait_q); + + if (signal_pending(current)) { + ret = -ERESTARTSYS; + goto up_out; + } + if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { + ret = -ERESTARTSYS; + goto up_out; + } + rcvdt = &dev->task->rcvdt.bk; + /* signal or 0-byte send from DSP */ + if (ipblink_empty(&rcvdt->link)) + goto unlock_out; + + /* + * We will not receive more than requested count. + */ + if (sndtyp_pvt(dev->task->ttyp)) { + /* private */ + struct ipbuf_p *ipbp = rcvdt->ipbuf_pvt_r; + size_t rcvcnt; + unsigned long dspadr; + void *src; + + if ((dspmem_access = is_dsp_internal_mem(ipbp)) != 0) + dsp_mem_enable(); + dspadr = MKLONG(ipbp->ah, ipbp->al); + if (!dspmem_access && + ((dspmem_access = is_dspword_internal_mem(dspadr)) != 0)) + dsp_mem_enable(); + rcvcnt = ((unsigned long)ipbp->c) * 2; + if (count > rcvcnt) + count = rcvcnt; + src = dspword_to_virt(dspadr); + if (copy_to_user_dsp(buf, src, count)) { + ret = -EFAULT; + goto unlock_out; + } + ipblink_del_pvt(&rcvdt->link); + release_ipbuf_pvt(ipbp); + ret = count; + } else { + /* global */ + unsigned short bid = rcvdt->link.top; + struct ipbuf *ipbp = ipbuf[bid]; + size_t rcvcnt; + + if ((dspmem_access = is_ipbuf_internal_mem()) != 0) + dsp_mem_enable(); + rcvcnt = ((unsigned long)ipbp->c) * 2; + if (count > rcvcnt) + count = rcvcnt; + if (copy_to_user_dsp(buf, ipbp->d, count)) { + ret = -EFAULT; + goto unlock_out; + } + ipblink_del_top(&rcvdt->link, ipbuf); + unuse_ipbuf(bid); + ret = count; + } + +unlock_out: + if (dspmem_access) + dsp_mem_disable(); + devstate_unlock(dev); +up_out: + up(&dev->read_sem); + return ret; +} + +static ssize_t dsp_task_write_wd(struct file *file, const char *buf, + size_t count, loff_t *ppos) +{ + unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); + struct taskdev *dev = taskdev[minor]; + struct mbcmd mb; + unsigned short wd; + int have_devstate_lock = 0; + int ret = 0; + + if (count == 0) { + return 0; + } else if (count & 0x1) { + printk(KERN_ERR + "omapdsp: odd count is illegal for dsp_task_write().\n"); + return -EINVAL; + } else { + /* force! */ + count = 2; + } + + if (down_tasksem_interruptible(dev, &dev->write_sem)) + return -ERESTARTSYS; + if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { + ret = -ERESTARTSYS; + goto up_out; + } + have_devstate_lock = 1; + + if (dev->task->wsz == 0) { + long current_state; + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&dev->write_wait_q, &wait); + current_state = current->state; + set_current_state(TASK_INTERRUPTIBLE); + if (dev->task->wsz == 0) { /* last check */ + devstate_unlock(dev); + have_devstate_lock = 0; + schedule(); + } + set_current_state(current_state); + remove_wait_queue(&dev->write_wait_q, &wait); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + goto up_out; + } + if (!have_devstate_lock) { + if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { + ret = -ERESTARTSYS; + goto up_out; + } + have_devstate_lock = 1; + } + if (dev->task->wsz == 0) /* should not occur */ + goto up_out; + } + + if (copy_from_user(&wd, buf, count)) { + ret = -EFAULT; + goto up_out; + } + + /* wsz protection */ + disable_irq(INT_D2A_MB1); + mbcmd_set(mb, MBCMD(WDSND), dev->task->tid, wd); + if (dsp_mbsend(&mb) < 0) + goto enirq_out; + ret = count; + if (rcvtyp_acv(dev->task->ttyp)) + dev->task->wsz = 0; + +enirq_out: + enable_irq(INT_D2A_MB1); +up_out: + if (have_devstate_lock) + devstate_unlock(dev); + up(&dev->write_sem); + return ret; +} + +static ssize_t dsp_task_write_bk(struct file *file, const char *buf, + size_t count, loff_t *ppos) +{ + unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); + struct taskdev *dev = taskdev[minor]; + struct mbcmd mb; + int dspmem_access = 0; + int have_devstate_lock = 0; + int ret = 0; + + if (count == 0) { + return 0; + } else if ((int)buf & 0x1) { + printk(KERN_ERR + "omapdsp: buf should be word aligned for " + "dsp_task_write().\n"); + return -EINVAL; + } else if (count & 0x1) { + printk(KERN_ERR + "omapdsp: odd count is illegal for dsp_task_write().\n"); + return -EINVAL; + } + + if (down_tasksem_interruptible(dev, &dev->write_sem)) + return -ERESTARTSYS; + if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { + ret = -ERESTARTSYS; + goto up_out; + } + have_devstate_lock = 1; + + if (dev->task->wsz == 0) { + long current_state; + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&dev->write_wait_q, &wait); + current_state = current->state; + set_current_state(TASK_INTERRUPTIBLE); + if (dev->task->wsz == 0) { /* last check */ + devstate_unlock(dev); + have_devstate_lock = 0; + schedule(); + } + set_current_state(current_state); + remove_wait_queue(&dev->write_wait_q, &wait); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + goto up_out; + } + if (!have_devstate_lock) { + if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { + ret = -ERESTARTSYS; + goto up_out; + } + have_devstate_lock = 1; + } + if (dev->task->wsz == 0) /* should not occur */ + goto up_out; + } + + /* wsz protection */ + disable_irq(INT_D2A_MB1); + + if (count > dev->task->wsz) + count = dev->task->wsz; + + if (rcvtyp_pvt(dev->task->ttyp)) { + /* private */ + struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_w; + unsigned long dspadr; + unsigned char *dst; + + if ((dspmem_access = is_dsp_internal_mem(ipbp)) != 0) + dsp_mem_enable(); + if (ipbp->s != OMAP_DSP_TID_FREE) + goto enirq_out; + dspadr = MKLONG(ipbp->ah, ipbp->al); + if (!dspmem_access && + ((dspmem_access = is_dspword_internal_mem(dspadr)) != 0)) + dsp_mem_enable(); + dst = dspword_to_virt(dspadr); + if (copy_from_user_dsp(dst, buf, count)) { + ret = -EFAULT; + goto enirq_out; + } + ipbp->c = count/2; + ipbp->s = dev->task->tid; + mbcmd_set(mb, MBCMD(BKSNDP), dev->task->tid, 0); + if (dsp_mbsend(&mb) < 0) + goto enirq_out; + } else { + /* global */ + struct ipbuf *ipbp; + unsigned short bid; + + if ((dspmem_access = is_ipbuf_internal_mem()) != 0) + dsp_mem_enable(); + bid = get_free_ipbuf(dev->task->tid); + if (bid == OMAP_DSP_BID_NULL) + goto enirq_out; + ipbp = ipbuf[bid]; + if (copy_from_user_dsp(ipbp->d, buf, count)) { + release_ipbuf(bid); + ret = -EFAULT; + goto enirq_out; + } + ipbp->c = count/2; + ipbp->sa = dev->task->tid; + mbcmd_set(mb, MBCMD(BKSND), dev->task->tid, bid); + if (dsp_mbsend(&mb) < 0) { + release_ipbuf(bid); + goto enirq_out; + } + ipb_bsycnt_inc(&ipbcfg); + } + ret = count; + + if (rcvtyp_acv(dev->task->ttyp)) + dev->task->wsz = 0; +enirq_out: + if (dspmem_access) + dsp_mem_disable(); + enable_irq(INT_D2A_MB1); +up_out: + if (have_devstate_lock) + devstate_unlock(dev); + up(&dev->write_sem); + return ret; +} + +static unsigned int dsp_task_poll(struct file * file, poll_table * wait) +{ + unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); + struct taskdev *dev = taskdev[minor]; + struct dsptask *task = dev->task; + unsigned int mask = 0; + + poll_wait(file, &dev->read_wait_q, wait); + poll_wait(file, &dev->write_wait_q, wait); + if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) + return 0; + if (sndtyp_psv(task->ttyp) || + (sndtyp_wd(task->ttyp) && !fifo_empty(&task->rcvdt.fifo)) || + (sndtyp_bk(task->ttyp) && !ipblink_empty(&task->rcvdt.bk.link))) + mask |= POLLIN | POLLRDNORM; + if (task->wsz) + mask |= POLLOUT | POLLWRNORM; + devstate_unlock(dev); + + return mask; +} + +static int dsp_task_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + unsigned int minor = MINOR(inode->i_rdev); + struct taskdev *dev = taskdev[minor]; + struct mbcmd mb; + unsigned char tid; + struct mb_exarg mbarg, *mbargp; + int mbargc; + unsigned short mbargv[1]; + int interactive; + int ret; + + /* LOCK / UNLOCK operations */ + switch (cmd) { + case OMAP_DSP_TASK_IOCTL_LOCK: + return taskdev_lock(dev); + case OMAP_DSP_TASK_IOCTL_UNLOCK: + return taskdev_unlock(dev); + } + + /* + * actually only interractive commands need to lock + * the semaphore, but here all commands do it for simplicity. + */ + if (down_tasksem_interruptible(dev, &dev->ioctl_sem)) + return -ERESTARTSYS; + if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { + ret = -ERESTARTSYS; + goto up_out; + } + + if ((cmd >= 0x0080) && (cmd < 0x0100)) { + /* + * 0x0080 - 0x00ff + * reserved for backward compatibility + * user-defined TCTL commands: no arg, non-interactive + */ + mbargc = 0; + interactive = 0; + } else if (cmd < 0x8000) { + /* + * 0x0000 - 0x7fff (except 0x0080 - 0x00ff) + * system reserved TCTL commands + */ + switch (cmd) { + case OMAP_DSP_MBCMD_TCTL_TEN: + case OMAP_DSP_MBCMD_TCTL_TDIS: + mbargc = 0; + interactive = 0; + break; + default: + ret = -ENOIOCTLCMD; + goto unlock_out; + } + } + /* + * 0x8000 - 0xffff + * user-defined TCTL commands + */ + else if (cmd < 0x8100) { + /* 0x8000-0x80ff: no arg, non-interactive */ + mbargc = 0; + interactive = 0; + } else if (cmd < 0x8200) { + /* 0x8100-0x81ff: 1 arg, non-interactive */ + mbargc = 1; + mbargv[0] = arg & 0xffff; + interactive = 0; + } else if (cmd < 0x9000) { + /* 0x8200-0x8fff: reserved */ + ret = -ENOIOCTLCMD; + goto up_out; + } else if (cmd < 0x9100) { + /* 0x9000-0x90ff: no arg, interactive */ + mbargc = 0; + interactive = 1; + } else if (cmd < 0x9200) { + /* 0x9100-0x91ff: 1 arg, interactive */ + mbargc = 1; + mbargv[0] = arg & 0xffff; + interactive = 1; + } else if (cmd < 0x10000) { + /* 0x9200-0xffff: reserved */ + ret = -ENOIOCTLCMD; + goto up_out; + } else { + /* + * 0x10000 - + * non TCTL ioctls + */ + switch (cmd) { + case OMAP_DSP_TASK_IOCTL_BFLSH: + ret = dsp_task_flush_buf(dev->task); + break; + case OMAP_DSP_TASK_IOCTL_SETBSZ: + ret = dsp_task_set_fifosz(dev->task, arg); + break; + case OMAP_DSP_TASK_IOCTL_GETNAME: + ret = 0; + if (copy_to_user((void *)arg, dev->name, + strlen(dev->name) + 1)) + ret = -EFAULT; + break; + default: + ret = -ENOIOCTLCMD; + } + goto unlock_out; + } + + /* + * issue TCTL + */ + tid = dev->task->tid; + mbcmd_set(mb, MBCMD(TCTL), tid, cmd); + if (mbargc > 0) { + mbarg.argc = mbargc; + mbarg.tid = tid; + mbarg.argv = mbargv; + mbargp = &mbarg; + } else + mbargp = NULL; + + if (interactive) { + dev->task->tctl_stat = -ERESTARTSYS; + devstate_unlock(dev); + + dsp_mbsend_and_wait_exarg(&mb, mbargp, &dev->ioctl_wait_q); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + goto up_out; + } + if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) { + ret = -ERESTARTSYS; + goto up_out; + } + ret = dev->task->tctl_stat; + if (ret < 0) { + printk(KERN_ERR "omapdsp: TCTL not responding.\n"); + goto unlock_out; + } + } else { + dsp_mbsend_exarg(&mb, mbargp); + ret = 0; + } + +unlock_out: + devstate_unlock(dev); +up_out: + up(&dev->ioctl_sem); + return ret; +} + +/** + * On demand page allocation is not allowed. The mapping area is defined by + * corresponding DSP tasks. + */ +static struct page *dsp_task_nopage_mmap(struct vm_area_struct *vma, + unsigned long address, int *type) +{ + return NOPAGE_SIGBUS; +} + +static struct vm_operations_struct dsp_task_vm_ops = { + .nopage = dsp_task_nopage_mmap, +}; + +static int dsp_task_mmap(struct file *filp, struct vm_area_struct *vma) +{ + void *tmp_vadr; + unsigned long tmp_padr, tmp_vmadr, off; + size_t req_len, tmp_len; + unsigned int minor = MINOR(filp->f_dentry->d_inode->i_rdev); + struct taskdev *dev = taskdev[minor]; + struct dsptask *task; + int ret = 0; + + if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) + return -ERESTARTSYS; + task = dev->task; + if (task->map_length == 0) { + printk(KERN_ERR + "omapdsp: task %s doesn't have mmap buffer.\n", + task->name); + ret = -EINVAL; + goto unlock_out; + } + if (is_dsp_internal_mem(task->map_base)) { + printk(KERN_ERR + "omapdsp: task %s: map_base = %p\n" + " DARAM/SARAM can't be used as mmap buffer.\n", + task->name, task->map_base); + ret = -EINVAL; + goto unlock_out; + } + + /* + * Don't swap this area out + * Don't dump this area to a core file + */ + vma->vm_flags |= VM_RESERVED | VM_IO; + + /* Do not cache this area */ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + req_len = vma->vm_end - vma->vm_start; + off = vma->vm_pgoff << PAGE_SHIFT; + tmp_vmadr = vma->vm_start; + tmp_vadr = task->map_base + off; + do { + tmp_padr = dsp_virt_to_phys(tmp_vadr, &tmp_len); + if (tmp_padr == 0) { + printk(KERN_ERR + "omapdsp: task %s: illegal address " + "for mmap: %p", task->name, tmp_vadr); + /* partial mapping will be cleared in upper layer */ + ret = -EINVAL; + goto unlock_out; + } + if (tmp_len > req_len) + tmp_len = req_len; + + printk(KERN_DEBUG + "omapdsp: mmap info: " + "vmadr = %08lx, padr = %08lx, len = %x\n", + tmp_vmadr, tmp_padr, tmp_len); + if (remap_pfn_range(vma, tmp_vmadr, tmp_padr >> PAGE_SHIFT, + tmp_len, vma->vm_page_prot) != 0) { + printk(KERN_ERR + "omapdsp: task %s: remap_page_range() failed.\n", + task->name); + /* partial mapping will be cleared in upper layer */ + ret = -EINVAL; + goto unlock_out; + } + + req_len -= tmp_len; + tmp_vmadr += tmp_len; + tmp_vadr += tmp_len; + } while (req_len); + + vma->vm_ops = &dsp_task_vm_ops; +unlock_out: + devstate_unlock(dev); + return ret; +} + +static int dsp_task_open(struct inode *inode, struct file *file) +{ + unsigned int minor = MINOR(inode->i_rdev); + struct taskdev *dev = taskdev[minor]; + int ret = 0; + + if (devstate_lock(dev, OMAP_DSP_DEVSTATE_NOTASK | + OMAP_DSP_DEVSTATE_ATTACHED) < 0) + return -ERESTARTSYS; +#ifndef CONFIG_OMAP_DSP_TASK_MULTIOPEN + if (dev->usecount > 0) { + ret = -EBUSY; + goto unlock_out; + } +#endif + + if (dev->state == OMAP_DSP_DEVSTATE_NOTASK) { + dev->state = OMAP_DSP_DEVSTATE_ADDREQ; + /* wake up twch daemon for tadd */ + dsp_twch_touch(); + devstate_unlock(dev); + if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED | + OMAP_DSP_DEVSTATE_ADDFAIL) < 0) + return -ERESTARTSYS; + if (dev->state == OMAP_DSP_DEVSTATE_ADDFAIL) { + printk(KERN_ERR "omapdsp: task attach failed for %s!\n", + dev->name); + ret = -EBUSY; + dev->state = OMAP_DSP_DEVSTATE_NOTASK; + wake_up_interruptible_all(&dev->state_wait_q); + goto unlock_out; + } + } + + /* state_lock covers usecount, proc_list as well. */ + dev->usecount++; + proc_list_add(&dev->proc_list, current); + file->f_op = &dev->fops; + devstate_unlock(dev); + + dsp_map_update(current); + dsp_cur_users_add(current); + return 0; + +unlock_out: + devstate_unlock(dev); + return ret; +} + +static int dsp_task_release(struct inode *inode, struct file *file) +{ + unsigned int minor = MINOR(inode->i_rdev); + struct taskdev *dev = taskdev[minor]; + + dsp_cur_users_del(current); + + /* state_lock covers usecount, proc_list as well. */ + spin_lock(&dev->state_lock); + + /* state can be ATTACHED, KILLREQ or GARBAGE here. */ + switch (dev->state) { + + case OMAP_DSP_DEVSTATE_KILLREQ: + dev->usecount--; + break; + + case OMAP_DSP_DEVSTATE_GARBAGE: + if(--dev->usecount == 0) { + dev->state = OMAP_DSP_DEVSTATE_NOTASK; + wake_up_interruptible_all(&dev->state_wait_q); + } + break; + + case OMAP_DSP_DEVSTATE_ATTACHED: + if (dev->lock_pid == current->pid) + taskdev_unlock(dev); + proc_list_del(&dev->proc_list, current); + if (--dev->usecount == 0) { + if (minor >= n_task) { /* dynamic task */ + dev->state = OMAP_DSP_DEVSTATE_DELREQ; + /* wake up twch daemon for tdel */ + dsp_twch_touch(); + } + } + break; + + } + + spin_unlock(&dev->state_lock); + return 0; +} + +/* + * mkdev / rmdev + */ +int dsp_mkdev(char *name) +{ + struct taskdev *dev; + int status; + unsigned char minor; + + if (!dsp_is_ready()) { + printk(KERN_ERR "omapdsp: dsp has not been configured.\n"); + return -EINVAL; + } + for (minor = n_task; minor < TASKDEV_MAX; minor++) { + if (taskdev[minor] == NULL) + goto do_make; + } + printk(KERN_ERR "omapdsp: Too many task devices.\n"); + return -EBUSY; + +do_make: + if ((dev = kmalloc(sizeof(struct taskdev), GFP_KERNEL)) == NULL) + return -ENOMEM; + memset(dev, 0, sizeof(struct taskdev)); + if ((status = taskdev_init(dev, name, minor)) < 0) { + kfree(dev); + return status; + } + return minor; +} + +int dsp_rmdev(char *name) +{ + unsigned char minor; + int ret; + + if (!dsp_is_ready()) { + printk(KERN_ERR "omapdsp: dsp has not been configured.\n"); + return -EINVAL; + } + for (minor = n_task; minor < TASKDEV_MAX; minor++) { + if (taskdev[minor] && !strcmp(taskdev[minor]->name, name)) { + if ((ret = dsp_rmdev_minor(minor)) < 0) + return ret; + return minor; + } + } + return -EINVAL; +} + +static int dsp_rmdev_minor(unsigned char minor) +{ + struct taskdev *dev = taskdev[minor]; + struct dsptask *task = dev->task; + + spin_lock(&dev->state_lock); + + switch (dev->state) { + + case OMAP_DSP_DEVSTATE_NOTASK: + /* fine */ + break; + + case OMAP_DSP_DEVSTATE_ATTACHED: + /* task is working. kill it. */ + { + siginfo_t info; + struct list_head *ptr; + struct proc_list *pl; + + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = SI_KERNEL; + info._sifields._sigfault._addr = NULL; + list_for_each(ptr, &dev->proc_list) { + pl = list_entry(ptr, struct proc_list, list_head); + send_sig_info(SIGBUS, &info, pl->tsk); + } + taskdev_detach_task(dev); + dsp_task_unconfig(task); + kfree(task); + dev->state = OMAP_DSP_DEVSTATE_GARBAGE; + } + break; + + case OMAP_DSP_DEVSTATE_ADDREQ: + /* open() is waiting. drain it. */ + dev->state = OMAP_DSP_DEVSTATE_ADDFAIL; + wake_up_interruptible_all(&dev->state_wait_q); + break; + + case OMAP_DSP_DEVSTATE_DELREQ: + /* nobody is waiting. */ + dev->state = OMAP_DSP_DEVSTATE_NOTASK; + wake_up_interruptible_all(&dev->state_wait_q); + break; + + case OMAP_DSP_DEVSTATE_KILLREQ: + case OMAP_DSP_DEVSTATE_GARBAGE: + case OMAP_DSP_DEVSTATE_ADDFAIL: + /* transient state. wait for a moment. */ + break; + + } + + spin_unlock(&dev->state_lock); + + /* wait for some time and hope the state is settled */ + devstate_lock_timeout(dev, OMAP_DSP_DEVSTATE_NOTASK, HZ); + if (dev->state != OMAP_DSP_DEVSTATE_NOTASK) { + printk(KERN_WARNING + "omapdsp: illegal device state on rmdev %s.\n", + dev->name); + } + + taskdev_delete(minor); + devstate_unlock(dev); + kfree(dev); + + return 0; +} + +struct file_operations dsp_task_fops = { + .owner = THIS_MODULE, + .poll = dsp_task_poll, + .ioctl = dsp_task_ioctl, + .open = dsp_task_open, + .release = dsp_task_release, + .mmap = dsp_task_mmap, +}; + +static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor) +{ + taskdev[minor] = dev; + + INIT_LIST_HEAD(&dev->proc_list); + init_waitqueue_head(&dev->read_wait_q); + init_waitqueue_head(&dev->write_wait_q); + init_waitqueue_head(&dev->ioctl_wait_q); + init_MUTEX(&dev->read_sem); + init_MUTEX(&dev->write_sem); + init_MUTEX(&dev->ioctl_sem); + init_MUTEX(&dev->lock_sem); + dev->lock_pid = 0; + + strncpy(dev->name, name, OMAP_DSP_TNM_LEN); + dev->name[OMAP_DSP_TNM_LEN-1] = '\0'; + dev->state = (minor < n_task) ? OMAP_DSP_DEVSTATE_ATTACHED : + OMAP_DSP_DEVSTATE_NOTASK; + dev->usecount = 0; + memcpy(&dev->fops, &dsp_task_fops, sizeof(struct file_operations)); + devfs_mk_cdev(MKDEV(OMAP_DSP_TASK_MAJOR, minor), + S_IFCHR | S_IRUGO | S_IWUGO, "dsptask/%s", dev->name); +#ifdef CONFIG_PROC_FS + taskdev_create_proc(dev); +#endif + + init_waitqueue_head(&dev->state_wait_q); + spin_lock_init(&dev->state_lock); + + return 0; +} + +static void taskdev_delete(unsigned char minor) +{ + struct taskdev *dev = taskdev[minor]; + + if (!dev) + return; +#ifdef CONFIG_PROC_FS + taskdev_remove_proc(dev); +#endif + devfs_remove("dsptask/%s", dev->name); + preempt_disable(); + proc_list_flush(&dev->proc_list); + preempt_enable(); + taskdev[minor] = NULL; +} + +static void taskdev_attach_task(struct taskdev *dev, struct dsptask *task) +{ + unsigned short ttyp = task->ttyp; + + dev->task = task; + task->dev = dev; + dev->fops.read = + sndtyp_acv(ttyp) ? + sndtyp_wd(ttyp) ? dsp_task_read_wd_acv: + /* sndtyp_bk */ dsp_task_read_bk_acv: + /* sndtyp_psv */ + sndtyp_wd(ttyp) ? dsp_task_read_wd_psv: + /* sndtyp_bk */ dsp_task_read_bk_psv; + dev->fops.write = + rcvtyp_wd(ttyp) ? dsp_task_write_wd: + /* rcvbyp_bk */ dsp_task_write_bk; +} + +static void taskdev_detach_task(struct taskdev *dev) +{ + if (dev->task) { + dev->task = NULL; + dev->fops.read = NULL; + dev->fops.write = NULL; + printk(KERN_INFO "omapdsp: taskdev %s disabled.\n", dev->name); + } +} + +/* + * tadd / tdel / tkill + */ +int dsp_tadd(unsigned char minor, unsigned long adr) +{ + struct taskdev *dev; + struct dsptask *task; + struct mbcmd mb; + struct mb_exarg arg; + unsigned char tid; + unsigned short argv[2]; + int ret = minor; + + if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) { + printk(KERN_ERR + "omapdsp: no task device with minor %d\n", minor); + return -EINVAL; + } + /* + * we don't need to lock state_lock because + * only tadd is allowed when devstate is ADDREQ. + */ + if (dev->state != OMAP_DSP_DEVSTATE_ADDREQ) { + printk(KERN_ERR + "omapdsp: taskdev %s is not requesting for tadd.\n", + dev->name); + return -EINVAL; + } + + if (adr == OMAP_DSP_TADD_ABORTADR) { + /* aborting tadd intentionally */ + printk(KERN_INFO "omapdsp: tadd address is ABORTADR.\n"); + goto fail_out; + } + if (adr >= DSPSPACE_SIZE) { + printk(KERN_ERR + "omapdsp: illegal address 0x%08lx for tadd\n", adr); + ret = -EINVAL; + goto fail_out; + } + + adr >>= 1; /* word address */ + argv[0] = adr >> 16; /* addrh */ + argv[1] = adr & 0xffff; /* addrl */ + + if (down_interruptible(&cfg_sem)) { + ret = -ERESTARTSYS; + goto fail_out; + } + cfg_tid = OMAP_DSP_TID_ANON; + cfg_cmd = MBCMD(TADD); + mbcmd_set(mb, MBCMD(TADD), 0, 0); + arg.tid = OMAP_DSP_TID_ANON; + arg.argc = 2; + arg.argv = argv; + + dsp_mbsend_and_wait_exarg(&mb, &arg, &cfg_wait_q); + + tid = cfg_tid; + cfg_tid = OMAP_DSP_TID_ANON; + cfg_cmd = 0; + up(&cfg_sem); + + if (tid == OMAP_DSP_TID_ANON) { + printk(KERN_ERR "omapdsp: tadd failed!\n"); + ret = -EINVAL; + goto fail_out; + } + if ((tid < n_task) || dsptask[tid]) { + printk(KERN_ERR "omapdsp: illegal tid (%d)!\n", tid); + ret = -EINVAL; + goto fail_out; + } + if ((task = kmalloc(sizeof(struct dsptask), GFP_KERNEL)) == NULL) { + ret = -ENOMEM; + goto fail_out; + } + memset(task, 0, sizeof(struct dsptask)); + + if ((ret = dsp_task_config(task, tid)) < 0) + goto free_out; + taskdev_attach_task(dev, task); + + if (strcmp(dev->name, task->name)) { + printk(KERN_ERR + "omapdsp: task name (%s) doesn't match with " + "device name (%s).\n", task->name, dev->name); + ret = -EINVAL; + dev->state = OMAP_DSP_DEVSTATE_DELREQ; + dsp_twch_touch(); + return -EINVAL; + } + + dsp_task_init(task); + printk(KERN_INFO "omapdsp: taskdev %s enabled.\n", dev->name); + dev->state = OMAP_DSP_DEVSTATE_ATTACHED; + wake_up_interruptible_all(&dev->state_wait_q); + return minor; + +free_out: + kfree(task); +fail_out: + dev->state = OMAP_DSP_DEVSTATE_ADDFAIL; + wake_up_interruptible_all(&dev->state_wait_q); + return ret; +} + +int dsp_tdel(unsigned char minor) +{ + struct taskdev *dev; + struct dsptask *task; + struct mbcmd mb; + unsigned char tid, tid_response; + int ret = minor; + + if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) { + printk(KERN_ERR + "omapdsp: no task device with minor %d\n", minor); + return -EINVAL; + } + /* + * we don't need to lock state_lock because + * only tdel is allowed when devstate is DELREQ. + */ + if (dev->state != OMAP_DSP_DEVSTATE_DELREQ) { + printk(KERN_ERR + "omapdsp: taskdev %s is not requesting for tdel.\n", + dev->name); + return -EINVAL; + } + + task = dev->task; + tid = task->tid; + if (down_interruptible(&cfg_sem)) { + return -ERESTARTSYS; + } + cfg_tid = OMAP_DSP_TID_ANON; + cfg_cmd = MBCMD(TDEL); + mbcmd_set(mb, MBCMD(TDEL), tid, OMAP_DSP_MBCMD_TDEL_SAFE); + dsp_mbsend_and_wait(&mb, &cfg_wait_q); + tid_response = cfg_tid; + cfg_tid = OMAP_DSP_TID_ANON; + cfg_cmd = 0; + up(&cfg_sem); + + taskdev_detach_task(dev); + dsp_task_unconfig(task); + kfree(task); + dev->state = OMAP_DSP_DEVSTATE_NOTASK; + wake_up_interruptible_all(&dev->state_wait_q); + + if (tid_response != tid) { + printk(KERN_ERR "omapdsp: tdel failed!\n"); + ret = -EINVAL; + } + + return ret; +} + +int dsp_tkill(unsigned char minor) +{ + struct taskdev *dev; + struct dsptask *task; + struct mbcmd mb; + unsigned char tid, tid_response; + siginfo_t info; + struct list_head *ptr; + struct proc_list *pl; + int ret = minor; + + if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) { + printk(KERN_ERR + "omapdsp: no task device with minor %d\n", minor); + return -EINVAL; + } + spin_lock(&dev->state_lock); + if (dev->state != OMAP_DSP_DEVSTATE_ATTACHED) { + printk(KERN_ERR + "omapdsp: task has not been attached for taskdev %s\n", + dev->name); + spin_unlock(&dev->state_lock); + return -EINVAL; + } + dev->state = OMAP_DSP_DEVSTATE_KILLREQ; + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = SI_KERNEL; + info._sifields._sigfault._addr = NULL; + list_for_each(ptr, &dev->proc_list) { + pl = list_entry(ptr, struct proc_list, list_head); + send_sig_info(SIGBUS, &info, pl->tsk); + } + spin_unlock(&dev->state_lock); + + task = dev->task; + tid = task->tid; + if (down_interruptible(&cfg_sem)) { + tid_response = OMAP_DSP_TID_ANON; + ret = -ERESTARTSYS; + goto detach_out; + } + cfg_tid = OMAP_DSP_TID_ANON; + cfg_cmd = MBCMD(TDEL); + mbcmd_set(mb, MBCMD(TDEL), tid, OMAP_DSP_MBCMD_TDEL_KILL); + dsp_mbsend_and_wait(&mb, &cfg_wait_q); + tid_response = cfg_tid; + cfg_tid = OMAP_DSP_TID_ANON; + cfg_cmd = 0; + up(&cfg_sem); + +detach_out: + taskdev_detach_task(dev); + dsp_task_unconfig(task); + kfree(task); + + if (tid_response != tid) + printk(KERN_ERR "omapdsp: tkill failed!\n"); + + spin_lock(&dev->state_lock); + dev->state = (dev->usecount > 0) ? OMAP_DSP_DEVSTATE_GARBAGE : + OMAP_DSP_DEVSTATE_NOTASK; + wake_up_interruptible_all(&dev->state_wait_q); + spin_unlock(&dev->state_lock); + + return ret; +} + +/* + * state inquiry + */ +long taskdev_state(unsigned char minor) +{ + return taskdev[minor] ? taskdev[minor]->state : + OMAP_DSP_DEVSTATE_NOTASK; +} + +/* + * functions called from mailbox1 interrupt routine + */ +void mbx1_wdsnd(struct mbcmd *mb) +{ + unsigned char tid = mb->cmd_l; + struct dsptask *task = dsptask[tid]; + + if ((tid >= TASKDEV_MAX) || (task == NULL)) { + printk(KERN_ERR "mbx: WDSND with illegal tid! %d\n", tid); + return; + } + if (sndtyp_bk(task->ttyp)) { + printk(KERN_ERR + "mbx: WDSND from block sending task! (task%d)\n", tid); + return; + } + if (sndtyp_psv(task->ttyp) && + !waitqueue_active(&task->dev->read_wait_q)) { + printk(KERN_WARNING + "mbx: WDSND from passive sending task (task%d) " + "without request!\n", tid); + return; + } + + write_word_to_fifo(&task->rcvdt.fifo, mb->data); + wake_up_interruptible(&task->dev->read_wait_q); +} + +void mbx1_wdreq(struct mbcmd *mb) +{ + unsigned char tid = mb->cmd_l; + struct dsptask *task = dsptask[tid]; + + if ((tid >= TASKDEV_MAX) || (task == NULL)) { + printk(KERN_ERR "mbx: WDREQ with illegal tid! %d\n", tid); + return; + } + if (rcvtyp_psv(task->ttyp)) { + printk(KERN_ERR + "mbx: WDREQ from passive receiving task! (task%d)\n", + tid); + return; + } + + task->wsz = 2; + wake_up_interruptible(&task->dev->write_wait_q); +} + +void mbx1_bksnd(struct mbcmd *mb) +{ + unsigned char tid = mb->cmd_l; + unsigned short bid = mb->data; + struct dsptask *task = dsptask[tid]; + unsigned short cnt; + + if (bid >= ipbcfg.ln) { + printk(KERN_ERR "mbx: BKSND with illegal bid! %d\n", bid); + return; + } + ipb_bsycnt_dec(&ipbcfg); + if ((tid >= TASKDEV_MAX) || (task == NULL)) { + printk(KERN_ERR "mbx: BKSND with illegal tid! %d\n", tid); + goto unuse_ipbuf_out; + } + if (sndtyp_wd(task->ttyp)) { + printk(KERN_ERR + "mbx: BKSND from word sending task! (task%d)\n", tid); + goto unuse_ipbuf_out; + } + if (sndtyp_pvt(task->ttyp)) { + printk(KERN_ERR + "mbx: BKSND from private sending task! (task%d)\n", tid); + goto unuse_ipbuf_out; + } + if (sync_with_dsp(&ipbuf[bid]->sd, tid, 10) < 0) { + printk(KERN_ERR "mbx: BKSND - IPBUF sync failed!\n"); + return; + } + + /* should be done in DSP, but just in case. */ + ipbuf[bid]->next = OMAP_DSP_BID_NULL; + + cnt = ipbuf[bid]->c; + if (cnt > ipbcfg.lsz) { + printk(KERN_ERR "mbx: BKSND cnt(%d) > ipbuf line size(%d)!\n", + cnt, ipbcfg.lsz); + unuse_ipbuf_nowait(bid); + return; + } + + if (cnt == 0) { + /* 0-byte send from DSP */ + unuse_ipbuf_nowait(bid); + goto done; + } + ipblink_add_tail(&task->rcvdt.bk.link, bid, ipbuf); + /* we keep coming bid and return alternative line to DSP. */ + balance_ipbuf(MBSEND_TYPE_NOWAIT); + +done: + wake_up_interruptible(&task->dev->read_wait_q); + return; + +unuse_ipbuf_out: + unuse_ipbuf_nowait(bid); + return; +} + +void mbx1_bkreq(struct mbcmd *mb) +{ + unsigned char tid = mb->cmd_l; + unsigned short cnt = mb->data; + struct dsptask *task = dsptask[tid]; + + if ((tid >= TASKDEV_MAX) || (task == NULL)) { + printk(KERN_ERR "mbx: BKREQ with illegal tid! %d\n", tid); + return; + } + if (rcvtyp_wd(task->ttyp)) { + printk(KERN_ERR + "mbx: BKREQ from word receiving task! (task%d)\n", tid); + return; + } + if (rcvtyp_pvt(task->ttyp)) { + printk(KERN_ERR + "mbx: BKREQ from private receiving task! (task%d)\n", + tid); + return; + } + if (rcvtyp_psv(task->ttyp)) { + printk(KERN_ERR + "mbx: BKREQ from passive receiving task! (task%d)\n", + tid); + return; + } + + task->wsz = cnt*2; + wake_up_interruptible(&task->dev->write_wait_q); +} + +void mbx1_bkyld(struct mbcmd *mb) +{ + unsigned short bid = mb->data; + + if (bid >= ipbcfg.ln) { + printk(KERN_ERR "mbx: BKYLD with illegal bid! %d\n", bid); + return; + } + + /* should be done in DSP, but just in case. */ + ipbuf[bid]->next = OMAP_DSP_BID_NULL; + + /* we don't need to sync with DSP */ + ipb_bsycnt_dec(&ipbcfg); + release_ipbuf(bid); +} + +void mbx1_bksndp(struct mbcmd *mb) +{ + unsigned char tid = mb->cmd_l; + struct dsptask *task = dsptask[tid]; + struct rcvdt_bk_struct *rcvdt = &task->rcvdt.bk; + struct ipbuf_p *ipbp = rcvdt->ipbuf_pvt_r; + + if ((tid >= TASKDEV_MAX) || (task == NULL)) { + printk(KERN_ERR "mbx: BKSNDP with illegal tid! %d\n", tid); + return; + } + if (sndtyp_wd(task->ttyp)) { + printk(KERN_ERR + "mbx: BKSNDP from word sending task! (task%d)\n", tid); + return; + } + if (sndtyp_gbl(task->ttyp)) { + printk(KERN_ERR + "mbx: BKSNDP from non-private sending task! (task%d)\n", + tid); + return; + } + + /* + * we should not have delayed block at this point + * because read() routine releases the lock of the buffer and + * until then DSP can't send next data. + */ + + if (sync_with_dsp(&ipbp->s, tid, 10) < 0) { + printk(KERN_ERR "mbx: BKSNDP - IPBUF sync failed!\n"); + return; + } + printk(KERN_DEBUG "mbx: ipbuf_pvt_r->a = 0x%08lx\n", + MKLONG(ipbp->ah, ipbp->al)); + ipblink_add_pvt(&rcvdt->link); + wake_up_interruptible(&task->dev->read_wait_q); +} + +void mbx1_bkreqp(struct mbcmd *mb) +{ + unsigned char tid = mb->cmd_l; + struct dsptask *task = dsptask[tid]; + struct ipbuf_p *ipbp = task->ipbuf_pvt_w; + + if ((tid >= TASKDEV_MAX) || (task == NULL)) { + printk(KERN_ERR "mbx: BKREQP with illegal tid! %d\n", tid); + return; + } + if (rcvtyp_wd(task->ttyp)) { + printk(KERN_ERR + "mbx: BKREQP from word receiving task! (task%d)\n", tid); + return; + } + if (rcvtyp_gbl(task->ttyp)) { + printk(KERN_ERR + "mbx: BKREQP from non-private receiving task! (task%d)\n", tid); + return; + } + if (rcvtyp_psv(task->ttyp)) { + printk(KERN_ERR + "mbx: BKREQP from passive receiving task! (task%d)\n", tid); + return; + } + + if (sync_with_dsp(&ipbp->s, OMAP_DSP_TID_FREE, 10) < 0) { + printk(KERN_ERR "mbx: BKREQP - IPBUF sync failed!\n"); + return; + } + printk(KERN_DEBUG "mbx: ipbuf_pvt_w->a = 0x%08lx\n", + MKLONG(ipbp->ah, ipbp->al)); + task->wsz = ipbp->c*2; + wake_up_interruptible(&task->dev->write_wait_q); +} + +void mbx1_tctl(struct mbcmd *mb) +{ + unsigned char tid = mb->cmd_l; + struct dsptask *task = dsptask[tid]; + + if ((tid >= TASKDEV_MAX) || (task == NULL)) { + printk(KERN_ERR "mbx: TCTL with illegal tid! %d\n", tid); + return; + } + + if (!waitqueue_active(&task->dev->ioctl_wait_q)) { + printk(KERN_WARNING "mbx: unexpected TCTL from DSP!\n"); + return; + } + + task->tctl_stat = mb->data; + wake_up_interruptible(&task->dev->ioctl_wait_q); +} + +void mbx1_tcfg(struct mbcmd *mb) +{ + unsigned char tid = mb->cmd_l; + struct dsptask *task = dsptask[tid]; + unsigned long tmp_ipbp_r, tmp_ipbp_w; + unsigned long tmp_mapstart, tmp_maplen; + unsigned long tmp_tnm; + unsigned short *tnm; + volatile unsigned short *buf; + int i; + + if ((tid >= TASKDEV_MAX) || (task == NULL)) { + printk(KERN_ERR "mbx: TCFG with illegal tid! %d\n", tid); + return; + } + if ((task->state != TASK_STATE_CFGREQ) || (cfg_cmd != MBCMD(TCFG))) { + printk(KERN_WARNING "mbx: unexpected TCFG from DSP!\n"); + return; + } + + if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) { + printk(KERN_ERR "mbx: TCFG - IPBUF sync failed!\n"); + return; + } + + /* + * read configuration data on system IPBUF + */ + buf = ipbuf_sys_da->d; + task->ttyp = buf[0]; + tmp_ipbp_r = MKLONG(buf[1], buf[2]); + tmp_ipbp_w = MKLONG(buf[3], buf[4]); + tmp_mapstart = MKLONG(buf[5], buf[6]); + tmp_maplen = MKLONG(buf[7], buf[8]); + tmp_tnm = MKLONG(buf[9], buf[10]); + + task->rcvdt.bk.ipbuf_pvt_r = dspword_to_virt(tmp_ipbp_r); + task->ipbuf_pvt_w = dspword_to_virt(tmp_ipbp_w); + task->map_base = dspword_to_virt(tmp_mapstart); + task->map_length = tmp_maplen << 1; /* word -> byte */ + tnm = dspword_to_virt(tmp_tnm); + for (i = 0; i < OMAP_DSP_TNM_LEN-1; i++) { + /* avoiding byte access */ + unsigned short tmp = tnm[i]; + task->name[i] = tmp & 0x00ff; + if (!tmp) + break; + } + task->name[OMAP_DSP_TNM_LEN-1] = '\0'; + + release_ipbuf_pvt(ipbuf_sys_da); + task->state = TASK_STATE_READY; + wake_up_interruptible(&cfg_wait_q); +} + +void mbx1_tadd(struct mbcmd *mb) +{ + unsigned char tid = mb->cmd_l; + + if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBCMD(TADD))) { + printk(KERN_WARNING "mbx: unexpected TADD from DSP!\n"); + return; + } + cfg_tid = tid; + wake_up_interruptible(&cfg_wait_q); +} + +void mbx1_tdel(struct mbcmd *mb) +{ + unsigned char tid = mb->cmd_l; + + if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBCMD(TDEL))) { + printk(KERN_WARNING "mbx: unexpected TDEL from DSP!\n"); + return; + } + cfg_tid = tid; + wake_up_interruptible(&cfg_wait_q); +} + +void mbx1_err_fatal(unsigned char tid) +{ + struct dsptask *task = dsptask[tid]; + struct list_head *ptr; + struct proc_list *pl; + siginfo_t info; + + if ((tid >= TASKDEV_MAX) || (task == NULL)) { + printk(KERN_ERR "mbx: FATAL ERR with illegal tid! %d\n", tid); + return; + } + + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = SI_KERNEL; + info._sifields._sigfault._addr = NULL; + list_for_each(ptr, &task->dev->proc_list) { + pl = list_entry(ptr, struct proc_list, list_head); + send_sig_info(SIGBUS, &info, pl->tsk); + } +} + +void mbx1_dbg(struct mbcmd *mb) +{ + unsigned char tid = mb->cmd_l; + char s[80], *s_end = &s[79], *p; + unsigned short *src; + volatile unsigned short *buf; + int cnt; + int i; + + if (((tid >= TASKDEV_MAX) || (dsptask[tid] == NULL)) && + (tid != OMAP_DSP_TID_ANON)) { + printk(KERN_ERR "mbx: DBG with illegal tid! %d\n", tid); + return; + } + if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) { + printk(KERN_ERR "mbx: DBG - IPBUF sync failed!\n"); + return; + } + buf = ipbuf_sys_da->d; + cnt = buf[0]; + src = dspword_to_virt(MKLONG(buf[1], buf[2])); + p = s; + for (i = 0; i < cnt; i++) { + unsigned short tmp; + /* + * Be carefull that ipbuf should not be read with + * 1-byte access since it might be placed in DARAM/SARAM + * and it can cause unexpected byteswap. + * For example, + * *(p++) = *(src++) & 0xff; + * causes 1-byte access! + */ + tmp = *src++; + *(p++) = tmp & 0xff; + if (*(p-1) == '\n') { + *p = '\0'; + printk(KERN_INFO "%s", s); + p = s; + continue; + } + if (p == s_end) { + *p = '\0'; + printk(KERN_INFO "%s\n", s); + p = s; + continue; + } + } + if (p > s) { + *p = '\0'; + printk(KERN_INFO "%s\n", s); + } + + release_ipbuf_pvt(ipbuf_sys_da); +} + + +#ifdef CONFIG_PROC_FS +/* + * proc file entry + */ + +#define devstate_name(stat) (\ + ((stat) == OMAP_DSP_DEVSTATE_NOTASK) ? "NOTASK" :\ + ((stat) == OMAP_DSP_DEVSTATE_ATTACHED) ? "ATTACHED" :\ + ((stat) == OMAP_DSP_DEVSTATE_GARBAGE) ? "GARBAGE" :\ + ((stat) == OMAP_DSP_DEVSTATE_ADDREQ) ? "ADDREQ" :\ + ((stat) == OMAP_DSP_DEVSTATE_DELREQ) ? "DELREQ" :\ + ((stat) == OMAP_DSP_DEVSTATE_KILLREQ) ? "KILLREQ" :\ + ((stat) == OMAP_DSP_DEVSTATE_ADDFAIL) ? "ADDFAIL" :\ + "unknown") + +#define taskstate_name(state) (\ + ((state) == TASK_STATE_ERR) ? "ERR" :\ + ((state) == TASK_STATE_CFGREQ) ? "CFGREQ" :\ + ((state) == TASK_STATE_READY) ? "READY" :\ + "unknown") + +static __inline__ char *bid_name(unsigned short bid) +{ + static char s[6]; + + switch (bid) { + case OMAP_DSP_BID_NULL: + return "NULL"; + case OMAP_DSP_BID_PVT: + return "PRIVATE"; + default: + sprintf(s, "%d", bid); + return s; + } +} + +static __inline__ char *sndtyp_name(unsigned short ttyp) +{ + static char s[32]; + + sprintf(s, "%s %s send", + (sndtyp_acv(ttyp)) ? "active" : + "passive", + (sndtyp_wd(ttyp)) ? "word" : + (sndtyp_pvt(ttyp)) ? "private block" : + "global block"); + return s; +} + +static __inline__ char *rcvtyp_name(unsigned short ttyp) +{ + static char s[32]; + + sprintf(s, "%s %s receive", + (rcvtyp_acv(ttyp)) ? "active" : + "passive", + (rcvtyp_wd(ttyp)) ? "word" : + (rcvtyp_pvt(ttyp)) ? "private block" : + "global block"); + return s; +} + +static int taskdev_stat_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct taskdev *dev; + struct dsptask *task; + struct list_head *ptr; + struct proc_list *pl; + char *out; + int len; + + preempt_disable(); + + dev = (struct taskdev *)data; + task = dev->task; + + out = page; + out += sprintf(out, + "device name: %s\n" + "state %s\n", + dev->name, devstate_name(dev->state)); + + if (task) { + unsigned short ttyp = task->ttyp; + + out += sprintf(out, + " attached task: %s\n" + " stat %s\n" + " tid %d\n" + " ttyp 0x%04x (%s, %s)\n", + task->name, + taskstate_name(task->state), + task->tid, + ttyp, sndtyp_name(ttyp), rcvtyp_name(ttyp)); + + if (sndtyp_wd(ttyp)) { + struct fifo_struct *fifo = &task->rcvdt.fifo; + out += sprintf(out, + " fifo->buf 0x%p\n" + " fifo->sz %d\n" + " fifo->cnt %d\n" + " fifo->wp %d\n", + fifo->buf, fifo->sz, + fifo->cnt, fifo->wp); + } else { /* sndtyp_bk */ + struct rcvdt_bk_struct *rcvdt = &task->rcvdt.bk; + out += sprintf(out, + " delayed list top %s\n" + " tail %s\n", + bid_name(rcvdt->link.top), + bid_name(rcvdt->link.tail)); + if (sndtyp_pvt(ttyp)) { + out += sprintf(out, + " private IPBUF for read 0x%p\n", + rcvdt->ipbuf_pvt_r); + } + } + + out += sprintf(out, " wsz %d\n", task->wsz); + if (rcvtyp_pvt(ttyp)) { + out += sprintf(out, + " private IPBUF for write 0x%p\n", + task->ipbuf_pvt_w); + } + + if (task->map_length) { + out += sprintf(out, + " map_base %p\n" + " map_length %d\n", + task->map_base, task->map_length); + } + + out += sprintf(out, " user pid "); + list_for_each(ptr, &dev->proc_list) { + pl = list_entry(ptr, struct proc_list, list_head); + out += sprintf(out, " %d", pl->tsk->pid); + } + out += sprintf(out, "\n"); + } + + preempt_enable(); + + len = out - page - off; + if (len < count) { + *eof = 1; + if (len <= 0) + return 0; + } else + len = count; + *start = page + off; + + return len; +} + +static int taskdev_fifosz_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct taskdev *dev; + struct dsptask *task; + size_t fifosz; + int len; + + dev = (struct taskdev *)data; + task = dev->task; + fifosz = (task && sndtyp_wd(task->ttyp)) ? task->rcvdt.fifo.sz : 0; + len = sprintf(page, "%d\n", fifosz); + + return len; +} + +static int taskdev_fifosz_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + struct taskdev *dev; + struct dsptask *task; + int len; + char tmp[16]; + unsigned long fifosz; + int ret; + + dev = (struct taskdev *)data; + task = dev->task; + + if (task == NULL) { + printk(KERN_ERR "task not attached.\n"); + return -EINVAL; + } + + len = (count > 15) ? 15 : count; + if (copy_from_user(tmp, buffer, len)) + return -EFAULT; + tmp[len] = '\0'; + + fifosz = simple_strtol(tmp, NULL, 10); + if ((ret = dsp_task_set_fifosz(task, fifosz)) < 0) + return ret; + + return len; +} + +/* + * called from ipbuf_read_proc() + */ +int ipbuf_is_held(unsigned char tid, unsigned short bid) +{ + struct dsptask *task = dsptask[tid]; + unsigned short b; + int ret = 0; + + if (task == NULL) + return 0; + + disable_irq(INT_D2A_MB1); + ipblink_for_each(b, &task->rcvdt.bk.link, ipbuf) { + if (b == bid) { /* found */ + ret = 1; + break; + } + } + enable_irq(INT_D2A_MB1); + + return ret; +} + +static void taskdev_create_proc(struct taskdev *dev) +{ + struct proc_dir_entry *ent; + + if (procdir_dsp_task == NULL) + return; + + dev->procent_dir = proc_mkdir(dev->name, procdir_dsp_task); + if (dev->procent_dir == NULL) { + printk(KERN_ERR + "omapdsp: failed to register proc directory: %s\n", + dev->name); + return; + } + + ent = create_proc_read_entry("status", 0, dev->procent_dir, + taskdev_stat_read_proc, dev); + if (ent == NULL) { + printk(KERN_ERR + "omapdsp: failed to register " + "status proc device for: %s\n", dev->name); + return; + } + + ent = create_proc_entry("fifosz", S_IFREG | S_IWUGO | S_IRUGO, + dev->procent_dir); + if (ent == NULL) { + printk(KERN_ERR + "omapdsp: failed to register fifosz " + "proc device for: %s\n", dev->name); + return; + } + ent->read_proc = taskdev_fifosz_read_proc; + ent->write_proc = taskdev_fifosz_write_proc; + ent->data = dev; +} + +static void taskdev_remove_proc(struct taskdev *dev) +{ + if (dev->procent_dir == NULL) + return; + + remove_proc_entry("status", dev->procent_dir); + remove_proc_entry("fifosz", dev->procent_dir); + remove_proc_entry(dev->name, procdir_dsp_task); + dev->procent_dir = NULL; +} + +static void __init taskdev_create_procdir(void) +{ + procdir_dsp_task = proc_mkdir("task", procdir_dsp); + if (procdir_dsp_task == NULL) { + printk(KERN_ERR + "omapdsp: failed to register proc device: dsp/task\n"); + } +} + +static void taskdev_remove_procdir(void) +{ + if (procdir_dsp_task == NULL) + return; + + remove_proc_entry("task", procdir_dsp); + procdir_dsp_task = NULL; +} + +#endif /* CONFIG_PROC_FS */ + +int __init dsp_taskmod_init(void) +{ + int retval; + + memset(taskdev, 0, sizeof(void *) * TASKDEV_MAX); + memset(dsptask, 0, sizeof(void *) * TASKDEV_MAX); + + retval = register_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask", + &dsp_task_fops); + if (retval < 0) { + printk(KERN_ERR + "omapdsp: failed to register task device: %d\n", retval); + return retval; + } + devfs_mk_dir("dsptask"); +#ifdef CONFIG_PROC_FS + taskdev_create_procdir(); +#endif + + return 0; +} + +void dsp_taskmod_exit(void) +{ + devfs_remove("dsptask"); + unregister_chrdev(OMAP_DSP_TASK_MAJOR, "dsptask"); +#ifdef CONFIG_PROC_FS + taskdev_remove_procdir(); +#endif +} diff -Nru a/arch/arm/mach-omap/dsp/taskwatch.c b/arch/arm/mach-omap/dsp/taskwatch.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/dsp/taskwatch.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,183 @@ +/* + * linux/arch/arm/mach-omap/dsp/taskwatch.c + * + * OMAP DSP task watch device driver + * + * Copyright (C) 2002-2004 Nokia Corporation + * + * Written by Toshihiro Kobayashi + * + * 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 + * + * 2004/12/01: DSP Gateway version 3.1 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dsp.h" + +static DECLARE_WAIT_QUEUE_HEAD(read_wait_q); +static unsigned int change_cnt; + +void dsp_twch_touch(void) +{ + change_cnt++; + wake_up_interruptible(&read_wait_q); +} + +/* + * @count: represents the device counts of the user's interst + */ +static ssize_t dsp_twch_read(struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + long taskstat[TASKDEV_MAX]; + int devcount = count / sizeof(long); + int i; + + if (!dsp_is_ready()) { + printk(KERN_ERR "omapdsp: dsp has not been configured.\n"); + return -EINVAL; + } + + if (change_cnt == 0) { + long current_state; + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&read_wait_q, &wait); + current_state = current->state; + set_current_state(TASK_INTERRUPTIBLE); + if (change_cnt == 0) /* last check */ + schedule(); + set_current_state(current_state); + remove_wait_queue(&read_wait_q, &wait); + + /* unconfigured while waiting ;-( */ + if (dsp_is_ready()) + return -EINVAL; + } + + if (devcount > TASKDEV_MAX) + devcount = TASKDEV_MAX; + + count = devcount * sizeof(long); + change_cnt = 0; + for (i = 0; i < devcount; i++) { + taskstat[i] = taskdev_state(i); + } + + if (copy_to_user(buf, taskstat, count)) + return -EFAULT; + + return count; +} + +static unsigned int dsp_twch_poll(struct file *file, poll_table *wait) +{ + unsigned int mask = 0; + + poll_wait(file, &read_wait_q, wait); + if (change_cnt) + mask |= POLLIN | POLLRDNORM; + + return mask; +} + +static int dsp_twch_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + static DECLARE_MUTEX(ioctl_sem); + int ret; + + if (down_interruptible(&ioctl_sem)) + return -ERESTARTSYS; + + switch (cmd) { + case OMAP_DSP_TWCH_IOCTL_MKDEV: + { + char name[OMAP_DSP_TNM_LEN]; + if (copy_from_user(name, (void *)arg, OMAP_DSP_TNM_LEN)) { + ret = -EFAULT; + goto up_out; + } + name[OMAP_DSP_TNM_LEN-1] = '\0'; + ret = dsp_mkdev(name); + break; + } + + case OMAP_DSP_TWCH_IOCTL_RMDEV: + { + char name[OMAP_DSP_TNM_LEN]; + if (copy_from_user(name, (void *)arg, OMAP_DSP_TNM_LEN)) { + ret = -EFAULT; + goto up_out; + } + name[OMAP_DSP_TNM_LEN-1] = '\0'; + ret = dsp_rmdev(name); + break; + } + + case OMAP_DSP_TWCH_IOCTL_TADD: + { + struct omap_dsp_taddinfo ti; + if (copy_from_user(&ti, (void *)arg, sizeof(ti))) { + ret = -EFAULT; + goto up_out; + } + ret = dsp_tadd(ti.minor, ti.taskadr); + break; + } + + case OMAP_DSP_TWCH_IOCTL_TDEL: + ret = dsp_tdel(arg); + break; + + case OMAP_DSP_TWCH_IOCTL_TKILL: + ret = dsp_tkill(arg); + break; + + default: + ret = -ENOIOCTLCMD; + } + +up_out: + up(&ioctl_sem); + return ret; +} + +struct file_operations dsp_twch_fops = { + .owner = THIS_MODULE, + .read = dsp_twch_read, + .poll = dsp_twch_poll, + .ioctl = dsp_twch_ioctl, +}; + +void dsp_twch_start(void) +{ + change_cnt = 1; /* first read will not wait */ +} + +void dsp_twch_stop(void) +{ + wake_up_interruptible(&read_wait_q); +} diff -Nru a/arch/arm/mach-omap/dsp/uaccess_dsp.S b/arch/arm/mach-omap/dsp/uaccess_dsp.S --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/dsp/uaccess_dsp.S 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,80 @@ +/* + * linux/arch/arm/mach-omap/dsp/uaccess_dsp.S + * + * user memory access functions for DSP driver + * + * Copyright (C) 2004 Nokia Corporation + * + * Written by Toshihiro Kobayashi + * + * 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 + * + * 2004/06/29: DSP Gateway version 3.1 + */ + +#include +#include + + .text + +/* Prototype: int __arch_copy_to_user_dsp_2b(void *to, const char *from) + * Purpose : copy 2 bytes to user memory from kernel(DSP) memory + * escaping from unexpected byte swap using __arch_copy_to_user() + * in OMAP architecture. + * Params : to - user memory + * : from - kernel(DSP) memory + * Returns : success = 0, failure = 2 + */ + +ENTRY(__arch_copy_to_user_dsp_2b) + stmfd sp!, {r4, lr} + ldrb r3, [r1], #1 + ldrb r4, [r1], #1 +USER( strbt r4, [r0], #1) @ May fault +USER( strbt r3, [r0], #1) @ May fault + mov r0, #0 + LOADREGS(fd,sp!,{r4, pc}) + + .section .fixup,"ax" + .align 0 +9001: mov r0, #2 + LOADREGS(fd,sp!, {r4, pc}) + .previous + +/* Prototype: unsigned long __arch_copy_from_user_dsp_2b(void *to, const void *from); + * Purpose : copy 2 bytes from user memory to kernel(DSP) memory + * escaping from unexpected byte swap using __arch_copy_to_user() + * in OMAP architecture. + * Params : to - kernel (DSP) memory + * : from - user memory + * Returns : success = 0, failure = 2 + */ + +ENTRY(__arch_copy_from_user_dsp_2b) + stmfd sp!, {r4, lr} +USER( ldrbt r3, [r1], #1) @ May fault +USER( ldrbt r4, [r1], #1) @ May fault + strb r4, [r0], #1 + strb r3, [r0], #1 + mov r0, #0 + LOADREGS(fd,sp!,{r4, pc}) + + .section .fixup,"ax" + .align 0 +9001: mov r3, #0 + strh r3, [r0], #2 + mov r0, #2 + LOADREGS(fd,sp!, {r4, pc}) + .previous diff -Nru a/arch/arm/mach-omap/dsp/uaccess_dsp.h b/arch/arm/mach-omap/dsp/uaccess_dsp.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/dsp/uaccess_dsp.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,186 @@ +/* + * linux/arch/arm/mach-omap/dsp/uaccess_dsp.h + * + * Header for user access functions for DSP driver + * + * Copyright (C) 2002-2004 Nokia Corporation + * + * Modified from linux/include/asm-arm/uaccess.h + * by Toshihiro Kobayashi + * + * 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 + * + * 2004/06/29: DSP Gateway version 3.1 + */ + +#ifndef _OMAP_DSP_UACCESS_DSP_H +#define _OMAP_DSP_UACCESS_DSP_H + +#include + +#define HAVE_ASM_COPY_FROM_USER_DSP_2B + +#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B +extern unsigned long __arch_copy_from_user_dsp_2b(void *to, + const void __user *from); +extern unsigned long __arch_copy_to_user_dsp_2b(void __user *to, + const void *from); +#endif + +extern unsigned long dspmem_base, dspmem_size; +#define is_dsp_internal_mem(va) \ + (((unsigned long)(va) >= dspmem_base) && \ + ((unsigned long)(va) < dspmem_base + dspmem_size)) + + +#ifndef HAVE_ASM_COPY_FROM_USER_DSP_2B +static __inline__ unsigned long copy_from_user_dsp_2b(void *to, + const void *from) +{ + unsigned short tmp; + + if (__arch_copy_from_user(&tmp, from, 2)) + return 2; + /* expecting compiler to generate "strh" instruction */ + *((unsigned short *)to) = tmp; + return 0; +} +#endif + +/* + * @n must be multiple of 2 + */ +static __inline__ unsigned long copy_from_user_dsp(void *to, const void *from, + unsigned long n) +{ + if (access_ok(VERIFY_READ, from, n)) { + if ((is_dsp_internal_mem(to)) && + (((unsigned long)to & 2) || (n & 2))) { + /* + * DARAM/SARAM with odd word alignment + */ + unsigned long n4; + unsigned long last_n; + + /* dest not aligned -- copy 2 bytes */ + if (((unsigned long)to & 2) && (n >= 2)) { +#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B + if (__arch_copy_from_user_dsp_2b(to, from)) +#else + if (copy_from_user_dsp_2b(to, from)) +#endif + return n; + to += 2; + from += 2; + n -= 2; + } + /* middle 4*n bytes */ + last_n = n & 2; + n4 = n - last_n; + if ((n = __arch_copy_from_user(to, from, n4)) != 0) + return n + last_n; + /* last 2 bytes */ + if (last_n) { + to += n4; + from += n4; +#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B + if (__arch_copy_from_user_dsp_2b(to, from)) +#else + if (copy_from_user_dsp_2b(to, from)) +#endif + return 2; + n = 0; + } + } else { + /* + * DARAM/SARAM with 4-byte alignment or + * external memory + */ + n = __arch_copy_from_user(to, from, n); + } + } + else /* security hole - plug it */ + memzero(to, n); + return n; +} + +#ifndef HAVE_ASM_COPY_FROM_USER_DSP_2B +static __inline__ unsigned long copy_to_user_dsp_2b(void *to, const void *from) +{ + /* expecting compiler to generate "strh" instruction */ + unsigned short tmp = *(unsigned short *)from; + + return __arch_copy_to_user(to, &tmp, 2); +} +#endif + +/* + * @n must be multiple of 2 + */ +static __inline__ unsigned long copy_to_user_dsp(void *to, const void *from, + unsigned long n) +{ + if (access_ok(VERIFY_WRITE, to, n)) { + if ((is_dsp_internal_mem(from)) && + (((unsigned long)to & 2) || (n & 2))) { + /* + * DARAM/SARAM with odd word alignment + */ + unsigned long n4; + unsigned long last_n; + + /* dest not aligned -- copy 2 bytes */ + if (((unsigned long)to & 2) && (n >= 2)) { +#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B + if (__arch_copy_to_user_dsp_2b(to, from)) +#else + if (copy_to_user_dsp_2b(to, from)) +#endif + return n; + to += 2; + from += 2; + n -= 2; + } + /* middle 4*n bytes */ + last_n = n & 2; + n4 = n - last_n; + if ((n = __arch_copy_to_user(to, from, n4)) != 0) + return n + last_n; + /* last 2 bytes */ + if (last_n) { + to += n4; + from += n4; +#ifdef HAVE_ASM_COPY_FROM_USER_DSP_2B + if (__arch_copy_to_user_dsp_2b(to, from)) +#else + if (copy_to_user_dsp_2b(to, from)) +#endif + return 2; + n = 0; + } + } else { + /* + * DARAM/SARAM with 4-byte alignment or + * external memory + */ + n = __arch_copy_to_user(to, from, n); + } + } + return n; +} + +#undef is_dsp_internal_mem + +#endif /* _OMAP_DSP_UACCESS_DSP_H */ diff -Nru a/arch/arm/mach-omap/fpga.c b/arch/arm/mach-omap/fpga.c --- a/arch/arm/mach-omap/fpga.c 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/mach-omap/fpga.c 2005-03-02 10:51:31 -08:00 @@ -92,26 +92,17 @@ u32 stat; int fpga_irq; - /* - * Acknowledge the parent IRQ. - */ - desc->chip->ack(irq); + stat = get_fpga_unmasked_irqs(); - for (;;) { - stat = get_fpga_unmasked_irqs(); + if (!stat) + return; - if (!stat) { - break; - } - - for (fpga_irq = OMAP1510_IH_FPGA_BASE; - (fpga_irq < (OMAP1510_IH_FPGA_BASE + NR_FPGA_IRQS)) && stat; - fpga_irq++, stat >>= 1) { - if (stat & 1) { - d = irq_desc + fpga_irq; - d->handle(fpga_irq, d, regs); - desc->chip->unmask(irq); - } + for (fpga_irq = OMAP1510_IH_FPGA_BASE; + (fpga_irq < (OMAP1510_IH_FPGA_BASE + NR_FPGA_IRQS)) && stat; + fpga_irq++, stat >>= 1) { + if (stat & 1) { + d = irq_desc + fpga_irq; + d->handle(fpga_irq, d, regs); } } } @@ -177,7 +168,7 @@ set_irq_chip(i, &omap_fpga_irq); } - set_irq_handler(i, do_level_IRQ); + set_irq_handler(i, do_edge_IRQ); set_irq_flags(i, IRQF_VALID); } diff -Nru a/arch/arm/mach-omap/gpio-switch.c b/arch/arm/mach-omap/gpio-switch.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/gpio-switch.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,317 @@ +/* + * linux/arch/arm/mach-omap/gpio-switch.c + * + * Copyright (C) 2004 Nokia corporation + * Written by Juha Yrjölä + * and Paul Mundt + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct gpio_switch { + char name[14]; + u16 gpio; + int flags; + int type; + int key_code; + int state; + + struct work_struct work; + struct timer_list timer; + struct platform_device pdev; + + struct list_head node; +}; + +static LIST_HEAD(gpio_switches); +static struct platform_device *gpio_sw_platform_dev; +static struct device_driver gpio_sw_driver; + +static const char *cover_str[2] = { "open", "closed" }; +static const char *connection_str[2] = { "disconnected", "connected" }; + +/* + * GPIO switch state poll delay in ms + */ +#define OMAP_GPIO_SW_POLL_DELAY 10 + +static void print_sw_state(struct gpio_switch *sw, int state) +{ + const char **str; + + switch (sw->type) { + case OMAP_GPIO_SWITCH_TYPE_COVER: + str = cover_str; + break; + case OMAP_GPIO_SWITCH_TYPE_CONNECTION: + str = connection_str; + break; + default: + str = NULL; + } + if (str != NULL) + printk(KERN_INFO "%s (GPIO %d) is now %s\n", sw->name, sw->gpio, str[state]); +} + +static int gpio_sw_get_state(struct gpio_switch *sw) +{ + int state; + + state = omap_get_gpio_datain(sw->gpio); + if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED) + state = !state; + + return state; +} + +#define gpio_sw_switch_attr(name) \ +static ssize_t gpio_sw_show_##name(struct device *dev, char *buf) \ +{ \ + struct gpio_switch *sw = dev_get_drvdata(dev); \ + return sprintf(buf, "%s\n", name##_str[gpio_sw_get_state(sw)]); \ +} \ +static DEVICE_ATTR(name##_switch, S_IRUGO, gpio_sw_show_##name, NULL) + +gpio_sw_switch_attr(cover); +gpio_sw_switch_attr(connection); + +static irqreturn_t gpio_sw_irq_handler(int irq, void *arg, struct pt_regs *regs) +{ + struct gpio_switch *sw = arg; + + mod_timer(&sw->timer, jiffies + OMAP_GPIO_SW_POLL_DELAY / (1000 / HZ)); + + return IRQ_HANDLED; +} + +static void gpio_sw_timer(unsigned long arg) +{ + struct gpio_switch *sw = (struct gpio_switch *)arg; + + schedule_work(&sw->work); +} + +static void gpio_sw_handler(void *data) +{ + struct gpio_switch *sw = data; + int state = gpio_sw_get_state(sw); + + if (sw->state == state) + return; + + if (sw->type == OMAP_GPIO_SWITCH_TYPE_CONNECTION) + kobject_uevent(&sw->pdev.dev.kobj, KOBJ_CHANGE, + &dev_attr_connection_switch.attr); + else + kobject_uevent(&sw->pdev.dev.kobj, KOBJ_CHANGE, + &dev_attr_cover_switch.attr); + sw->state = state; + if (omap_get_gpio_datain(sw->gpio)) + omap_set_gpio_edge_ctrl(sw->gpio, OMAP_GPIO_FALLING_EDGE); + else + omap_set_gpio_edge_ctrl(sw->gpio, OMAP_GPIO_RISING_EDGE); + print_sw_state(sw, state); +} + +static int __init new_switch(struct gpio_switch *sw) +{ + int r; + + sw->pdev.name = sw->name; + sw->pdev.id = -1; + + sw->pdev.dev.parent = &gpio_sw_platform_dev->dev; + sw->pdev.dev.driver = &gpio_sw_driver; + + r = platform_device_register(&sw->pdev); + if (r) + return r; + + dev_set_drvdata(&sw->pdev.dev, sw); + + r = omap_request_gpio(sw->gpio); + if (r < 0) { + platform_device_unregister(&sw->pdev); + return r; + } + omap_set_gpio_direction(sw->gpio, 1); + if (omap_get_gpio_datain(sw->gpio)) + omap_set_gpio_edge_ctrl(sw->gpio, OMAP_GPIO_FALLING_EDGE); + else + omap_set_gpio_edge_ctrl(sw->gpio, OMAP_GPIO_RISING_EDGE); + r = request_irq(OMAP_GPIO_IRQ(sw->gpio), gpio_sw_irq_handler, SA_SHIRQ, + sw->name, sw); + if (r < 0) { + printk(KERN_ERR "gpio-switch: request_irq() failed for GPIO %d\n", sw->gpio); + platform_device_unregister(&sw->pdev); + omap_free_gpio(sw->gpio); + return r; + } + + switch (sw->type) { + case OMAP_GPIO_SWITCH_TYPE_COVER: + device_create_file(&sw->pdev.dev, &dev_attr_cover_switch); + break; + case OMAP_GPIO_SWITCH_TYPE_CONNECTION: + device_create_file(&sw->pdev.dev, &dev_attr_connection_switch); + break; + } + + INIT_WORK(&sw->work, gpio_sw_handler, sw); + init_timer(&sw->timer); + + sw->timer.function = gpio_sw_timer; + sw->timer.data = (unsigned long)sw; + + list_add(&sw->node, &gpio_switches); + + schedule_work(&sw->work); + + return 0; +} + +static int __init add_atag_switches(void) +{ + const struct omap_gpio_switch_config *cfg; + struct gpio_switch *sw; + int i, r; + + for (i = 0; ; i++) { + cfg = omap_get_nr_config(OMAP_TAG_GPIO_SWITCH, + struct omap_gpio_switch_config, i); + if (cfg == NULL) + break; + sw = kmalloc(sizeof(*sw), GFP_KERNEL); + if (sw == NULL) { + printk(KERN_ERR "gpio-switch: kmalloc failed\n"); + return -ENOMEM; + } + memset(sw, 0, sizeof(*sw)); + strncpy(sw->name, cfg->name, sizeof(cfg->name)); + sw->gpio = cfg->gpio; + sw->flags = cfg->flags; + sw->type = cfg->type; + sw->key_code = cfg->key_code; + sw->state = gpio_sw_get_state(sw); + if ((r = new_switch(sw)) < 0) { + kfree(sw); + return r; + } + } + return 0; +} + +static void gpio_sw_cleanup(void) +{ + struct gpio_switch *sw = NULL, *old = NULL; + + list_for_each_entry(sw, &gpio_switches, node) { + kfree(old); + + flush_scheduled_work(); + del_timer_sync(&sw->timer); + + free_irq(OMAP_GPIO_IRQ(sw->gpio), sw); + + if (sw->type == OMAP_GPIO_SWITCH_TYPE_CONNECTION) + device_remove_file(&sw->pdev.dev, + &dev_attr_connection_switch); + else + device_remove_file(&sw->pdev.dev, + &dev_attr_cover_switch); + + platform_device_unregister(&sw->pdev); + omap_free_gpio(sw->gpio); + old = sw; + } + + kfree(sw); +} + +static void __init report_initial_state(void) +{ + struct gpio_switch *sw; + + list_for_each_entry(sw, &gpio_switches, node) { + int state; + + state = omap_get_gpio_datain(sw->gpio); + if (sw->flags & OMAP_GPIO_SWITCH_FLAG_INVERTED) + state = !state; + print_sw_state(sw, state); + } +} + +static void gpio_sw_shutdown(struct device *dev) +{ +} + +static struct device_driver gpio_sw_driver = { + .name = "gpio-switch", + .bus = &platform_bus_type, + .shutdown = gpio_sw_shutdown, +}; + +static int __init gpio_sw_init(void) +{ + int r; + + printk(KERN_INFO "OMAP GPIO switch handler initializing\n"); + + r = driver_register(&gpio_sw_driver); + if (r) + return r; + + gpio_sw_platform_dev = platform_device_register_simple("gpio-switch", + -1, NULL, 0); + if (IS_ERR(gpio_sw_platform_dev)) { + driver_unregister(&gpio_sw_driver); + return PTR_ERR(gpio_sw_platform_dev); + } + + r = add_atag_switches(); + if (r < 0) { + platform_device_unregister(gpio_sw_platform_dev); + driver_unregister(&gpio_sw_driver); + gpio_sw_cleanup(); + return r; + } + + report_initial_state(); + + return 0; +} + +static void __exit gpio_sw_exit(void) +{ + gpio_sw_cleanup(); + platform_device_unregister(gpio_sw_platform_dev); + driver_unregister(&gpio_sw_driver); +} + +#ifndef MODULE +late_initcall(gpio_sw_init); +#else +module_init(gpio_sw_init); +#endif +module_exit(gpio_sw_exit); + +MODULE_AUTHOR("Juha Yrjölä "); +MODULE_DESCRIPTION("GPIO switch driver"); +MODULE_LICENSE("GPL"); diff -Nru a/arch/arm/mach-omap/gpio.c b/arch/arm/mach-omap/gpio.c --- a/arch/arm/mach-omap/gpio.c 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/mach-omap/gpio.c 2005-03-02 10:51:31 -08:00 @@ -407,13 +407,13 @@ } } -static void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio) +static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask) { u32 reg = bank->base; switch (bank->method) { case METHOD_MPUIO: - /* MPUIO irqstatus cannot be cleared one bit at a time, + /* MPUIO irqstatus is reset by reading the status register, * so do nothing here */ return; case METHOD_GPIO_1510: @@ -429,10 +429,15 @@ BUG(); return; } - __raw_writel(1 << get_gpio_index(gpio), reg); + __raw_writel(gpio_mask, reg); } -static void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable) +static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio) +{ + _clear_gpio_irqbank(bank, 1 << get_gpio_index(gpio)); +} + +static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enable) { u32 reg = bank->base; u32 l; @@ -442,33 +447,32 @@ reg += OMAP_MPUIO_GPIO_MASKIT; l = __raw_readl(reg); if (enable) - l &= ~(1 << gpio); + l &= ~(gpio_mask); else - l |= 1 << gpio; + l |= gpio_mask; break; case METHOD_GPIO_1510: reg += OMAP1510_GPIO_INT_MASK; l = __raw_readl(reg); if (enable) - l &= ~(1 << gpio); + l &= ~(gpio_mask); else - l |= 1 << gpio; + l |= gpio_mask; break; case METHOD_GPIO_1610: - if (enable) { + if (enable) reg += OMAP1610_GPIO_SET_IRQENABLE1; - _clear_gpio_irqstatus(bank, gpio); - } else + else reg += OMAP1610_GPIO_CLEAR_IRQENABLE1; - l = 1 << gpio; + l = gpio_mask; break; case METHOD_GPIO_730: reg += OMAP730_GPIO_INT_MASK; l = __raw_readl(reg); if (enable) - l &= ~(1 << gpio); + l &= ~(gpio_mask); else - l |= 1 << gpio; + l |= gpio_mask; break; default: BUG(); @@ -477,6 +481,11 @@ __raw_writel(l, reg); } +static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable) +{ + _enable_gpio_irqbank(bank, 1 << get_gpio_index(gpio), enable); +} + int omap_request_gpio(int gpio) { struct gpio_bank *bank; @@ -523,31 +532,31 @@ } bank->reserved_map &= ~(1 << get_gpio_index(gpio)); _set_gpio_direction(bank, get_gpio_index(gpio), 1); - _set_gpio_irqenable(bank, get_gpio_index(gpio), 0); + _set_gpio_irqenable(bank, gpio, 0); + _clear_gpio_irqstatus(bank, gpio); spin_unlock(&bank->lock); } +/* + * We need to unmask the GPIO bank interrupt as soon as possible to + * avoid missing GPIO interrupts for other lines in the bank. + * Then we need to mask-read-clear-unmask the triggered GPIO lines + * in the bank to avoid missing nested interrupts for a GPIO line. + * If we wait to unmask individual GPIO lines in the bank after the + * line's interrupt handler has been run, we may miss some nested + * interrupts. + */ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) { u32 isr_reg = 0; - struct gpio_bank *bank = (struct gpio_bank *) desc->data; + u32 isr; + unsigned int gpio_irq; + struct gpio_bank *bank; - /* - * Acknowledge the parent IRQ. - */ desc->chip->ack(irq); - /* Since the level 1 GPIO interrupt cascade (IRQ14) is configured as - * edge-sensitive, we need to unmask it here in order to avoid missing - * any additional GPIO interrupts that might occur after the last time - * we check for pending GPIO interrupts here. - * We are relying on the fact that this interrupt handler was installed - * with the SA_INTERRUPT flag so that interrupts are disabled at the - * CPU while it is executing. - */ - desc->chip->unmask(irq); - + bank = (struct gpio_bank *) desc->data; if (bank->method == METHOD_MPUIO) isr_reg = bank->base + OMAP_MPUIO_GPIO_INT; #ifdef CONFIG_ARCH_OMAP1510 @@ -562,20 +571,23 @@ if (bank->method == METHOD_GPIO_730) isr_reg = bank->base + OMAP730_GPIO_INT_STATUS; #endif - for (;;) { - u32 isr = __raw_readl(isr_reg); - unsigned int gpio_irq; - - if (!isr) - break; - gpio_irq = bank->virtual_irq_start; - - for (; isr != 0; isr >>= 1, gpio_irq++) { - if (isr & 1) { - struct irqdesc *d = irq_desc + gpio_irq; - d->handle(gpio_irq, d, regs); - } - } + + isr = __raw_readl(isr_reg); + _enable_gpio_irqbank(bank, isr, 0); + _clear_gpio_irqbank(bank, isr); + _enable_gpio_irqbank(bank, isr, 1); + desc->chip->unmask(irq); + + if (unlikely(!isr)) + return; + + gpio_irq = bank->virtual_irq_start; + for (; isr != 0; isr >>= 1, gpio_irq++) { + struct irqdesc *d; + if (!(isr & 1)) + continue; + d = irq_desc + gpio_irq; + d->handle(gpio_irq, d, regs); } } @@ -584,18 +596,7 @@ unsigned int gpio = irq - IH_GPIO_BASE; struct gpio_bank *bank = get_gpio_bank(gpio); -#ifdef CONFIG_ARCH_OMAP1510 - if (bank->method == METHOD_GPIO_1510) - __raw_writew(1 << (gpio & 0x0f), bank->base + OMAP1510_GPIO_INT_STATUS); -#endif -#if defined(CONFIG_ARCH_OMAP16XX) - if (bank->method == METHOD_GPIO_1610) - __raw_writew(1 << (gpio & 0x0f), bank->base + OMAP1610_GPIO_IRQSTATUS1); -#endif -#ifdef CONFIG_ARCH_OMAP730 - if (bank->method == METHOD_GPIO_730) - __raw_writel(1 << (gpio & 0x1f), bank->base + OMAP730_GPIO_INT_STATUS); -#endif + _clear_gpio_irqstatus(bank, gpio); } static void gpio_mask_irq(unsigned int irq) @@ -603,7 +604,7 @@ unsigned int gpio = irq - IH_GPIO_BASE; struct gpio_bank *bank = get_gpio_bank(gpio); - _set_gpio_irqenable(bank, get_gpio_index(gpio), 0); + _set_gpio_irqenable(bank, gpio, 0); } static void gpio_unmask_irq(unsigned int irq) @@ -616,7 +617,7 @@ gpio); _set_gpio_edge_ctrl(bank, get_gpio_index(gpio), OMAP_GPIO_RISING_EDGE); } - _set_gpio_irqenable(bank, get_gpio_index(gpio), 1); + _set_gpio_irqenable(bank, gpio, 1); } static void mpuio_ack_irq(unsigned int irq) @@ -629,7 +630,7 @@ unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE); struct gpio_bank *bank = get_gpio_bank(gpio); - _set_gpio_irqenable(bank, get_gpio_index(gpio), 0); + _set_gpio_irqenable(bank, gpio, 0); } static void mpuio_unmask_irq(unsigned int irq) @@ -637,7 +638,7 @@ unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE); struct gpio_bank *bank = get_gpio_bank(gpio); - _set_gpio_irqenable(bank, get_gpio_index(gpio), 1); + _set_gpio_irqenable(bank, gpio, 1); } static struct irqchip gpio_irq_chip = { @@ -722,7 +723,7 @@ set_irq_chip(j, &mpuio_irq_chip); else set_irq_chip(j, &gpio_irq_chip); - set_irq_handler(j, do_edge_IRQ); + set_irq_handler(j, do_simple_IRQ); set_irq_flags(j, IRQF_VALID); } set_irq_chained_handler(bank->irq, gpio_irq_handler); diff -Nru a/arch/arm/mach-omap/kgdb-serial.c b/arch/arm/mach-omap/kgdb-serial.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/kgdb-serial.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,169 @@ +/* + * FILE NAME: arch/arm/mach-omap/kgdb-serial.c + * + * BRIEF MODULE DESCRIPTION: + * Provides low level kgdb serial support hooks for the TI OMAP + * + * TODO: This should be adapted to work on any 1655x UART + * + * Author: George Davis + * + * Copyright 2002 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 as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +static struct async_struct pinfo = {0}; + +static __inline__ unsigned int +serial_inp(struct async_struct *info, int offset) +{ + return __raw_readb((unsigned long) info->iomem_base + + (offset<iomem_reg_shift)); +} + +static __inline__ void +serial_outp(struct async_struct *info, int offset, int value) +{ + __raw_writeb(value, (unsigned long) info->iomem_base + + (offset<iomem_reg_shift)); +} + +void +kgdb_serial_init(void) +{ + extern struct serial_state rs_table[]; + struct serial_state *ser = &rs_table[kgdb_ttyS]; + unsigned short quot; + + pinfo.state = ser; + pinfo.magic = SERIAL_MAGIC; + pinfo.port = ser->port; + pinfo.flags = ser->flags; + pinfo.iomem_base = ser->iomem_base; + pinfo.iomem_reg_shift = ser->iomem_reg_shift; + + serial_outp(&pinfo, UART_OMAP_MDR1, 0x07); /* disable UART */ + serial_outp(&pinfo, UART_LCR, 0xBF); /* select EFR */ + serial_outp(&pinfo, UART_EFR, UART_EFR_ECB); + serial_outp(&pinfo, UART_LCR, UART_LCR_DLAB); /* set DLAB */ + serial_outp(&pinfo, UART_DLL, 0x00); + serial_outp(&pinfo, UART_DLM, 0x00); + serial_outp(&pinfo, UART_LCR, 0x00); /* reset DLAB */ + serial_outp(&pinfo, UART_OMAP_SCR, 0x00); + serial_outp(&pinfo, UART_FCR, 0x00); + serial_outp(&pinfo, UART_MCR, 0x40); /* enable TCR/TLR */ + serial_outp(&pinfo, UART_OMAP_TCR, 0x0F); + serial_outp(&pinfo, UART_OMAP_TLR, 0x00); + serial_outp(&pinfo, UART_MCR, 0x00); + serial_outp(&pinfo, UART_LCR, 0xBF); /* select EFR */ + serial_outp(&pinfo, UART_EFR, 0x00); + serial_outp(&pinfo, UART_LCR, 0x00); /* reset DLAB */ + serial_outp(&pinfo, UART_OMAP_MDR1, 0x00); /* enable UART */ + + /* + * Clear the FIFO buffers and disable them + * (they will be reenabled later) + */ + serial_outp(&pinfo, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_outp(&pinfo, UART_FCR, (UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT)); + serial_outp(&pinfo, UART_FCR, 0); + + /* + * Clear the interrupt registers. + */ + (void) serial_inp(&pinfo, UART_LSR); + (void) serial_inp(&pinfo, UART_RX); + (void) serial_inp(&pinfo, UART_IIR); + (void) serial_inp(&pinfo, UART_MSR); + + /* + * Now, initialize the UART + */ + serial_outp(&pinfo, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ +#if CONFIG_ARCH_OMAP1510 /* NOTE: Needed for 1510 only */ + if (kgdb_baud == 115200) { + quot = 1; + serial_outp(&pinfo, UART_OMAP_OSC_12M_SEL, 1); + } else { + quot = pinfo.state->baud_base / kgdb_baud; + serial_outp(&pinfo, UART_OMAP_OSC_12M_SEL, 0); + } +#endif + serial_outp(&pinfo, UART_LCR, UART_LCR_WLEN8); + serial_outp(&pinfo, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_outp(&pinfo, UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB); + serial_outp(&pinfo, UART_DLL, quot & 0xff); + serial_outp(&pinfo, UART_DLM, quot >> 8); + serial_outp(&pinfo, UART_LCR, UART_LCR_WLEN8); + serial_outp(&pinfo, UART_IER, 0); + serial_outp(&pinfo, UART_MCR, 0); +} + +void +kgdb_serial_putchar(unsigned char ch) +{ + unsigned char status; + + if (!pinfo.state) + return; /* need to init device first */ + + do { + status = serial_inp(&pinfo, UART_LSR); + } while ((status & (UART_LSR_TEMT | UART_LSR_THRE)) != + (UART_LSR_TEMT | UART_LSR_THRE)); + + serial_outp(&pinfo, UART_TX, ch); +} + +unsigned char +kgdb_serial_getchar(void) +{ + if (!pinfo.state) + return 0; /* need to init device first */ + + while ((serial_inp(&pinfo, UART_LSR) & UART_LSR_DR) == 0) + ; + + return(serial_inp(&pinfo, UART_RX)); +} diff -Nru a/arch/arm/mach-omap/leds-h2p2-debug.c b/arch/arm/mach-omap/leds-h2p2-debug.c --- a/arch/arm/mach-omap/leds-h2p2-debug.c 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/mach-omap/leds-h2p2-debug.c 2005-03-02 10:51:31 -08:00 @@ -3,6 +3,11 @@ * * Copyright 2003 by Texas Instruments Incorporated * + * There are 16 LEDs on the debug board (all green); four may be used + * for logical 'green', 'amber', 'red', and 'blue' (after "claiming"). + * + * The "surfer" expansion board and H2 sample board also have two-color + * green+red LEDs (in parallel), used here for timer and idle indicators. */ #include #include @@ -16,78 +21,111 @@ #include #include +#include #include "leds.h" + +#define GPIO_LED_RED 3 +#define GPIO_LED_GREEN OMAP_MPUIO(4) + + +#define LED_STATE_ENABLED 0x01 +#define LED_STATE_CLAIMED 0x02 +#define LED_TIMER_ON 0x04 + +#define GPIO_IDLE GPIO_LED_GREEN +#define GPIO_TIMER GPIO_LED_RED + + void h2p2_dbg_leds_event(led_event_t evt) { unsigned long flags; - static unsigned long hw_led_state = 0; + + static struct h2p2_dbg_fpga __iomem *fpga; + static u16 led_state, hw_led_state; local_irq_save(flags); + if (!(led_state & LED_STATE_ENABLED) && evt != led_start) + goto done; + switch (evt) { case led_start: - hw_led_state |= H2P2_DBG_FPGA_LED_STARTSTOP; + if (!fpga) + fpga = ioremap(H2P2_DBG_FPGA_START, + H2P2_DBG_FPGA_SIZE); + if (fpga) { + led_state |= LED_STATE_ENABLED; + __raw_writew(~0, &fpga->leds); + } break; case led_stop: - hw_led_state &= ~H2P2_DBG_FPGA_LED_STARTSTOP; - break; + case led_halted: + /* all leds off during suspend or shutdown */ + omap_set_gpio_dataout(GPIO_TIMER, 0); + omap_set_gpio_dataout(GPIO_IDLE, 0); + __raw_writew(~0, &fpga->leds); + led_state &= ~LED_STATE_ENABLED; + if (evt == led_halted) { + iounmap(fpga); + fpga = NULL; + } + goto done; case led_claim: - hw_led_state |= H2P2_DBG_FPGA_LED_CLAIMRELEASE; + led_state |= LED_STATE_CLAIMED; + hw_led_state = 0; break; case led_release: - hw_led_state &= ~H2P2_DBG_FPGA_LED_CLAIMRELEASE; + led_state &= ~LED_STATE_CLAIMED; break; #ifdef CONFIG_LEDS_TIMER case led_timer: - /* - * Toggle Timer LED - */ - if (hw_led_state & H2P2_DBG_FPGA_LED_TIMER) - hw_led_state &= ~H2P2_DBG_FPGA_LED_TIMER; - else - hw_led_state |= H2P2_DBG_FPGA_LED_TIMER; - break; + led_state ^= LED_TIMER_ON; + omap_set_gpio_dataout(GPIO_TIMER, led_state & LED_TIMER_ON); + goto done; #endif #ifdef CONFIG_LEDS_CPU case led_idle_start: - hw_led_state |= H2P2_DBG_FPGA_LED_IDLE; - break; + omap_set_gpio_dataout(GPIO_IDLE, 1); + goto done; case led_idle_end: - hw_led_state &= ~H2P2_DBG_FPGA_LED_IDLE; - break; + omap_set_gpio_dataout(GPIO_IDLE, 0); + goto done; #endif - case led_halted: - if (hw_led_state & H2P2_DBG_FPGA_LED_HALTED) - hw_led_state &= ~H2P2_DBG_FPGA_LED_HALTED; - else - hw_led_state |= H2P2_DBG_FPGA_LED_HALTED; - break; - case led_green_on: + hw_led_state |= H2P2_DBG_FPGA_LED_GREEN; break; - case led_green_off: + hw_led_state &= ~H2P2_DBG_FPGA_LED_GREEN; break; case led_amber_on: + hw_led_state |= H2P2_DBG_FPGA_LED_AMBER; break; - case led_amber_off: + hw_led_state &= ~H2P2_DBG_FPGA_LED_AMBER; break; case led_red_on: + hw_led_state |= H2P2_DBG_FPGA_LED_RED; break; - case led_red_off: + hw_led_state &= ~H2P2_DBG_FPGA_LED_RED; + break; + + case led_blue_on: + hw_led_state |= H2P2_DBG_FPGA_LED_BLUE; + break; + case led_blue_off: + hw_led_state &= ~H2P2_DBG_FPGA_LED_BLUE; break; default: @@ -98,7 +136,9 @@ /* * Actually burn the LEDs */ - __raw_writew(~hw_led_state & 0xffff, H2P2_DBG_FPGA_LEDS); + if (led_state & LED_STATE_CLAIMED) + __raw_writew(~hw_led_state, &fpga->leds); +done: local_irq_restore(flags); } diff -Nru a/arch/arm/mach-omap/leds-osk.c b/arch/arm/mach-omap/leds-osk.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/arch/arm/mach-omap/leds-osk.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,198 @@ +/* + * linux/arch/arm/mach-omap/leds-osk.c + * + * LED driver for OSK, and optionally Mistral QVGA, boards + */ +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "leds.h" + + +#define LED_STATE_ENABLED (1 << 0) +#define LED_STATE_CLAIMED (1 << 1) +static u8 led_state; + +#define GREEN_LED (1 << 0) /* TPS65010 LED1 */ +#define AMBER_LED (1 << 1) /* TPS65010 LED2 */ +#define RED_LED (1 << 2) /* TPS65010 GPIO2 */ +#define TIMER_LED (1 << 3) /* Mistral board */ +#define IDLE_LED (1 << 4) /* Mistral board */ +static u8 hw_led_state; + + +/* TPS65010 leds are changed using i2c -- from a task context. + * Using one of these for the "idle" LED would be impractical... + */ +#define TPS_LEDS (GREEN_LED | RED_LED | AMBER_LED) + +static u8 tps_leds_change; + +static void tps_work(void *unused) +{ + for (;;) { + u8 leds; + + local_irq_disable(); + leds = tps_leds_change; + tps_leds_change = 0; + local_irq_enable(); + + if (!leds) + break; + + /* careful: the set_led() value is on/off/blink */ + if (leds & GREEN_LED) + tps65010_set_led(LED1, !!(hw_led_state & GREEN_LED)); + if (leds & AMBER_LED) + tps65010_set_led(LED2, !!(hw_led_state & AMBER_LED)); + + /* the gpio led doesn't have that issue */ + if (leds & RED_LED) + tps65010_set_gpio_out_value(GPIO2, + !(hw_led_state & RED_LED)); + } +} + +static DECLARE_WORK(work, tps_work, NULL); + +#ifdef CONFIG_FB_OMAP + +/* For now, all system indicators require the Mistral board, since that + * LED can be manipulated without a task context. This LED is either red, + * or green, but not both; it can't give the full "disco led" effect. + */ + +#define GPIO_LED_RED 3 +#define GPIO_LED_GREEN OMAP_MPUIO(4) + +static void mistral_setled(void) +{ + int red = 0; + int green = 0; + + if (hw_led_state & TIMER_LED) + red = 1; + else if (hw_led_state & IDLE_LED) + green = 1; + // else both sides are disabled + + omap_set_gpio_dataout(GPIO_LED_GREEN, green); + omap_set_gpio_dataout(GPIO_LED_RED, red); +} + +#endif + +void osk_leds_event(led_event_t evt) +{ + unsigned long flags; + u16 leds; + + local_irq_save(flags); + + if (!(led_state & LED_STATE_ENABLED) && evt != led_start) + goto done; + + leds = hw_led_state; + switch (evt) { + case led_start: + led_state |= LED_STATE_ENABLED; + hw_led_state = 0; + leds = ~0; + break; + + case led_halted: + case led_stop: + led_state &= ~LED_STATE_ENABLED; + hw_led_state = 0; + // NOTE: work may still be pending!! + break; + + case led_claim: + led_state |= LED_STATE_CLAIMED; + hw_led_state = 0; + leds = ~0; + break; + + case led_release: + led_state &= ~LED_STATE_CLAIMED; + hw_led_state = 0; + break; + +#ifdef CONFIG_FB_OMAP + +#ifdef CONFIG_LEDS_TIMER + case led_timer: + hw_led_state ^= TIMER_LED; + mistral_setled(); + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: + hw_led_state |= IDLE_LED; + mistral_setled(); + break; + + case led_idle_end: + hw_led_state &= ~IDLE_LED; + mistral_setled(); + break; +#endif + +#endif /* CONFIG_FB_OMAP */ + + /* "green" == tps LED1 (leftmost, normally power-good) + * works only with DC adapter, not on battery power! + */ + case led_green_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= GREEN_LED; + break; + case led_green_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~GREEN_LED; + break; + + /* "amber" == tps LED2 (middle) */ + case led_amber_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= AMBER_LED; + break; + case led_amber_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~AMBER_LED; + break; + + /* "red" == LED on tps gpio3 (rightmost) */ + case led_red_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= RED_LED; + break; + case led_red_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~RED_LED; + break; + + default: + break; + } + + leds ^= hw_led_state; + leds &= TPS_LEDS; + if (leds && (led_state & LED_STATE_CLAIMED)) { + tps_leds_change |= leds; + schedule_work(&work); + } + +done: + local_irq_restore(flags); +} diff -Nru a/arch/arm/mach-omap/leds.c b/arch/arm/mach-omap/leds.c --- a/arch/arm/mach-omap/leds.c 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/mach-omap/leds.c 2005-03-02 10:51:31 -08:00 @@ -9,6 +9,9 @@ #include #include +#include +#include + #include "leds.h" static int __init @@ -17,8 +20,38 @@ if (machine_is_omap_innovator()) leds_event = innovator_leds_event; - else if (machine_is_omap_h2() || machine_is_omap_perseus2()) { + else if (machine_is_omap_h2() || machine_is_omap_perseus2()) leds_event = h2p2_dbg_leds_event; + + else if (machine_is_omap_osk()) + leds_event = osk_leds_event; + + else + return -1; + + if (machine_is_omap_h2() + || machine_is_omap_perseus2() + || machine_is_omap_osk()) { + + /* LED1/LED2 pins can be used as GPIO (as done here), or by + * the LPG (works even in deep sleep!), to drive a bicolor + * LED on the H2 sample board, and another on the H2/P2 + * "surfer" expansion board. + * + * The same pins drive a LED on the OSK Mistral board, but + * that's a different kind of LED (just one color at a time). + */ + omap_cfg_reg(P18_1610_GPIO3); + if (omap_request_gpio(3) == 0) + omap_set_gpio_direction(3, 0); + else + printk(KERN_WARNING "LED: can't get GPIO3/red?\n"); + + omap_cfg_reg(MPUIO4); + if (omap_request_gpio(OMAP_MPUIO(4)) == 0) + omap_set_gpio_direction(OMAP_MPUIO(4), 0); + else + printk(KERN_WARNING "LED: can't get MPUIO4/green?\n"); } leds_event(led_start); diff -Nru a/arch/arm/mach-omap/leds.h b/arch/arm/mach-omap/leds.h --- a/arch/arm/mach-omap/leds.h 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/mach-omap/leds.h 2005-03-02 10:51:31 -08:00 @@ -1,2 +1,3 @@ extern void innovator_leds_event(led_event_t evt); extern void h2p2_dbg_leds_event(led_event_t evt); +extern void osk_leds_event(led_event_t evt); diff -Nru a/arch/arm/mach-omap/mcbsp.c b/arch/arm/mach-omap/mcbsp.c --- a/arch/arm/mach-omap/mcbsp.c 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/mach-omap/mcbsp.c 2005-03-02 10:51:31 -08:00 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -175,7 +176,7 @@ return 0; } - if (cpu_is_omap1510() || cpu_is_omap1610() || cpu_is_omap1710()) { + if (cpu_is_omap1510() || cpu_is_omap16xx()) { if (id > OMAP_MAX_MCBSP_COUNT) { printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1); return -1; @@ -191,9 +192,8 @@ static void omap_mcbsp_dsp_request(void) { - if (cpu_is_omap1510() || cpu_is_omap1610() || cpu_is_omap1710()) { - omap_writew((omap_readw(ARM_RSTCT1) | (1 << 1) | (1 << 2)), - ARM_RSTCT1); + if (cpu_is_omap1510() || cpu_is_omap16xx()) { + omap_dsp_request_idle(); clk_enable(mcbsp_dsp_ck); clk_enable(mcbsp_api_ck); @@ -350,6 +350,73 @@ } +/* polled mcbsp i/o operations */ +int omap_mcbsp_pollwrite(unsigned int id, u16 buf) +{ + u32 base = mcbsp[id].io_base; + writew(buf, base + OMAP_MCBSP_REG_DXR1); + /* if frame sync error - clear the error */ + if (readw(base + OMAP_MCBSP_REG_SPCR2) & XSYNC_ERR) { + /* clear error */ + writew(readw(base + OMAP_MCBSP_REG_SPCR2) & (~XSYNC_ERR), + base + OMAP_MCBSP_REG_SPCR2); + /* resend */ + return -1; + } else { + /* wait for transmit confirmation */ + int attemps = 0; + while (!(readw(base + OMAP_MCBSP_REG_SPCR2) & XRDY)) { + if (attemps++ > 1000) { + writew(readw(base + OMAP_MCBSP_REG_SPCR2) & + (~XRST), + base + OMAP_MCBSP_REG_SPCR2); + udelay(10); + writew(readw(base + OMAP_MCBSP_REG_SPCR2) | + (XRST), + base + OMAP_MCBSP_REG_SPCR2); + udelay(10); + printk(KERN_ERR + " Could not write to McBSP Register\n"); + return -2; + } + } + } + return 0; +} + +int omap_mcbsp_pollread(unsigned int id, u16 * buf) +{ + u32 base = mcbsp[id].io_base; + /* if frame sync error - clear the error */ + if (readw(base + OMAP_MCBSP_REG_SPCR1) & RSYNC_ERR) { + /* clear error */ + writew(readw(base + OMAP_MCBSP_REG_SPCR1) & (~RSYNC_ERR), + base + OMAP_MCBSP_REG_SPCR1); + /* resend */ + return -1; + } else { + /* wait for recieve confirmation */ + int attemps = 0; + while (!(readw(base + OMAP_MCBSP_REG_SPCR1) & RRDY)) { + if (attemps++ > 1000) { + writew(readw(base + OMAP_MCBSP_REG_SPCR1) & + (~RRST), + base + OMAP_MCBSP_REG_SPCR1); + udelay(10); + writew(readw(base + OMAP_MCBSP_REG_SPCR1) | + (RRST), + base + OMAP_MCBSP_REG_SPCR1); + udelay(10); + printk(KERN_ERR + " Could not read from McBSP Register\n"); + return -2; + } + } + } + *buf = readw(base + OMAP_MCBSP_REG_DRR1); + return 0; +} + /* * IRQ based word transmission. */ @@ -625,7 +692,7 @@ return PTR_ERR(mcbsp_dsp_ck); } mcbsp_api_ck = clk_get(0, "api_ck"); - if (IS_ERR(mcbsp_dsp_ck)) { + if (IS_ERR(mcbsp_api_ck)) { printk(KERN_ERR "mcbsp: could not acquire api_ck handle.\n"); return PTR_ERR(mcbsp_api_ck); } @@ -643,7 +710,7 @@ } #endif #if defined(CONFIG_ARCH_OMAP16XX) - if (cpu_is_omap1610() || cpu_is_omap1710()) { + if (cpu_is_omap16xx()) { mcbsp_info = mcbsp_1610; mcbsp_count = ARRAY_SIZE(mcbsp_1610); } diff -Nru a/arch/arm/mach-omap/mux.c b/arch/arm/mach-omap/mux.c --- a/arch/arm/mach-omap/mux.c 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/mach-omap/mux.c 2005-03-02 10:51:31 -08:00 @@ -40,7 +40,7 @@ int __init_or_module omap_cfg_reg(const reg_cfg_t reg_cfg) { - static DEFINE_SPINLOCK(mux_spin_lock); + static spinlock_t mux_spin_lock = SPIN_LOCK_UNLOCKED; unsigned long flags; reg_cfg_set *cfg; diff -Nru a/arch/arm/mach-omap/ocpi.c b/arch/arm/mach-omap/ocpi.c --- a/arch/arm/mach-omap/ocpi.c 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/mach-omap/ocpi.c 2005-03-02 10:51:31 -08:00 @@ -1,11 +1,13 @@ /* * linux/arch/arm/mach-omap/ocpi.c * - * Minimal OCP bus support for OMAP-1610 and OMAP-5912 + * Minimal OCP bus support for omap16xx * - * Copyright (C) 2003 - 2004 Nokia Corporation + * Copyright (C) 2003 - 2005 Nokia Corporation * Written by Tony Lindgren * + * Modified for clock framework by Paul Mundt . + * * 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 @@ -29,8 +31,10 @@ #include #include #include +#include #include +#include #include #define OCPI_BASE 0xfffec320 @@ -42,13 +46,12 @@ #define OCPI_PROT (OCPI_BASE + 0x14) #define OCPI_SEC (OCPI_BASE + 0x18) -#define EN_OCPI_CK (1 << 0) -#define IDLOCPI_ARM (1 << 1) - /* USB OHCI OCPI access error registers */ #define HOSTUEADDR 0xfffba0e0 #define HOSTUESTATUS 0xfffba0e4 +static struct clk *ocpi_ck; + /* * Enables device access to OMAP buses via the OCPI bridge * FIXME: Add locking @@ -57,16 +60,12 @@ { unsigned int val; + if (!cpu_is_omap16xx()) + return -ENODEV; + /* Make sure there's clock for OCPI */ + clk_enable(ocpi_ck); -#if defined(CONFIG_ARCH_OMAP16XX) - if (cpu_is_omap1610() || cpu_is_omap1710()) { - val = omap_readl(OMAP16XX_ARM_IDLECT3); - val |= EN_OCPI_CK; - val &= ~IDLOCPI_ARM; - omap_writel(val, OMAP16XX_ARM_IDLECT3); - } -#endif /* Enable access for OHCI in OCPI */ val = omap_readl(OCPI_PROT); val &= ~0xff; @@ -81,19 +80,16 @@ } EXPORT_SYMBOL(ocpi_enable); -int ocpi_status(void) +static int __init omap_ocpi_init(void) { - printk("OCPI: addr: 0x%08x cmd: 0x%08x\n" - " ohci-addr: 0x%08x ohci-status: 0x%08x\n", - omap_readl(OCPI_FAULT), omap_readl(OCPI_CMD_FAULT), - omap_readl(HOSTUEADDR), omap_readl(HOSTUESTATUS)); + if (!cpu_is_omap16xx()) + return -ENODEV; - return 1; -} -EXPORT_SYMBOL(ocpi_status); + ocpi_ck = clk_get(NULL, "l3_ocpi_ck"); + if (IS_ERR(ocpi_ck)) + return PTR_ERR(ocpi_ck); -static int __init omap_ocpi_init(void) -{ + clk_use(ocpi_ck); ocpi_enable(); printk("OMAP OCPI interconnect driver loaded\n"); @@ -102,7 +98,13 @@ static void __exit omap_ocpi_exit(void) { - /* FIXME: Disable OCPI */ + /* REVISIT: Disable OCPI */ + + if (!cpu_is_omap16xx()) + return; + + clk_unuse(ocpi_ck); + clk_put(ocpi_ck); } MODULE_AUTHOR("Tony Lindgren "); diff -Nru a/arch/arm/mach-omap/pm.c b/arch/arm/mach-omap/pm.c --- a/arch/arm/mach-omap/pm.c 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/mach-omap/pm.c 2005-03-02 10:51:31 -08:00 @@ -41,8 +41,12 @@ #include #include +#include +#include + #include #include +#include #include #include #include @@ -83,10 +87,19 @@ local_irq_enable(); #if defined(CONFIG_OMAP_32K_TIMER) && defined(CONFIG_NO_IDLE_HZ) - /* Override timer to use VST for the next cycle */ - omap_32k_timer_next_vst_interrupt(); + /* Override timer to use dynamic tick for the next cycle */ + if ((system_timer->dyn_tick->state & DYN_TICK_ENABLED) + && system_timer->dyn_tick->reprogram) + system_timer->dyn_tick->reprogram(); #endif + /* + * Prevent the ULPD from entering low power state by setting + * POWER_CTRL_REG:4 = 0 + */ + omap_writew(omap_readw(ULPD_POWER_CTRL) & + ~ULPD_DEEP_SLEEP_TRANSITION_EN, ULPD_POWER_CTRL); + if ((mask32 & DSP_IDLE) == 0) { __asm__ volatile ("mcr p15, 0, r0, c7, c0, 4"); } else { @@ -111,16 +124,6 @@ static void omap_pm_wakeup_setup(void) { /* - * Enable ARM XOR clock and release peripheral from reset by - * writing 1 to PER_EN bit in ARM_RSTCT2, this is required - * for UART configuration to use UART2 to wake up. - */ - - omap_writel(omap_readl(ARM_IDLECT2) | ENABLE_XORCLK, ARM_IDLECT2); - omap_writel(omap_readl(ARM_RSTCT2) | PER_EN, ARM_RSTCT2); - omap_writew(MODEM_32K_EN, ULPD_CLOCK_CTRL); - - /* * Turn off all interrupts except L1-2nd level cascade, * and the L2 wakeup interrupts: keypad and UART2. */ @@ -139,29 +142,61 @@ omap_writel(~0x0, OMAP_IH2_3_MIR); } - /* New IRQ agreement */ + /* New IRQ agreement, recalculate in cascade order */ + omap_writel(1, OMAP_IH2_CONTROL); omap_writel(1, OMAP_IH1_CONTROL); - - /* external PULL to down, bit 22 = 0 */ - omap_writel(omap_readl(PULL_DWN_CTRL_2) & ~(1<<22), PULL_DWN_CTRL_2); } void omap_pm_suspend(void) { - unsigned int mask32 = 0; unsigned long arg0 = 0, arg1 = 0; int (*func_ptr)(unsigned short, unsigned short) = 0; unsigned short save_dsp_idlect2; + int restore_usb_mclk = 0; /* FIXME: remove after fixing driver */ + int restore_usb_w2fc_pvci = 0; /* FIXME: remove after fixing driver */ + int restore_soft_requests = 0; /* FIXME: remove after fixing drivers */ + int restore_bclk = 0; /* FIXME: remove after fixing driver */ - printk("PM: OMAP%x is entering deep sleep now ...\n", system_rev); + printk("PM: OMAP%x is trying to enter deep sleep...\n", system_rev); if (machine_is_omap_osk()) { /* Stop LED1 (D9) blink */ tps65010_set_led(LED1, OFF); } + /* --- BEGIN FIXME: broken drivers --- */ + if ((omap_readw(ULPD_CLOCK_CTRL) & 0x20) == 0) { + printk("FIXME: USB W2FC PVCI clock is still enabled!\n"); + omap_writew(omap_readw(ULPD_CLOCK_CTRL) | 0x20, ULPD_CLOCK_CTRL); + restore_usb_w2fc_pvci = 1; + } + if ((omap_readw(ULPD_CLOCK_CTRL) & 0x10)) { + printk("FIXME: USB hub clock is still enabled!\n"); + omap_writew(omap_readw(ULPD_CLOCK_CTRL) & ~0x10, ULPD_CLOCK_CTRL); + restore_usb_mclk = 1; + } + restore_soft_requests = omap_readw(ULPD_SOFT_REQ); + if (restore_soft_requests) { + printk("FIXME: SOFT_REQ_REG for ULPD clocks as still enabled: %04x\n", + restore_soft_requests); + omap_writew(0, ULPD_SOFT_REQ); + } + restore_bclk = omap_readw(ULPD_SDW_CLK_DIV_CTRL_SEL); + if (restore_bclk & 2) { + printk("FIXME: BCLK is still enabled!\n"); + omap_writew(restore_bclk & ~2, ULPD_SDW_CLK_DIV_CTRL_SEL); +#if 0 + printk("Assuming display DMA is active, resetting DMA" + " controller.\n"); + omap_writew(1, 0xfffedc08); +#endif + } + + omap_writew(0xffff, ULPD_SOFT_DISABLE_REQ_REG); + /* --- END FIXME: broken drivers --- */ + /* - * Step 1: turn off interrupts + * Step 1: turn off interrupts (FIXME: NOTE: already disabled) */ local_irq_disable(); @@ -210,22 +245,11 @@ ULPD_SAVE(ULPD_STATUS_REQ); /* - * Step 3: LOW_PWR signal enabling - * - * Allow the LOW_PWR signal to be visible on MPUIO5 ball. + * Step 3: Allow the ULPD to enter low power state by setting + * POWER_CTRL_REG:4 = 1 */ - if (cpu_is_omap1510()) { - /* POWER_CTRL_REG = 0x1 (LOW_POWER is available) */ - omap_writew(omap_readw(ULPD_POWER_CTRL) | - OMAP1510_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL); - } else if (cpu_is_omap16xx()) { - /* POWER_CTRL_REG = 0x1 (LOW_POWER is available) */ - omap_writew(omap_readw(ULPD_POWER_CTRL) | - OMAP1610_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL); - } - - /* configure LOW_PWR pin */ - omap_cfg_reg(T20_1610_LOW_PWR); + omap_writew(ULPD_POWER_CTRL_REG_VAL | + ULPD_DEEP_SLEEP_TRANSITION_EN, ULPD_POWER_CTRL); /* * Step 4: OMAP DSP Shutdown @@ -253,24 +277,9 @@ omap_pm_wakeup_setup(); /* - * Step 6a: ARM and Traffic controller shutdown - * - * Step 6 starts here with clock and watchdog disable + * Step 6: ARM and Traffic controller shutdown */ - /* stop clocks */ - mask32 = omap_readl(ARM_IDLECT2); - mask32 &= ~(1< 0 (WDT clock) */ - mask32 |= (1< 1 (XORPCK clock) */ - mask32 &= ~(1< 0 (MPUPER_CK clock) */ - mask32 &= ~(1< 0 (LCDC clock) */ - mask32 &= ~(1< 0 (local bus clock) */ - mask32 |= (1< 1 (MPUI clock) */ - mask32 &= ~(1< 0 (MPU timer clock) */ - mask32 &= ~(1< 0 (DMAC clock) */ - mask32 &= ~(1< 0 (GPIO clock) */ - omap_writel(mask32, ARM_IDLECT2); - /* disable ARM watchdog */ omap_writel(0x00F5, OMAP_WDT_TIMER_MODE); omap_writel(0x00A0, OMAP_WDT_TIMER_MODE); @@ -311,17 +320,6 @@ * If we are here, processor is woken up! */ - if (cpu_is_omap1510()) { - /* POWER_CTRL_REG = 0x0 (LOW_POWER is disabled) */ - omap_writew(omap_readw(ULPD_POWER_CTRL) & - ~OMAP1510_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL); - } else if (cpu_is_omap16xx()) { - /* POWER_CTRL_REG = 0x0 (LOW_POWER is disabled) */ - omap_writew(omap_readw(ULPD_POWER_CTRL) & - ~OMAP1610_ULPD_LOW_POWER_REQ, ULPD_POWER_CTRL); - } - - /* Restore DSP clocks */ omap_writel(omap_readl(ARM_IDLECT2) | (1< and * Tuukka Tikkanen * @@ -48,9 +48,12 @@ #include #include #include +#include struct sys_timer omap_timer; +#ifdef CONFIG_OMAP_MPU_TIMER + /* * --------------------------------------------------------------------------- * MPU timer @@ -67,6 +70,36 @@ #define MPU_TIMER_AR (1 << 1) #define MPU_TIMER_ST (1 << 0) +/* cycles to nsec conversions taken from arch/i386/kernel/timers/timer_tsc.c, + * converted to use kHz by Kevin Hilman */ +/* convert from cycles(64bits) => nanoseconds (64bits) + * basic equation: + * ns = cycles / (freq / ns_per_sec) + * ns = cycles * (ns_per_sec / freq) + * ns = cycles * (10^9 / (cpu_khz * 10^3)) + * ns = cycles * (10^6 / cpu_khz) + * + * Then we use scaling math (suggested by george at mvista.com) to get: + * ns = cycles * (10^6 * SC / cpu_khz / SC + * ns = cycles * cyc2ns_scale / SC + * + * And since SC is a constant power of two, we can convert the div + * into a shift. + * -johnstul at us.ibm.com "math is hard, lets go shopping!" + */ +static unsigned long cyc2ns_scale; +#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */ + +static inline void set_cyc2ns_scale(unsigned long cpu_khz) +{ + cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR)/cpu_khz; +} + +static inline unsigned long long cycles_2_ns(unsigned long long cyc) +{ + return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR; +} + /* * MPU_TICKS_PER_SEC must be an even number, otherwise machinecycles_to_usecs * will break. On P2, the timer count rate is 6.5 MHz after programming PTV @@ -112,8 +145,10 @@ unsigned long omap_mpu_timer_ticks_to_usecs(unsigned long nr_ticks) { - /* Round up to nearest usec */ - return ((nr_ticks * 1000) / (MPU_TICKS_PER_SEC / 2 / 1000) + 1) >> 1; + unsigned long long nsec; + + nsec = cycles_2_ns((unsigned long long)nr_ticks); + return (unsigned long)nsec / 1000; } /* @@ -158,22 +193,268 @@ .handler = omap_mpu_timer_interrupt }; +static unsigned long omap_mpu_timer1_overflows; +static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + omap_mpu_timer1_overflows++; + return IRQ_HANDLED; +} + +static struct irqaction omap_mpu_timer1_irq = { + .name = "mpu timer1 overflow", + .flags = SA_INTERRUPT, + .handler = omap_mpu_timer1_interrupt +}; + static __init void omap_init_mpu_timer(void) { + set_cyc2ns_scale(MPU_TICKS_PER_SEC / 1000); omap_timer.offset = omap_mpu_timer_gettimeoffset; + setup_irq(INT_TIMER1, &omap_mpu_timer1_irq); setup_irq(INT_TIMER2, &omap_mpu_timer_irq); omap_mpu_timer_start(0, 0xffffffff); omap_mpu_timer_start(1, MPU_TIMER_TICK_PERIOD); } /* + * Scheduler clock - returns current time in nanosec units. + */ +unsigned long long sched_clock(void) +{ + unsigned long ticks = 0 - omap_mpu_timer_read(0); + unsigned long long ticks64; + + ticks64 = omap_mpu_timer1_overflows; + ticks64 <<= 32; + ticks64 |= ticks; + + return cycles_2_ns(ticks64); +} +#endif /* CONFIG_OMAP_MPU_TIMER */ + +#ifdef CONFIG_OMAP_32K_TIMER + +#ifdef CONFIG_ARCH_OMAP1510 +#error OMAP 32KHz timer does not currently work on 1510! +#endif + +/* + * --------------------------------------------------------------------------- + * 32KHz OS timer + * + * This currently works only on 16xx, as 1510 does not have the continuous + * 32KHz synchronous timer. The 32KHz synchronous timer is used to keep track + * of time in addition to the 32KHz OS timer. Using only the 32KHz OS timer + * on 1510 would be possible, but the timer would not be as accurate as + * with the 32KHz synchronized timer. + * --------------------------------------------------------------------------- + */ +#define OMAP_32K_TIMER_BASE 0xfffb9000 +#define OMAP_32K_TIMER_CR 0x08 +#define OMAP_32K_TIMER_TVR 0x00 +#define OMAP_32K_TIMER_TCR 0x04 + +#define OMAP_32K_TICKS_PER_HZ (32768 / HZ) +#if (32768 % HZ) != 0 +/* We cannot ignore modulo. + * Potential error can be as high as several percent. + */ +#define OMAP_32K_TICK_MODULO (32768 % HZ) +static unsigned modulo_count = 0; /* Counts 1/HZ units */ +#endif + +/* + * TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1 + * so with HZ = 100, TVR = 327.68. + */ +#define OMAP_32K_TIMER_TICK_PERIOD ((32768 / HZ) - 1) +#define MAX_SKIP_JIFFIES 25 +#define TIMER_32K_SYNCHRONIZED 0xfffbc410 + +#define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \ + (((nr_jiffies) * (clock_rate)) / HZ) + +static inline void omap_32k_timer_write(int val, int reg) +{ + omap_writew(val, reg + OMAP_32K_TIMER_BASE); +} + +static inline unsigned long omap_32k_timer_read(int reg) +{ + return omap_readl(reg + OMAP_32K_TIMER_BASE) & 0xffffff; +} + +/* + * The 32KHz synchronized timer is an additional timer on 16xx. + * It is always running. + */ +static inline unsigned long omap_32k_sync_timer_read(void) +{ + return omap_readl(TIMER_32K_SYNCHRONIZED); +} + +static inline void omap_32k_timer_start(unsigned long load_val) +{ + omap_32k_timer_write(load_val, OMAP_32K_TIMER_TVR); + omap_32k_timer_write(0x0f, OMAP_32K_TIMER_CR); +} + +static inline void omap_32k_timer_stop(void) +{ + omap_32k_timer_write(0x0, OMAP_32K_TIMER_CR); +} + +/* + * Rounds down to nearest usec + */ +static inline unsigned long omap_32k_ticks_to_usecs(unsigned long ticks_32k) +{ + return (ticks_32k * 5*5*5*5*5*5) >> 9; +} + +static unsigned long omap_32k_last_tick = 0; + +/* + * Returns elapsed usecs since last 32k timer interrupt + */ +static unsigned long omap_32k_timer_gettimeoffset(void) +{ + unsigned long now = omap_32k_sync_timer_read(); + return omap_32k_ticks_to_usecs(now - omap_32k_last_tick); +} + +/* + * Timer interrupt for 32KHz timer. When dynamic tick is enabled, this + * function is also called from other interrupts to remove latency + * issues with dynamic tick. In the dynamic tick case, we need to lock + * with irqsave. + */ +static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + unsigned long flags; + unsigned long now; + + write_seqlock_irqsave(&xtime_lock, flags); + now = omap_32k_sync_timer_read(); + + while (now - omap_32k_last_tick >= OMAP_32K_TICKS_PER_HZ) { +#ifdef OMAP_32K_TICK_MODULO + /* Modulo addition may put omap_32k_last_tick ahead of now + * and cause unwanted repetition of the while loop. + */ + if (unlikely(now - omap_32k_last_tick == ~0)) + break; + + modulo_count += OMAP_32K_TICK_MODULO; + if (modulo_count > HZ) { + ++omap_32k_last_tick; + modulo_count -= HZ; + } +#endif + omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ; + timer_tick(regs); + } + + /* Restart timer so we don't drift off due to modulo or dynamic tick. + * By default we program the next timer to be continuous to avoid + * latencies during high system load. During dynamic tick operation the + * continuous timer can be overridden from pm_idle to be longer. + */ + omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now); + write_sequnlock_irqrestore(&xtime_lock, flags); + + return IRQ_HANDLED; +} + +#ifdef CONFIG_NO_IDLE_HZ +/* + * Programs the next timer interrupt needed. Called when dynamic tick is + * enabled, and to reprogram the ticks to skip from pm_idle. + */ +void omap_32k_timer_next_dyn_tick_interrupt(void) +{ + unsigned long next; + + if (!system_timer->dyn_tick->state & DYN_TICK_ENABLED) + return; + + next = next_timer_interrupt() - jiffies; + + if (next > MAX_SKIP_JIFFIES) + next = MAX_SKIP_JIFFIES; + + /* + * We can keep the timer continuous, no need to set it to + * run in one-shot mode. When using dynamic tick, the timer + * will get reprogrammed again after the next interrupt. + */ + omap_32k_timer_start(JIFFIES_TO_HW_TICKS(next, 32768) + 1); +} + +static struct irqaction omap_32k_timer_irq; +extern struct timer_update_handler timer_update; + +static int omap_32k_timer_enable_dyn_tick(void) +{ + omap_32k_timer_next_dyn_tick_interrupt(); + return 0; +} + +static int omap_32k_timer_disable_dyn_tick(void) +{ + omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD); + return 0; +} + +static struct dyn_tick_timer omap_dyn_tick_timer = { + .enable = omap_32k_timer_enable_dyn_tick, + .disable = omap_32k_timer_disable_dyn_tick, + .reprogram = omap_32k_timer_next_dyn_tick_interrupt +}; + +static struct dyn_tick_timer_int omap_dyn_tick_int = { + .skip = INT_OS_TIMER, + .handler = omap_32k_timer_interrupt +}; +#endif /* CONFIG_NO_IDLE_HZ */ + +static struct irqaction omap_32k_timer_irq = { + .name = "32KHz timer", + .flags = SA_INTERRUPT, + .handler = omap_32k_timer_interrupt +}; + +static __init void omap_init_32k_timer(void) +{ + setup_irq(INT_OS_TIMER, &omap_32k_timer_irq); + omap_timer.offset = omap_32k_timer_gettimeoffset; + +#ifdef CONFIG_NO_IDLE_HZ + omap_timer.dyn_tick = &omap_dyn_tick_timer; + omap_timer.dyn_tick_int = &omap_dyn_tick_int; +#endif + + omap_32k_last_tick = omap_32k_sync_timer_read(); + omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD); +} +#endif /* CONFIG_OMAP_32K_TIMER */ + +/* * --------------------------------------------------------------------------- * Timer initialization * --------------------------------------------------------------------------- */ void __init omap_timer_init(void) { +#if defined(CONFIG_OMAP_MPU_TIMER) omap_init_mpu_timer(); +#elif defined(CONFIG_OMAP_32K_TIMER) + omap_init_32k_timer(); +#else +#error No system timer selected in Kconfig! +#endif } struct sys_timer omap_timer = { diff -Nru a/arch/arm/mach-omap/usb.c b/arch/arm/mach-omap/usb.c --- a/arch/arm/mach-omap/usb.c 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/mach-omap/usb.c 2005-03-02 10:51:31 -08:00 @@ -49,10 +49,13 @@ /* TESTED ON: * - 1611B H2 (with usb1 mini-AB) using standard Mini-B or OTG cables + * - 5912 OSK OHCI (with usb0 standard-A), standard A-to-B cables + * - 5912 OSK UDC, with *nonstandard* A-to-A cable * - 1510 Innovator UDC with bundled usb0 cable * - 1510 Innovator OHCI with bundled usb1/usb2 cable * - 1510 Innovator OHCI with custom usb0 cable, feeding 5V VBUS * - 1710 custom development board using alternate pin group + * - 1710 H3 (with usb1 mini-AB) using standard Mini-B or OTG cables */ /*-------------------------------------------------------------------------*/ @@ -101,50 +104,48 @@ return 0; } - /* - * VP and VM are needed for all active usb0 configurations. - * USB0_VP and USB0_VM are always set on 1510, there's no muxing - * available for them. - */ - if (nwires >= 2 && !cpu_is_omap15xx()) { - omap_cfg_reg(AA9_USB0_VP); - omap_cfg_reg(R9_USB0_VM); - } if (is_device) omap_cfg_reg(W4_USB_PUEN); /* internal transceiver */ if (nwires == 2) { + // omap_cfg_reg(P9_USB_DP); + // omap_cfg_reg(R8_USB_DM); + if (cpu_is_omap15xx()) { - /* This works for OHCI on 1510-Innovator */ + /* This works on 1510-Innovator */ return 0; } - /* NOTE: host OR device mode for now, no OTG */ + /* NOTES: + * - peripheral should configure VBUS detection! + * - only peripherals may use the internal D+/D- pulldowns + * - OTG support on this port not yet written + */ + USB_TRANSCEIVER_CTRL_REG &= ~(7 << 4); - if (is_device) { - omap_cfg_reg(R18_1510_USB_GPIO0); - // omap_cfg_reg(USB0_VBUS); - // USB_TRANSCEIVER_CTRL_REG.CONF_USB0_PORT_R = 7 - } else /* host mode needs D+ and D- pulldowns */ - USB_TRANSCEIVER_CTRL_REG &= ~(3 << 1); + if (!is_device) + USB_TRANSCEIVER_CTRL_REG |= (3 << 1); return 3 << 16; } /* alternate pin config, external transceiver */ + if (cpu_is_omap15xx()) { + printk(KERN_ERR "no usb0 alt pin config on 15xx\n"); + return 0; + } + omap_cfg_reg(V6_USB0_TXD); omap_cfg_reg(W9_USB0_TXEN); omap_cfg_reg(W5_USB0_SE0); -#ifdef CONFIG_ARCH_OMAP_USB_SPEED - /* FIXME: there's good chance that pin V9 is used for MMC2 port cmddir */ - omap_cfg_reg(V9_USB0_SPEED); - // omap_cfg_reg(V9_USB0_SUSP); -#endif + /* NOTE: SPEED and SUSP aren't configured here */ if (nwires != 3) omap_cfg_reg(Y5_USB0_RCV); + if (nwires != 6) + USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R; switch (nwires) { case 3: @@ -155,7 +156,8 @@ break; case 6: syscon1 = 3; - /* REVISIT: Is CONF_USB2_UNI_R only needed when nwires = 6? */ + omap_cfg_reg(AA9_USB0_VP); + omap_cfg_reg(R9_USB0_VM); USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R; break; default: @@ -181,10 +183,13 @@ omap_cfg_reg(USB1_SEO); omap_cfg_reg(USB1_SPEED); // SUSP - } else if (cpu_is_omap16xx()) { + } else if (cpu_is_omap1610() || cpu_is_omap5912()) { omap_cfg_reg(W13_1610_USB1_SE0); omap_cfg_reg(R13_1610_USB1_SPEED); // SUSP + } else if (cpu_is_omap1710()) { + omap_cfg_reg(R13_1710_USB1_SE0); + // SUSP } else { pr_debug("usb unrecognized\n"); } @@ -216,12 +221,11 @@ { u32 syscon1 = 0; + /* NOTE erratum: must leave USB2_UNI_R set if usb0 in use */ if (alt_pingroup || nwires == 0) return 0; if (nwires != 6 && !cpu_is_omap15xx()) USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R; - if (nwires == 0) - return 0; /* external transceiver */ if (cpu_is_omap15xx()) { @@ -412,12 +416,15 @@ syscon = config->hmc_mode; syscon |= USBX_SYNCHRO | (4 << 16) /* B_ASE0_BRST */; +#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) if (config->otg || config->register_host) syscon |= UHOST_EN; +#endif #ifdef CONFIG_USB_OTG if (config->otg) syscon |= OTG_EN; #endif + pr_debug("USB_TRANSCEIVER_CTRL_REG = %03x\n", USB_TRANSCEIVER_CTRL_REG); pr_debug("OTG_SYSCON_2_REG = %08x\n", syscon); OTG_SYSCON_2_REG = syscon; @@ -443,6 +450,7 @@ if (config->otg || config->register_dev) { syscon &= ~DEV_IDLE_EN; udc_device.dev.platform_data = config; + /* FIXME patch IRQ numbers for omap730 */ status = platform_device_register(&udc_device); if (status) pr_debug("can't register UDC device, %d\n", status); @@ -453,6 +461,8 @@ if (config->otg || config->register_host) { syscon &= ~HST_IDLE_EN; ohci_device.dev.platform_data = config; + if (cpu_is_omap730()) + ohci_resources[1].start = INT_730_USB_HHC_1; status = platform_device_register(&ohci_device); if (status) pr_debug("can't register OHCI device, %d\n", status); @@ -462,10 +472,12 @@ #ifdef CONFIG_USB_OTG if (config->otg) { syscon &= ~OTG_IDLE_EN; + otg_device.dev.platform_data = config; if (cpu_is_omap730()) otg_resources[1].start = INT_730_USB_OTG; status = platform_device_register(&otg_device); - // ... + if (status) + pr_debug("can't register OTG device, %d\n", status); } #endif pr_debug("OTG_SYSCON_1_REG = %08x\n", syscon); @@ -564,7 +576,8 @@ config = omap_get_config(OMAP_TAG_USB, struct omap_usb_config); if (config == NULL) { - printk(KERN_ERR "USB: No board-specific platform config found\n"); + printk(KERN_ERR "USB: No board-specific " + "platform config found\n"); return -ENODEV; } platform_data = *config; diff -Nru a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c --- a/arch/arm/mm/alignment.c 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/mm/alignment.c 2005-03-02 10:51:31 -08:00 @@ -412,7 +412,7 @@ * Switch this message off if we've got a ARM92[02], otherwise * [ls]dm alignment faults are noisy! */ -#if !(defined CONFIG_CPU_ARM922T) && !(defined CONFIG_CPU_ARM920T) +#if !(defined CONFIG_CPU_ARM922T) && !(defined CONFIG_CPU_ARM920T) && !(defined CONFIG_CPU_ARM925T) /* * This is a "hint" - we already have eaddr worked out by the * processor for us. diff -Nru a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types --- a/arch/arm/tools/mach-types 2005-03-02 10:51:31 -08:00 +++ b/arch/arm/tools/mach-types 2005-03-02 10:51:31 -08:00 @@ -226,7 +226,7 @@ pnp1110 SA1100_PNP1110 PNP1110 215 csb226 ARCH_CSB226 CSB226 216 arnold SA1100_ARNOLD ARNOLD 217 -voiceblue SA1100_PSIBOARD PSIBOARD 218 +voiceblue MACH_VOICEBLUE VOICEBLUE 218 jz8028 ARCH_JZ8028 JZ8028 219 h5400 ARCH_H5400 H5400 220 forte SA1100_FORTE FORTE 221 @@ -667,3 +667,4 @@ manga_ks8695 MACH_MANGA_KS8695 MANGA_KS8695 657 ajax MACH_AJAX AJAX 658 nec_mp900 MACH_NEC_MP900 NEC_MP900 659 +netstar MACH_NETSTAR NETSTAR 692 diff -Nru a/drivers/Kconfig b/drivers/Kconfig --- a/drivers/Kconfig 2005-03-02 10:51:31 -08:00 +++ b/drivers/Kconfig 2005-03-02 10:51:31 -08:00 @@ -58,4 +58,6 @@ source "drivers/infiniband/Kconfig" +source "drivers/ssi/Kconfig" + endmenu diff -Nru a/drivers/Makefile b/drivers/Makefile --- a/drivers/Makefile 2005-03-02 10:51:31 -08:00 +++ b/drivers/Makefile 2005-03-02 10:51:31 -08:00 @@ -26,7 +26,9 @@ obj-$(CONFIG_SERIO) += input/serio/ obj-y += serial/ obj-$(CONFIG_PARPORT) += parport/ -obj-y += base/ block/ misc/ net/ media/ +obj-y += base/ block/ misc/ net/ +obj-$(CONFIG_I2C) += i2c/ +obj-y += media/ ssi/ obj-$(CONFIG_NUBUS) += nubus/ obj-$(CONFIG_ATM) += atm/ obj-$(CONFIG_PPC_PMAC) += macintosh/ @@ -50,7 +52,6 @@ obj-$(CONFIG_INPUT) += input/ obj-$(CONFIG_GAMEPORT) += input/gameport/ obj-$(CONFIG_I2O) += message/ -obj-$(CONFIG_I2C) += i2c/ obj-$(CONFIG_W1) += w1/ obj-$(CONFIG_PHONE) += telephony/ obj-$(CONFIG_MD) += md/ diff -Nru a/drivers/char/Kconfig b/drivers/char/Kconfig --- a/drivers/char/Kconfig 2005-03-02 10:51:31 -08:00 +++ b/drivers/char/Kconfig 2005-03-02 10:51:31 -08:00 @@ -764,6 +764,11 @@ config EFI_RTC bool "EFI Real Time Clock Services" depends on IA64 +config OMAP_RTC + bool "TI OMAP Real Time Clock" + depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730 + help + Support for TI OMAP RTC config DS1302 tristate "DS1302 RTC support" diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile --- a/drivers/char/Makefile 2005-03-02 10:51:31 -08:00 +++ b/drivers/char/Makefile 2005-03-02 10:51:31 -08:00 @@ -64,6 +64,7 @@ obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o obj-$(CONFIG_DS1302) += ds1302.o obj-$(CONFIG_S3C2410_RTC) += s3c2410-rtc.o +obj-$(CONFIG_OMAP_RTC)+= omap-rtc.o ifeq ($(CONFIG_GENERIC_NVRAM),y) obj-$(CONFIG_NVRAM) += generic_nvram.o else diff -Nru a/drivers/char/omap-rtc.c b/drivers/char/omap-rtc.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/char/omap-rtc.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,791 @@ +/* + * TI OMAP Real Time Clock interface for Linux + * + * Copyright (C) 2003 MontaVista Software, Inc. + * Author: George G. Davis or + * + * Initially based on linux-2.4.20/drivers/char/rtc.c + * Copyright (C) 1996 Paul Gortmaker + * + * This driver allows use of the real time clock (built into + * nearly all computers) from user space. It exports the /dev/rtc + * interface supporting various ioctl() and also the + * /proc/driver/rtc pseudo-file for status information. + * + * The ioctls can be used to set the interrupt behaviour from the + * RTC via IRQs. Then the /dev/rtc interface can be used to make + * use of RTC interrupts, be they time update or alarm based. + * + * The /dev/rtc interface will block on reads until an interrupt + * has been received. If a RTC interrupt has already happened, + * it will output an unsigned long and then block. The output value + * contains the interrupt status in the low byte and the number of + * interrupts since the last read in the remaining high bytes. The + * /dev/rtc interface can also be used with the select(2) call. + * + * 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, etc. etc. + * + * Change Log : + * v1.0 Initial version based on rtc.c v1.10e + * Added support for 2.6 kernel, + * - changed the return value of the interrupt handler + */ + +#define RTC_VERSION "1.0" + +/* + * Note that *all* calls to CMOS_READ and CMOS_WRITE are done with + * interrupts disabled. + * REVISIT: Elaborate on OMAP1510 TRM 15uS BUSY access rule. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include "omap-rtc.h" + +extern spinlock_t rtc_lock; + + +/* OMAP RTC register access macros: */ + +#define CMOS_READ(addr) omap_readb(addr) +#define CMOS_WRITE(val, addr) omap_writeb(val, addr) + + +/* Local BCD/BIN conversion macros: */ +#ifdef BCD_TO_BIN +#undef BCD_TO_BIN +#endif +#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) + +#ifdef BIN_TO_BCD +#undef BIN_TO_BCD +#endif +#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10) + + +/* + * We sponge a minor off of the misc major. No need slurping + * up another valuable major dev number for this. If you add + * an ioctl, make sure you don't conflict with SPARC's RTC + * ioctls. + */ + +static struct fasync_struct *rtc_async_queue; + +static DECLARE_WAIT_QUEUE_HEAD(rtc_wait); + +static ssize_t rtc_read(struct file *file, char *buf, + size_t count, loff_t *ppos); + +static int rtc_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); + +static unsigned int rtc_poll(struct file *file, poll_table *wait); + +static void get_rtc_time (struct rtc_time *rtc_tm); +static void get_rtc_alm_time (struct rtc_time *alm_tm); + +static void set_rtc_irq_bit(unsigned char bit); +static void mask_rtc_irq_bit(unsigned char bit); + +static inline unsigned char rtc_is_updating(void); + +static int rtc_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data); + +/* + * Bits in rtc_status. (7 bits of room for future expansion) + */ + +#define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ + +/* + * REVISIT: fix this comment: + * rtc_status is never changed by rtc_interrupt, and ioctl/open/close is + * protected by the big kernel lock. + */ +static unsigned long rtc_status = 0; /* bitmapped status byte. */ +static unsigned long rtc_irq_data = 0; /* our output to the world */ + +/* + * If this driver ever becomes modularised, it will be really nice + * to make the epoch retain its value across module reload... + */ + +static unsigned long epoch = 1900; /* year corresponding to 0x00 */ + +static const unsigned char days_in_mo[] = +{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +/* + * A very tiny interrupt handler. It runs with SA_INTERRUPT set. + */ + +static irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + /* + * Either an alarm interrupt or update complete interrupt. + * We store the status in the low byte and the number of + * interrupts received since the last read in the remainder + * of rtc_irq_data. + */ + + spin_lock (&rtc_lock); + + rtc_irq_data += 0x100; + rtc_irq_data &= ~0xff; + rtc_irq_data |= CMOS_READ(OMAP_RTC_STATUS_REG); + + if (rtc_irq_data & OMAP_RTC_STATUS_ALARM) + CMOS_WRITE(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG); + + spin_unlock (&rtc_lock); + + /* Now do the rest of the actions */ + wake_up_interruptible(&rtc_wait); + + kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); + return IRQ_HANDLED; +} + +/* + * Now all the various file operations that we export. + */ + +static ssize_t rtc_read(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + unsigned long data; + ssize_t retval; + + if (count < sizeof(unsigned long)) + return -EINVAL; + + add_wait_queue(&rtc_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + for (;;) { + spin_lock_irq (&rtc_lock); + data = rtc_irq_data; + if (data != 0) { + rtc_irq_data = 0; + break; + } + spin_unlock_irq (&rtc_lock); + + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto out; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + goto out; + } + schedule(); + } + + spin_unlock_irq (&rtc_lock); + retval = put_user(data, (unsigned long *)buf); + if (!retval) + retval = sizeof(unsigned long); + out: + set_current_state(TASK_RUNNING); + remove_wait_queue(&rtc_wait, &wait); + + return retval; +} + +static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct rtc_time wtime; + + switch (cmd) { + case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ + { + mask_rtc_irq_bit(OMAP_RTC_INTERRUPTS_IT_ALARM); + return 0; + } + case RTC_AIE_ON: /* Allow alarm interrupts. */ + { + set_rtc_irq_bit(OMAP_RTC_INTERRUPTS_IT_ALARM); + return 0; + } + case RTC_UIE_OFF: /* Mask ints from RTC updates. */ + { + mask_rtc_irq_bit(OMAP_RTC_INTERRUPTS_IT_TIMER); + return 0; + } + case RTC_UIE_ON: /* Allow ints for RTC updates. */ + { + set_rtc_irq_bit(OMAP_RTC_INTERRUPTS_IT_TIMER); + return 0; + } + case RTC_ALM_READ: /* Read the present alarm time */ + { + /* + * This returns a struct rtc_time. Reading >= 0xc0 + * means "don't care" or "match all". Only the tm_hour, + * tm_min, and tm_sec values are filled in. + */ + memset(&wtime, 0, sizeof(struct rtc_time)); + get_rtc_alm_time(&wtime); + break; + } + case RTC_ALM_SET: /* Store a time into the alarm */ + { + struct rtc_time alm_tm; + unsigned char mon, day, hrs, min, sec, leap_yr; + unsigned int yrs; + + if (copy_from_user(&alm_tm, (struct rtc_time*)arg, + sizeof(struct rtc_time))) + return -EFAULT; + + yrs = alm_tm.tm_year + 1900; + mon = alm_tm.tm_mon + 1; + day = alm_tm.tm_mday; + hrs = alm_tm.tm_hour; + min = alm_tm.tm_min; + sec = alm_tm.tm_sec; + + if (yrs < 1970) + return -EINVAL; + + leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); + + if ((mon > 12) || (day == 0)) + return -EINVAL; + + if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) + return -EINVAL; + + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) + return -EINVAL; + + if ((yrs -= epoch) > 255) /* They are unsigned */ + return -EINVAL; + + if (yrs > 169) { + return -EINVAL; + } + + if (yrs >= 100) + yrs -= 100; + + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hrs); + BIN_TO_BCD(day); + BIN_TO_BCD(mon); + BIN_TO_BCD(yrs); + + spin_lock_irq(&rtc_lock); + CMOS_WRITE(yrs, OMAP_RTC_ALARM_YEARS_REG); + CMOS_WRITE(mon, OMAP_RTC_ALARM_MONTHS_REG); + CMOS_WRITE(day, OMAP_RTC_ALARM_DAYS_REG); + CMOS_WRITE(hrs, OMAP_RTC_ALARM_HOURS_REG); + CMOS_WRITE(min, OMAP_RTC_ALARM_MINUTES_REG); + CMOS_WRITE(sec, OMAP_RTC_ALARM_SECONDS_REG); + spin_unlock_irq(&rtc_lock); + + return 0; + } + case RTC_RD_TIME: /* Read the time/date from RTC */ + { + memset(&wtime, 0, sizeof(struct rtc_time)); + get_rtc_time(&wtime); + break; + } + case RTC_SET_TIME: /* Set the RTC */ + { + struct rtc_time rtc_tm; + unsigned char mon, day, hrs, min, sec, leap_yr; + unsigned char save_control; + unsigned int yrs; + + if (!capable(CAP_SYS_TIME)) + return -EACCES; + + if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, + sizeof(struct rtc_time))) + return -EFAULT; + + yrs = rtc_tm.tm_year + 1900; + mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ + day = rtc_tm.tm_mday; + hrs = rtc_tm.tm_hour; + min = rtc_tm.tm_min; + sec = rtc_tm.tm_sec; + + if (yrs < 1970) + return -EINVAL; + + leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); + + if ((mon > 12) || (day == 0)) + return -EINVAL; + + if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) + return -EINVAL; + + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) + return -EINVAL; + + if ((yrs -= epoch) > 255) /* They are unsigned */ + return -EINVAL; + + if (yrs > 169) { + return -EINVAL; + } + + if (yrs >= 100) + yrs -= 100; + + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hrs); + BIN_TO_BCD(day); + BIN_TO_BCD(mon); + BIN_TO_BCD(yrs); + + spin_lock_irq(&rtc_lock); + save_control = CMOS_READ(OMAP_RTC_CTRL_REG); + CMOS_WRITE((save_control & ~OMAP_RTC_CTRL_STOP), + OMAP_RTC_CTRL_REG); + CMOS_WRITE(yrs, OMAP_RTC_YEARS_REG); + CMOS_WRITE(mon, OMAP_RTC_MONTHS_REG); + CMOS_WRITE(day, OMAP_RTC_DAYS_REG); + CMOS_WRITE(hrs, OMAP_RTC_HOURS_REG); + CMOS_WRITE(min, OMAP_RTC_MINUTES_REG); + CMOS_WRITE(sec, OMAP_RTC_SECONDS_REG); + CMOS_WRITE((save_control | OMAP_RTC_CTRL_STOP), + OMAP_RTC_CTRL_REG); + spin_unlock_irq(&rtc_lock); + + return 0; + } + case RTC_EPOCH_READ: /* Read the epoch. */ + { + return put_user (epoch, (unsigned long *)arg); + } + case RTC_EPOCH_SET: /* Set the epoch. */ + { + /* + * There were no RTC clocks before 1900. + */ + if (arg < 1900) + return -EINVAL; + + if (!capable(CAP_SYS_TIME)) + return -EACCES; + + epoch = arg; + return 0; + } + default: +#if !defined(CONFIG_ARCH_OMAP) + return -ENOTTY; +#else + return -EINVAL; +#endif + } + return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; +} + +/* + * We enforce only one user at a time here with the open/close. + * Also clear the previous interrupt data on an open, and clean + * up things on a close. + */ + +/* We use rtc_lock to protect against concurrent opens. So the BKL is not + * needed here. Or anywhere else in this driver. */ +static int rtc_open(struct inode *inode, struct file *file) +{ + spin_lock_irq (&rtc_lock); + + if(rtc_status & RTC_IS_OPEN) + goto out_busy; + + rtc_status |= RTC_IS_OPEN; + + rtc_irq_data = 0; + spin_unlock_irq (&rtc_lock); + return 0; + +out_busy: + spin_unlock_irq (&rtc_lock); + return -EBUSY; +} + +static int rtc_fasync (int fd, struct file *filp, int on) + +{ + return fasync_helper (fd, filp, on, &rtc_async_queue); +} + +static int rtc_release(struct inode *inode, struct file *file) +{ + unsigned char tmp; + + /* + * Turn off all interrupts once the device is no longer + * in use, and clear the data. + */ + + spin_lock_irq(&rtc_lock); + tmp = CMOS_READ(OMAP_RTC_INTERRUPTS_REG); + tmp &= ~OMAP_RTC_INTERRUPTS_IT_ALARM; + tmp &= ~OMAP_RTC_INTERRUPTS_IT_TIMER; + CMOS_WRITE(tmp, OMAP_RTC_INTERRUPTS_REG); + spin_unlock_irq(&rtc_lock); + + if (file->f_flags & FASYNC) { + rtc_fasync (-1, file, 0); + } + + spin_lock_irq (&rtc_lock); + rtc_irq_data = 0; + spin_unlock_irq (&rtc_lock); + + /* No need for locking -- nobody else can do anything until this rmw + * is committed, and we don't implement timer support in omap-rtc. + */ + rtc_status &= ~RTC_IS_OPEN; + return 0; +} + +/* Called without the kernel lock - fine */ +static unsigned int rtc_poll(struct file *file, poll_table *wait) +{ + unsigned long l; + + poll_wait(file, &rtc_wait, wait); + + spin_lock_irq (&rtc_lock); + l = rtc_irq_data; + spin_unlock_irq (&rtc_lock); + + if (l != 0) + return POLLIN | POLLRDNORM; + return 0; +} + +/* + * The various file operations we support. + */ + +static struct file_operations rtc_fops = { + owner: THIS_MODULE, + llseek: no_llseek, + read: rtc_read, + poll: rtc_poll, + ioctl: rtc_ioctl, + open: rtc_open, + release: rtc_release, + fasync: rtc_fasync, +}; + +static struct miscdevice rtc_dev= +{ + RTC_MINOR, + "rtc", + &rtc_fops +}; + +static int __init rtc_init(void) +{ + if (!request_region(OMAP_RTC_VIRT_BASE, OMAP_RTC_SIZE, + rtc_dev.name)) { + printk(KERN_ERR "%s: RTC I/O port %d is not free.\n", + rtc_dev.name, OMAP_RTC_VIRT_BASE); + return -EIO; + } + + if (CMOS_READ(OMAP_RTC_STATUS_REG) & OMAP_RTC_STATUS_POWER_UP) { + printk(KERN_WARNING "%s: RTC power up reset detected.\n", + rtc_dev.name); + /* Clear OMAP_RTC_STATUS_POWER_UP */ + CMOS_WRITE(OMAP_RTC_STATUS_POWER_UP, OMAP_RTC_STATUS_REG); + } + + if (CMOS_READ(OMAP_RTC_STATUS_REG) & OMAP_RTC_STATUS_ALARM) { + printk(KERN_WARNING "%s: Clearing RTC ALARM interrupt.\n", + rtc_dev.name); + /* Clear OMAP_RTC_STATUS_ALARM */ + CMOS_WRITE(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG); + } + + if (!(CMOS_READ(OMAP_RTC_CTRL_REG) & OMAP_RTC_CTRL_STOP)) { + printk(KERN_INFO "%s: Enabling RTC.\n", rtc_dev.name); + CMOS_WRITE(OMAP_RTC_CTRL_STOP, OMAP_RTC_CTRL_REG); + } + + if (request_irq(INT_RTC_TIMER, rtc_interrupt, SA_INTERRUPT, + rtc_dev.name, NULL)) { + printk(KERN_ERR "%s: RTC timer interrupt IRQ%d is not free.\n", + rtc_dev.name, INT_RTC_TIMER); + release_region(OMAP_RTC_VIRT_BASE, OMAP_RTC_SIZE); + return -EIO; + } + + if (request_irq(INT_RTC_ALARM, rtc_interrupt, SA_INTERRUPT, + "omap-rtc alarm", NULL)) { + printk(KERN_ERR "%s: RTC alarm interrupt IRQ%d is not free.\n", + rtc_dev.name, INT_RTC_ALARM); + release_region(OMAP_RTC_VIRT_BASE, OMAP_RTC_SIZE); + return -EIO; + } + + spin_lock_init(&rtc_lock); + misc_register(&rtc_dev); + create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL); + + printk(KERN_INFO "Real Time Clock Driver v" RTC_VERSION "\n"); + + return 0; +} + +static void __exit rtc_exit (void) +{ + free_irq (INT_RTC_TIMER, NULL); + free_irq (INT_RTC_ALARM, NULL); + + remove_proc_entry ("driver/rtc", NULL); + misc_deregister(&rtc_dev); + + release_region (OMAP_RTC_VIRT_BASE, OMAP_RTC_SIZE); +} + +/* + * Info exported via "/proc/driver/rtc". + */ + +static int rtc_proc_output (char *buf) +{ +#define YN(value) ((value) ? "yes" : "no") +#define NY(value) ((value) ? "no" : "yes") + char *p; + struct rtc_time tm; + + p = buf; + + get_rtc_time(&tm); + + /* + * There is no way to tell if the luser has the RTC set for local + * time or for Universal Standard Time (GMT). Probably local though. + */ + p += sprintf(p, + "rtc_time\t: %02d:%02d:%02d\n" + "rtc_date\t: %04d-%02d-%02d\n" + "rtc_epoch\t: %04lu\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); + + get_rtc_alm_time(&tm); + + /* + * We implicitly assume 24hr mode here. Alarm values >= 0xc0 will + * match any value for that particular field. Values that are + * greater than a valid time, but less than 0xc0 shouldn't appear. + */ + p += sprintf(p, + "alarm_time\t: %02d:%02d:%02d\n" + "alarm_date\t: %04d-%02d-%02d\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + + p += sprintf(p, + "BCD\t\t: %s\n" + "24hr\t\t: %s\n" + "alarm_IRQ\t: %s\n" + "update_IRQ\t: %s\n" + "update_rate\t: %ud\n", + YN(1), + YN(1), + YN(CMOS_READ(OMAP_RTC_INTERRUPTS_REG) & + OMAP_RTC_INTERRUPTS_IT_ALARM), + YN(CMOS_READ(OMAP_RTC_INTERRUPTS_REG) & + OMAP_RTC_INTERRUPTS_IT_TIMER), + CMOS_READ(OMAP_RTC_INTERRUPTS_REG) & 3 /* REVISIT */); + + return p - buf; +#undef YN +#undef NY +} + +static int rtc_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = rtc_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; +} + +/* + * Returns true if a clock update is in progress + */ +/* FIXME shouldn't this be above rtc_init to make it fully inlined? */ +static inline unsigned char rtc_is_updating(void) +{ + unsigned char uip; + + spin_lock_irq(&rtc_lock); + uip = (CMOS_READ(OMAP_RTC_STATUS_REG) & OMAP_RTC_STATUS_BUSY); + spin_unlock_irq(&rtc_lock); + return uip; +} + +static void get_rtc_time(struct rtc_time *rtc_tm) +{ + unsigned char ctrl; + + /* REVISIT: Fix this comment!!! + * read RTC once any update in progress is done. The update + * can take just over 2ms. We wait 10 to 20ms. There is no need to + * to poll-wait (up to 1s - eeccch) for the falling edge of OMAP_RTC_STATUS_BUSY. + * If you need to know *exactly* when a second has started, enable + * periodic update complete interrupts, (via ioctl) and then + * immediately read /dev/rtc which will block until you get the IRQ. + * Once the read clears, read the RTC time (again via ioctl). Easy. + */ + +#if 0 /* REVISIT: This need to do as the TRM says. */ + unsigned long uip_watchdog = jiffies; + if (rtc_is_updating() != 0) + while (jiffies - uip_watchdog < 2*HZ/100) { + barrier(); + cpu_relax(); + } +#endif + + /* + * Only the values that we read from the RTC are set. We leave + * tm_wday, tm_yday and tm_isdst untouched. Even though the + * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated + * by the RTC when initially set to a non-zero value. + */ + spin_lock_irq(&rtc_lock); + rtc_tm->tm_sec = CMOS_READ(OMAP_RTC_SECONDS_REG); + rtc_tm->tm_min = CMOS_READ(OMAP_RTC_MINUTES_REG); + rtc_tm->tm_hour = CMOS_READ(OMAP_RTC_HOURS_REG); + rtc_tm->tm_mday = CMOS_READ(OMAP_RTC_DAYS_REG); + rtc_tm->tm_mon = CMOS_READ(OMAP_RTC_MONTHS_REG); + rtc_tm->tm_year = CMOS_READ(OMAP_RTC_YEARS_REG); + ctrl = CMOS_READ(OMAP_RTC_CTRL_REG); + spin_unlock_irq(&rtc_lock); + + BCD_TO_BIN(rtc_tm->tm_sec); + BCD_TO_BIN(rtc_tm->tm_min); + BCD_TO_BIN(rtc_tm->tm_hour); + BCD_TO_BIN(rtc_tm->tm_mday); + BCD_TO_BIN(rtc_tm->tm_mon); + BCD_TO_BIN(rtc_tm->tm_year); + + /* + * Account for differences between how the RTC uses the values + * and how they are defined in a struct rtc_time; + */ + if ((rtc_tm->tm_year += (epoch - 1900)) <= 69) + rtc_tm->tm_year += 100; + + rtc_tm->tm_mon--; +} + +static void get_rtc_alm_time(struct rtc_time *alm_tm) +{ + unsigned char ctrl; + + spin_lock_irq(&rtc_lock); + alm_tm->tm_sec = CMOS_READ(OMAP_RTC_ALARM_SECONDS_REG); + alm_tm->tm_min = CMOS_READ(OMAP_RTC_ALARM_MINUTES_REG); + alm_tm->tm_hour = CMOS_READ(OMAP_RTC_ALARM_HOURS_REG); + alm_tm->tm_mday = CMOS_READ(OMAP_RTC_ALARM_DAYS_REG); + alm_tm->tm_mon = CMOS_READ(OMAP_RTC_ALARM_MONTHS_REG); + alm_tm->tm_year = CMOS_READ(OMAP_RTC_ALARM_YEARS_REG); + ctrl = CMOS_READ(OMAP_RTC_CTRL_REG); + spin_unlock_irq(&rtc_lock); + + BCD_TO_BIN(alm_tm->tm_sec); + BCD_TO_BIN(alm_tm->tm_min); + BCD_TO_BIN(alm_tm->tm_hour); + BCD_TO_BIN(alm_tm->tm_mday); + BCD_TO_BIN(alm_tm->tm_mon); + BCD_TO_BIN(alm_tm->tm_year); + + /* + * Account for differences between how the RTC uses the values + * and how they are defined in a struct rtc_time; + */ + if ((alm_tm->tm_year += (epoch - 1900)) <= 69) + alm_tm->tm_year += 100; + + alm_tm->tm_mon--; +} + +/* + * Used to disable/enable UIE and AIE interrupts. + */ + +static void mask_rtc_irq_bit(unsigned char bit) +{ + unsigned char val; + + spin_lock_irq(&rtc_lock); + val = CMOS_READ(OMAP_RTC_INTERRUPTS_REG); + val &= ~bit; + CMOS_WRITE(val, OMAP_RTC_INTERRUPTS_REG); + rtc_irq_data = 0; + spin_unlock_irq(&rtc_lock); +} + +static void set_rtc_irq_bit(unsigned char bit) +{ + unsigned char val; + + spin_lock_irq(&rtc_lock); + val = CMOS_READ(OMAP_RTC_INTERRUPTS_REG); + val |= bit; + CMOS_WRITE(val, OMAP_RTC_INTERRUPTS_REG); + rtc_irq_data = 0; + spin_unlock_irq(&rtc_lock); +} + +MODULE_AUTHOR("George G. Davis"); +MODULE_LICENSE("GPL"); + +module_init(rtc_init); +module_exit(rtc_exit); diff -Nru a/drivers/char/omap-rtc.h b/drivers/char/omap-rtc.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/char/omap-rtc.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,59 @@ +/* + * TI OMAP Real Time Clock header file + * + * Copyright (C) 2003 TI + * + * 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. + * + */ + +#define OMAP_RTC_BASE 0xfffb4800 +#define OMAP_RTC_SIZE 128 + +#define OMAP_RTC_VIRT_BASE IO_ADDRESS(OMAP_RTC_BASE) + +/* + * Real-Time Clock + */ + +#define OMAP_RTC_SECONDS_REG (OMAP_RTC_BASE + 0x00) +#define OMAP_RTC_MINUTES_REG (OMAP_RTC_BASE + 0x04) +#define OMAP_RTC_HOURS_REG (OMAP_RTC_BASE + 0x08) +#define OMAP_RTC_DAYS_REG (OMAP_RTC_BASE + 0x0C) +#define OMAP_RTC_MONTHS_REG (OMAP_RTC_BASE + 0x10) +#define OMAP_RTC_YEARS_REG (OMAP_RTC_BASE + 0x14) +#define OMAP_RTC_WEEKS_REG (OMAP_RTC_BASE + 0x18) +#define OMAP_RTC_ALARM_SECONDS_REG (OMAP_RTC_BASE + 0x20) +#define OMAP_RTC_ALARM_MINUTES_REG (OMAP_RTC_BASE + 0x24) +#define OMAP_RTC_ALARM_HOURS_REG (OMAP_RTC_BASE + 0x28) +#define OMAP_RTC_ALARM_DAYS_REG (OMAP_RTC_BASE + 0x2c) +#define OMAP_RTC_ALARM_MONTHS_REG (OMAP_RTC_BASE + 0x30) +#define OMAP_RTC_ALARM_YEARS_REG (OMAP_RTC_BASE + 0x34) +#define OMAP_RTC_CTRL_REG (OMAP_RTC_BASE + 0x40) +#define OMAP_RTC_STATUS_REG (OMAP_RTC_BASE + 0x44) +#define OMAP_RTC_INTERRUPTS_REG (OMAP_RTC_BASE + 0x48) +#define OMAP_RTC_COMP_LSB_REG (OMAP_RTC_BASE + 0x4c) +#define OMAP_RTC_COMP_MSB_REG (OMAP_RTC_BASE + 0x50) + +/* RTC Control Register bit fields: */ + +#define OMAP_RTC_CTRL_STOP (1<<0) + +/* RTC Status Register bit fields: */ + +#define OMAP_RTC_STATUS_POWER_UP (1<<7) +#define OMAP_RTC_STATUS_ALARM (1<<6) +#define OMAP_RTC_STATUS_1D_EVENT (1<<5) +#define OMAP_RTC_STATUS_1H_EVENT (1<<4) +#define OMAP_RTC_STATUS_1M_EVENT (1<<3) +#define OMAP_RTC_STATUS_1S_EVENT (1<<2) +#define OMAP_RTC_STATUS_RUN (1<<1) +#define OMAP_RTC_STATUS_BUSY (1<<0) + +/* RTC Interrupt Register bit fields: */ + +#define OMAP_RTC_INTERRUPTS_IT_ALARM (1<<3) +#define OMAP_RTC_INTERRUPTS_IT_TIMER (1<<2) diff -Nru a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig --- a/drivers/char/watchdog/Kconfig 2005-03-02 10:51:31 -08:00 +++ b/drivers/char/watchdog/Kconfig 2005-03-02 10:51:31 -08:00 @@ -546,4 +546,11 @@ Most people will say N. +config OMAP16XX_WATCHDOG + tristate "OMAP1610/OMAP1710 Watchdog" + depends on WATCHDOG && ARCH_OMAP16XX + help + Support for TI OMAP1610/OMAP1710 watchdog. Say 'Y' here to enable the + OMAP1610/OMAP1710 watchdog timer. + endmenu diff -Nru a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile --- a/drivers/char/watchdog/Makefile 2005-03-02 10:51:31 -08:00 +++ b/drivers/char/watchdog/Makefile 2005-03-02 10:51:31 -08:00 @@ -39,3 +39,4 @@ obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o +obj-$(CONFIG_OMAP16XX_WATCHDOG) += omap1610_wdt.o diff -Nru a/drivers/char/watchdog/omap1610_wdt.c b/drivers/char/watchdog/omap1610_wdt.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/char/watchdog/omap1610_wdt.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,243 @@ +/* + * linux/drivers/char/omap1610_wdt.c + * + * Watchdog driver for the TI OMAP + * + * Author: MontaVista Software, Inc. + * or + * + * 2003 (c) MontaVista Software, Inc. This file is licensed under the + * terms of the GNU General Public License version 2. This program is + * licensed "as is" without any warranty of any kind, whether express + * or implied. + * + * History: + * + * 20030527: George G. Davis + * Initially based on linux-2.4.19-rmk7-pxa1/drivers/char/sa1100_wdt.c + * (c) Copyright 2000 Oleg Drokin + * Based on SoftDog driver by Alan Cox + * + * Copyright (c) 2004 Texas Instruments. + * + * 1. Modified to support OMAP1610 32-KHz watchdog timer + * 2. Ported to 2.6 kernel + * + * + * TODO: + * 1. Need to disable watchdog when entering chip idle mode. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "omap1610_wdt.h" + +static int timer_margin; /* in seconds */ +static int pre_margin; +static int omap_wdt_users; +static struct clk *armwdt_ck = 0; +static struct miscdevice omap_wdt_miscdev; /* Forward declaration */ + +static unsigned int wdt_trgr_pattern = 0x1234; + +static void +omap_wdt_ping(void) +{ + while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08) ; /* wait for posted write to complete */ + wdt_trgr_pattern = ~wdt_trgr_pattern; + omap_writel(wdt_trgr_pattern, (OMAP_WATCHDOG_TGR)); + while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08) ; /* wait for posted write to complete */ + return; +} + +static void +omap_wdt_enable(void) +{ + /* Sequence to enable the watchdog */ + omap_writel(0xBBBB, OMAP_WATCHDOG_SPR); + while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10) ; + omap_writel(0x4444, OMAP_WATCHDOG_SPR); + while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10) ; + return; +} + +static void +omap_wdt_disable(void) +{ + /* sequence required to disable watchdog */ + omap_writel(0xAAAA, OMAP_WATCHDOG_SPR); /* TIMER_MODE */ + while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10) ; + omap_writel(0x5555, OMAP_WATCHDOG_SPR); /* TIMER_MODE */ + while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10) ; + return; +} + +/* + * Allow only one person to hold it open + */ + +static int +omap_wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(1, (unsigned long *) &omap_wdt_users)) + return -EBUSY; + + if (armwdt_ck == 0 || IS_ERR(armwdt_ck)) { + armwdt_ck = clk_get(omap_wdt_miscdev.dev, "armwdt_ck"); + if (IS_ERR(armwdt_ck)) { + omap_wdt_users = 0; + return PTR_ERR(armwdt_ck); + } + clk_use(armwdt_ck); /* Enable the clock */ + } + + omap_wdt_enable(); + + return 0; +} + +static int +omap_wdt_release(struct inode *inode, struct file *file) +{ + /* + * Shut off the timer. + * Lock it in if it's a module and we defined ...NOWAYOUT + */ +#ifndef CONFIG_WATCHDOG_NOWAYOUT + omap_wdt_disable(); + clk_unuse(armwdt_ck); /* Disable the clock */ + clk_put(armwdt_ck); + armwdt_ck = 0; +#endif + omap_wdt_users = 0; + return 0; +} + +static ssize_t +omap_wdt_write(struct file *file, const char *data, size_t len, loff_t * ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + /* Refresh LOAD_TIME. */ + if (len) { + omap_wdt_ping(); + return 1; + } + return 0; +} + +static int +omap_wdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int new_margin; + static struct watchdog_info ident = { + .identity = "OMAP Watchdog", + .options = WDIOF_SETTIMEOUT, + .firmware_version = 0, + }; + + switch (cmd) { + default: + return -ENOIOCTLCMD; + case WDIOC_GETSUPPORT: + return copy_to_user((struct watchdog_info *) arg, &ident, + sizeof (ident)); + case WDIOC_GETSTATUS: + return put_user(0, (int *) arg); + case WDIOC_GETBOOTSTATUS: + return put_user(omap_readw(ARM_SYSST), (int *) arg); + case WDIOC_KEEPALIVE: + omap_wdt_ping(); + return 0; + case WDIOC_SETTIMEOUT: + if (get_user(new_margin, (int *) arg)) + return -EFAULT; + if ((new_margin < TIMER_MARGIN_MIN) + || (new_margin > TIMER_MARGIN_MAX)) + timer_margin = TIMER_MARGIN_MAX; /* default timeout */ + else + timer_margin = new_margin; + pre_margin = GET_WLDR_VAL(timer_margin); + + omap_wdt_disable(); + + while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x04) ; /* wait for posted write to complete */ + omap_writel(pre_margin, (OMAP_WATCHDOG_LDR)); + while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x04) ; /* wait for posted write to complete */ + + omap_wdt_enable(); + + omap_wdt_ping(); + /* Fall */ + case WDIOC_GETTIMEOUT: + return put_user(timer_margin, (int *) arg); + } +} + +static struct file_operations omap_wdt_fops = { + .owner = THIS_MODULE, + .write = omap_wdt_write, + .ioctl = omap_wdt_ioctl, + .open = omap_wdt_open, + .release = omap_wdt_release, +}; + +static struct miscdevice omap_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "omap_wdt", + .fops = &omap_wdt_fops +}; + +static int __init +omap_wdt_init(void) +{ + int ret; + + ret = misc_register(&omap_wdt_miscdev); + + if (ret) + return ret; + + omap_wdt_disable(); + + if (timer_margin < 1 || timer_margin > 32) + timer_margin = 32; + + printk(KERN_INFO "%s: TI OMAP Watchdog Timer: timer margin %d sec\n", + omap_wdt_miscdev.name, timer_margin); + + return 0; +} + +static void __exit +omap_wdt_exit(void) +{ + misc_deregister(&omap_wdt_miscdev); +} + +module_init(omap_wdt_init); +module_exit(omap_wdt_exit); + +MODULE_AUTHOR("George G. Davis"); +MODULE_LICENSE("GPL"); +module_param(timer_margin, int, 0); diff -Nru a/drivers/char/watchdog/omap1610_wdt.h b/drivers/char/watchdog/omap1610_wdt.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/char/watchdog/omap1610_wdt.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,52 @@ +/* + * linux/drivers/char/watchdog/omap1610_wdt.h + * + * BRIEF MODULE DESCRIPTION + * OMAP Watchdog timer register definitions + * + * Copyright (C) 2004 Texas Instruments. + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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. + */ + +#ifndef _OMAP_WATCHDOG_H +#define _OMAP_WATCHDOG_H + +#define OMAP1610_WATCHDOG_BASE 0xfffeb000 + +#define OMAP_WATCHDOG_BASE OMAP1610_WATCHDOG_BASE + +#define OMAP_WATCHDOG_REV (OMAP_WATCHDOG_BASE + 0x00) +#define OMAP_WATCHDOG_SYS_CONFIG (OMAP_WATCHDOG_BASE + 0x10) +#define OMAP_WATCHDOG_STATUS (OMAP_WATCHDOG_BASE + 0x14) +#define OMAP_WATCHDOG_CNTRL (OMAP_WATCHDOG_BASE + 0x24) +#define OMAP_WATCHDOG_CRR (OMAP_WATCHDOG_BASE + 0x28) +#define OMAP_WATCHDOG_LDR (OMAP_WATCHDOG_BASE + 0x2c) +#define OMAP_WATCHDOG_TGR (OMAP_WATCHDOG_BASE + 0x30) +#define OMAP_WATCHDOG_WPS (OMAP_WATCHDOG_BASE + 0x34) +#define OMAP_WATCHDOG_SPR (OMAP_WATCHDOG_BASE + 0x48) + +#define TIMER_MARGIN_MAX 32 /* Default is 32 seconds */ +#define TIMER_MARGIN_MIN 1 + +#define GET_WLDR_VAL(x) (0xffffffff - ((x) * 32768)) + 1 + +#endif /* _OMAP_WATCHDOG_H */ diff -Nru a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig --- a/drivers/i2c/Kconfig 2005-03-02 10:51:31 -08:00 +++ b/drivers/i2c/Kconfig 2005-03-02 10:51:31 -08:00 @@ -6,6 +6,7 @@ config I2C tristate "I2C support" + default y if MACH_OMAP_H3 || MACH_OMAP_OSK ---help--- I2C (pronounce: I-square-C) is a slow serial bus protocol used in many micro controller applications and developed by Philips. SMBus, diff -Nru a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig --- a/drivers/i2c/busses/Kconfig 2005-03-02 10:51:31 -08:00 +++ b/drivers/i2c/busses/Kconfig 2005-03-02 10:51:31 -08:00 @@ -486,4 +486,11 @@ This driver can also be built as a module. If so, the module will be called i2c-pca-isa. +config I2C_OMAP + tristate "OMAP I2C adapter" + depends on I2C + default y if MACH_OMAP_H3 || MACH_OMAP_OSK + help + Support for TI OMAP I2C driver. Say yes if you want to use the OMAP + I2C interface. endmenu diff -Nru a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile --- a/drivers/i2c/busses/Makefile 2005-03-02 10:51:31 -08:00 +++ b/drivers/i2c/busses/Makefile 2005-03-02 10:51:31 -08:00 @@ -40,6 +40,7 @@ obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o obj-$(CONFIG_SCx200_ACB) += scx200_acb.o obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o +obj-$(CONFIG_I2C_OMAP) += i2c-omap.o ifeq ($(CONFIG_I2C_DEBUG_BUS),y) EXTRA_CFLAGS += -DDEBUG diff -Nru a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/i2c/busses/i2c-omap.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,631 @@ +/* + * linux/drivers/i2c/i2c-omap.c + * + * TI OMAP I2C unified algorith+adapter driver (inspired by i2c-ibm_iic.c and i2c-omap1510.c) + * + * Copyright (C) 2003 MontaVista Software, Inc. + * + * Copyright (C) 2004 Texas Instruments. + * + * ---------------------------------------------------------------------------- + * This file was highly leveraged from i2c-elektor.c, which was created + * by Simon G. Vogl and Hans Berglund: + * + * + * Copyright 1995-97 Simon G. Vogl + * 1998-99 Hans Berglund + * + * With some changes from Kysti M�kki and even + * Frodo Looijaard + * + * 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. + * ---------------------------------------------------------------------------- + Modifications: + ver. 1.1: Nov 2003, MontaVista Software + - added DPM support + ver. 1.2: Feb 2004, Texas Instruments + - Ported to 2.6 kernel (Feb 2004) + - Added support for I2C_M_IGNORE_NAK option. + ver. 1.3: Mar 2004, Juha Yrjölä + - Cleaned up + ver. 1.4: Aug 2004, Thiago Radicchi DCC-UFMG / iNdT + - Updated omap_i2c_isr to remove messages of too much work in one IRQ, + by reading the interrupt vector, as specified on ref [1] + ver. 1.5: Oct 2004, Tuukka Tikkanen + - Changed clock handling + * + * REFERENCES: + * + * 1. OMAP5910 Dual-Core Processor Inter-Integrated Circuit (I2C) + * Controller Reference Guide + * Document number: spru681 + * Date: October 2003 + * http://www-s.ti.com/sc/psheets/spru681/spru681.pdf + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "i2c-omap.h" + +/* ----- global defines ----------------------------------------------- */ +#define MODULE_NAME "OMAP I2C" +#define OMAP_I2C_TIMEOUT (1*HZ) /* timeout waiting for an I2C transaction */ + +#define I2C_OMAP_DEBUG +#ifdef I2C_OMAP_DEBUG +static int i2c_debug = 0; +#define DEB0(format, arg...) printk(KERN_DEBUG MODULE_NAME " DEBUG: " format "\n", ## arg ) +#define DEB1(format, arg...) \ + if (i2c_debug>=1) { \ + printk(KERN_DEBUG MODULE_NAME " DEBUG: " format "\n", ## arg ); \ + } +#define DEB2(format, arg...) \ + if (i2c_debug>=2) { \ + printk(KERN_DEBUG MODULE_NAME " DEBUG: " format "\n", ## arg ); \ + } +#define DEB3(format, arg...) \ + if (i2c_debug>=3) { \ + printk(KERN_DEBUG MODULE_NAME " DEBUG: " format "\n", ## arg ); \ + } +#define DEB9(format, arg...) \ + /* debug the protocol by showing transferred bits */ \ + if (i2c_debug>=9) { \ + printk(KERN_DEBUG MODULE_NAME " DEBUG: " format "\n", ## arg ); \ + } +#else +#define DEB0(fmt, args...) +#define DEB1(fmt, args...) +#define DEB2(fmt, args...) +#define DEB3(fmt, args...) +#define DEB9(fmt, args...) +#endif + +#define err(format, arg...) printk(KERN_ERR MODULE_NAME " ERROR: " format "\n", ## arg ) +#define info(format, arg...) printk(KERN_INFO MODULE_NAME ": " format "\n", ## arg ) +#define warn(format, arg...) printk(KERN_WARNING MODULE_NAME " WARNING: " format "\n", ## arg ) +#define emerg(format, arg...) printk(KERN_EMERG MODULE_NAME " EMERGENCY: " format "\n", ## arg ) + +#ifdef CONFIG_ARCH_OMAP1510 +#define omap_i2c_rev1() (readw(OMAP_I2C_REV) < 0x20) +#else +#define omap_i2c_rev1() 0 +#endif + +#define DEFAULT_OWN 1 /*default own I2C address */ +#define MAX_MESSAGES 65536 /* max number of messages */ + +static int clock = 100; /* Default: Fast Mode = 400 KHz, Standard Mode = 100 KHz */ +static int own; +static int i2c_scan; /* have a look at what's hanging 'round */ + +static struct omap_i2c_dev { + int cmd_complete, cmd_err; + wait_queue_head_t cmd_wait; + u8 *buf; + size_t buf_len; +} omap_i2c_dev; + + +static int omap_i2c_reset(void) +{ + unsigned long timeout; + u16 psc; + struct clk *armxor_ck; + unsigned long armxor_rate; + + if(!cpu_is_omap1510()) { + + writew(OMAP_I2C_SYSC_SRST, OMAP_I2C_SYSC); /*soft reset */ + } + else { + writew(OMAP_I2C_CON_RST, OMAP_I2C_CON); /* reset */ + } + + armxor_ck = clk_get(0, "armxor_ck"); + if (IS_ERR(armxor_ck)) { + printk(KERN_WARNING "i2c: Could not obtain armxor_ck rate.\n"); + armxor_rate = 12000000; + } else { + armxor_rate = clk_get_rate(armxor_ck); + clk_put(armxor_ck); + } + + if (armxor_rate <= 16000000) + psc = 0; + else + psc = (armxor_rate + 8000000) / 12000000; + + /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */ + writew(psc, OMAP_I2C_PSC); + + /* Program desired operating rate */ + armxor_rate /= (psc + 1) * 1000; + if (psc > 2) + psc = 2; + writew(armxor_rate / (clock * 2) - 7 + psc, OMAP_I2C_SCLL); + writew(armxor_rate / (clock * 2) - 7 + psc, OMAP_I2C_SCLH); + + + /* Set Own Address: */ + writew(own, OMAP_I2C_OA); + + /* Enable interrupts */ + writew((OMAP_I2C_IE_XRDY_IE | OMAP_I2C_IE_RRDY_IE | OMAP_I2C_IE_ARDY_IE | + OMAP_I2C_IE_NACK_IE | OMAP_I2C_IE_AL_IE), OMAP_I2C_IE); + + /* Take the I2C module out of reset: */ + writew(OMAP_I2C_CON_EN, OMAP_I2C_CON); + + if(!cpu_is_omap1510()){ + timeout = jiffies + OMAP_I2C_TIMEOUT; + while (!(readw(OMAP_I2C_SYSS) & OMAP_I2C_SYSS_RDONE)) { + if (time_after(jiffies, timeout)) { + err("timeout waiting for I2C reset complete"); + return -EFAULT; + } + schedule_timeout(1); + } + } + + return 0; + +} + +/* + * Waiting on Bus Busy + */ +static int +omap_i2c_wait_for_bb(char allow_sleep) +{ + unsigned long timeout; + + timeout = jiffies + OMAP_I2C_TIMEOUT; + while (readw(OMAP_I2C_STAT) & OMAP_I2C_STAT_BB) { + if (time_after(jiffies, timeout)) { + warn("timeout waiting for bus ready"); + return -ETIMEDOUT; + } + if (allow_sleep) + schedule_timeout(1); + } + + return 0; +} + +/* + * Low level master read/write transaction. + */ +static int +omap_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) +{ + struct omap_i2c_dev *dev = i2c_get_adapdata(adap); + u8 zero_byte = 0; + int r; + u16 w; + + DEB2("addr: 0x%04x, len: %d, flags: 0x%x, stop: %d", + msg->addr, msg->len, msg->flags, stop); + + writew(msg->addr, OMAP_I2C_SA); + + /* Sigh, seems we can't do zero length transactions. Thus, we + * can't probe for devices w/o actually sending/receiving at least + * a single byte. So we'll set count to 1 for the zero length + * transaction case and hope we don't cause grief for some + * arbitrary device due to random byte write/read during + * probes. + */ + if (msg->len == 0) { + dev->buf = &zero_byte; + dev->buf_len = 1; + } else { + dev->buf = msg->buf; + dev->buf_len = msg->len; + } + writew(dev->buf_len, OMAP_I2C_CNT); + dev->cmd_complete = 0; + dev->cmd_err = 0; + w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT; + if (msg->flags & I2C_M_TEN) + w |= OMAP_I2C_CON_XA; + if (!(msg->flags & I2C_M_RD)) + w |= OMAP_I2C_CON_TRX; + if (stop) + w |= OMAP_I2C_CON_STP; + writew(w, OMAP_I2C_CON); + + r = wait_event_interruptible_timeout(dev->cmd_wait, + dev->cmd_complete, + OMAP_I2C_TIMEOUT); + dev->buf_len = 0; + if (r < 0) + return r; + if (!dev->cmd_complete) { + omap_i2c_reset(); + return -ETIMEDOUT; + } + if (!dev->cmd_err) + return msg->len; + + /* We have an error */ + if (dev->cmd_err & OMAP_I2C_STAT_NACK) { + if (msg->flags & I2C_M_IGNORE_NAK) + return msg->len; + if (stop) + writew(readw(OMAP_I2C_CON) | OMAP_I2C_CON_STP, OMAP_I2C_CON); + return -EREMOTEIO; + } + if (dev->cmd_err & OMAP_I2C_STAT_AL || + dev->cmd_err & OMAP_I2C_STAT_ROVR || + dev->cmd_err & OMAP_I2C_STAT_XUDF) { + omap_i2c_reset(); + return -EIO; + } + return msg->len; +} + +/* + * Prepare controller for a transaction and call omap_i2c_rxbytes + * to do the work. + */ +static int +omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + int i; + int r = 0; + + DEB1("msgs: %d", num); + + if (num < 1 || num > MAX_MESSAGES) + return -EINVAL; + + /* Check for valid parameters in messages */ + for (i = 0; i < num; i++) + if (msgs[i].buf == NULL) + return -EINVAL; + + if ((r = omap_i2c_wait_for_bb(1)) < 0) + return r; + + for (i = 0; i < num; i++) { + DEB2("msg: %d, addr: 0x%04x, len: %d, flags: 0x%x", + i, msgs[i].addr, msgs[i].len, msgs[i].flags); + + r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1))); + + DEB2("r: %d", r); + + if (r != msgs[i].len) + break; + } + + if (r >= 0 && num > 1) + r = num; + + DEB1("r: %d", r); + + return r; +} + +/* + * Sanity check for the adapter hardware - check the reaction of + * the bus lines only if it seems to be idle. + * + * Scan the I2C bus for valid 7 bit addresses + * (ie things that ACK on 1byte read) + * if i2c_debug is off we print everything on one line. + * if i2c_debug is on we do a newline per print so we don't + * clash too much with printf's in the other functions. + * TODO: check for 10-bit mode and never run as a slave. + */ +static int +omap_i2c_scan_bus(struct i2c_adapter *adap) +{ + int found = 0; + int i; + struct i2c_msg msg; + char data[1]; + + info("scanning for active I2C devices on the bus..."); + + for (i = 1; i < 0x7f; i++) { + if (readw(OMAP_I2C_OA) == i) + continue; + + msg.addr = i; + msg.buf = data; + msg.len = 0; + msg.flags = I2C_M_RD; + + if (omap_i2c_xfer(adap, &msg, 1) == 0) { + info("I2C device 0x%02x found", i); + found++; + } + } + + if (!found) + info("found nothing"); + + return found; +} + + +static u32 +omap_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static inline void +omap_i2c_complete_cmd(struct omap_i2c_dev *dev) +{ + dev->cmd_complete = 1; + wake_up(&dev->cmd_wait); +} + +static irqreturn_t +omap_i2c_isr(int this_irq, void *dev_id, struct pt_regs *regs) +{ + struct omap_i2c_dev *dev = dev_id; + u16 bits; + u16 stat, w; + int count = 0; + u16 iv_read; + + bits = readw(OMAP_I2C_IE); + while ((stat = readw(OMAP_I2C_STAT)) & bits) { + + if (count++ == 100) { + warn("Too much work in one IRQ"); + break; + } + + writew(stat, OMAP_I2C_STAT); + if (stat & OMAP_I2C_STAT_ARDY) { + omap_i2c_complete_cmd(dev); + writew(OMAP_I2C_STAT_ARDY, OMAP_I2C_STAT); + if (omap_i2c_rev1()) + iv_read = readw(OMAP_I2C_IV); + continue; + } + if (stat & OMAP_I2C_STAT_RRDY) { + w = readw(OMAP_I2C_DATA); + if (dev->buf_len) { + *dev->buf++ = w; + dev->buf_len--; + if (dev->buf_len) { + *dev->buf++ = w >> 8; + dev->buf_len--; + } + if (omap_i2c_rev1() && !dev->buf_len) + omap_i2c_complete_cmd(dev); + } else + err("RRDY IRQ while no data requested"); + writew(OMAP_I2C_STAT_RRDY, OMAP_I2C_STAT); + if (omap_i2c_rev1()) + iv_read = readw(OMAP_I2C_IV); + continue; + } + if (stat & OMAP_I2C_STAT_XRDY) { + w = 0; + if (dev->buf_len) { + w = *dev->buf++; + dev->buf_len--; + if (dev->buf_len) { + w |= *dev->buf++ << 8; + dev->buf_len--; + } + } else { + err("XRDY IRQ while no data to send"); + } + writew(w, OMAP_I2C_DATA); + /* We have to make sure the XRDY bit is reset */ + writew(OMAP_I2C_STAT_XRDY, OMAP_I2C_STAT); + if (omap_i2c_rev1()) { + iv_read = readw(OMAP_I2C_IV); + if (!dev->buf_len) + omap_i2c_complete_cmd(dev); + } + continue; + } + if (stat & OMAP_I2C_STAT_ROVR) { + warn("Receive overrun"); + dev->cmd_err |= OMAP_I2C_STAT_ROVR; + } + if (stat & OMAP_I2C_STAT_XUDF) { + warn("Transmit overflow"); + dev->cmd_err |= OMAP_I2C_STAT_XUDF; + } + if (stat & OMAP_I2C_STAT_NACK) { + dev->cmd_err |= OMAP_I2C_STAT_NACK; + omap_i2c_complete_cmd(dev); + writew(OMAP_I2C_CON_STP, OMAP_I2C_CON); + } + if (stat & OMAP_I2C_STAT_AL) { + warn("Arbitration lost"); + dev->cmd_err |= OMAP_I2C_STAT_AL; + omap_i2c_complete_cmd(dev); + } + if (omap_i2c_rev1()) + iv_read = readw(OMAP_I2C_IV); + + } + return IRQ_HANDLED; +} + +static int omap_i2c_remove(struct device *dev) +{ + return 0; +} + +static void omap_i2c_device_release(struct device *dev) +{ + /* Nothing */ +} + +static struct i2c_algorithm omap_i2c_algo = { + .name = "OMAP I2C algorithm", + .id = I2C_ALGO_EXP, + .master_xfer = omap_i2c_xfer, + .smbus_xfer = NULL, + .slave_send = NULL, + .slave_recv = NULL, + .algo_control = NULL, + .functionality = omap_i2c_func, +}; + +static struct i2c_adapter omap_i2c_adap = { + .owner = THIS_MODULE, + .name = "OMAP I2C adapter", + .id = I2C_ALGO_EXP, /* REVISIT: register for id */ + .algo = &omap_i2c_algo, + .algo_data = NULL, + .client_register = NULL, + .client_unregister = NULL, +}; + +static struct device_driver omap_i2c_driver = { + .name = "omap_i2c", + .bus = &platform_bus_type, + .remove = omap_i2c_remove, +}; + +static struct platform_device omap_i2c_device = { + .name = "i2c", + .id = -1, + .dev = { + .driver = &omap_i2c_driver, + .release = omap_i2c_device_release, + }, +}; + +static int __init +omap_i2c_init(void) +{ + int r; + + info("Driver ver. 1.3"); + DEB0("%s %s", __TIME__, __DATE__); + + if (clock > 200) + clock = 400; /*Fast mode */ + else + clock = 100; /*Standard mode */ + + if (own < 1 || own > 0x7f) + own = DEFAULT_OWN; + + memset(&omap_i2c_dev, 0, sizeof(omap_i2c_dev)); + init_waitqueue_head(&omap_i2c_dev.cmd_wait); + + r = (int) request_region(OMAP_I2C_BASE, OMAP_I2C_IOSIZE, MODULE_NAME); + if (!r) { + err("I2C is already in use"); + return -ENODEV; + } + + r = request_irq(INT_I2C, omap_i2c_isr, 0, MODULE_NAME, &omap_i2c_dev); + if (r) { + err("failed to request I2C IRQ"); + goto do_release_region; + } + + i2c_set_adapdata(&omap_i2c_adap, &omap_i2c_dev); + r = i2c_add_adapter(&omap_i2c_adap); + if (r) { + err("failed to add adapter"); + goto do_free_irq; + return r; + } + + /* configure I/O pin multiplexing */ + /* FIXME: This should be done in bootloader */ + omap_cfg_reg(I2C_SCL); + omap_cfg_reg(I2C_SDA); + + omap_i2c_reset(); + + if (i2c_scan) + omap_i2c_scan_bus(&omap_i2c_adap); + if(driver_register(&omap_i2c_driver) != 0) + printk(KERN_ERR "Driver register failed for omap_i2c\n"); + if(platform_device_register(&omap_i2c_device) != 0) { + printk(KERN_ERR "Device register failed for i2c\n"); + driver_unregister(&omap_i2c_driver); + } + + return 0; + +do_free_irq: + free_irq(INT_I2C, &omap_i2c_dev); +do_release_region: + release_region(OMAP_I2C_BASE, OMAP_I2C_IOSIZE); + + return r; +} + +static void __exit +omap_i2c_exit(void) +{ + i2c_del_adapter(&omap_i2c_adap); + writew(0, OMAP_I2C_CON); + free_irq(INT_I2C, &omap_i2c_dev); + release_region(OMAP_I2C_BASE, OMAP_I2C_IOSIZE); + driver_unregister(&omap_i2c_driver); + platform_device_unregister(&omap_i2c_device); +} + +MODULE_AUTHOR("MontaVista Software, Inc."); +MODULE_DESCRIPTION("TI OMAP I2C bus adapter"); +MODULE_LICENSE("GPL"); + +module_param(clock, int, 0); +MODULE_PARM_DESC(clock, + "Set I2C clock in KHz: 100 (Standard Mode) or 400 (Fast Mode)"); + +module_param(own, int, 0); + +module_param(i2c_scan, int, 0); +MODULE_PARM_DESC(i2c_scan, "Scan for active I2C clients on the bus"); + +#ifdef I2C_OMAP_DEBUG +module_param(i2c_debug, int, 0); +MODULE_PARM_DESC(i2c_debug, + "debug level - 0 off; 1 normal; 2,3 more verbose; " + "9 omap-protocol"); +#endif + +/* i2c may be needed to bring up other drivers */ +subsys_initcall(omap_i2c_init); +module_exit(omap_i2c_exit); diff -Nru a/drivers/i2c/busses/i2c-omap.h b/drivers/i2c/busses/i2c-omap.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/i2c/busses/i2c-omap.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,114 @@ +/* + * linux/drivers/i2c/i2c-omap1610.h + * + * BRIEF MODULE DESCRIPTION + * OMAP I2C register definitions + * + * Copyright (C) 2004 Texas Instruments. + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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. + * + * HISTORY: + * + * 20040824: Thiago Radicchi DCC-UFMG / iNdT + * Removed some ifdefs which broke compilation for some platforms. + * Added new defintion for interrupt vector. + */ + +/* I2C Registers: */ + +#define OMAP_I2C_BASE IO_ADDRESS(0xfffb3800) +#define OMAP_I2C_IOSIZE (0x40) +#define OMAP_I2C_REV (OMAP_I2C_BASE + 0x00) +#define OMAP_I2C_IE (OMAP_I2C_BASE + 0x04) +#define OMAP_I2C_STAT (OMAP_I2C_BASE + 0x08) +#define OMAP_I2C_IV (OMAP_I2C_BASE + 0x0c) +#define OMAP_I2C_SYSS (OMAP_I2C_BASE + 0x10) +#define OMAP_I2C_BUF (OMAP_I2C_BASE + 0x14) +#define OMAP_I2C_CNT (OMAP_I2C_BASE + 0x18) +#define OMAP_I2C_DATA (OMAP_I2C_BASE + 0x1c) +#define OMAP_I2C_SYSC (OMAP_I2C_BASE + 0x20) +#define OMAP_I2C_CON (OMAP_I2C_BASE + 0x24) +#define OMAP_I2C_OA (OMAP_I2C_BASE + 0x28) +#define OMAP_I2C_SA (OMAP_I2C_BASE + 0x2c) +#define OMAP_I2C_PSC (OMAP_I2C_BASE + 0x30) +#define OMAP_I2C_SCLL (OMAP_I2C_BASE + 0x34) +#define OMAP_I2C_SCLH (OMAP_I2C_BASE + 0x38) +#define OMAP_I2C_SYSTEST (OMAP_I2C_BASE + 0x3c) + +/* I2C Interrupt Enable Register (OMAP_I2C_IE): */ + +#define OMAP_I2C_IE_XRDY_IE (1 << 4) /* Transmit data ready interrupt enable */ +#define OMAP_I2C_IE_RRDY_IE (1 << 3) /* Receive data ready interrupt enable */ +#define OMAP_I2C_IE_ARDY_IE (1 << 2) /* Register access ready interrupt enable */ +#define OMAP_I2C_IE_NACK_IE (1 << 1) /* No acknowledgment interrupt enable */ +#define OMAP_I2C_IE_AL_IE (1 << 0) /* Arbitration lost interrupt enable */ + +/* I2C Status Register (OMAP_I2C_STAT): */ + +#define OMAP_I2C_STAT_SBD (1 << 15) /* Single byte data */ +#define OMAP_I2C_STAT_BB (1 << 12) /* Bus busy */ +#define OMAP_I2C_STAT_ROVR (1 << 11) /* Receive overrun */ +#define OMAP_I2C_STAT_XUDF (1 << 10) /* Transmit underflow */ +#define OMAP_I2C_STAT_AAS (1 << 9) /* Address as slave */ +#define OMAP_I2C_STAT_AD0 (1 << 8) /* Address zero */ +#define OMAP_I2C_STAT_XRDY (1 << 4) /* Transmit data ready */ +#define OMAP_I2C_STAT_RRDY (1 << 3) /* Receive data ready */ +#define OMAP_I2C_STAT_ARDY (1 << 2) /* Register access ready */ +#define OMAP_I2C_STAT_NACK (1 << 1) /* No acknowledgment interrupt enable */ +#define OMAP_I2C_STAT_AL (1 << 0) /* Arbitration lost interrupt enable */ + +/* I2C Buffer Configuration Register (OMAP_I2C_BUF): */ + +#define OMAP_I2C_BUF_RDMA_EN (1 << 15) /* Receive DMA channel enable */ +#define OMAP_I2C_BUF_XDMA_EN (1 << 7) /* Transmit DMA channel enable */ + +/* I2C Configuration Register (OMAP_I2C_CON): */ + +#define OMAP_I2C_CON_EN (1 << 15) /* I2C module enable */ +#define OMAP_I2C_CON_RST (0 << 15) /* I2C module reset */ +#define OMAP_I2C_CON_BE (1 << 14) /* Big endian mode */ +#define OMAP_I2C_CON_STB (1 << 11) /* Start byte mode (master mode only) */ +#define OMAP_I2C_CON_MST (1 << 10) /* Master/slave mode */ +#define OMAP_I2C_CON_TRX (1 << 9) /* Transmitter/receiver mode (master mode only) */ +#define OMAP_I2C_CON_XA (1 << 8) /* Expand address */ +#define OMAP_I2C_CON_RM (1 << 2) /* Repeat mode (master mode only) */ +#define OMAP_I2C_CON_STP (1 << 1) /* Stop condition (master mode only) */ +#define OMAP_I2C_CON_STT (1 << 0) /* Start condition (master mode only) */ + +/* I2C System Test Register (OMAP_I2C_SYSTEST): */ + +#define OMAP_I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */ +#define OMAP_I2C_SYSTEST_FREE (1 << 14) /* Free running mode (on breakpoint) */ +#define OMAP_I2C_SYSTEST_TMODE_MASK (3 << 12) /* Test mode select */ +#define OMAP_I2C_SYSTEST_TMODE_SHIFT (12) /* Test mode select */ +#define OMAP_I2C_SYSTEST_SCL_I (1 << 3) /* SCL line sense input value */ +#define OMAP_I2C_SYSTEST_SCL_O (1 << 2) /* SCL line drive output value */ +#define OMAP_I2C_SYSTEST_SDA_I (1 << 1) /* SDA line sense input value */ +#define OMAP_I2C_SYSTEST_SDA_O (1 << 0) /* SDA line drive output value */ + +/* I2C System Status register (OMAP_I2C_SYSS): */ + +#define OMAP_I2C_SYSS_RDONE 1 /* Reset Done */ + +/* I2C System Configuration Register (OMAP_I2C_SYSC): */ + +#define OMAP_I2C_SYSC_SRST (1 << 1) /* Soft Reset */ diff -Nru a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig --- a/drivers/i2c/chips/Kconfig 2005-03-02 10:51:31 -08:00 +++ b/drivers/i2c/chips/Kconfig 2005-03-02 10:51:31 -08:00 @@ -371,4 +371,27 @@ This driver can also be built as a module. If so, the module will be called isp1301_omap. +config TPS65010 + tristate "TPS65010 Power management chip" + depends on I2C + default y if MACH_OMAP_H3 || MACH_OMAP_OSK + help + If you say yes here you get support for the TPS65010 Power management + chip. + + This driver can also be built as a module. If so, the module + will be called tps65010. + +config SENSORS_TLV320AIC23 + tristate "Texas Instruments TLV320AIC23 Codec" + depends on I2C && I2C_OMAP + help + If you say yes here you get support for the I2C control + interface for Texas Instruments TLV320AIC23 audio codec. + +config GPIOEXPANDER_OMAP + bool "GPIO Expander PCF8574PWR for OMAP" + depends on I2C && ARCH_OMAP16XX + help + If you say yes here you get support for I/O expander calls to configure IrDA, Camera and audio devices endmenu diff -Nru a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile --- a/drivers/i2c/chips/Makefile 2005-03-02 10:51:31 -08:00 +++ b/drivers/i2c/chips/Makefile 2005-03-02 10:51:31 -08:00 @@ -34,7 +34,10 @@ obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o +obj-$(CONFIG_TPS65010) += tps65010.o obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o +obj-$(CONFIG_SENSORS_TLV320AIC23) += tlv320aic23.o +obj-$(CONFIG_GPIOEXPANDER_OMAP) += gpio_expander_omap.o ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) EXTRA_CFLAGS += -DDEBUG diff -Nru a/drivers/i2c/chips/gpio_expander_omap.c b/drivers/i2c/chips/gpio_expander_omap.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/i2c/chips/gpio_expander_omap.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,82 @@ +/* + * drivers/i2c/chips/gpio_expander_omap.c + * + * Copyright (C) 2004 Texas Instruments Inc + * Author: + * + * gpio expander is used to configure IrDA, camera and audio devices on omap 1710 processor. + * + * 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 +#include +#include + +int read_gpio_expa(u8 * val, int addr); +int write_gpio_expa(u8 val, int addr); + +#define OMAP_IRDA_DEBUG 0 + +#if (OMAP_IRDA_DEBUG > 0) +#define DBG(format, args...) printk(KERN_ERR "%s(): " format, __FUNCTION__, ## args); +#define DBG_IRQ(format, args...) printk(KERN_ERR "%s(): " format, __FUNCTION__, ## args); +#else +#define DBG(format, args...) +#define DBG_IRQ(format, args...) +#endif + +int write_gpio_expa(u8 val, int addr) +{ + struct i2c_adapter *adap; + int err; + struct i2c_msg msg[1]; + unsigned char data[1]; + + adap = i2c_get_adapter(0); + if (!adap) + return -ENODEV; + msg->addr = addr; /* I2C address of GPIO EXPA */ + msg->flags = 0; + msg->len = 1; + msg->buf = data; + data[0] = val; + err = i2c_transfer(adap, msg, 1); + if (err >= 0) + return 0; + return err; +} + +/* Read from I/O EXPANDER on the H3 board. + * The IO expanders need an independent I2C client driver. + */ + +int read_gpio_expa(u8 * val, int addr) +{ + struct i2c_adapter *adap; + int err; + struct i2c_msg msg[1]; + unsigned char data[1]; + + adap = i2c_get_adapter(0); + if (!adap) + return -ENODEV; + msg->addr = addr; /* I2C address of GPIO EXPA */ + msg->flags = I2C_M_RD; + msg->len = 2; + msg->buf = data; + err = i2c_transfer(adap, msg, 1); + *val = data[0]; + + DBG("I2C: Read data is %x\n", (u8) * data); + if (err >= 0) + return 0; + return err; +} + +EXPORT_SYMBOL(read_gpio_expa); +EXPORT_SYMBOL(write_gpio_expa); + diff -Nru a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c --- a/drivers/i2c/chips/isp1301_omap.c 2005-03-02 10:51:31 -08:00 +++ b/drivers/i2c/chips/isp1301_omap.c 2005-03-02 10:51:31 -08:00 @@ -37,6 +37,7 @@ #include #include +#include #ifndef DEBUG @@ -91,7 +92,8 @@ /*-------------------------------------------------------------------------*/ -#ifdef CONFIG_MACH_OMAP_H2 +#if defined(CONFIG_MACH_OMAP_H2) || \ + defined(CONFIG_MACH_OMAP_H3) /* board-specific PM hooks */ @@ -516,6 +518,7 @@ static void update_otg1(struct isp1301 *isp, u8 int_src) { u32 otg_ctrl; + u8 int_id; otg_ctrl = OTG_CTRL_REG & OTG_CTRL_MASK @@ -529,7 +532,10 @@ } if (int_src & INTR_VBUS_VLD) otg_ctrl |= OTG_VBUSVLD; - if (int_src & INTR_ID_GND) { /* default-A */ + + int_id = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE); + + if (int_id & INTR_ID_GND) { /* default-A */ if (isp->otg.state == OTG_STATE_B_IDLE || isp->otg.state == OTG_STATE_UNDEFINED) { a_idle(isp, "init"); @@ -1082,7 +1088,7 @@ /* update the OTG controller state to match the isp1301; may * trigger OPRT_CHG irqs for changes going to the isp1301. */ - update_otg1(isp, isp_stat); + update_otg1(isp, stat); // pass the actual interrupt latch status update_otg2(isp, isp_bstat); check_state(isp, __FUNCTION__); #endif @@ -1223,6 +1229,9 @@ if (machine_is_omap_h2()) omap_free_gpio(2); + if (machine_is_omap_h3()) + omap_free_gpio(14); + isp->timer.data = 0; set_bit(WORK_STOP, &isp->todo); del_timer_sync(&isp->timer); @@ -1301,7 +1310,7 @@ power_up(isp); - if (machine_is_omap_h2()) + if (machine_is_omap_h2() || machine_is_omap_h3()) isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); dev_info(&isp->client.dev, "A-Host sessions ok\n"); @@ -1364,13 +1373,13 @@ power_up(isp); isp->otg.state = OTG_STATE_B_IDLE; - if (machine_is_omap_h2()) + if (machine_is_omap_h2() || machine_is_omap_h3()) isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING, - INTR_SESS_VLD); + INTR_SESS_VLD | INTR_VBUS_VLD); isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING, - INTR_VBUS_VLD); + INTR_VBUS_VLD | INTR_SESS_VLD); dev_info(&isp->client.dev, "B-Peripheral sessions ok\n"); dump_regs(isp, __FUNCTION__); @@ -1447,6 +1456,10 @@ * So do this part as early as possible... */ switch (isp->otg.state) { + case OTG_STATE_B_PERIPHERAL: + isp->otg.state = OTG_STATE_B_WAIT_ACON; + isp1301_defer_work(isp, WORK_UPDATE_ISP); + break; case OTG_STATE_B_HOST: isp->otg.state = OTG_STATE_B_PERIPHERAL; /* caller will suspend next */ @@ -1563,19 +1576,30 @@ } #endif - if (machine_is_omap_h2()) { + if (machine_is_omap_h2() || machine_is_omap_h3()) { /* full speed signaling by default */ isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SPEED_REG); isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_SPD_SUSP_CTRL); + } + if (machine_is_omap_h2()) { /* IRQ wired at M14 */ omap_cfg_reg(M14_1510_GPIO2); isp->irq = OMAP_GPIO_IRQ(2); omap_request_gpio(2); omap_set_gpio_direction(2, 1); omap_set_gpio_edge_ctrl(2, OMAP_GPIO_FALLING_EDGE); + } + + if (machine_is_omap_h3()) { + /* IRQ wired at N21 */ + omap_cfg_reg(N21_1710_GPIO14); + isp->irq = OMAP_GPIO_IRQ(14); + omap_request_gpio(14); + omap_set_gpio_direction(14, 1); + omap_set_gpio_edge_ctrl(14, OMAP_GPIO_FALLING_EDGE); } status = request_irq(isp->irq, isp1301_irq, diff -Nru a/drivers/i2c/chips/tlv320aic23.c b/drivers/i2c/chips/tlv320aic23.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/i2c/chips/tlv320aic23.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,174 @@ +/* + * Texas Instrumens TLV320AIC23 audio codec's i2c interface. + * + * Copyright (c) by Kai Svahn + * + * 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 +#include +#include +#include +#include +#include +#include + +#define TLV320AIC23_VERSION "0.1" +#define TLV320AIC23_DATE "12-Aug-2004" + +/* I2C Addresses to scan */ +static unsigned short normal_i2c[] = { TLV320AIC23ID1, TLV320AIC23ID2, I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; + +/* This makes all addr_data:s */ +I2C_CLIENT_INSMOD; + +static int tlv320aic23_id = 0; +static struct i2c_driver tlv320aic23_driver; +static struct i2c_client *new_client; +//static struct i2c_client *client; + +static int _tlv320aic23_write_value(struct i2c_client *client, u8 reg, u16 value) +{ + u8 val, wreg; + + /* TLV320AIC23 has 7 bit address and 9 bits of data + * so we need to switch one data bit into reg and rest + * of data into val + */ + + wreg = (reg << 1); + val = (0x01 & (value >> 8)); + wreg = (wreg | val); + val = (0x00ff & value); + + return i2c_smbus_write_byte_data(client, wreg, val); +} + +int tlv320aic23_write_value(u8 reg, u16 value) +{ + static struct i2c_client *client; + client = new_client; + _tlv320aic23_write_value(client, reg, value); + + return 0; +} + +static int tlv320aic23_detect_client(struct i2c_adapter *adapter, int address, + int kind) +{ + int err = 0; + const char *client_name = "TLV320AIC23 Audio Codec"; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_WRITE_BYTE)) { + printk(KERN_WARNING "%s functinality check failed\n", client_name); + return err; + } + + if (!(new_client = kmalloc(sizeof(struct i2c_client), + GFP_KERNEL))) { + err = -ENOMEM; + printk(KERN_WARNING "Couldn't allocate memory for %s\n", client_name); + return err; + } + + memset(new_client, 0x00, sizeof(struct i2c_client)); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &tlv320aic23_driver; + new_client->flags = 0; + strlcpy(new_client->name, client_name, I2C_NAME_SIZE); + new_client->id = tlv320aic23_id++; + + if ((err = i2c_attach_client(new_client))) { + printk(KERN_WARNING "Couldn't attach %s\n", client_name); + kfree(new_client); + return err; + } + + return 0; +} + +static int tlv320aic23_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + printk("tlv320aic23.o: Client deregistration failed, client not detached.\n"); + return err; + } + + kfree(client); + return 0; +} + +static int tlv320aic23_attach_adapter(struct i2c_adapter *adapter) +{ + int res; + + res = i2c_probe(adapter, &addr_data, &tlv320aic23_detect_client); + return res; +} + +/*-----------------------------------------------------------------------*/ + +static struct i2c_driver tlv320aic23_driver = { + .owner = THIS_MODULE, + .name = "OMAP+TLV320AIC23 codec", + .id = I2C_DRIVERID_EXP0, /* Experimental ID */ + .flags = I2C_DF_NOTIFY, + .attach_adapter = tlv320aic23_attach_adapter, + .detach_client = tlv320aic23_detach_client, +}; + +/* + * INIT part + */ + +static int __init tlv320aic23_init(void) +{ + int res; + struct i2c_client *client = client; + + if ((res = i2c_add_driver(&tlv320aic23_driver))) { + printk("tlv320aic23 i2c: Driver registration failed, module not inserted.\n"); + return res; + } + + printk("TLV320AIC23 I2C version %s (%s)\n", TLV320AIC23_VERSION, + TLV320AIC23_DATE); + + return 0; +} + +static void __exit tlv320aic23_exit(void) +{ + int res; + + if ((res = i2c_del_driver(&tlv320aic23_driver))) + printk("tlv320aic23 i2c: Driver remove failed, module not removed.\n"); +} + +MODULE_AUTHOR("Kai Svahn "); +MODULE_DESCRIPTION("I2C interface for TLV320AIC23 codec."); +MODULE_LICENSE("GPL"); + +module_init(tlv320aic23_init) +module_exit(tlv320aic23_exit) + +EXPORT_SYMBOL(tlv320aic23_write_value); diff -Nru a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/i2c/chips/tps65010.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,729 @@ +/* + * tps65010 - driver for tps6501x power management chips + * + * Copyright (C) 2004 Texas Instruments + * + * 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. + */ +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/*-------------------------------------------------------------------------*/ + +#define DRIVER_VERSION "20 Jan 2005" +#define DRIVER_NAME (tps65010_driver.name) + +MODULE_DESCRIPTION("TPS6501x Power Management Driver"); +MODULE_LICENSE("GPL"); + +/* only two addresses possible */ +#define TPS_BASE 0x48 +static unsigned short normal_i2c[] = { + TPS_BASE, + I2C_CLIENT_END }; +static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; + +I2C_CLIENT_INSMOD; + +static struct i2c_driver tps65010_driver; + +/*-------------------------------------------------------------------------*/ + +struct tps65010 { + struct i2c_client client; + struct semaphore lock; + int irq; + struct work_struct work; + u16 vbus; + unsigned long flags; +#define FLAG_VBUS_CHANGED 0 + + /* copies of last register state */ + u8 chgstatus, regstatus, chgconf; + u8 nmask1, nmask2; + + /* plus four GPIOs, probably used to switch power */ +}; + +#ifdef DEBUG + +static void show_chgstatus(const char *label, u8 chgstatus) +{ + pr_debug("%s: %s %02x%s%s%s%s%s%s%s%s\n", + DRIVER_NAME, label, chgstatus, + (chgstatus & TPS_CHG_USB) ? " USB" : "", + (chgstatus & TPS_CHG_AC) ? " AC" : "", + (chgstatus & TPS_CHG_THERM) ? " therm" : "", + (chgstatus & TPS_CHG_TERM) ? " done" : " (charging)", + (chgstatus & TPS_CHG_TAPER_TMO) ? " taper_tmo" : "", + (chgstatus & TPS_CHG_CHG_TMO) ? " charge_tmo" : "", + (chgstatus & TPS_CHG_PRECHG_TMO) ? " prechg_tmo" : "", + (chgstatus & TPS_CHG_TEMP_ERR) ? " temp_err" : ""); +} + +static void show_regstatus(const char *label, u8 regstatus) +{ + pr_debug("%s: %s %02x %s%s%s%s%s%s%s\n", + DRIVER_NAME, label, regstatus, + (regstatus & TPS_REG_ONOFF) ? "off" : "(on)", + (regstatus & TPS_REG_COVER) ? " uncover" : "", + (regstatus & TPS_REG_UVLO) ? " UVLO" : "", + (regstatus & TPS_REG_PG_LD02) ? " ld01_bad" : "", + (regstatus & TPS_REG_PG_LD01) ? " ld01_bad" : "", + (regstatus & TPS_REG_PG_MAIN) ? " main_bad" : "", + (regstatus & TPS_REG_PG_CORE) ? " core_bad" : ""); +} + +static void show_chgconfig(const char *label, u8 chgconfig) +{ + pr_debug("%s: %s 0x%02x %dms%s%s AC=%d%% USB=%dmA %sCharge\n", + DRIVER_NAME, label, chgconfig, + (chgconfig & TPS_CHARGE_POR) ? 69: 1000, + (chgconfig & TPS_CHARGE_RESET) ? " reset" : "", + (chgconfig & TPS_CHARGE_FAST) ? " fast" : "", + ({int p; switch ((chgconfig >> 3) & 3) { + case 3: p = 100; break; + case 2: p = 75; break; + case 1: p = 50; break; + default: p = 25; break; + }; p; }), + (chgconfig & TPS_VBUS_CHARGING) + ? ((chgconfig & TPS_VBUS_500MA) ? 500 : 100) + : 0, + (chgconfig & TPS_CHARGE_ENABLE) ? "" : "No"); +} + +#else + +static inline void show_chgstatus(const char *label, u8 chgstatus) { } +static inline void show_regstatus(const char *label, u8 chgstatus) { } +static inline void show_chgconfig(const char *label, u8 chgconfig) { } + +#endif + +/*-------------------------------------------------------------------------*/ + +/* handle IRQs using keventd for now */ +static void tps65010_interrupt(struct tps65010 *tps) +{ + u8 tmp = 0, mask; + + /* regstatus irqs */ + if (tps->nmask2) { + tmp = i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS); + mask = tmp ^ tps->regstatus; + tps->regstatus = tmp; + mask &= tps->nmask2; + } else + mask = 0; + if (mask) { + show_regstatus("reg/irq", tmp); + tps->regstatus = tmp; + /* may need to shut something down ... */ + } + + /* chgstatus irqs */ + if (tps->nmask1) { + tmp = i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS); + mask = tmp ^ tps->chgstatus; + tps->chgstatus = tmp; + mask &= tps->nmask1; + } else + mask = 0; + if (mask) { + show_chgstatus("chg/irq", tmp); + if (tmp & (TPS_CHG_USB|TPS_CHG_AC)) + show_chgconfig("conf", tps->chgconf); + /* charging starts or stops */ + } + + /* also potentially gpio-in rise or fall */ +} + +/* handle IRQs using keventd for now */ +static void tps65010_work(void *_tps) +{ + struct tps65010 *tps = _tps; + + down(&tps->lock); + + tps65010_interrupt(tps); + + if (test_and_clear_bit(FLAG_VBUS_CHANGED, &tps->flags)) { + int status; + u8 chgconfig, tmp; + + chgconfig = i2c_smbus_read_byte_data(&tps->client, + TPS_CHGCONFIG); + chgconfig &= ~(TPS_VBUS_500MA | TPS_VBUS_CHARGING); + if (tps->vbus == 500) + chgconfig |= TPS_VBUS_500MA | TPS_VBUS_CHARGING; + else if (tps->vbus >= 100) + chgconfig |= TPS_VBUS_CHARGING; + + status = i2c_smbus_write_byte_data(&tps->client, + TPS_CHGCONFIG, chgconfig); + + /* fails unless a battery is connected! */ + tmp = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG); + pr_debug("%s: %d mA from vbus %d: 0x%02x%s, expect %02x\n", + DRIVER_NAME, tps->vbus, status, tmp, + (tmp != chgconfig) ? " (BAD)" : "", + chgconfig); + } + + up(&tps->lock); +} + +static irqreturn_t tps65010_irq(int irq, void *_tps, struct pt_regs *regs) +{ + struct tps65010 *tps = _tps; + + (void) schedule_work(&tps->work); + return IRQ_HANDLED; +} + +/*-------------------------------------------------------------------------*/ + +static struct tps65010 *the_tps; + +static int tps65010_detach_client(struct i2c_client *client) +{ + struct tps65010 *tps; + + tps = container_of(client, struct tps65010, client); +#ifdef CONFIG_ARM + if (machine_is_omap_h2()) + omap_free_gpio(58); + if (machine_is_omap_osk()) + omap_free_gpio(OMAP_MPUIO(1)); +#endif + free_irq(tps->irq, tps); + if (i2c_detach_client(client) == 0) + kfree(tps); + the_tps = 0; + return 0; +} + +/* no error returns, they'd just make bus scanning stop */ +static int tps65010_probe(struct i2c_adapter *bus, int address, int kind) +{ + static int tps65010_id; + struct tps65010 *tps; + int status; + + if (the_tps) { + dev_dbg(&bus->dev, "only one %s for now\n", DRIVER_NAME); + return 0; + } + + tps = kmalloc(sizeof *tps, GFP_KERNEL); + if (!tps) + return 0; + + memset(tps, 0, sizeof *tps); + init_MUTEX(&tps->lock); + INIT_WORK(&tps->work, tps65010_work, tps); + tps->irq = -1; + tps->client.addr = address; + i2c_set_clientdata(&tps->client, tps); + tps->client.adapter = bus; + tps->client.id = tps65010_id++; + tps->client.driver = &tps65010_driver; + strlcpy(tps->client.name, DRIVER_NAME, I2C_NAME_SIZE); + + status = i2c_attach_client(&tps->client); + if (status < 0) { + dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n", + DRIVER_NAME, address, status); +fail1: + kfree(tps); + return 0; + } + +#ifdef CONFIG_ARM + if (machine_is_omap_h2()) { + omap_cfg_reg(W4_GPIO58); + tps->irq = OMAP_GPIO_IRQ(58); + omap_request_gpio(58); + omap_set_gpio_direction(58, 1); + omap_set_gpio_edge_ctrl(58, OMAP_GPIO_FALLING_EDGE); + } + if (machine_is_omap_osk()) { + // omap_cfg_reg(U19_1610_MPUIO1); + tps->irq = OMAP_GPIO_IRQ(OMAP_MPUIO(1)); + omap_request_gpio(OMAP_MPUIO(1)); + omap_set_gpio_direction(OMAP_MPUIO(1), 1); + omap_set_gpio_edge_ctrl(OMAP_MPUIO(1), OMAP_GPIO_FALLING_EDGE); + } +#endif + + if (tps->irq > 0) { + status = request_irq(tps->irq, tps65010_irq, + /* SA_SAMPLE_RANDOM */ 0, DRIVER_NAME, tps); + if (status < 0) { + dev_dbg(&tps->client.dev, "can't get IRQ %d, err %d\n", + tps->irq, status); + i2c_detach_client(&tps->client); + goto fail1; + } + } + + /* FIXME use IRQs to report "interesting" PM events + * to the current PM policy agent + */ + tps->nmask1 = ~0; + tps->nmask2 = TPS_REG_ONOFF|TPS_REG_COVER|TPS_REG_UVLO; + + /* unmask the irqs */ + tps->chgconf = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG); + show_chgconfig("conf/init", tps->chgconf); + + tps->chgstatus = i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS); + (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK1, ~tps->nmask1); + show_chgstatus("chg/init", tps->chgstatus); + show_chgstatus("mask1", tps->nmask1); + + tps->regstatus = i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS); + (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK2, ~tps->nmask2); + show_regstatus("reg/init", tps->regstatus); + show_regstatus("mask2", tps->nmask2); + + pr_debug("%s: vdcdc1 0x%02x, vdcdc2 %02x, vregs1 %02x\n", DRIVER_NAME, + i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC1), + i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC2), + i2c_smbus_read_byte_data(&tps->client, TPS_VREGS1)); + pr_debug("%s: defgpio 0x%02x, mask3 0x%02x\n", DRIVER_NAME, + i2c_smbus_read_byte_data(&tps->client, TPS_DEFGPIO), + i2c_smbus_read_byte_data(&tps->client, TPS_MASK3)); + + the_tps = tps; + return 0; +} + +static int tps65010_scan_bus(struct i2c_adapter *bus) +{ + if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EINVAL; + return i2c_probe(bus, &addr_data, tps65010_probe); +} + +static struct i2c_driver tps65010_driver = { + .owner = THIS_MODULE, + .name = "tps65010", + .id = 888, /* FIXME assign "official" value */ + .flags = I2C_DF_NOTIFY, + .attach_adapter = tps65010_scan_bus, + .detach_client = tps65010_detach_client, +}; + +/*-------------------------------------------------------------------------*/ + +/* Draw from VBUS: + * 0 mA -- DON'T DRAW (might supply power instead) + * 100 mA -- usb unit load (slowest charge rate) + * 500 mA -- usb high power (fast battery charge) + */ +int tps65010_set_vbus_draw(unsigned mA) +{ + unsigned long flags; + + if (!the_tps) + return -ENODEV; + + /* assumes non-SMP */ + local_irq_save(flags); + if (mA >= 500) + mA = 500; + else if (mA >= 100) + mA = 100; + else + mA = 0; + if (the_tps->vbus != mA && test_and_set_bit( + FLAG_VBUS_CHANGED, &the_tps->flags)) { + /* gadget drivers call this in_irq() */ + the_tps->vbus = mA; + (void) schedule_work(&the_tps->work); + } + local_irq_restore(flags); + + return 0; +} +EXPORT_SYMBOL(tps65010_set_vbus_draw); + +/*-------------------------------------------------------------------------*/ +/* tps65010_set_gpio_out_value parameter: + * gpio: GPIO1, GPIO2, GPIO3 or GPIO4 + * value: LOW or HIGH + */ +int tps65010_set_gpio_out_value(unsigned gpio, unsigned value) +{ + int status; + unsigned defgpio; + + if (!the_tps) + return -ENODEV; + if ((gpio < GPIO1) || (gpio > GPIO4)) + return -EINVAL; + + down(&the_tps->lock); + + defgpio = i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO); + + /* Configure GPIO for output */ + defgpio |= 1 << (gpio + 3); + + /* Writing 1 forces a logic 0 on that GPIO and vice versa */ + switch (value) { + case LOW: + defgpio |= 1 << (gpio - 1); /* set GPIO low by writing 1 */ + break; + /* case HIGH: */ + default: + defgpio &= ~(1 << (gpio - 1)); /* set GPIO high by writing 0 */ + break; + } + + status = i2c_smbus_write_byte_data(&the_tps->client, + TPS_DEFGPIO, defgpio); + + pr_debug("%s: gpio%dout = %s, defgpio 0x%02x\n", DRIVER_NAME, + gpio, value ? "high" : "low", + i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO)); + + up(&the_tps->lock); + return status; +} +EXPORT_SYMBOL(tps65010_set_gpio_out_value); + +/*-------------------------------------------------------------------------*/ +/* tps65010_set_led parameter: + * led: LED1 or LED2 + * mode: ON, OFF or BLINK + */ +int tps65010_set_led(unsigned led, unsigned mode) +{ + int status; + unsigned led_on, led_per, offs; + + if (!the_tps) + return -ENODEV; + + if(led == LED1) + offs = 0; + else { + offs = 2; + led = LED2; + } + + down(&the_tps->lock); + + dev_dbg (&the_tps->client.dev, "led%i_on 0x%02x\n", led, + i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs)); + + dev_dbg (&the_tps->client.dev, "led%i_per 0x%02x\n", led, + i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_PER + offs)); + + switch (mode) { + case OFF: + led_on = 1 << 7; + led_per = 0 << 7; + break; + case ON: + led_on = 1 << 7; + led_per = 1 << 7; + break; + case BLINK: + led_on = 0x30 | (0 << 7); + led_per = 0x08 | (1 << 7); + break; + default: + printk(KERN_ERR "%s: Wrong mode parameter for tps65010_set_led()\n", + DRIVER_NAME); + up(&the_tps->lock); + return -EINVAL; + } + + status = i2c_smbus_write_byte_data(&the_tps->client, + TPS_LED1_ON + offs, led_on); + + if (status != 0) { + printk(KERN_ERR "%s: Failed to write led%i_on register\n", + DRIVER_NAME, led); + up(&the_tps->lock); + return status; + } + + dev_dbg (&the_tps->client.dev, "led%i_on 0x%02x\n", led, + i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs)); + + status = i2c_smbus_write_byte_data(&the_tps->client, + TPS_LED1_PER + offs, led_per); + + if (status != 0) { + printk(KERN_ERR "%s: Failed to write led%i_per register\n", + DRIVER_NAME, led); + up(&the_tps->lock); + return status; + } + + dev_dbg (&the_tps->client.dev, "led%i_per 0x%02x\n", led, + i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_PER + offs)); + + up(&the_tps->lock); + + return status; +} +EXPORT_SYMBOL(tps65010_set_led); + +/*-------------------------------------------------------------------------*/ +/* tps65010_set_low_pwr parameter: + * mode: ON or OFF + */ +int tps65010_set_low_pwr(unsigned mode) +{ + int status; + unsigned vdcdc1; + + if (!the_tps) + return -ENODEV; + + down(&the_tps->lock); + + pr_debug("%s: %s low_pwr, vdcdc1 0x%02x\n", DRIVER_NAME, + mode ? "enable" : "disable", + i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); + + vdcdc1 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1); + + switch (mode) { + case OFF: + vdcdc1 &= ~TPS_ENABLE_LP; /* disable ENABLE_LP bit */ + break; + /* case ON: */ + default: + vdcdc1 |= TPS_ENABLE_LP; /* enable ENABLE_LP bit */ + break; + } + + status = i2c_smbus_write_byte_data(&the_tps->client, + TPS_VDCDC1, vdcdc1); + + if (status != 0) + printk(KERN_ERR "%s: Failed to write vdcdc1 register\n", + DRIVER_NAME); + else + pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME, + i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); + + up(&the_tps->lock); + + return status; +} +EXPORT_SYMBOL(tps65010_set_low_pwr); + +/*-------------------------------------------------------------------------*/ +/* tps65010_config_vregs1 parameter: + * value to be written to VREGS1 register + * Note: The complete register is written, set all bits you need + */ +int tps65010_config_vregs1(unsigned value) +{ + int status; + + if (!the_tps) + return -ENODEV; + + down(&the_tps->lock); + + pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, + i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1)); + + status = i2c_smbus_write_byte_data(&the_tps->client, + TPS_VREGS1, value); + + if (status != 0) + printk(KERN_ERR "%s: Failed to write vregs1 register\n", + DRIVER_NAME); + else + pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME, + i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1)); + + up(&the_tps->lock); + + return status; +} +EXPORT_SYMBOL(tps65010_config_vregs1); + +/*-------------------------------------------------------------------------*/ +/* tps65013_set_low_pwr parameter: + * mode: ON or OFF + */ + +/* FIXME: Assumes AC or USB power is present. Setting AUA bit is not + required if power supply is through a battery */ + +int tps65013_set_low_pwr(unsigned mode) +{ + int status; + unsigned vdcdc1, chgconfig; + + if (!the_tps) + return -ENODEV; + + down(&the_tps->lock); + + pr_debug("%s: %s low_pwr, chgconfig 0x%02x vdcdc1 0x%02x\n", DRIVER_NAME, + mode ? "enable" : "disable", + i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG), + i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); + + chgconfig = i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG); + vdcdc1 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1); + + switch (mode) { + case OFF: + chgconfig &= ~TPS65013_AUA; /* disable AUA bit */ + vdcdc1 &= ~TPS_ENABLE_LP; /* disable ENABLE_LP bit */ + break; + /* case ON: */ + default: + chgconfig |= TPS65013_AUA; /* enable AUA bit */ + vdcdc1 |= TPS_ENABLE_LP; /* enable ENABLE_LP bit */ + break; + } + + status = i2c_smbus_write_byte_data(&the_tps->client, + TPS_CHGCONFIG, chgconfig); + if (status != 0) { + printk(KERN_ERR "%s: Failed to write chconfig register\n", + DRIVER_NAME); + up(&the_tps->lock); + return status; + } + + pr_debug("%s: chgconfig 0x%02x\n", DRIVER_NAME, + i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG)); + + status = i2c_smbus_write_byte_data(&the_tps->client, + TPS_VDCDC1, vdcdc1); + + if (status != 0) + printk(KERN_ERR "%s: Failed to write vdcdc1 register\n", + DRIVER_NAME); + else + pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME, + i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1)); + + up(&the_tps->lock); + + return status; +} +EXPORT_SYMBOL(tps65013_set_low_pwr); + +/*-------------------------------------------------------------------------*/ + +static int __init tps_init(void) +{ + u32 tries = 3; + int status = -ENODEV; + + printk(KERN_INFO "%s: version %s\n", DRIVER_NAME, DRIVER_VERSION); + + /* some boards have startup glitches */ + while (tries--) { + status = i2c_add_driver(&tps65010_driver); + if (the_tps) + break; + i2c_del_driver(&tps65010_driver); + if (!tries) { + printk(KERN_ERR "%s: no chip?\n", DRIVER_NAME); + return -ENODEV; + } + pr_debug("%s: re-probe ...\n", DRIVER_NAME); + msleep(10); + } + +#if defined(CONFIG_ARM) + if (machine_is_omap_osk()) { + + // FIXME: More should be placed in the initialization code + // of the submodules (DSP, ethernet, power management, + // board-osk.c). Careful: I2C is initialized "late". + + /* Let LED1 (D9) blink */ + tps65010_set_led(LED1, BLINK); + + /* Disable LED 2 (D2) */ + tps65010_set_led(LED2, OFF); + + /* Set GPIO 1 HIGH to disable VBUS power supply; + * OHCI driver powers it up/down as needed. + */ + tps65010_set_gpio_out_value(GPIO1, HIGH); + + /* Set GPIO 2 low to turn on LED D3 */ + tps65010_set_gpio_out_value(GPIO2, HIGH); + + /* Set GPIO 3 low to take ethernet out of reset */ + tps65010_set_gpio_out_value(GPIO3, LOW); + + /* gpio4 for VDD_DSP */ + + /* Enable LOW_PWR */ + tps65010_set_low_pwr(ON); + + /* Switch VLDO2 to 3.0V for AIC23 */ + tps65010_config_vregs1(TPS_LDO2_ENABLE | TPS_VLDO2_3_0V | TPS_LDO1_ENABLE); + + } else if (machine_is_omap_h2()) { + /* gpio3 for SD, gpio4 for VDD_DSP */ + + /* Enable LOW_PWR */ + tps65010_set_low_pwr(ON); + } else if (machine_is_omap_h3()) { + /* gpio4 for SD, gpio3 for VDD_DSP */ + + /* Enable LOW_PWR */ + tps65013_set_low_pwr(ON); + } +#endif + + return status; +} +subsys_initcall(tps_init); + +static void __exit tps_exit(void) +{ + i2c_del_driver(&tps65010_driver); +} +module_exit(tps_exit); + diff -Nru a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig --- a/drivers/input/keyboard/Kconfig 2005-03-02 10:51:31 -08:00 +++ b/drivers/input/keyboard/Kconfig 2005-03-02 10:51:31 -08:00 @@ -97,3 +97,23 @@ To compile this driver as a module, choose M here: the module will be called amikbd. + +config KEYBOARD_OMAP + tristate "TI OMAP keypad support" + depends on ARCH_OMAP && INPUT && INPUT_KEYBOARD + help + Say Y here if you want to use the OMAP keypad. + + To compile this driver as a module, choose M here: the + module will be called omap-keypad. + +config OMAP_PS2 + tristate "TI OMAP Innovator 1510 PS/2 keyboard & mouse support" + depends on ARCH_OMAP1510 && MACH_OMAP_INNOVATOR && INPUT && INPUT_KEYBOARD + help + Say Y here if you want to use the OMAP Innovator 1510 PS/2 + keyboard and mouse. + + To compile this driver as a module, choose M here: the + module will be called innovator_ps2. + diff -Nru a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile --- a/drivers/input/keyboard/Makefile 2005-03-02 10:51:31 -08:00 +++ b/drivers/input/keyboard/Makefile 2005-03-02 10:51:31 -08:00 @@ -12,3 +12,5 @@ obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o obj-$(CONFIG_KEYBOARD_98KBD) += 98kbd.o +obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o +obj-$(CONFIG_OMAP_PS2) += innovator_ps2.o diff -Nru a/drivers/input/keyboard/innovator_ps2.c b/drivers/input/keyboard/innovator_ps2.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/input/keyboard/innovator_ps2.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,1303 @@ +/* + * drivers/char/innovator_ps2.c + * + * Basic PS/2 keyboard/mouse driver for the Juno® USAR HID controller + * present on the TI Innovator/OMAP1510 Break-out-board. + * + * + * Author: MontaVista Software, Inc. + * or + * + * + * 2003 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + * + * + * REFERENCES: + * + * 1. Technical Reference Manual + * Juno® 01 + * Multi-function ICs family + * UR8HC007-001 HID & Power management controller + * Document Number: DOC8-007-001-TR-075 + * Date: February 2002 + * Copyright ©1998-2002 Semtech Corporation + * http://www.semtech.com/pdf/doc8-007-001-tr.pdf + * + * 2. Juno® 01 UR8HC007-001 Data Sheet + * Extremely Low-power Input Device and Power Management IC + * Copyright ©1998-2002 Semtech Corporation + * DOC8-007-001-DS-112 + * http://www.semtech.com/pdf/doc8-007-001-ds.pdf + * + * + * HISTORY: + * + * 20030626: George G. Davis + * Initially based on the following RidgeRun DSPlinux Version 1.6 files: + * linux-2.4.15-rmk1-dsplinux/arch/arm/dsplinux/hid/omap1510_hid.c + * linux-2.4.15-rmk1-dsplinux/arch/arm/dsplinux/hid/omap1510_hid.h + * linux-2.4.15-rmk1-dsplinux/arch/arm/dsplinux/hid/omap1510_ps2.c + * linux-2.4.15-rmk1-dsplinux/arch/arm/dsplinux/hid/omap1510_spi.c + * All original files above are + * Copyright (C) 2001 RidgeRun, Inc. + * Author: Alex McMains + * + * 20040812: Thiago Radicchi + * Cleanup of old code from 2.4 driver and some debug code. + * Minor changes in interrupt handling code. + * + * NOTES: + * + * 1. This driver does not provide support for setting keyboard/mouse + * configuration parameters. Both devices are managed directly by + * the Juno UR8HC007-001 on behalf of the host. This minimises the + * amount of host processing required to manage HID events and state + * changes, e.g. both keyboard and mouse devices are hot pluggable + * with no host intervention required. However, we cannot customise + * keyboard/mouse settings in this case. So we live with the defaults + * as setup by the Juno UR8HC007-001 whatever they may be. + * 2. Keyboard auto repeat does not work. See 1 above. : ) + * + * + * TODO: + * + * 1. Complete DPM/LDM stubs and test. + * 2. Add SPI error handling support, i.e. resend, etc.,. + * 3. Determine why innovator_hid_interrupt() is called for every + * invocation of Innovator FPGA IRQ demux. It appears that the + * missed Innovator ethernet workaround may be to blame. However, + * it does not adversely affect operation of this driver since we + * check for assertion of ATN prior to servicing the interrupt. If + * ATN is negated, we bug out right away. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#undef INNOVATOR_KEYB_DEBUG +#ifdef INNOVATOR_KEYB_DEBUG +#define dbg(format, arg...) printk(KERN_DEBUG "%s:%d: " format , \ + __FUNCTION__ , __LINE__ , ## arg) +#define entry() printk(KERN_DEBUG "%s:%d: Entry\n" , __FUNCTION__ , __LINE__) +#define exit() printk(KERN_DEBUG "%s:%d: Exit\n" , __FUNCTION__ , __LINE__) +#define dump_packet(p, n) \ + { \ + int i; \ + printk(KERN_DEBUG "%s:%d: %08x:" , \ + __FUNCTION__ , __LINE__ , (int) p); \ + for (i = 0; i < n; i += 1) { \ + printk(" %02x", (int) p[i]); \ + } \ + printk("\n"); \ + } +#else +#define dbg(format, arg...) do {} while (0) +#define entry() do {} while (0) +#define exit() do {} while (0) +#define dump_packet(p, n) do {} while (0) +#endif + + +#define PFX "innovator_ps2" +#define err(format, arg...) printk(KERN_ERR PFX ": " format , ## arg) +#define info(format, arg...) printk(KERN_INFO PFX ": " format , ## arg) +#define warn(format, arg...) printk(KERN_WARNING PFX ": " format , ## arg) + + +/****************************************************************************/ + +/* + * Synchronous communications timing parameters (Reference [1] pg 7-7) + */ + +#define tMSA 5000 /* -/5ms _SS to _ATN (master transfer) */ +#define tMAC 100 /* 100us/5ms _ATN to first clock pulse (master + transfer) */ +#define tMIB 150 /* 150us/5ms Beginning of byte transfer to beginning + of next byte transfer */ +#define tSIB 150 /* 150us/5ms Beginning of byte transfer to beginning + of next byte transfer */ +#define tMSP 100 /* -/100us Last clock pulse of packet to _SS + de-assertion */ +#define tMNSA 100 /* -/100us _SS de-assertion to _ATN de-assertion */ +#define tMNEXT 120 /* 120uS/- _ATN release to _SS re-assertion + (master transfer) */ +#define tSAS 5000 /* -/5ms _ATN to _SS (slave transfer) */ +#define tSSC 100 /* 100us/5ms _SS to first clock pulse (slave + transfer) */ +#define tSNA 100 /* -/100us Last clock pulse of packet to _ATN + de-assertion */ +#define tSNAS 100 /* -/100us _ATN release to _SS de-assertion */ +#define tSNEXT 120 /* 120us/- _SS release to _ATN re-assertion + (slave transfer) */ +#define tSCK 4 /* 4us/- Clock period */ +#define tSLOW 2 /* 2us/- Clock LOW period */ +#define tHOLD 200 /* 200ns/- Master data hold time */ +#define tSETUP 100 /* 100ns/- Master data setup Time */ +#define tSSETUP 500 /* -/500ns Slave data setup time from clock + falling edge */ + + +/* + * Protocol Headers (Reference [1], pg. 5-1): + */ + + +/* Protocols used in commands issued by the host: */ +#define SIMPLE 0x80 /* Simple commands + * Common for both host and controller + * protocol headers. + */ +#define WRITE_REGISTER_BIT 0x81 /* Write register bit */ +#define READ_REGISTER_BIT 0x82 /* Read register bit */ +#define WRITE_REGISTER 0x83 /* Write register */ +#define READ_REGISTER 0x84 /* Read register */ +#define WRITE_BLOCK 0x85 /* Write block */ +#define READ_BLOCK 0x86 /* Read block */ + + +/* Protocols used in responses, reports and alerts issued by the controller: */ +#define REPORT_REGISTER_BIT 0x81 /* Report register bit & event alerts */ +#define REPORT_REGISTER 0x83 /* Report register */ +#define REPORT_BLOCK 0x85 /* Report block */ +#define POINTING_REPORT 0x87 /* Pointing device data report */ +#define KEYBOARD_REPORT 0x88 /* Keyboard device data report */ + + +/* Simple Commands (Reference [1], pg 5-3): */ +#define INITIALIZE 0x00 /* Forces the recipient to enter the + * known default power-on state. + */ +#define INITIALIZATION_COMPLETE 0x01 /* Issued as a hand-shake response only + * to the "Initialize" command. + */ +#define RESEND_REQUEST 0x05 /* Issued upon error in the reception + * of a package. The recipient resends + * the last transmitted packet. + */ + +/* Register offsets (Reference [1], pg 6-1 thru 6-9): */ + +#define REG_PM_COMM 0 +#define REG_PM_STATUS 1 +#define REG_PAGENO 255 + +/* Power management bits ((Reference [1], pg 6-10): */ + +#define SUS_STATE 0x2 /* in REG_PM_COMM */ + +/* Miscellaneous constants: */ + +#define X_MSB_SHIFT (8-4) +#define X_MSB_MASK (3<<4) +#define Y_MSB_SHIFT (8-6) +#define Y_MSB_MASK (3<<6) + + +#define JUNO_BLOCK_SIZE 32 +#define JUNO_BUFFER_SIZE 256 + + +/* + * Errors: + */ + +#define E_BAD_HEADER 1 +#define E_BAD_LRC 2 +#define E_ZERO_BYTES 3 +#define E_BAD_VALUE 4 +#define E_BAD_MODE 5 +#define E_REPORT_MODE 6 +#define E_BAD_ACK 7 +#define E_BAD_DEVICE_ID 8 +#define E_PKT_SZ 9 + + +/* + * Host/Controller Command/Response Formats: + */ + +typedef struct _simple_t { + u8 header; + u8 cmd_code; + u8 LRC; +} __attribute__ ((packed)) simple_t; + +typedef struct _write_bit_t { + u8 header; + u8 offset; + u8 value_bit; + u8 LRC; +} __attribute__ ((packed)) write_bit_t; + +typedef struct _read_bit_t { + u8 header; + u8 offset; + u8 bit; + u8 LRC; +} __attribute__ ((packed)) read_bit_t; + +typedef struct _write_reg_t { + u8 header; + u8 offset; + u8 value; + u8 LRC; +} __attribute__ ((packed)) write_reg_t; + +typedef struct _read_reg_t { + u8 header; + u8 offset; + u8 LRC; +} __attribute__ ((packed)) read_reg_t; + +typedef struct _write_block_t { + u8 header; + u8 offset; + u8 length; + u8 block[JUNO_BLOCK_SIZE + 1]; /* Hack: LRC is last element of block[] */ +} __attribute__ ((packed)) write_block_t; + +typedef struct _read_block_t { + u8 header; + u8 offset; + u8 length; + u8 LRC; +} __attribute__ ((packed)) read_block_t; + +typedef struct _report_bit_t { + u8 header; + u8 offset; + u8 value_bit; + u8 LRC; +} __attribute__ ((packed)) report_bit_t; + +typedef struct _report_reg_t { + u8 header; + u8 offset; + u8 value; + u8 LRC; +} __attribute__ ((packed)) report_reg_t; + +typedef struct _report_block_t { + u8 header; + u8 offset; + u8 length; + u8 block[32]; + u8 LRC; +} __attribute__ ((packed)) report_block_t; + +typedef struct _mse_report_t { + u8 header; + u8 buttons; + u8 Xdisplacement; + u8 Ydisplacement; + u8 Zdisplacement; + u8 LRC; +} __attribute__ ((packed)) mse_report_t; + +typedef struct _kdb_report_t { + u8 header; + u8 keynum; /* up > 0x80, down < 0x7E, all keys up 0x00 */ + u8 LRC; +} __attribute__ ((packed)) kdb_report_t; + + +static u8 buffer[JUNO_BUFFER_SIZE]; +static u8 block[JUNO_BLOCK_SIZE]; + +static void do_hid_tasklet(unsigned long); +DECLARE_TASKLET(hid_tasklet, do_hid_tasklet, 0); +static struct innovator_hid_dev *hid; +static spinlock_t innovator_fpga_hid_lock = SPIN_LOCK_UNLOCKED; +static atomic_t innovator_fpga_hid_busy = ATOMIC_INIT(0); + +struct innovator_hid_dev { + struct input_dev mouse, keyboard; + int open; + int irq_enabled; +}; + +/****************************************************************************/ + +/* + * Low-level TI Innovator/OMAP1510 FPGA HID SPI interface helper functions: + */ + +static u8 +innovator_fpga_hid_rd(void) +{ + u8 val = inb(INNOVATOR_FPGA_HID_SPI); + return val; +} + +static void +innovator_fpga_hid_wr(u8 val) +{ + outb(val, INNOVATOR_FPGA_HID_SPI); +} + +static void +innovator_fpga_hid_frob(u8 mask, u8 val) +{ + unsigned long flags; + local_irq_save(flags); + innovator_fpga_hid_wr((innovator_fpga_hid_rd() & ~mask) | val); + local_irq_restore(flags); +} + +static void +innovator_fpga_hid_set_bits(u8 x) +{ + innovator_fpga_hid_frob(x, x); +} + +static void +innovator_fpga_hid_clear_bits(u8 x) +{ + innovator_fpga_hid_frob(x, 0); +} + +static void +SS(int value) +{ + innovator_fpga_hid_frob(OMAP1510_FPGA_HID_nSS, value ? OMAP1510_FPGA_HID_nSS : 0); +} + +static void +SCLK(int value) +{ + innovator_fpga_hid_frob(OMAP1510_FPGA_HID_SCLK, value ? OMAP1510_FPGA_HID_SCLK : 0); +} + +static void +MOSI(int value) +{ + innovator_fpga_hid_frob(OMAP1510_FPGA_HID_MOSI, value ? OMAP1510_FPGA_HID_MOSI : 0); +} + +static u8 +MISO(void) +{ + return ((innovator_fpga_hid_rd() & OMAP1510_FPGA_HID_MISO) ? 1 : 0); +} + +static u8 +ATN(void) +{ + return ((innovator_fpga_hid_rd() & OMAP1510_FPGA_HID_ATN) ? 1 : 0); +} + +static int +wait_for_ATN(int assert, int timeout) +{ + do { + if (ATN() == assert) + return 0; + udelay(1); + } while (timeout -= 1); + return -1; +} + +static u8 +innovator_fpga_hid_xfer_byte(u8 xbyte) +{ + int i; + u8 rbyte; + + for (rbyte = 0, i = 7; i >= 0; i -= 1) { + SCLK(0); + MOSI((xbyte >> i) & 1); + udelay(tSLOW); + SCLK(1); + rbyte = (rbyte << 1) | MISO(); + udelay(tSLOW); + } + + return rbyte; +} + +static void +innovator_fpga_hid_reset(void) +{ + innovator_fpga_hid_wr(OMAP1510_FPGA_HID_SCLK | OMAP1510_FPGA_HID_MOSI); + mdelay(1); + innovator_fpga_hid_set_bits(OMAP1510_FPGA_HID_RESETn); +} + + +/***************************************************************************** + + Refer to Reference [1], Chapter 7 / Low-level communications, Serial + Peripheral Interface (SPI) implementation Host (master) packet + transmission timing, pg. 7-3, for timing and implementation details + for spi_xmt(). + + *****************************************************************************/ + +int +spi_xmt(u8 * p, u8 n) +{ + unsigned long flags; + + dump_packet(p, n); + local_irq_save(flags); + disable_irq(OMAP1510_INT_FPGA_ATN); + + if (ATN()) { + /* Oops, we have a collision. */ + enable_irq(OMAP1510_INT_FPGA_ATN); + local_irq_restore(flags); + dbg("Protocol error: ATN is asserted\n"); + return -EAGAIN; + } + + SS(1); + + if (wait_for_ATN(1, tMSA) < 0) { + SS(0); + enable_irq(OMAP1510_INT_FPGA_ATN); + local_irq_restore(flags); + dbg("timeout waiting for ATN assertion\n"); + return -EREMOTEIO; + } + + udelay(tMAC); + + while (n--) { + innovator_fpga_hid_xfer_byte(*p++); + if (n) { + udelay(tMIB - 8 * tSCK); + } + } + + MOSI(1); /* Set MOSI to idle high. */ + + /* NOTE: The data sheet does not specify a minimum delay + * here. But innovator_fpga_hid_xfer_byte() gives us a half-clock + * delay (tSLOW) after the last bit is sent. So I'm happy with + * that. + */ + + SS(0); + + if (wait_for_ATN(0, tMNSA) < 0) { + enable_irq(OMAP1510_INT_FPGA_ATN); + local_irq_restore(flags); + dbg("timeout waiting for ATN negation\n"); + return -EREMOTEIO; + } + + udelay(tMNEXT); + enable_irq(OMAP1510_INT_FPGA_ATN); + local_irq_restore(flags); + return 0; +} + + +/***************************************************************************** + + Refer to Reference [1], Chapter 7 / Low-level communications, Serial + Peripheral Interface (SPI) implementation, Slave packet transmission + timing, pg. 7-5, for timing and implementation details for spi_rcv(). + + *****************************************************************************/ + +int +spi_rcv(u8 * p, int len) +{ + unsigned long flags; + int ret = 0; + + if (len > 256) { + /* Limit packet size to something reasonable */ + return -1; + } + + local_irq_save(flags); + + if (wait_for_ATN(1, tMSA) < 0) { + local_irq_restore(flags); + dbg("Protocol error: ATN is not asserted\n"); + return -EREMOTEIO; + } + + SS(1); + + udelay(tSSC); + + while (ATN()) { + if (ret >= len) { + err("over run error\n"); + ret = -1; + break; + } + p[ret++] = innovator_fpga_hid_xfer_byte(0xff); + udelay(tSNA); /* Wait long enough to detect negation of ATN + * after last clock pulse of packet. + * + * NOTE: Normally, we need a minimum delay of + * tSIB between the start of one byte + * and the start of the next. However, + * we also need to wait long enough + * for the USAR to negate ATN before + * starting the next byte. So we use + * max(tSIB - 8 * tSCK, tSNA) here to + * satisfy both constraints. + */ + } + + SS(0); /* NOTE: The data sheet does not specify a minimum delay + * here. But innovator_fpga_hid_xfer_byte() gives us a + * half-clock delay (tSLOW) after the last bit is sent. So + * I'm happy with that (rather than no delay at all : ). + */ + + + udelay(tSNEXT); /* This isn't quite right. Assertion of ATN after + * negation of SS is an USAR timing constraint. + * What we need here is a spec for the minimum + * delay from SS negation to SS assertion. But + * for now, just use this brain dead delay. + */ + + local_irq_restore(flags); + + if (ret > 0) { + dump_packet(p, ret); + } + + return ret; +} + + +/***************************************************************************** + Calculate Host/Controller Command/Response Longitudinal Redundancy Check (LRC) + + The algorithm implemented in calculate_LRC() below is taken directly from + the reference [1], Chapter 7 / Low-level communications, LRC (Longitudinal + Redundancy Check), pg 5-10. + + *****************************************************************************/ + +static u8 +calculate_LRC(u8 * p, int n) +{ + u8 LRC; + int i; + + /* + * Init the LRC using the first two message bytes. + */ + LRC = p[0] ^ p[1]; + + /* + * Update the LRC using the remainder of the p. + */ + for (i = 2; i < n; i++) + LRC ^= p[i]; + + /* + * If the MSB is set then clear the MSB and change the next + * most significant bit + */ + if (LRC & 0x80) + LRC ^= 0xC0; + + return LRC; +} + + +/* + * Controller response helper functions: + */ + +static inline int +report_mouse(mse_report_t * p, int n) +{ + if (p->header != POINTING_REPORT) + return -E_BAD_HEADER; + + if (n != sizeof(mse_report_t)) + return -E_PKT_SZ; + + return (p->LRC != calculate_LRC((u8 *) p, sizeof(mse_report_t) - 1)) ? + -E_BAD_LRC : POINTING_REPORT; +} + +static inline int +report_keyboard(kdb_report_t * p, int n) +{ + if (p->header != KEYBOARD_REPORT) + return -E_BAD_HEADER; + + if (n != sizeof(kdb_report_t)) + return -E_PKT_SZ; + + return (p->LRC != calculate_LRC((u8 *) p, sizeof(kdb_report_t) - 1)) ? + -E_BAD_LRC : KEYBOARD_REPORT; +} + + +/* + * Miscellaneous helper functions: + */ + +static inline int +report_type(u8 * type) +{ + /* check the header to find out what kind of report it is */ + if ((*type) == KEYBOARD_REPORT) + return KEYBOARD_REPORT; + else if ((*type) == POINTING_REPORT) + return POINTING_REPORT; + else + return -E_BAD_HEADER; +} + +static inline int +report_async(void * p, int n) +{ + int ret; + + if ((ret = spi_rcv((u8 *) p, n)) < 0) + return ret; + + if (report_type((u8 *) p) == POINTING_REPORT) + ret = report_mouse((mse_report_t *) p, ret); + else if (report_type((u8 *) p) == KEYBOARD_REPORT) + ret = report_keyboard((kdb_report_t *) p, ret); + + return ret; +} + +static int +verify_init(u8 * p) +{ + return (((simple_t *)p)->cmd_code == 0x01) ? 0 : -1; +} + + +/* + * Host command helper functions: + */ + +#if 0 +/* REVISIT/TODO: Wrapper for command/response with resend handing. */ +static int +spi_xfer(u8 * optr, u8 osz, u8 * iptr, u8 isz) +{ + static u8 buf[256]; + int ret; + int xretries = 3; + + do { + if (optr != NULL && osz) { + do { + ret = spi_xmt((u8 *) optr, osz); + } while (ret < 0); + } + + ret = spi_rcv((u8 *) buf, 256); + + if (ret == -EREMOTEIO) { + if (iptr == NULL) { + break; + } + } + } while (xretries--); + + return ret; +} +#endif + +/* REVISIT: Enable these when/if additional Juno features are required. */ +static inline int +simple(u8 cmd) +{ + static simple_t p; + int ret; + + p.header = SIMPLE; + p.cmd_code = cmd; + p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1); + + if ((ret = spi_xmt((u8 *) & p, sizeof(p))) < 0) + return ret; + + if ((ret = spi_rcv((u8 *) & p, sizeof(p))) < 0) + return ret; + + if (ret == 0) + return -E_ZERO_BYTES; + + if (ret != sizeof(p)) + return -E_PKT_SZ; + + if (p.header != SIMPLE) + return -E_BAD_HEADER; + + if (p.LRC != calculate_LRC((u8 *) & p, sizeof(p) - 1)) + return -E_BAD_LRC; + + /* REVISIT: Need to check or return response code here? */ +} + +static inline int +write_bit(u8 offset, u8 bit, u8 value) +{ + static write_bit_t p; + + p.header = WRITE_REGISTER_BIT; + p.offset = offset; + p.value_bit = (bit << 1) | (value & 1); + p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1); + + return spi_xmt((u8 *) & p, sizeof(p)); +} + +static inline int +read_bit(u8 offset, u8 bit, u8 * data) +{ + static read_bit_t p; + static report_bit_t q; + int ret; + + p.header = READ_REGISTER_BIT; + p.offset = offset; + p.bit = bit; + p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1); + + if ((ret = spi_xmt((u8 *) & p, sizeof(p))) < 0) + return ret; + + if ((ret = spi_rcv((u8 *) & q, sizeof(q))) < 0) + return ret; + + if (ret == 0) + return -E_ZERO_BYTES; + + if (ret != sizeof(q)) + return -E_PKT_SZ; + + if (q.header != REPORT_REGISTER_BIT) + return -E_BAD_HEADER; + + if (q.LRC != calculate_LRC((u8 *) & q, sizeof(q) - 1)) + return -E_BAD_LRC; + + *data = q.value_bit; + + return 0; +} + +static inline int +write_reg(u8 offset, u8 value) +{ + static write_reg_t p; + + p.header = WRITE_REGISTER; + p.offset = offset; + p.value = value; + p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1); + + return spi_xmt((u8 *) & p, sizeof(p)); +} + +static inline int +read_reg(u8 offset, u8 * data) +{ + static read_reg_t p; + static report_reg_t q; + int ret; + + p.header = READ_REGISTER; + p.offset = offset; + p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1); + + if ((ret = spi_xmt((u8 *) & p, sizeof(p))) < 0) + return ret; + + if ((ret = spi_rcv((u8 *) & q, sizeof(q))) < 0) + return ret; + + if (ret == 0) + return -E_ZERO_BYTES; + + if (ret != sizeof(q)) + return -E_PKT_SZ; + + if (q.header != REPORT_REGISTER) + return -E_BAD_HEADER; + + if (q.LRC != calculate_LRC((u8 *) & q, sizeof(q) - 1)) + return -E_BAD_LRC; + + *data = q.value; + + return 0; +} + +static inline int +write_block(u8 offset, u8 length, u8 * block) +{ + static write_block_t p; + + p.header = WRITE_BLOCK; + p.offset = offset; + p.length = length; + memcpy(&p.block, block, length); + p.block[length] = calculate_LRC((u8 *) & p, 3 + length); + + return spi_xmt((u8 *) & p, 4 + length); +} + +static inline int +read_block(u8 offset, u8 length, u8 * buf) +{ + static read_block_t p; + static report_block_t q; + int ret; + + p.header = READ_BLOCK; + p.offset = offset; + p.length = length; + p.LRC = calculate_LRC((u8 *) & p, sizeof(p) - 1); + + if ((ret = spi_xmt((u8 *) & p, sizeof(p))) < 0) + return ret; + + if ((ret = spi_rcv((u8 *) & q, sizeof(q))) < 0) + return ret; + + if (ret == 0) + return -E_ZERO_BYTES; + + if (ret != sizeof(4 + q.length)) + return -E_PKT_SZ; + + if (q.header != REPORT_BLOCK) + return -E_BAD_HEADER; + + if (q.block[q.length] != calculate_LRC((u8 *) & q, 3 + q.length)) + return -E_BAD_LRC; + + if (length != q.length) + return -E_PKT_SZ; + + memcpy(buf, &q.block, length); + + return 0; +} + +#ifdef INNOVATOR_KEYB_DEBUG +static void +ctrl_dump_regs(void) +{ + int i; + int n; + + for (i = 0; i < 256; i += 8) { + read_block(i, 16, buffer); + mdelay(1); + } +} +#endif + +/*****************************************************************************/ + +static void +process_pointing_report(struct innovator_hid_dev *hid, u8 * buffer) +{ + static int prev_x, prev_y, prev_btn; + int x, y, btn; + + if (buffer[1] & (1 << 3)) { + /* relative pointing device report */ + x = buffer[2]; + y = buffer[3]; + + /* check the sign and convert from 2's complement if negative */ + if (buffer[1] & (1<<4)) + x = ~(-x) - 255; + + /* input driver wants -y */ + if (buffer[1] & (1<<5)) + y = -(~(-y) - 255); + else + y = -y; + + input_report_key(&hid->mouse, + BTN_LEFT, buffer[1] & (1<<0)); + input_report_key(&hid->mouse, + BTN_RIGHT, buffer[1] & (1<<1)); + input_report_key(&hid->mouse, + BTN_MIDDLE, buffer[1] & (1<<2)); + input_report_rel(&hid->mouse, REL_X, x); + input_report_rel(&hid->mouse, REL_Y, y); + } else { + /* REVISIT: Does this work? */ + /* absolute pointing device report */ + x = buffer[2] + ((buffer[1] & X_MSB_MASK) << X_MSB_SHIFT); + y = buffer[3] + ((buffer[1] & Y_MSB_MASK) << Y_MSB_SHIFT); + btn = buffer[1] & (1<<0); + + if ((prev_x == x) && (prev_y == y) + && (prev_btn == btn)) + return; + + input_report_key(&hid->mouse, BTN_LEFT, btn); + input_report_abs(&hid->mouse, ABS_X, x); + input_report_abs(&hid->mouse, ABS_Y, y); + prev_x = x; + prev_y = y; + prev_btn = btn; + } + input_sync(&hid->mouse); + dbg("HID X: %d Y: %d Functions: %x\n", x, y, buffer[1]); +} + +/* + * Reference [1], Appendix A, Semtech standard PS/2 key number definitions, + * pgs. A-1 through A-3. The following table lists standard PS/2 key numbers + * used by the Juno® 01 keyboard manager. + * + * NOTES: + * 1. The following table indices are E0 codes which require special handling: + * 53..62, 77..78, 94, 96, 100, 102..104, 108..110 + * 2. The following table indices are E1 codes which require special handling: + * 101 + */ + +static unsigned char usar2scancode[128] = { + 0x00, 0x29, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x2b, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x1c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, + 0x33, 0x34, 0x35, 0x39, 0x01, 0x52, 0x53, 0x4b, + 0x47, 0x4f, 0x48, 0x50, 0x49, 0x51, 0x4d, 0x37, + 0x4e, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, + 0x48, 0x49, 0x52, 0x53, 0x4a, 0x1c, 0x35, 0x3b, + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, + 0x44, 0x57, 0x58, 0x2a, 0x36, 0x38, 0x38, 0x1d, + 0x1d, 0x3a, 0x45, 0x46, 0x2a, 0x1d, 0x5b, 0x5c, + 0x5d, 0xff, 0x00, 0x00, 0x5e, 0x5f, 0x63, 0x70, + 0x7b, 0x79, 0x7d, 0x73, 0x5b, 0x5c, 0x5d, 0x63, + 0x65, 0x66, 0x68, 0x69, 0x6b, 0x56, 0x54, 0x00 +}; + +/* + * The following are bit masks used to encode E0 scan codes which + * require special handling. However, scan codes 100 and 101 are + * excludable here since they each require unique multi-byte scan + * code translations and are therefore dealt with individually via + * handle_print_scr() and handle_pause() respectively below. + */ + +static unsigned long int e0_codes1 = 0x030003ff; /* scan codes 53..84 */ +static unsigned long int e0_codes2 = 0x038e0a00; /* scan codes 85..116 */ + +static void +handle_print_scr(int up) +{ + if (up) { + input_report_key(&hid->keyboard, 0xe0, 1); + input_report_key(&hid->keyboard, 0xb7, 1); + input_report_key(&hid->keyboard, 0xe0, 1); + input_report_key(&hid->keyboard, 0xaa, 1); + } else { + input_report_key(&hid->keyboard, 0xe0, 0); + input_report_key(&hid->keyboard, 0x2a, 0); + input_report_key(&hid->keyboard, 0xe0, 0); + input_report_key(&hid->keyboard, 0x37, 0); + } +} + +static void +handle_pause(void) +{ + input_report_key(&hid->keyboard, 0xe1, 0); + input_report_key(&hid->keyboard, 0x1d, 0); + input_report_key(&hid->keyboard, 0x45, 0); + input_report_key(&hid->keyboard, 0xe1, 0); + input_report_key(&hid->keyboard, 0x9d, 0); + input_report_key(&hid->keyboard, 0xc5, 0); +} + +static void +process_keyboard_report(struct innovator_hid_dev *hid, u8 * buffer) +{ + unsigned char ch = buffer[1] & 0x7f; + int up = buffer[1] & 0x80 ? 1 : 0; + int is_e0 = 0; + + if ((ch == 106) || (ch == 107)) + return; /* no code */ + + if (ch == 100) { + handle_print_scr(up); + return; + } + + if (ch == 101) { + handle_pause(); + return; + } + + if ((ch >= 53) && (ch <= 84)) { + /* first block of e0 codes */ + is_e0 = e0_codes1 & (1 << (ch - 53)); + } else if ((ch >= 85) && (ch <= 116)) { + /* second block of e0 codes */ + is_e0 = e0_codes2 & (1 << (ch - 85)); + } + + if (is_e0) { + input_report_key(&hid->keyboard, 0xe0, !up); + } + input_report_key(&hid->keyboard, usar2scancode[ch], !up); + input_sync(&hid->keyboard); +} + +static irqreturn_t +innovator_hid_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + if (ATN()) { + disable_irq(OMAP1510_INT_FPGA_ATN); + tasklet_schedule(&hid_tasklet); + } + return IRQ_HANDLED; +} + +static void +do_hid_tasklet(unsigned long unused) +{ + int ret; + if ((ret = report_async(buffer, 256)) == -1) { + dbg("Error: Bad Juno return value: %d\n", ret); + } else if (ret == KEYBOARD_REPORT) { + process_keyboard_report(hid, buffer); + } else if (ret == POINTING_REPORT) { + process_pointing_report(hid, buffer); + } else { + dbg("ERROR: bad report\n"); + } + enable_irq(OMAP1510_INT_FPGA_ATN); +} + +static int +innovator_hid_open(struct input_dev *dev) +{ + if (hid->open++) + return 0; + + if (request_irq(OMAP1510_INT_FPGA_ATN, (void *) innovator_hid_interrupt, + SA_INTERRUPT, PFX, hid) < 0) + return -EINVAL; + + return 0; +} + +static void +innovator_hid_close(struct input_dev *dev) +{ + if (!--hid->open) + return; + + if (hid == NULL) + return; + + kfree(hid); +} + +static int innovator_ps2_remove(struct device *dev) +{ + return 0; +} + +static void innovator_ps2_device_release(struct device *dev) +{ + /* Nothing */ +} + +static int innovator_ps2_suspend(struct device *dev, u32 state, u32 level) +{ + u8 pmcomm; + + + switch(level) { + case SUSPEND_DISABLE: + + /* + * Set SUS_STATE in REG_PM_COMM (Page 0 R0). This will cause + * PM_MOD bits of REG_PM_STATUS to show suspended state, + * but the SUS_STAT bit of REG_PM_STATUS will continue to + * reflect the state of the _HSUS pin. + */ + + if (write_reg(REG_PAGENO, 0) < 0) + printk("ps2 suspend: write_reg REG_PAGENO error\n"); + + if (read_reg(REG_PM_COMM, &pmcomm) < 0) + printk("ps2 suspend: read_reg REG_PM_COMM error\n"); + + if (write_reg(REG_PM_COMM, pmcomm | SUS_STATE) < 0) + printk("ps2 suspend: write_reg REG_PM_COMM error\n"); + break; + } + + return 0; +} + +static int innovator_ps2_resume(struct device *dev, u32 level) +{ + u8 pmcomm; + + switch(level) { + case RESUME_ENABLE: + + /* + * Clear SUS_STATE from REG_PM_COMM (Page 0 R0). + */ + + if (write_reg(REG_PAGENO, 0) < 0) + printk("ps2 resume: write_reg REG_PAGENO error\n"); + + if (read_reg(REG_PM_COMM, &pmcomm) < 0) + printk("ps2 resume: read_reg REG_PM_COMM error\n"); + + if (write_reg(REG_PM_COMM, pmcomm & ~SUS_STATE) < 0) + printk("ps2 resume: write_reg REG_PM_COMM error\n"); + + break; + } + + return 0; +} + +static struct device_driver innovator_ps2_driver = { + .name = "innovator_ps2", + .bus = &platform_bus_type, + .remove = innovator_ps2_remove, + .suspend = innovator_ps2_suspend, + .resume = innovator_ps2_resume, +}; + +static struct platform_device innovator_ps2_device = { + .name = "ps2", + .id = -1, + .dev = { + .driver = &innovator_ps2_driver, + .release = innovator_ps2_device_release, + }, +}; + +static int __init +innovator_kbd_init(void) +{ + int i; + info("Innovator PS/2 keyboard/mouse driver v1.0\n"); + + innovator_fpga_hid_reset(); + + if ((hid = kmalloc(sizeof(struct innovator_hid_dev), + GFP_KERNEL)) == NULL) { + warn("unable to allocate space for HID device\n"); + return -ENOMEM; + } + + /* setup the mouse */ + memset(hid, 0, sizeof(struct innovator_hid_dev)); + hid->mouse.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + hid->mouse.keybit[LONG(BTN_MOUSE)] = + BIT(BTN_LEFT) | BIT(BTN_RIGHT) | + BIT(BTN_MIDDLE) | BIT(BTN_TOUCH); + hid->mouse.relbit[0] = BIT(REL_X) | BIT(REL_Y); + hid->mouse.private = hid; + hid->mouse.open = innovator_hid_open; + hid->mouse.close = innovator_hid_close; + hid->mouse.name = "innovator_mouse"; + hid->mouse.id.bustype = 0; + hid->mouse.id.vendor = 0; + hid->mouse.id.product = 0; + hid->mouse.id.version = 0; + hid->keyboard.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + init_input_dev(&hid->keyboard); + hid->keyboard.keycodesize = sizeof(unsigned char); + hid->keyboard.keycodemax = ARRAY_SIZE(usar2scancode); + for(i = 0; i < 128; i++) + set_bit(usar2scancode[i], hid->keyboard.keybit); + hid->keyboard.private = hid; + hid->keyboard.open = innovator_hid_open; + hid->keyboard.close = innovator_hid_close; + hid->keyboard.name = "innovator_keyboard"; + hid->keyboard.id.bustype = 0; + hid->keyboard.id.vendor = 0; + hid->keyboard.id.product = 0; + hid->keyboard.id.version = 0; + input_register_device(&hid->mouse); + input_register_device(&hid->keyboard); + innovator_hid_open(&hid->mouse); + innovator_hid_open(&hid->keyboard); + + if (driver_register(&innovator_ps2_driver) != 0) + printk(KERN_ERR "Driver register failed for innovator_ps2\n"); + + if (platform_device_register(&innovator_ps2_device) != 0) { + printk(KERN_ERR "Device register failed for ps2\n"); + driver_unregister(&innovator_ps2_driver); + } + +#ifdef INNOVATOR_KEYB_DEBUG + ctrl_dump_regs(); +#endif + return 0; +} + +static void __exit +innovator_kbd_exit(void) +{ + input_unregister_device(&hid->mouse); + input_unregister_device(&hid->keyboard); + free_irq(OMAP1510_INT_FPGA_ATN, hid); + if (hid != NULL) + kfree(hid); + driver_unregister(&innovator_ps2_driver); + platform_device_unregister(&innovator_ps2_device); + return; +} + +module_init(innovator_kbd_init); +module_exit(innovator_kbd_exit); + +MODULE_AUTHOR("George G. Davis "); +MODULE_DESCRIPTION("Innovator PS/2 Driver"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/input/keyboard/omap-keypad.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,312 @@ +/* + * linux/drivers/char/omap-keypad.c + * + * OMAP Keypad Driver + * + * Copyright (C) 2003 Nokia Corporation + * Written by Timo Teräs + * + * Added support for H2 & H3 Keypad + * Copyright (C) 2004 Texas Instruments + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef NEW_BOARD_LEARNING_MODE + +static void omap_kp_tasklet(unsigned long); +static void omap_kp_timer(unsigned long); + +static struct input_dev omap_kp_dev; +static unsigned char keypad_state[8]; + +static struct timer_list kp_timer; +DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0); + +#define KEY(col, row, val) (((col) << 28) | ((row) << 24) | (val)) + +static int h2_keymap[] = { + KEY(0, 0, KEY_LEFT), + KEY(0, 1, KEY_RIGHT), + KEY(0, 2, KEY_3), + KEY(0, 3, KEY_F10), + KEY(0, 4, KEY_F5), + KEY(0, 5, KEY_9), + KEY(1, 0, KEY_DOWN), + KEY(1, 1, KEY_UP), + KEY(1, 2, KEY_2), + KEY(1, 3, KEY_F9), + KEY(1, 4, KEY_F7), + KEY(1, 5, KEY_0), + KEY(2, 0, KEY_ENTER), + KEY(2, 1, KEY_6), + KEY(2, 2, KEY_1), + KEY(2, 3, KEY_F2), + KEY(2, 4, KEY_F6), + KEY(2, 5, KEY_HOME), + KEY(3, 0, KEY_8), + KEY(3, 1, KEY_5), + KEY(3, 2, KEY_F12), + KEY(3, 3, KEY_F3), + KEY(3, 4, KEY_F8), + KEY(3, 5, KEY_END), + KEY(4, 0, KEY_7), + KEY(4, 1, KEY_4), + KEY(4, 2, KEY_F11), + KEY(4, 3, KEY_F1), + KEY(4, 4, KEY_F4), + KEY(4, 5, KEY_ESC), + KEY(5, 0, KEY_F13), + KEY(5, 1, KEY_F14), + KEY(5, 2, KEY_F15), + KEY(5, 3, KEY_F16), + KEY(5, 4, KEY_SLEEP), + 0 +}; + +static int test_keymap[] = { + KEY(0, 0, KEY_F4), + KEY(1, 0, KEY_LEFT), + KEY(2, 0, KEY_F1), + KEY(0, 1, KEY_DOWN), + KEY(1, 1, KEY_ENTER), + KEY(2, 1, KEY_UP), + KEY(0, 2, KEY_F3), + KEY(1, 2, KEY_RIGHT), + KEY(2, 2, KEY_F2), + 0 +}; + +static int innovator_keymap[] = { + KEY(0, 0, KEY_F1), + KEY(0, 3, KEY_DOWN), + KEY(1, 1, KEY_F2), + KEY(1, 2, KEY_RIGHT), + KEY(2, 0, KEY_F3), + KEY(2, 1, KEY_F4), + KEY(2, 2, KEY_UP), + KEY(3, 2, KEY_ENTER), + KEY(3, 3, KEY_LEFT), + 0 +}; + +static int osk_keymap[] = { + KEY(0, 0, KEY_F1), + KEY(0, 3, KEY_UP), + KEY(1, 1, KEY_LEFTCTRL), + KEY(1, 2, KEY_LEFT), + KEY(2, 0, KEY_SPACE), + KEY(2, 1, KEY_ESC), + KEY(2, 2, KEY_DOWN), + KEY(3, 2, KEY_ENTER), + KEY(3, 3, KEY_RIGHT), + 0 +}; + +static int *keymap; + +static irqreturn_t omap_kp_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + /* disable keyboard interrupt and schedule for handling */ + omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); + tasklet_schedule(&kp_tasklet); + + return IRQ_HANDLED; +} + +static void omap_kp_timer(unsigned long data) +{ + tasklet_schedule(&kp_tasklet); +} + +static void omap_kp_scan_keypad(unsigned char *state) +{ + int col = 0; + + /* read the keypad status */ + omap_writew(0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC); + for (col = 0; col < 8; col++) { + omap_writew(~(1 << col) & 0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC); + + if (machine_is_omap_osk() || machine_is_omap_h2() || machine_is_omap_h3()) { + udelay(9); + } else { + udelay(2); + } + + state[col] = ~omap_readw(OMAP_MPUIO_BASE + OMAP_MPUIO_KBR_LATCH) & 0xff; + } + omap_writew(0x00, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC); + udelay(2); +} + +static inline int omap_kp_find_key(int col, int row) +{ + int i, key; + + key = KEY(col, row, 0); + for (i = 0; keymap[i] != 0; i++) + if ((keymap[i] & 0xff000000) == key) + return keymap[i] & 0x00ffffff; + return -1; +} + +static void omap_kp_tasklet(unsigned long data) +{ + unsigned char new_state[8], changed, key_down = 0; + int col, row; + int spurious = 0; + + /* check for any changes */ + omap_kp_scan_keypad(new_state); + + /* check for changes and print those */ + for (col = 0; col < 8; col++) { + changed = new_state[col] ^ keypad_state[col]; + key_down |= new_state[col]; + if (changed == 0) + continue; + + for (row = 0; row < 8; row++) { + int key; + if (!(changed & (1 << row))) + continue; +#ifdef NEW_BOARD_LEARNING_MODE + printk(KERN_INFO "omap-keypad: key %d-%d %s\n", col, row, (new_state[col] & (1 << row)) ? "pressed" : "released"); +#else + key = omap_kp_find_key(col, row); + if (key < 0) { + printk(KERN_WARNING "omap-keypad: Spurious key event %d-%d\n", + col, row); + /* We scan again after a couple of seconds */ + spurious = 1; + continue; + } + + input_report_key(&omap_kp_dev, key, + new_state[col] & (1 << row)); +#endif + } + } + memcpy(keypad_state, new_state, sizeof(keypad_state)); + + if (key_down) { + int delay = HZ / 20; + /* some key is pressed - keep irq disabled and use timer + * to poll the keypad */ + if (spurious) + delay = 2 * HZ; + mod_timer(&kp_timer, jiffies + delay); + } else { + /* enable interrupts */ + omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); + } +} + +static int __init omap_kp_init(void) +{ + int i; + + printk(KERN_INFO "OMAP Keypad Driver\n"); + + /* Disable the interrupt for the MPUIO keyboard */ + omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); + + if (machine_is_omap_h2() || machine_is_omap_h3()) { + keymap = h2_keymap; + set_bit(EV_REP, omap_kp_dev.evbit); + } else if (machine_is_omap_innovator()) { + keymap = innovator_keymap; + } else if (machine_is_omap_osk()) { + keymap = osk_keymap; + } else { + keymap = test_keymap; + } + + init_timer(&kp_timer); + kp_timer.function = omap_kp_timer; + + /* get the irq and init timer*/ + tasklet_enable(&kp_tasklet); + if (request_irq(INT_KEYBOARD, omap_kp_interrupt, 0, + "omap-keypad", 0) < 0) + return -EINVAL; + + /* setup input device */ + set_bit(EV_KEY, omap_kp_dev.evbit); + for (i = 0; keymap[i] != 0; i++) + set_bit(keymap[i] & 0x00ffffff, omap_kp_dev.keybit); + omap_kp_dev.name = "omap-keypad"; + input_register_device(&omap_kp_dev); + + if (machine_is_omap_h2() || machine_is_omap_h3()) { + omap_cfg_reg(F18_1610_KBC0); + omap_cfg_reg(D20_1610_KBC1); + omap_cfg_reg(D19_1610_KBC2); + omap_cfg_reg(E18_1610_KBC3); + omap_cfg_reg(C21_1610_KBC4); + + omap_cfg_reg(G18_1610_KBR0); + omap_cfg_reg(F19_1610_KBR1); + omap_cfg_reg(H14_1610_KBR2); + omap_cfg_reg(E20_1610_KBR3); + omap_cfg_reg(E19_1610_KBR4); + omap_cfg_reg(N19_1610_KBR5); + + omap_writew(0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_DEBOUNCING); + } + + /* scan current status and enable interrupt */ + omap_kp_scan_keypad(keypad_state); + omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); + + return 0; +} + +static void __exit omap_kp_exit(void) +{ + /* disable keypad interrupt handling */ + tasklet_disable(&kp_tasklet); + omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); + + free_irq(INT_KEYBOARD, 0); + del_timer_sync(&kp_timer); + + /* unregister everything */ + input_unregister_device(&omap_kp_dev); +} + +module_init(omap_kp_init); +module_exit(omap_kp_exit); + +MODULE_AUTHOR("Timo Teräs"); +MODULE_DESCRIPTION("OMAP Keypad Driver"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig --- a/drivers/input/touchscreen/Kconfig 2005-03-02 10:51:31 -08:00 +++ b/drivers/input/touchscreen/Kconfig 2005-03-02 10:51:31 -08:00 @@ -35,3 +35,17 @@ To compile this driver as a module, choose M here: the module will be called gunze. +config TOUCHSCREEN_OMAP + tristate "OMAP touchscreen input driver" + depends on INPUT && INPUT_TOUCHSCREEN + help + Say Y here if you have an OMAP based board with touchscreen + attached to it, e.g. OMAP Innovator, OSK, H2 or H3 + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called omap_ts. + + + diff -Nru a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile --- a/drivers/input/touchscreen/Makefile 2005-03-02 10:51:31 -08:00 +++ b/drivers/input/touchscreen/Makefile 2005-03-02 10:51:31 -08:00 @@ -1,8 +1,9 @@ # -# Makefile for the mouse drivers. +# Makefile for the touchscreen input drivers. # # Each configuration option enables a list of files. obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o +obj-$(CONFIG_TOUCHSCREEN_OMAP) += omap/ diff -Nru a/drivers/input/touchscreen/omap/Makefile b/drivers/input/touchscreen/omap/Makefile --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/input/touchscreen/omap/Makefile 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,12 @@ +# +# Makefile for the OMAP touchscreen input driver +# + +obj-$(CONFIG_TOUCHSCREEN_OMAP) += omapts.o + +objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_H2) += ts_hx.o +objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_H3) += ts_hx.o +objs-$(CONFIG_ARCH_OMAP1510)$(CONFIG_MACH_OMAP_INNOVATOR) += ts_inn1510.o +objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_OSK) += ts_osk.o + +omapts-objs := omap_ts.o $(objs-yy) diff -Nru a/drivers/input/touchscreen/omap/ads7846.h b/drivers/input/touchscreen/omap/ads7846.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/input/touchscreen/omap/ads7846.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,53 @@ +/* + * ads7846.h - header file for ADS7846 touchscreen controller + * + * Copyright 2002 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * stevel@mvista.com or source@mvista.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, 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 + */ + +#ifndef __ADS7846_H +#define __ADS7846_H + +// ADS7846 Control Byte bit defines +#define ADS7846_S (1<<7) +#define ADS7846_ADDR_BIT 4 +#define ADS7846_ADDR_MASK (0x7< + * + * Assembled using driver code copyright the companies above. + * + * 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 + * History: + * 12/12/2004 Srinath Modified and intergrated code for H2 and H3 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +//#define DEBUG + +#include "omap_ts.h" + +#define OMAP_TS_NAME "omap_ts" + +extern struct ts_device hx_ts; +extern struct ts_device osk_ts; +extern struct ts_device innovator1510_ts; + +static struct ts_device *__initdata ts_devs[] = { +#if defined(CONFIG_MACH_OMAP_H2) || defined(CONFIG_MACH_OMAP_H3) + &hx_ts, +#endif +#ifdef CONFIG_MACH_OMAP_OSK + &osk_ts, +#endif +#if defined(CONFIG_MACH_OMAP_INNOVATOR) && defined(CONFIG_ARCH_OMAP1510) + &innovator1510_ts, +#endif +}; + +static struct omap_ts_t ts_omap; + +static int omap_ts_read(void) +{ + u16 data[4] = { 0, 0, 0, 0 }; + + ts_omap.dev->read(data); + + input_report_abs(&(ts_omap.inputdevice), ABS_X, data[0]); + input_report_abs(&(ts_omap.inputdevice), ABS_Y, data[1]); + input_report_abs(&(ts_omap.inputdevice), ABS_PRESSURE, data[2]); + input_sync(&(ts_omap.inputdevice)); + + DEBUG_TS("omap_ts_read: read x=%d,y=%d,p=%d\n", data[0], data[1], + data[2]); + + return 0; +} + +static void omap_ts_timer(unsigned long data) +{ + unsigned long flags; + + spin_lock_irqsave(&ts_omap.lock, flags); + + if (!ts_omap.dev->penup()) { + if (!ts_omap.touched) { + DEBUG_TS("omap_ts_timer: pen down\n"); + input_report_key(&(ts_omap.inputdevice), BTN_TOUCH, 1); + } + ts_omap.touched = 1; + omap_ts_read(); + ts_omap.ts_timer.expires = jiffies + HZ / 100; + add_timer(&(ts_omap.ts_timer)); + } else { + if (ts_omap.touched) { + DEBUG_TS("omap_ts_timer: pen up\n"); + ts_omap.touched = 0; + input_report_abs(&(ts_omap.inputdevice), ABS_X, 0); + input_report_abs(&(ts_omap.inputdevice), ABS_Y, 0); + input_report_abs(&(ts_omap.inputdevice), ABS_PRESSURE, + 0); + input_sync(&(ts_omap.inputdevice)); + input_report_key(&(ts_omap.inputdevice), BTN_TOUCH, 0); + } + if (!ts_omap.irq_enabled) { + ts_omap.irq_enabled = 1; + enable_irq(ts_omap.irq); + } + } + + spin_unlock_irqrestore(&ts_omap.lock, flags); +} + +static irqreturn_t omap_ts_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + spin_lock(&ts_omap.lock); + + if (ts_omap.irq_enabled) { + ts_omap.irq_enabled = 0; + disable_irq(irq); + } + // restart acquire + ts_omap.ts_timer.expires = jiffies + HZ / 100; + add_timer(&(ts_omap.ts_timer)); + + spin_unlock(&ts_omap.lock); + + return IRQ_HANDLED; +} + +static int __init omap_ts_probe(struct device *dev) +{ + int i; + int status = -ENODEV; + + memset(&ts_omap, 0, sizeof(ts_omap)); + spin_lock_init(&ts_omap.lock); + + for (i = 0; i < ARRAY_SIZE(ts_devs); i++) { + if (!ts_devs[i] || !ts_devs[i]->probe) + continue; + status = ts_devs[i]->probe(&ts_omap); + if (status == 0) { + ts_omap.dev = ts_devs[i]; + break; + } + } + + if (status != 0) + return status; + + // Init acquisition timer function + init_timer(&ts_omap.ts_timer); + ts_omap.ts_timer.function = omap_ts_timer; + + /* request irq */ + if (ts_omap.irq != -1) { + if (request_irq(ts_omap.irq, omap_ts_handler, 0, + OMAP_TS_NAME, &ts_omap)) { + printk(KERN_ERR + "omap_ts.c: Could not allocate touchscreen IRQ!\n"); + ts_omap.irq = -1; + return -EINVAL; + } + ts_omap.irq_enabled = 1; + } else { + printk(KERN_ERR "omap_ts.c: No touchscreen IRQ assigned!\n"); + return -EINVAL; + } + + init_input_dev(&(ts_omap.inputdevice)); + ts_omap.inputdevice.name = OMAP_TS_NAME; + ts_omap.inputdevice.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + ts_omap.inputdevice.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH); + ts_omap.inputdevice.absbit[0] = + BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); + input_register_device(&(ts_omap.inputdevice)); + + ts_omap.dev->enable(); + + printk("OMAP touchscreen driver initialized\n"); + + return 0; +} + +static int __exit omap_ts_remove(struct device *dev) +{ + ts_omap.dev->disable(); + input_unregister_device(&ts_omap.inputdevice); + if (ts_omap.irq != -1) + free_irq(ts_omap.irq, &ts_omap); + + ts_omap.dev->remove(); + + return 0; +} + +static int omap_ts_suspend(struct device *dev, u32 state, u32 level) +{ + if (level != SUSPEND_POWER_DOWN) { + return 0; + } + + ts_omap.dev->disable(); + return 0; +} + +static int omap_ts_resume(struct device *dev, u32 level) +{ + if (level != RESUME_POWER_ON) { + return 0; + } + + ts_omap.dev->enable(); + return 0; +} + +static void omap_ts_device_release(struct device *dev) +{ + /* Nothing */ +} + +static struct device_driver omap_ts_driver = { + .name = OMAP_TS_NAME, + .bus = &platform_bus_type, + .probe = omap_ts_probe, + .remove = __exit_p(omap_ts_remove), + .suspend = omap_ts_suspend, + .resume = omap_ts_resume, +}; + +static struct platform_device omap_ts_device = { + .name = OMAP_TS_NAME, + .id = -1, + .dev = { + .release = omap_ts_device_release, + }, +}; + +static int __init omap_ts_init(void) +{ + int ret; + + ret = platform_device_register(&omap_ts_device); + if (ret != 0) + return -ENODEV; + + ret = driver_register(&omap_ts_driver); + if (ret != 0) { + platform_device_unregister(&omap_ts_device); + return -ENODEV; + } + + return 0; +} + +static void __exit omap_ts_exit(void) +{ + driver_unregister(&omap_ts_driver); + platform_device_unregister(&omap_ts_device); +} + +module_init(omap_ts_init); +module_exit(omap_ts_exit); + +MODULE_LICENSE("GPL"); diff -Nru a/drivers/input/touchscreen/omap/omap_ts.h b/drivers/input/touchscreen/omap/omap_ts.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/input/touchscreen/omap/omap_ts.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,54 @@ +/* + * omap_ts.h - header file for OMAP touchscreen support + * + * Copyright (c) 2002 MontaVista Software Inc. + * Copyright (c) 2004 Texas Instruments, Inc. + * + * Assembled using driver code copyright the companies above. + * + * 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 + */ + +#ifndef __OMAP_TS_H +#define __OMAP_TS_H + +#ifdef DEBUG +#define DEBUG_TS(fmt...) printk(fmt) +#else +#define DEBUG_TS(fmt...) do { } while (0) +#endif + +struct omap_ts_t; + +struct ts_device { + int (*probe) (struct omap_ts_t *); + void (*read) (u16 *); + void (*enable) (void); + void (*disable) (void); + void (*remove) (void); + int (*penup) (void); +}; + +struct omap_ts_t{ + struct input_dev inputdevice; + struct timer_list ts_timer; // Timer for triggering acquisitions + int touched; + int irq; + int irq_enabled; + struct ts_device *dev; + spinlock_t lock; +}; + +#endif /* __OMAP_TS_H */ diff -Nru a/drivers/input/touchscreen/omap/ts_hx.c b/drivers/input/touchscreen/omap/ts_hx.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/input/touchscreen/omap/ts_hx.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,180 @@ +/* + * input/touchscreen/omap/ts_hx.c + * touchscreen support for OMAP H3 and H2 boards + * + * Copyright (c) 2002 MontaVista Software Inc. + * Copyright (c) 2004 Texas Instruments, Inc. + * + * Assembled using driver code copyright the companies above. + * + * 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 + * + * History: + * 9/12/2004 Srinath Modified and integrated H2 and H3 code + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "../drivers/ssi/omap-tsc2101.h" +#include "omap_ts.h" + +#define H2_GPIO_NUM 4 +#define H3_GPIO_NUM 48 + +#define OMAP_TSC2101_XRES 500 +#define TOUCHSCREEN_DATA_REGISTERS_PAGE 0x0 +#define TOUCHSCREEN_CONTROL_REGISTERS_PAGE 0x1 +#define OMAP_TSC2101_READ_MAX 0x4 +#define TSC2101_GETSTATUS(ret) (((ret) >> 11) & 0x1) +#define TSC2101_MASKVAL 0xFFF +#define TSC2101_PRESSUREVAL(x) ((x) << 12) + +static int hx_ts_penup(void); +static int hx_ts_probe(struct omap_ts_t *ts); +static void hx_ts_read(u16 * data); +static void hx_ts_enable(void); +static void hx_ts_disable(void); +static void hx_ts_remove(void); + +struct ts_device hx_ts = { + .probe = hx_ts_probe, + .read = hx_ts_read, + .enable = hx_ts_enable, + .disable = hx_ts_disable, + .remove = __exit_p(hx_ts_remove), + .penup = hx_ts_penup, +}; + +static int hx_ts_penup(void) +{ + int ret = 0; + /* Read the status register */ + ret = omap_tsc2101_read(TOUCHSCREEN_CONTROL_REGISTERS_PAGE, + TSC2101_TS_STATUS); + /* Check for availability of data in status register */ + ret = TSC2101_GETSTATUS(ret); + return !ret; + +} + +static int __init hx_ts_probe(struct omap_ts_t *ts) +{ + unsigned gpio; + + if (machine_is_omap_h2()) { + gpio = H2_GPIO_NUM; + omap_cfg_reg(P20_1610_GPIO4); + } else if (machine_is_omap_h3()) { + gpio = H3_GPIO_NUM; + omap_cfg_reg(W19_1610_GPIO48); + } else + return -ENODEV; + + ts->irq = OMAP_GPIO_IRQ(gpio); + if (omap_request_gpio(gpio) != 0) { + printk(KERN_ERR "hX_ts_init.c: Could not reserve GPIO!\n"); + return -EINVAL; + }; + + omap_set_gpio_direction(gpio, 1); + omap_set_gpio_edge_ctrl(gpio, OMAP_GPIO_FALLING_EDGE); + return 0; +} + +static void hx_ts_read(u16 * values) +{ + s32 t, p = 0; + int i; + + /* Read X, Y, Z1 and Z2 */ + omap_tsc2101_reads(TOUCHSCREEN_DATA_REGISTERS_PAGE, TSC2101_TS_X, + values, OMAP_TSC2101_READ_MAX); + + for (i = 0; i < OMAP_TSC2101_READ_MAX; i++) + values[i] &= TSC2101_MASKVAL; + + /* Calculate Pressure */ + if (values[TSC2101_TS_Z1] != 0) { + t = ((OMAP_TSC2101_XRES * values[TSC2101_TS_X]) * + (values[TSC2101_TS_Z2] - values[TSC2101_TS_Z1])); + p = t / (u32) (TSC2101_PRESSUREVAL(values[TSC2101_TS_Z1])); + if (p < 0) + p = 0; + } + + values[TSC2101_TS_Z1] = p; +} + +static void hx_ts_enable(void) +{ + int ret = omap_tsc2101_enable(); + if (ret) { + printk(KERN_ERR "FAILED TO INITIALIZE TSC CODEC\n"); + return; + } + + /* PINTDAV is data available only */ + omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE, + TSC2101_TS_STATUS, TSC2101_DATA_AVAILABLE); + /* disable buffer mode */ + omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE, + TSC2101_TS_BUFFER_CTRL, TSC2101_BUFFERMODE_DISABLE); + /* use internal reference, 100 usec power-up delay, + * * power down between conversions, 1.25V internal reference */ + omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE, + TSC2101_TS_REF_CTRL, TSC2101_REF_POWERUP); + /* enable touch detection, 84usec precharge time, 32 usec sense time */ + omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE, + TSC2101_TS_CONFIG_CTRL, TSC2101_ENABLE_TOUCHDETECT); + /* 3 msec conversion delays */ + omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE, + TSC2101_TS_PROG_DELAY, TSC2101_PRG_DELAY); + /* + * TSC2101-controlled conversions + * 12-bit samples + * continuous X,Y,Z1,Z2 scan mode + * average (mean) 4 samples per coordinate + * 1 MHz internal conversion clock + * 500 usec panel voltage stabilization delay + */ + omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE, + TSC2101_TS_ADC_CTRL, TSC2101_ADC_CONTROL); + + return; + +} + +static void hx_ts_disable(void) +{ + /* stop conversions and power down */ + omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE, + TSC2101_TS_ADC_CTRL, TSC2101_ADC_POWERDOWN); + omap_tsc2101_disable(); +} + +static void __exit hx_ts_remove(void) +{ + if (machine_is_omap_h2()) + omap_free_gpio(H2_GPIO_NUM); + else if (machine_is_omap_h3()) + omap_free_gpio(H3_GPIO_NUM); +} diff -Nru a/drivers/input/touchscreen/omap/ts_inn1510.c b/drivers/input/touchscreen/omap/ts_inn1510.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/input/touchscreen/omap/ts_inn1510.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,218 @@ +/* + * ts_inn1510.c - touchscreen support for OMAP1510 Innovator board + * + * Copyright 2002 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * stevel@mvista.com or source@mvista.com + * + * The touchscreen hardware on the Innovator consists of an FPGA + * register which is bit-banged to generate SPI-like transactions + * to an ADS7846 touch screen controller. + * + * 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 +#include +#include +#include +#include + +#include "omap_ts.h" +#include "ads7846.h" + +// The Touch Screen Register on Innovator FPGA +#define FPGA_TS_BCLK (1<<0) +#define FPGA_TS_BDIN (1<<1) +#define FPGA_TS_BCS (1<<2) +#define FPGA_TS_BBUSY (1<<3) +#define FPGA_TS_BOUT (1<<4) +#define FPGA_TS_BPENUP (1<<5) + +#define X_PLATE_OHMS 419 +#define Y_PLATE_OHMS 486 + +static int inn1510_ts_penup(void); +static int inn1510_ts_probe(struct omap_ts_t *ts); +static void inn1510_ts_read(u16 * data); +static void inn1510_ts_enable(void); +static void inn1510_ts_disable(void); +#ifdef MODULE +static void inn1510_ts_remove(void); +#endif + +struct ts_device innovator1510_ts = { + .probe = inn1510_ts_probe, + .read = inn1510_ts_read, + .enable = inn1510_ts_enable, + .disable = inn1510_ts_disable, + .remove = __exit_p(inn1510_ts_remove), + .penup = inn1510_ts_penup, +}; + +static inline u8 fpga_ts_read(void) +{ + return fpga_read(OMAP1510_FPGA_TOUCHSCREEN); +} + +static inline void fpga_ts_write(u8 val) +{ + fpga_write(val, OMAP1510_FPGA_TOUCHSCREEN); +} + +static inline void fpga_ts_set_bits(u8 mask) +{ + fpga_ts_write(fpga_ts_read() | mask); +} + +static inline void fpga_ts_clear_bits(u8 mask) +{ + fpga_ts_write(fpga_ts_read() & ~mask); +} + +static inline void CS_H(void) +{ + // EPLD inverts active low signals. + fpga_ts_clear_bits(FPGA_TS_BCS); +} + +static inline void CS_L(void) +{ + fpga_ts_set_bits(FPGA_TS_BCS); +} + +static inline void SCLK_L(void) +{ + fpga_ts_clear_bits(FPGA_TS_BCLK); +} + +static inline void SCLK_H(void) +{ + fpga_ts_set_bits(FPGA_TS_BCLK); +} + +static inline void SDI_L(void) +{ + fpga_ts_clear_bits(FPGA_TS_BDIN); +} + +static inline void SDI_H(void) +{ + fpga_ts_set_bits(FPGA_TS_BDIN); +} + +static inline int BUSY(void) +{ + return (((fpga_ts_read() & FPGA_TS_BBUSY) == 0) ? 1 : 0) ; +} + +static inline u8 DOUT(void) +{ + return ((fpga_ts_read() & FPGA_TS_BOUT) ? 1 : 0) ; +} + +static u16 ads7846_do(u8 cmd) +{ + int i; + u16 val=0; + + SCLK_L() ; + SDI_L(); + CS_L() ; // enable the chip select + + // send the command to the ADS7846 + for (i=0; i<8; i++ ) { + if (cmd & 0x80) + SDI_H(); + else + SDI_L(); // prepare the data on line sdi OR din + + SCLK_H() ; // clk in the data + cmd <<= 1 ; + SCLK_L() ; + } + + SDI_L(); + while (BUSY()) + ; + + // now read returned data + for (i=0 ; i<16 ; i++ ) { + SCLK_L() ; + + if (i < 12) { + val <<= 1 ; + val |= DOUT(); + } + SCLK_H() ; + } + + SCLK_L() ; + CS_H() ; // disable the chip select + + return val; +} + +static int inn1510_ts_penup(void) +{ + return ((fpga_ts_read() & FPGA_TS_BPENUP) ? 0 : 1) ; +} + +static int __init inn1510_ts_probe(struct omap_ts_t *ts) +{ + if (!cpu_is_omap15xx() || !machine_is_omap_innovator()) + return -ENODEV; + + ts->irq = OMAP1510_INT_FPGA_TS; + + return 0; +} + +static void inn1510_ts_read(u16 *data) +{ + unsigned int Rt = 0; + + data[0] = ads7846_do(MEASURE_12BIT_X); + data[1] = ads7846_do(MEASURE_12BIT_Y); + data[2] = ads7846_do(MEASURE_12BIT_Z1); + data[3] = ads7846_do(MEASURE_12BIT_Z2); + + // Calculate touch pressure resistance + if (data[2]) { + Rt = (X_PLATE_OHMS * (u32)data[0] * + ((u32)data[3] - (u32)data[2])) / (u32)data[2]; + + Rt = (Rt + 2048) >> 12; // round up to nearest ohm + } + + data[2] = Rt; +} + +static void inn1510_ts_enable(void) +{ + +} + +static void inn1510_ts_disable(void) +{ + +} + +#ifdef MODULE +static void __exit inn1510_ts_remove(void) +{ + /* Nothing to do here */ +} +#endif diff -Nru a/drivers/input/touchscreen/omap/ts_osk.c b/drivers/input/touchscreen/omap/ts_osk.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/input/touchscreen/omap/ts_osk.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,149 @@ +/* + * ts_osk.c - touchscreen support for OMAP OSK board + * + * Copyright 2002 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * stevel@mvista.com or source@mvista.com + * + * The touchscreen hardware on the OSK uses OMAP5912 uWire interface, + * GPIO4 (/PENIRQ) and GPIO6 (BUSY) to connect to an ADS7846 + * touch screen controller. GPIO6 doesn't seem to be necessary here. + * + * 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 +#include +#include +#include +#include + +#include "../drivers/ssi/omap-uwire.h" + +#include "omap_ts.h" +#include "ads7846.h" + +// /PENIRQ on GPIO4 on OSK +#define PEN_IRQ OMAP_GPIO_IRQ(4) + +// ADS7846 is on OSK uWire CS 0 +#define ADS7846_UWIRE_CS 0 +#define UWIRE_LEAVE_CS 1 + +#define X_PLATE_OHMS 419 +#define Y_PLATE_OHMS 486 + +static int osk_ts_penup(void); +static int osk_ts_probe(struct omap_ts_t *ts); +static void osk_ts_read(u16 * data); +static void osk_ts_enable(void); +static void osk_ts_disable(void); +#ifdef MODULE +static void osk_ts_remove(void); +#endif + +struct ts_device osk_ts = { + .probe = osk_ts_probe, + .read = osk_ts_read, + .enable = osk_ts_enable, + .disable = osk_ts_disable, + .remove = __exit_p(osk_ts_remove), + .penup = osk_ts_penup, +}; + +static u16 ads7846_do(u8 cmd) +{ + u16 val = 0; + + // send the command to the ADS7846, leave CS active after this + omap_uwire_data_transfer(ADS7846_UWIRE_CS, cmd, 8, 0, NULL, UWIRE_LEAVE_CS); + + // now read returned data + omap_uwire_data_transfer(ADS7846_UWIRE_CS, 0, 0, 16, &val, !UWIRE_LEAVE_CS); + + return val; +} + +static int osk_ts_penup(void) +{ + return (omap_get_gpio_datain(4)); +} + +static int __init osk_ts_probe(struct omap_ts_t *ts) +{ + if (!machine_is_omap_osk()) + return -ENODEV; + + /* Configure GPIO4 (pin M17 ZDY) as /PENIRQ interrupt input */ + omap_cfg_reg(P20_1610_GPIO4); + omap_request_gpio(4); + omap_set_gpio_direction(4, 1); + omap_set_gpio_edge_ctrl(4, OMAP_GPIO_FALLING_EDGE); + + ts->irq = PEN_IRQ; + + /* Configure uWire interface. ADS7846 is on CS0 */ + omap_uwire_configure_mode(ADS7846_UWIRE_CS, UWIRE_READ_RISING_EDGE | + UWIRE_WRITE_RISING_EDGE | + UWIRE_CS_ACTIVE_LOW | + UWIRE_FREQ_DIV_2); + + return 0; +} + +static void osk_ts_read(u16 *data) +{ + unsigned int Rt = 0; + + data[0] = ads7846_do(MEASURE_12BIT_X); + data[1] = ads7846_do(MEASURE_12BIT_Y); + data[2] = ads7846_do(MEASURE_12BIT_Z1); + data[3] = ads7846_do(MEASURE_12BIT_Z2); + + // Calculate touch pressure resistance + if (data[2]) { + Rt = (X_PLATE_OHMS * (u32)data[0] * + ((u32)data[3] - (u32)data[2])) / (u32)data[2]; + + Rt = (Rt + 2048) >> 12; // round up to nearest ohm + } + + /* + * Raw OSK touchscreen data values are between ~4000 and + * ~60000. This seems to be to large for calibration + * systems (e.g. tslib). Make the values smaller. + */ + data[0] = data[0] >> 4; + data[1] = data[1] >> 4; + + data[2] = Rt; +} + +static void osk_ts_enable(void) +{ + +} + +static void osk_ts_disable(void) +{ + +} + +#ifdef MODULE +static void __exit osk_ts_remove(void) +{ + omap_free_gpio(4); +} +#endif diff -Nru a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig --- a/drivers/media/video/Kconfig 2005-03-02 10:51:31 -08:00 +++ b/drivers/media/video/Kconfig 2005-03-02 10:51:31 -08:00 @@ -350,4 +350,10 @@ Say Y here to use the Renesas M64278E-800 camera module, which supports VGA(640x480 pixcels) size of images. +config VIDEO_OMAP_CAMERA + tristate "OMAP Video for Linux camera driver" + depends on VIDEO_DEV && ARCH_OMAP16XX + select VIDEO_BUF + + endmenu diff -Nru a/drivers/media/video/Makefile b/drivers/media/video/Makefile --- a/drivers/media/video/Makefile 2005-03-02 10:51:31 -08:00 +++ b/drivers/media/video/Makefile 2005-03-02 10:51:31 -08:00 @@ -51,5 +51,6 @@ obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o +obj-$(CONFIG_VIDEO_OMAP_CAMERA) += omap/ EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core diff -Nru a/drivers/media/video/omap/Makefile b/drivers/media/video/omap/Makefile --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/video/omap/Makefile 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,7 @@ +# Makefile for camera driver for H2/H3 + +omapCamera-objs := camera_core.o omap16xxcam.o sensor_ov9640.o + +obj-y += omapCamera.o + +EXTRA_CFLAGS = -I$(src)/.. diff -Nru a/drivers/media/video/omap/camera_core.c b/drivers/media/video/omap/camera_core.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/video/omap/camera_core.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,1094 @@ +/* + * drivers/media/video/omap/camera_core.c + * + * Copyright (C) 2004 Texas Instruments, Inc. + * + * Video-for-Linux (Version 2) camera capture driver for + * the OMAP H2 and H3 camera controller. + * + * Adapted from omap24xx driver written by Andy Lowe (source@mvista.com) + * Copyright (C) 2003-2004 MontaVista Software, Inc. + * + * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "sensor_if.h" +#include "camera_hw_if.h" +#include "camera_core.h" + +struct camera_device *camera_dev; +extern struct camera_sensor camera_sensor_if; +extern struct camera_hardware camera_hardware_if; + +static void camera_core_sgdma_process(struct camera_device *cam); + +/* module parameters */ +static int video_nr = -1; /* video device minor (-1 ==> auto assign) */ + +/* Maximum amount of memory to use for capture buffers. + * Default is 4800KB, enough to double-buffer SXGA. + */ +static int capture_mem = 1280*960*2*2; + +/*Size of video overlay framebuffer. This determines the maximum image size + *that can be previewed. Default is 600KB, enough for sxga. + */ +static int overlay_mem = 640*480*2; + + +/* DMA completion routine for the scatter-gather DMA fragments. */ +/* This function is called when a scatter DMA fragment is completed */ +static void +camera_core_callback_sgdma(void *arg1, void *arg2) +{ + struct camera_device *cam = (struct camera_device *)arg1; + int sgslot = (int)arg2; + + struct sgdma_state *sgdma; + + spin_lock(&cam->sg_lock); + sgdma = cam->sgdma + sgslot; + if (!sgdma->queued_sglist) + { + spin_unlock(&cam->sg_lock); + printk(KERN_ERR CAM_NAME ": SGDMA completed when none queued\n"); + return; + } + if (!--sgdma->queued_sglist) { + /* queue for this sglist is empty so check whether transfer + ** of the frame has been completed */ + if (sgdma->next_sglist == sgdma->sglen) { + dma_callback_t callback = sgdma->callback; + void *arg = sgdma->arg; + /* all done with this sglist */ + cam->free_sgdma++; + if (callback) { + spin_unlock(&cam->sg_lock); + (*callback)(cam, arg); + camera_core_sgdma_process(cam); + return; + } + } + } + spin_unlock(&cam->sg_lock); + camera_core_sgdma_process(cam); + + return; +} + +static void +camera_core_sgdma_init(struct camera_device *cam) +{ + int sg; + + /* Initialize the underlying camera DMA */ + cam->cam_hardware->init_dma(cam->hardware_data); + spin_lock_init(&cam->sg_lock); + + cam->free_sgdma = NUM_SG_DMA; + cam->next_sgdma = 0; + for (sg = 0; sg < NUM_SG_DMA; sg++) { + cam->sgdma[sg].sglen = 0; + cam->sgdma[sg].next_sglist = 0; + cam->sgdma[sg].queued_sglist = 0; + cam->sgdma[sg].csr = 0; + cam->sgdma[sg].callback = NULL; + cam->sgdma[sg].arg = NULL; + } +} + +/* + * Process the scatter-gather DMA queue by starting queued transfers + * This function is called to program the dma to start the transfer of an image. + */ +static void +camera_core_sgdma_process(struct camera_device *cam) +{ + unsigned long irqflags; + int queued_sgdma, sgslot; + struct sgdma_state *sgdma; + const struct scatterlist *sglist; + + spin_lock_irqsave(&cam->sg_lock, irqflags); + + queued_sgdma = NUM_SG_DMA - cam->free_sgdma; + sgslot = (cam->next_sgdma + cam->free_sgdma) % (NUM_SG_DMA); + while (queued_sgdma > 0) { + sgdma = cam->sgdma + sgslot; + while (sgdma->next_sglist < sgdma->sglen) { + sglist = sgdma->sglist + sgdma->next_sglist; + if (cam->cam_hardware->start_dma(sgdma, camera_core_callback_sgdma, + (void *)cam, (void *)sgslot, cam->hardware_data)) { + /* dma start failed */ + spin_unlock_irqrestore(&cam->sg_lock, irqflags); + return; + } + else { + /* dma start successful */ + sgdma->next_sglist ++; + sgdma->queued_sglist ++; + } + } + queued_sgdma-- ; + sgslot = (sgslot + 1) % (NUM_SG_DMA); + } + + spin_unlock_irqrestore(&cam->sg_lock, irqflags); +} + +/* Queue a scatter-gather DMA transfer from the camera to memory. + * Returns zero if the transfer was successfully queued, or + * non-zero if all of the scatter-gather slots are already in use. + */ +static int +camera_core_sgdma_queue(struct camera_device *cam, + const struct scatterlist *sglist, int sglen, dma_callback_t callback, + void *arg) +{ + unsigned long irqflags; + struct sgdma_state *sgdma; + + if ((sglen < 0) || ((sglen > 0) & !sglist)) + return -EINVAL; + + spin_lock_irqsave(&cam->sg_lock, irqflags); + + if (!cam->free_sgdma) { + spin_unlock_irqrestore(&cam->sg_lock, irqflags); + return -EBUSY; + } + + sgdma = cam->sgdma + cam->next_sgdma; + + sgdma->sglist = sglist; + sgdma->sglen = sglen; + sgdma->next_sglist = 0; + sgdma->queued_sglist = 0; + sgdma->csr = 0; + sgdma->callback = callback; + sgdma->arg = arg; + + cam->next_sgdma = (cam->next_sgdma + 1) % (NUM_SG_DMA); + cam->free_sgdma--; + + spin_unlock_irqrestore(&cam->sg_lock, irqflags); + + camera_core_sgdma_process(cam); + + return 0; +} + + +/* -------------------overlay routines ------------------------------*/ +/* callback routine for overlay DMA completion. We just start another DMA + * transfer unless overlay has been turned off + */ + +static void +camera_core_overlay_callback(void *arg1, void *arg) +{ + struct camera_device *cam = (struct camera_device *)arg1; + int err; + unsigned long irqflags; + int i, j; + int count, index; + unsigned char *fb_buf = phys_to_virt((unsigned long)camera_dev->fbuf.base); + + spin_lock_irqsave(&cam->overlay_lock, irqflags); + + if (!cam->previewing || cam->overlay_cnt == 0) { + spin_unlock_irqrestore(&cam->overlay_lock, irqflags); + return; + } + + --cam->overlay_cnt; + sg_dma_address(&cam->overlay_sglist) = cam->overlay_base_phys; + sg_dma_len(&cam->overlay_sglist) = cam->pix.sizeimage; + + count = 0; + j = ((cam->pix.width - 1) * cam->fbuf.fmt.bytesperline); + for (i = 0 ; i < cam->pix.sizeimage; i += cam->pix.bytesperline) { + for (index = 0; index < cam->pix.bytesperline; index++) { + fb_buf[j] = *(((unsigned char *) cam->overlay_base) + + i + index); + index++; + fb_buf[j + 1] = *(((unsigned char *) cam->overlay_base) + i + index); + j = j - cam->fbuf.fmt.bytesperline; + } + count += 2; + j = ((cam->pix.width - 1) * cam->fbuf.fmt.bytesperline) + count; + } + + while (cam->overlay_cnt < 2) { + err = camera_core_sgdma_queue(cam, &cam->overlay_sglist, 1, + camera_core_overlay_callback, NULL); + if (err) + break; + ++cam->overlay_cnt; + } + + spin_unlock_irqrestore(&cam->overlay_lock, irqflags); + +} + + +static void +camera_core_start_overlay(struct camera_device *cam) +{ + int err; + unsigned long irqflags; + + if (!cam->previewing) + return; + + spin_lock_irqsave(&cam->overlay_lock, irqflags); + + sg_dma_address(&cam->overlay_sglist) = cam->overlay_base_phys; + sg_dma_len(&cam->overlay_sglist)= cam->pix.sizeimage; + while (cam->overlay_cnt < 2) { + err = camera_core_sgdma_queue(cam, &cam->overlay_sglist, 1, + camera_core_overlay_callback, NULL); + if (err) + break; + ++cam->overlay_cnt; + } + + spin_unlock_irqrestore(&cam->overlay_lock, irqflags); +} + +/* ------------------ videobuf_queue_ops ---------------------------------------- */ + +/* This routine is called from interrupt context when a scatter-gather DMA + * transfer of a videobuf_buffer completes. + */ +static void +camera_core_vbq_complete(void *arg1, void *arg) +{ + struct camera_device *cam = (struct camera_device *)arg1; + struct videobuf_buffer *vb = (struct videobuf_buffer *)arg; + + spin_lock(&cam->vbq_lock); + + do_gettimeofday(&vb->ts); + vb->field_count = cam->field_count; + cam->field_count += 2; + vb->state = STATE_DONE; + + wake_up(&vb->done); + + spin_unlock(&cam->vbq_lock); +} + +static void +camera_core_vbq_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + videobuf_waiton(vb, 0, 0); + videobuf_dma_pci_unmap(NULL, &vb->dma); + videobuf_dma_free(&vb->dma); + + vb->state = STATE_NEEDS_INIT; +} + +/* Limit the number of available kernel image capture buffers based on the + * number requested, the currently selected image size, and the maximum + * amount of memory permitted for kernel capture buffers. + */ +static int +camera_core_vbq_setup(struct videobuf_queue *q, unsigned int *cnt, unsigned int *size) +{ + struct camera_device *cam = q->priv_data; + + if (*cnt <= 0) + *cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */ + + if (*cnt > VIDEO_MAX_FRAME) + *cnt = VIDEO_MAX_FRAME; + + spin_lock(&cam->img_lock); + *size = cam->pix.sizeimage; + spin_unlock(&cam->img_lock); + + while (*size * *cnt > capture_mem) + (*cnt)--; + + return 0; +} + +static int +camera_core_vbq_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct camera_device *cam = q->priv_data; + int err = 0; + + spin_lock(&cam->img_lock); + if (cam->pix.sizeimage > vb->bsize) { + spin_unlock(&cam->img_lock); + return -EINVAL; + } + vb->size = cam->pix.sizeimage; + vb->width = cam->pix.width; + vb->height = cam->pix.height; + vb->field = field; + spin_unlock(&cam->img_lock); + + if (vb->state == STATE_NEEDS_INIT) + err = videobuf_iolock(NULL, vb, NULL); + + if (!err) + vb->state = STATE_PREPARED; + else + camera_core_vbq_release (q, vb); + + return err; +} + +static void +camera_core_vbq_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct camera_device *cam = q->priv_data; + enum videobuf_state state = vb->state; + int err; + + vb->state = STATE_QUEUED; + err = camera_core_sgdma_queue(cam, vb->dma.sglist, vb->dma.sglen, + camera_core_vbq_complete, vb); + if (err) { + /* Oops. We're not supposed to get any errors here. The only + * way we could get an error is if we ran out of scatter-gather + * DMA slots, but we are supposed to have at least as many + * scatter-gather DMA slots as video buffers so that can't + * happen. + */ + printk(KERN_DEBUG CAM_NAME + ": Failed to queue a video buffer for SGDMA\n"); + vb->state = state; + } +} + +/* ------------------ videobuf_queue_ops ---------------------------------------- */ + +static int +camera_core_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + void *arg) +{ + struct camera_fh *fh = file->private_data; + struct camera_device *cam = fh->cam; + int err; + + switch (cmd) { + case VIDIOC_ENUMINPUT: + { + /* default handler assumes 1 video input (the camera) */ + struct v4l2_input *input = (struct v4l2_input *)arg; + int index = input->index; + + memset(input, 0, sizeof(*input)); + input->index = index; + + if (index > 0) + return -EINVAL; + + strlcpy(input->name, "camera", sizeof(input->name)); + input->type = V4L2_INPUT_TYPE_CAMERA; + + return 0; + } + + case VIDIOC_G_INPUT: + { + unsigned int *input = arg; + *input = 0; + + return 0; + } + + case VIDIOC_S_INPUT: + { + unsigned int *input = arg; + + if (*input > 0) + return -EINVAL; + + return 0; + } + + case VIDIOC_ENUM_FMT: + { + struct v4l2_fmtdesc *fmt = arg; + return cam->cam_sensor->enum_pixformat(fmt, cam->sensor_data); + } + + case VIDIOC_TRY_FMT: + { + struct v4l2_format *fmt = arg; + return cam->cam_sensor->try_format(&fmt->fmt.pix, cam->sensor_data); + + } + + case VIDIOC_G_FMT: + { + struct v4l2_format *fmt = arg; + + /* get the current format */ + memset(&fmt->fmt.pix, 0, sizeof (fmt->fmt.pix)); + fmt->fmt.pix = cam->pix; + + return 0; + } + + case VIDIOC_S_FMT: + { + struct v4l2_format *fmt = arg; + unsigned int temp_sizeimage = 0; + + temp_sizeimage = cam->pix.sizeimage; + cam->cam_sensor->try_format(&fmt->fmt.pix, cam->sensor_data); + cam->pix = fmt->fmt.pix; + + cam->xclk = cam->cam_sensor->calc_xclk(&cam->pix, + &cam->nominal_timeperframe, cam->sensor_data); + cam->cparm.timeperframe = cam->nominal_timeperframe; + cam->xclk = cam->cam_hardware->set_xclk(cam->xclk, cam->hardware_data); + return cam->cam_sensor->configure(&cam->pix, cam->xclk, + &cam->cparm.timeperframe, cam->sensor_data); + } + + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + return cam->cam_sensor->query_control(qc, cam->sensor_data); + } + + case VIDIOC_G_CTRL: + { + struct v4l2_control *vc = arg; + return cam->cam_sensor->get_control(vc, cam->sensor_data); + } + + case VIDIOC_S_CTRL: + { + struct v4l2_control *vc = arg; + return cam->cam_sensor->set_control(vc, cam->sensor_data); + } + + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *cap = + (struct v4l2_capability *) arg; + + memset(cap, 0, sizeof(*cap)); + strlcpy(cap->driver, CAM_NAME, sizeof(cap->driver)); + strlcpy(cap->card, cam->vfd->name, sizeof(cap->card)); + cap->bus_info[0] = '\0'; + cap->version = KERNEL_VERSION(0, 0, 0); + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VIDEO_OVERLAY | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + return 0; + } + + case VIDIOC_G_FBUF: /* Get the frame buffer parameters */ + { + struct v4l2_framebuffer *fbuf = + (struct v4l2_framebuffer *) arg; + + spin_lock(&cam->img_lock); + *fbuf = cam->fbuf; + spin_unlock(&cam->img_lock); + return 0; + } + + case VIDIOC_S_FBUF: /* set the frame buffer parameters */ + { + struct v4l2_framebuffer *fbuf = + (struct v4l2_framebuffer *) arg; + + spin_lock(&cam->img_lock); + if (cam->previewing) { + spin_unlock(&cam->img_lock); + return -EBUSY; + } + cam->fbuf.base = fbuf->base; + cam->fbuf.fmt = fbuf->fmt; + + spin_unlock(&cam->img_lock); + return 0; + } + + case VIDIOC_OVERLAY: + { + int enable = *((int *) arg); + + /* + * check whether the capture format and + ** the display format matches + * return failure if they are different + */ + if (cam->pix.pixelformat != cam->fbuf.fmt.pixelformat) + { + return -EINVAL; + } + + /* If the camera image size is greater + ** than LCD size return failure */ + if ((cam->pix.width > cam->fbuf.fmt.height) || + (cam->pix.height > cam->fbuf.fmt.width)) + { + return -EINVAL; + } + + if (!cam->previewing && enable) + { + cam->previewing = fh; + cam->overlay_cnt = 0; + camera_core_start_overlay(cam); + } + else if (!enable) + { + cam->previewing = NULL; + } + + return 0; + } + + case VIDIOC_REQBUFS: + return videobuf_reqbufs(&fh->vbq, arg); + + case VIDIOC_QUERYBUF: + return videobuf_querybuf(&fh->vbq, arg); + + case VIDIOC_QBUF: + return videobuf_qbuf(&fh->vbq, arg); + + case VIDIOC_DQBUF: + return videobuf_dqbuf(&fh->vbq, arg, + file->f_flags & O_NONBLOCK); + + case VIDIOC_STREAMON: + { + spin_lock(&cam->img_lock); + + if (cam->streaming || cam->reading) { + spin_unlock(&cam->img_lock); + return -EBUSY; + } + else { + cam->streaming = fh; + /* FIXME: start camera interface */ + } + + spin_unlock(&cam->img_lock); + + return videobuf_streamon(&fh->vbq); + } + case VIDIOC_STREAMOFF: + { + err = videobuf_streamoff(&fh->vbq); + if (err < 0) + return err; + + spin_lock(&cam->img_lock); + if (cam->streaming == fh) { + cam->streaming = NULL; + /* FIXME: stop camera interface */ + } + spin_unlock(&cam->img_lock); + return 0; + } + case VIDIOC_ENUMSTD: + case VIDIOC_G_STD: + case VIDIOC_S_STD: + case VIDIOC_QUERYSTD: + { + /* Digital cameras don't have an analog video standard, + * so we don't need to implement these ioctls. + */ + return -EINVAL; + } + case VIDIOC_G_AUDIO: + case VIDIOC_S_AUDIO: + case VIDIOC_G_AUDOUT: + case VIDIOC_S_AUDOUT: + { + /* we don't have any audio inputs or outputs */ + return -EINVAL; + } + + case VIDIOC_G_JPEGCOMP: + case VIDIOC_S_JPEGCOMP: + { + /* JPEG compression is not supported */ + return -EINVAL; + } + + case VIDIOC_G_TUNER: + case VIDIOC_S_TUNER: + case VIDIOC_G_MODULATOR: + case VIDIOC_S_MODULATOR: + case VIDIOC_G_FREQUENCY: + case VIDIOC_S_FREQUENCY: + { + /* we don't have a tuner or modulator */ + return -EINVAL; + } + + case VIDIOC_ENUMOUTPUT: + case VIDIOC_G_OUTPUT: + case VIDIOC_S_OUTPUT: + { + /* we don't have any video outputs */ + return -EINVAL; + } + + default: + { + /* unrecognized ioctl */ + return -ENOIOCTLCMD; + } + } + return 0; +} + +/* + * file operations + */ + +static unsigned +int camera_core_poll(struct file *file, struct poll_table_struct *wait) +{ + return -EINVAL; +} + +/* ------------------------------------------------------------ */ +/* callback routine for read DMA completion. We just start another DMA + * transfer unless overlay has been turned off + */ +static void +camera_core_capture_callback(void *arg1, void *arg) +{ + struct camera_device *cam = (struct camera_device *)arg1; + int err; + unsigned long irqflags; + static int done = 0; + + spin_lock_irqsave(&cam->capture_lock, irqflags); + if (!cam->reading) + { + done = 0; + cam->capture_started = 0; + spin_unlock_irqrestore(&cam->capture_lock, irqflags); + return; + } + + if (done < 14) { + ++done; + sg_dma_address(&cam->capture_sglist) = cam->capture_base_phys; + sg_dma_len(&cam->capture_sglist) = cam->pix.sizeimage; + err = camera_core_sgdma_queue(cam, &cam->capture_sglist, 1, + camera_core_capture_callback, NULL); + } else { + cam->capture_completed = 1; + if (cam->reading) + { + /* Wake up any process which are waiting for the + ** DMA to complete */ + wake_up_interruptible(&camera_dev->new_video_frame); + sg_dma_address(&cam->capture_sglist) = cam->capture_base_phys; + sg_dma_len(&cam->capture_sglist) = cam->pix.sizeimage; + err = camera_core_sgdma_queue(cam, &cam->capture_sglist, 1, + camera_core_capture_callback, NULL); + } + } + + spin_unlock_irqrestore(&cam->capture_lock, irqflags); +} + + +static ssize_t +camera_core_read(struct file *file, char *data, size_t count, loff_t *ppos) +{ + struct camera_fh *fh = file->private_data; + struct camera_device *cam = fh->cam; + int err; + unsigned long irqflags; + long timeout; +#if 0 /* use video_buf to do capture */ + int i; + for (i = 0; i < 14; i++) + videobuf_read_one(file, &fh->vbq, data, count, ppos); + i = videobuf_read_one(file, &fh->vbq, data, count, ppos); + return i; +#endif + + if (!cam->capture_base) { + cam->capture_base = (unsigned long)dma_alloc_coherent(NULL, + cam->pix.sizeimage, + (dma_addr_t *) &cam->capture_base_phys, + GFP_KERNEL | GFP_DMA); + } + if (!cam->capture_base) { + printk(KERN_ERR CAM_NAME + ": cannot allocate capture buffer\n"); + return 0; + } + + spin_lock_irqsave(&cam->capture_lock, irqflags); + cam->reading = fh; + cam->capture_started = 1; + sg_dma_address(&cam->capture_sglist) = cam->capture_base_phys; + sg_dma_len(&cam->capture_sglist)= cam->pix.sizeimage; + spin_unlock_irqrestore(&cam->capture_lock, irqflags); + + err = camera_core_sgdma_queue(cam, &cam->capture_sglist, 1, + camera_core_capture_callback, NULL); + + /* Wait till DMA is completed */ + timeout = HZ * 10; + cam->capture_completed = 0; + while (cam->capture_completed == 0) { + timeout = interruptible_sleep_on_timeout + (&cam->new_video_frame, timeout); + if (timeout == 0) { + printk(KERN_ERR CAM_NAME ": timeout waiting video frame\n"); + return -EIO; /* time out */ + } + } + /* copy the data to the user buffer */ + err = copy_to_user(data, (void *)cam->capture_base, cam->pix.sizeimage); + return (cam->pix.sizeimage - err); + +} + +static int +camera_core_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct camera_fh *fh = file->private_data; + + return videobuf_mmap_mapper(&fh->vbq, vma); +} + +static int +camera_core_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + + return video_usercopy(inode, file, cmd, arg, camera_core_do_ioctl); +} + +static int +camera_core_release(struct inode *inode, struct file *file) +{ + struct camera_fh *fh = file->private_data; + struct camera_device *cam = fh->cam; + + file->private_data = NULL; + kfree(fh); + + spin_lock(&cam->img_lock); + if (cam->previewing == fh) { + cam->previewing = NULL; + } + if (cam->streaming == fh) { + cam->streaming = NULL; + } + if (cam->reading == fh) { + cam->reading = NULL; + } + spin_unlock(&cam->img_lock); + + camera_dev->cam_hardware->finish_dma(cam->hardware_data); + + if (cam->capture_base) { + dma_free_coherent(NULL, cam->pix.sizeimage, + (void *)cam->capture_base, + cam->capture_base_phys); + cam->capture_base = 0; + cam->capture_base_phys = 0; + } + if (fh->vbq.read_buf) { + camera_core_vbq_release(&fh->vbq, fh->vbq.read_buf); + kfree(fh->vbq.read_buf); + } + + cam->cam_hardware->close(cam->hardware_data); + return 0; +} + +static int +camera_core_open(struct inode *inode, struct file *file) +{ + int minor = iminor(inode); + struct camera_device *cam = camera_dev; + struct camera_fh *fh; + + if (!cam || !cam->vfd || (cam->vfd->minor != minor)) + return -ENODEV; + + /* allocate per-filehandle data */ + fh = kmalloc(sizeof(*fh), GFP_KERNEL); + if (NULL == fh) + return -ENOMEM; + file->private_data = fh; + fh->cam = cam; + fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + videobuf_queue_init(&fh->vbq, &cam->vbq_ops, NULL, &cam->vbq_lock, + fh->type, V4L2_FIELD_NONE, sizeof(struct videobuf_buffer), fh); + + cam->capture_completed = 0; + cam->capture_started = 0; + + if (cam->cam_hardware->open(cam->hardware_data)) + { + printk (KERN_ERR CAM_NAME ": Camera IF configuration failed\n"); + return -ENODEV; + } + + cam->xclk = cam->cam_hardware->set_xclk(cam->xclk, cam->hardware_data); + /* program the sensor for the capture format and rate */ + if (cam->cam_sensor->configure(&cam->pix, cam->xclk, + &cam->cparm.timeperframe, cam->sensor_data)) + { + printk (KERN_ERR CAM_NAME ": Camera sensor configuration failed\n"); + return -ENODEV; + } + + return 0; +} + +static struct file_operations camera_core_fops = +{ + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = camera_core_read, + .poll = camera_core_poll, + .ioctl = camera_core_ioctl, + .mmap = camera_core_mmap, + .open = camera_core_open, + .release = camera_core_release, +}; + +void +camera_core_cleanup(void) +{ + struct camera_device *cam = camera_dev; + struct video_device *vfd; + + if (!cam) + return; + + vfd = cam->vfd; + if (vfd) { + if (vfd->minor == -1) { + /* The device never got registered, so release the + ** video_device struct directly + */ + video_device_release(vfd); + } else { + /* The unregister function will release the video_device + ** struct as well as unregistering it. + */ + video_unregister_device(vfd); + } + cam->vfd = NULL; + } + if (cam->overlay_base) { + dma_free_coherent(NULL, cam->overlay_size, + (void *)cam->overlay_base, + cam->overlay_base_phys); + cam->overlay_base = 0; + } + cam->overlay_base_phys = 0; + + cam->cam_sensor->cleanup(cam->sensor_data); + cam->cam_hardware->cleanup(cam->hardware_data); + kfree(cam); + camera_dev = NULL; + + return; +} + + +int __init +camera_core_init(void) +{ + struct camera_device *cam; + struct video_device *vfd; + + cam = kmalloc(sizeof(struct camera_device), GFP_KERNEL); + if (!cam) { + printk(KERN_ERR CAM_NAME ": could not allocate memory\n"); + goto init_error; + } + memset(cam, 0, sizeof(struct camera_device)); + + /* Save the pointer to camera device in a global variable */ + camera_dev = cam; + + /* initialize the video_device struct */ + vfd = cam->vfd = video_device_alloc(); + if (!vfd) { + printk(KERN_ERR CAM_NAME + ": could not allocate video device struct\n"); + goto init_error; + } + + vfd->release = video_device_release; +#if FIXME_FIXME +/* If the dev fields are not initlized (parent and such) sysfs will crash you + * when it tries to set you up....most drivers seem to chain in the info their + * parent bus gave them. Getting this associated right is likely necessary + * for power mangement. Revisit when adding PM code. + */ + vfd->dev = &cam->dev; +#endif + strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name)); + vfd->type = VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CHROMAKEY; + + /* need to register for a VID_HARDWARE_* ID in videodev.h */ + vfd->hardware = 0; + vfd->fops = &camera_core_fops; + video_set_drvdata(vfd, cam); + vfd->minor = -1; + + /* initialize the videobuf queue ops */ + cam->vbq_ops.buf_setup = camera_core_vbq_setup; + cam->vbq_ops.buf_prepare = camera_core_vbq_prepare; + cam->vbq_ops.buf_queue = camera_core_vbq_queue; + cam->vbq_ops.buf_release = camera_core_vbq_release; + + /* initilize the overlay interface */ + cam->overlay_size = overlay_mem; + if (cam->overlay_size > 0) + { + cam->overlay_base = (unsigned long) dma_alloc_coherent(NULL, + cam->overlay_size, + (dma_addr_t *) &cam->overlay_base_phys, + GFP_KERNEL | GFP_DMA); + if (!cam->overlay_base) { + printk(KERN_ERR CAM_NAME + ": cannot allocate overlay framebuffer\n"); + goto init_error; + } + } + memset((void*)cam->overlay_base, 0, cam->overlay_size); + spin_lock_init(&cam->overlay_lock); + + /*Initialise the pointer to the sensor interface and camera interface */ + cam->cam_sensor = &camera_sensor_if; + cam->cam_hardware = &camera_hardware_if; + + /* initialize the camera interface */ + cam->hardware_data = cam->cam_hardware->init(); + if (!cam->hardware_data) { + printk(KERN_ERR CAM_NAME ": cannot initialize interface hardware\n"); + goto init_error; + } + + /* initialize the spinlock used to serialize access to the image + * parameters + */ + spin_lock_init(&cam->img_lock); + + /* initialize the streaming capture parameters */ + cam->cparm.capability = V4L2_CAP_TIMEPERFRAME; + cam->cparm.readbuffers = 1; + + /* Enable the xclk output. The sensor may (and does, in the case of + * the OV9640) require an xclk input in order for its initialization + * routine to work. + */ + cam->xclk = 21000000; /* choose an arbitrary xclk frequency */ + cam->xclk = cam->cam_hardware->set_xclk(cam->xclk, cam->hardware_data); + + /* initialize the sensor and define a default capture format cam->pix */ + cam->sensor_data = cam->cam_sensor->init(&cam->pix); + if (!cam->sensor_data) { + printk(KERN_ERR CAM_NAME ": cannot initialize sensor\n"); + goto init_error; + } + + printk(KERN_INFO CAM_NAME ": %s interface with %s sensor\n", + cam->cam_hardware->name, cam->cam_sensor->name); + + /* select an arbitrary default capture frame rate of 15fps */ + cam->nominal_timeperframe.numerator = 1; + cam->nominal_timeperframe.denominator = 15; + + /* calculate xclk based on the default capture format and default + * frame rate + */ + cam->xclk = cam->cam_sensor->calc_xclk(&cam->pix, + &cam->nominal_timeperframe, cam->sensor_data); + cam->cparm.timeperframe = cam->nominal_timeperframe; + + /* initialise the wait queue */ + init_waitqueue_head(&cam->new_video_frame); + + /* Initialise the DMA structures */ + camera_core_sgdma_init(cam); + + if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) { + printk(KERN_ERR CAM_NAME + ": could not register Video for Linux device\n"); + vfd->minor = -1; + goto init_error; + } + + printk(KERN_INFO CAM_NAME + ": registered device video%d [v4l2]\n", vfd->minor); + return 0; + +init_error: + camera_core_cleanup(); + return -ENODEV; +} + +MODULE_AUTHOR("Texas Instruments."); +MODULE_DESCRIPTION("OMAP Video for Linux camera driver"); +MODULE_LICENSE("GPL"); +module_param(video_nr, int, 0); +MODULE_PARM_DESC(video_nr, + "Minor number for video device (-1 ==> auto assign)"); +module_param(capture_mem, int, 0); +MODULE_PARM_DESC(capture_mem, + "Maximum amount of memory for capture buffers (default 4800KB)"); + +module_init(camera_core_init); +module_exit(camera_core_cleanup); + + diff -Nru a/drivers/media/video/omap/camera_core.h b/drivers/media/video/omap/camera_core.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/video/omap/camera_core.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,153 @@ +/* + * drivers/media/video/omap/camera_core.h + * + * Copyright (C) 2004 Texas Instruments, Inc. + * + * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef CAMERA_CORE__H +#define CAMERA_CORE__H + +struct camera_fh; + +#include +#include + +struct camera_device; +typedef void (*dma_callback_t)(void *arg1, void *arg2); + +struct sgdma_state { + const struct scatterlist *sglist; + int sglen; /* number of sglist entries */ + int next_sglist; /* index of next sglist entry to process */ + int queued_sglist; /* number of sglist entries queued for DMA */ + unsigned long csr; /* DMA return code */ + dma_callback_t callback; + void *arg; +}; + +/* NUM_SG_DMA is the number of scatter-gather DMA transfers that can be queued. + */ +#define NUM_SG_DMA VIDEO_MAX_FRAME+2 + +/* per-device data structure */ +struct camera_device { + struct device dev; + struct video_device *vfd; + + spinlock_t overlay_lock; /* spinlock for overlay DMA counter */ + int overlay_cnt; /* count of queued overlay DMA xfers */ + struct scatterlist overlay_sglist; + unsigned long overlay_base_phys; + unsigned long overlay_base; + unsigned long overlay_size; + + spinlock_t vbq_lock; /* spinlock for videobuf queues */ + struct videobuf_queue_ops vbq_ops; /* videobuf queue operations */ + unsigned long field_count; /* field counter for videobuf_buffer */ + + /* scatter-gather DMA management */ + spinlock_t sg_lock; + int free_sgdma; /* number of free sg dma slots */ + int next_sgdma; /* index of next sg dma slot to use */ + struct sgdma_state sgdma[NUM_SG_DMA]; + + /* The img_lock is used to serialize access to the image parameters for + * overlay and capture. Need to use spin_lock_irq when writing to the + * reading, streaming, and previewing parameters. A regular spin_lock + * will suffice for all other cases. + */ + spinlock_t img_lock; + + /* We allow reading from at most one filehandle at a time. + * non-NULL means reading is in progress. + */ + struct camera_fh *reading; + /* We allow streaming from at most one filehandle at a time. + * non-NULL means streaming is in progress. + */ + struct camera_fh *streaming; + /* We allow previewing from at most one filehandle at a time. + * non-NULL means previewing is in progress. + */ + struct camera_fh *previewing; + + /* capture parameters (frame rate, number of buffers) */ + struct v4l2_captureparm cparm; + + /* This is the frame period actually requested by the user. */ + struct v4l2_fract nominal_timeperframe; + + /* frequency (in Hz) of camera interface xclk output */ + unsigned long xclk; + + /* Pointer to the sensor interface ops */ + struct camera_sensor *cam_sensor; + void *sensor_data; + + /* Pointer to the camera interface hardware ops */ + struct camera_hardware *cam_hardware; + void *hardware_data; + + /* pix defines the size and pixel format of the image captured by the + * sensor. This also defines the size of the framebuffers. The + * same pool of framebuffers is used for video capture and video + * overlay. These parameters are set/queried by the + * VIDIOC_S_FMT/VIDIOC_G_FMT ioctls with a CAPTURE buffer type. + */ + struct v4l2_pix_format pix; + + /* crop defines the size and offset of the video overlay source window + * within the framebuffer. These parameters are set/queried by the + * VIDIOC_S_CROP/VIDIOC_G_CROP ioctls with an OVERLAY buffer type. + * The cropping rectangle allows a subset of the captured image to be + * previewed. It only affects the portion of the image previewed, not + * captured; the entire camera image is always captured. + */ + struct v4l2_rect crop; + + /* win defines the size and offset of the video overlay target window + * within the video display. These parameters are set/queried by the + * VIDIOC_S_FMT/VIDIOC_G_FMT ioctls with an OVERLAY buffer type. + */ + struct v4l2_window win; + + /* fbuf reflects the size of the video display. It is queried with the + * VIDIOC_G_FBUF ioctl. The size of the video display cannot be + * changed with the VIDIOC_S_FBUF ioctl. + */ + struct v4l2_framebuffer fbuf; + + /* end of generic stuff, the above should be common to all omaps */ + + /* note, 2420 uses videobuf to do caprure, it is more memory efficient + we need 1710 and 2420 do capture in the same way */ + /* Variables to store the capture state */ + /* Wait till DMA is completed */ + wait_queue_head_t new_video_frame; + char capture_completed; + char capture_started; + spinlock_t capture_lock; + struct scatterlist capture_sglist; + unsigned long capture_base; + unsigned long capture_base_phys; + +}; + +/* per-filehandle data structure */ +struct camera_fh { + struct camera_device *cam; + enum v4l2_buf_type type; + struct videobuf_queue vbq; +}; + +#define CAM_NAME "omap-camera" + +#endif /* CAMERA_CORE__H */ diff -Nru a/drivers/media/video/omap/camera_hw_if.h b/drivers/media/video/omap/camera_hw_if.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/video/omap/camera_hw_if.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,48 @@ +/* + * drivers/media/video/omap/camera_hw_if.h + * + * Copyright (C) 2004 Texas Instruments, Inc. + * + * Camera interface to OMAP camera capture drivers + * Camera interface hardware driver should implement this interface + * + * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef OMAP_CAMERA_HW_IF_H +#define OMAP_CAMERA_HW_IF_H + +#define LEN_HW_IF_NAME 31 + +struct sgdma_state; + +struct camera_hardware { + unsigned int version; //version of camera driver module + char name[LEN_HW_IF_NAME + 1]; + + void *(*init)(void); + int (*cleanup)(void *); + + int (*open)(void *); /* acquire h/w resources (irq,DMA), etc. */ + int (*close)(void *); /* free h/w resources, stop i/f */ + + int (*enable)(void *); + int (*disable)(void *); + + int (*abort)(void *); + + int (*set_xclk)(int, void *); + + int (*init_dma)(void *); + int (*start_dma)(struct sgdma_state *, void (*)(void *arg1, void *arg2), + void *, void *, void *); + int (*finish_dma)(void *); +}; + +#endif /* OMAP_CAMERA_HW_IF_H */ diff -Nru a/drivers/media/video/omap/omap16xxcam.c b/drivers/media/video/omap/omap16xxcam.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/video/omap/omap16xxcam.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,582 @@ +/* + * drivers/media/video/omap/omap16xxcam.c + * + * Copyright (C) 2004 Texas Instruments, Inc. + * + * Video-for-Linux (Version 2) camera capture driver for + * the OMAP H2 and H3 camera controller. + * + * leverage some code from CEE distribution + * Copyright (C) 2003-2004 MontaVista Software, Inc. + * + * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "omap16xxcam.h" +#include "camera_hw_if.h" +#include "camera_core.h" + +#define CONF_CAMERAIF_RESET_R 5 +#define EN_PER 0 + +/* NUM_CAMDMA_CHANNELS is the number of logical channels used for + * DMA data transfer. + */ +#define NUM_CAMDMA_CHANNELS 2 + +typedef struct { + unsigned int ctrlclock; /* 00 */ + unsigned int it_status; /* 04 */ + unsigned int mode; /* 08 */ + unsigned int status; /* 0C */ + unsigned int camdata; /* 10 */ + unsigned int gpio; /* 14 */ + unsigned int peak_counter; /* 18 */ +} camera_regs_t; + +struct camdma_state { + dma_callback_t callback; + void *arg1; + void *arg2; +}; + +struct omap16xxcam { + camera_regs_t *camera_regs; + unsigned long iobase_phys; + + /* frequncy (in Hz) of camera interface functional clock (ocp_clk) */ + unsigned long ocp_clk; + + /* dma related stuff */ + spinlock_t dma_lock; + int free_dmach; + int next_dmach; + struct camdma_state camdma[NUM_CAMDMA_CHANNELS]; + int dma_channel_number1; + int dma_channel_number2; + + wait_queue_head_t vsync_wait; + + int new; +}; +static struct omap16xxcam hardware_data; + +static int omap16xxcam_set_xclk(int, void *); +static void omap16xx_cam_dma_link_callback(int, unsigned short, void *); + +/* Clears the camera data FIFO by setting RAZ_FIFO bit in MODE configuration + register. */ +static void +omap16xx_cam_clear_fifo(struct omap16xxcam *data) +{ + data->camera_regs->mode |= RAZ_FIFO; + udelay(10); + data->camera_regs->mode &= ~RAZ_FIFO; +} + +static void +omap16xx_cam_reset(struct omap16xxcam *data, int yes) +{ + if (machine_is_omap_h3()) + data->camera_regs->gpio = yes ? 0 : 1; + else + data->camera_regs->gpio = yes ? 1 : 0; +} + +static void +omap16xx_cam_init(void) +{ + /* + * FIXME - Use mux API's instead of directly writing in to MUX registers + */ + omap_writel(omap_readl(FUNC_MUX_CTRL_4) & ~(0x1ff << 21), FUNC_MUX_CTRL_4); + omap_writel(0, FUNC_MUX_CTRL_5); + omap_writel(omap_readl(PULL_DWN_CTRL_0) & ~(0x1FFF << 17), PULL_DWN_CTRL_0); + omap_writel(omap_readl(PU_PD_SEL_0) & ~(0x1FFF << 17), PU_PD_SEL_0); + + omap_writel(0xeaef, COMP_MODE_CTRL_0); + omap_writel(omap_readl(OMAP1610_RESET_CONTROL) & ~(1 << CONF_CAMERAIF_RESET_R), + OMAP1610_RESET_CONTROL); + omap_writel(omap_readl(OMAP1610_RESET_CONTROL) | (1 << CONF_CAMERAIF_RESET_R), + OMAP1610_RESET_CONTROL); + + /* Enable peripheral reset */ + omap_writew(omap_readw(ARM_RSTCT2) | (1 << EN_PER), ARM_RSTCT2); + + /* enable peripheral clock */ + if (machine_is_omap_h3()) + clk_enable(clk_get(0, "tc2_ck")); + else { + clk_enable(clk_get(0, "armper_ck")); + clk_enable(clk_get(0, "armxor_ck")); + } +} + +static void +omap16xx_cam_waitfor_syncedge(struct omap16xxcam *data, u32 edge_mask) +{ + data->camera_regs->mode = (FIFO_TRIGGER_LVL << THRESHOLD_BIT) | edge_mask; + do { + interruptible_sleep_on(&data->vsync_wait); + } while (signal_pending(current)); +} + +static void +omap16xx_cam_configure_dma(struct omap16xxcam *data) +{ + + data->camera_regs->mode = (FIFO_TRIGGER_LVL << THRESHOLD_BIT) + | EN_DMA | EN_FIFO_FULL; + data->camera_regs->ctrlclock |= LCLK_EN; +} + +/* acquire h/w resources DMA */ +static int +omap16xx_cam_link_open(struct omap16xxcam *data) +{ + int ret; + + /* Acquire first dma channel */ + if ((ret = omap_request_dma(OMAP_DMA_CAMERA_IF_RX, + "camera dma 1", omap16xx_cam_dma_link_callback, + (void *)data, &data->dma_channel_number1))) { + return ret; + } + /* Acquire second dma channel */ + if ((ret = omap_request_dma(OMAP_DMA_CAMERA_IF_RX, + "camera dma 2", omap16xx_cam_dma_link_callback, + (void *)data, &data->dma_channel_number2))) { + printk ("No DMA available for camera\n"); + return ret; + } + data->next_dmach = data->dma_channel_number1; + omap_writew(data->dma_channel_number2, + OMAP_DMA_CLNK_CTRL(data->dma_channel_number1)); + omap_writew(data->dma_channel_number1, + OMAP_DMA_CLNK_CTRL(data->dma_channel_number2)); + + return 0; +} + +/* free h/w resources, stop i/f */ +static int +omap16xx_cam_link_close(struct omap16xxcam *data) +{ + /* free dma channels */ + omap_stop_dma(data->dma_channel_number1); + omap_stop_dma(data->dma_channel_number2); + + omap_free_dma (data->dma_channel_number1); + omap_free_dma (data->dma_channel_number2); + + return 0; +} + +/* dma callback routine. */ +static void +omap16xx_cam_dma_link_callback(int lch, unsigned short ch_status, void *data) +{ + int count; + void *arg1, *arg2; + struct sgdma_state *sgdma = sgdma; + struct omap16xxcam *cam = (struct omap16xxcam *)data; + dma_callback_t callback; + + spin_lock(&cam->dma_lock); + if (cam->free_dmach == 2) + { + printk("callback all CHANNELS WERE IDLE \n"); + spin_unlock(&cam->dma_lock); + return; + } + if (cam->free_dmach == 0) { + lch = cam->next_dmach; + } else { + lch = cam->next_dmach == cam->dma_channel_number1 ? + cam->dma_channel_number2 : cam->dma_channel_number1; + } + + while (cam->free_dmach < 2) + { + if ((omap_readw(OMAP_DMA_CCR(lch)) & (1 << 7) )) + break; + + count = (lch == cam->dma_channel_number2) ? 1 : 0; + + callback = cam->camdma[count].callback; + arg1 = cam->camdma[count].arg1; + arg2 = cam->camdma[count].arg2; + cam->free_dmach++; + + spin_unlock(&cam->dma_lock); + callback(arg1, arg2); + spin_lock(&cam->dma_lock); + + lch = (lch == cam->dma_channel_number2) ? cam->dma_channel_number1 : + cam->dma_channel_number2; + } + spin_unlock(&cam->dma_lock); + +} + +static irqreturn_t +omap16xx_cam_isr(int irq, void *client_data, struct pt_regs *regs) +{ + struct omap16xxcam *data = (struct omap16xxcam *)client_data; + unsigned int itstat = data->camera_regs->it_status; + + /* VSYNC UP interrupt, start filling FIFO and enabling DMA */ + if (itstat & V_UP) { + data->camera_regs->mode &= ~EN_V_UP; + omap16xx_cam_clear_fifo(data); + omap16xx_cam_configure_dma(data); + omap_start_dma(data->next_dmach); + wake_up_interruptible(&data->vsync_wait); + } + + if (itstat & V_DOWN) { + data->camera_regs->mode &= ~EN_V_DOWN; + wake_up_interruptible(&data->vsync_wait); + } + + if (itstat & H_UP) + printk("H_UP\n"); + + if (itstat & H_DOWN) + printk("H_DOWN\n"); + + if (itstat & FIFO_FULL) { + omap16xx_cam_clear_fifo(data); + printk("FIFO_FULL\n"); + } + + if (itstat & DATA_XFER) + printk("DATA_TRANS\n"); + + return IRQ_HANDLED; +} + +/* ------------- below are interface functions ----------------- */ +/* ------------- these functions are named omap16xxcam_ -- */ +static int +omap16xxcam_init_dma(void *priv) +{ + int ch; + struct omap16xxcam *data = (struct omap16xxcam *) priv; + + spin_lock_init(&data->dma_lock); + data->free_dmach = 2; + for (ch = 0; ch < 2; ++ch) { + data->camdma[ch].callback = NULL; + data->camdma[ch].arg1 = NULL; + data->camdma[ch].arg2 = NULL; + } + + return 0; +} + +/* start the dma of chains */ +static int +omap16xxcam_start_dma(struct sgdma_state *sgdma, + dma_callback_t callback, void *arg1, void *arg2, void *priv) +{ + struct omap16xxcam *data = (struct omap16xxcam *) priv; + struct scatterlist *sglist; + unsigned long irqflags; + int dmach; + int prev_dmach; + int count; + + spin_lock_irqsave(&data->dma_lock, irqflags); + sglist = (struct scatterlist *)(sgdma->sglist + sgdma->next_sglist); + + if (!data->free_dmach) { + spin_unlock_irqrestore(&data->dma_lock, irqflags); + return -EBUSY; + } + dmach = data->next_dmach; + count = (dmach == data->dma_channel_number2) ? 1:0; + data->camdma[count].callback = callback; + data->camdma[count].arg1 = arg1; + data->camdma[count].arg2 = arg2; + + if (machine_is_omap_h3()) + omap_set_dma_src_params(dmach, OMAP_DMA_PORT_OCP_T1, + OMAP_DMA_AMODE_CONSTANT, CAM_CAMDATA_REG); + else + omap_set_dma_src_params(dmach, OMAP_DMA_PORT_TIPB, + OMAP_DMA_AMODE_CONSTANT, CAM_CAMDATA_REG); + + omap_set_dma_dest_params(dmach, OMAP_DMA_PORT_EMIFF, + OMAP_DMA_AMODE_POST_INC, sg_dma_address(sglist)); + + omap_set_dma_transfer_params(dmach, OMAP_DMA_DATA_TYPE_S32, + FIFO_TRIGGER_LVL, + sg_dma_len(sglist)/(4 * FIFO_TRIGGER_LVL), + OMAP_DMA_SYNC_FRAME); + + + omap_writew(omap_readw(OMAP_DMA_CLNK_CTRL(dmach)) & ~(1<<15), + OMAP_DMA_CLNK_CTRL(dmach)); + + prev_dmach = (dmach == data->dma_channel_number2) ? + data->dma_channel_number1 : data->dma_channel_number2; + + if (data->new) { + data->new = 0; + omap16xx_cam_waitfor_syncedge(data, EN_V_UP); + } else { + if (omap_readw(OMAP_DMA_CCR(prev_dmach)) & (1 << 7)) { + omap_writew((omap_readw(OMAP_DMA_CLNK_CTRL(prev_dmach)) | + (1 << 15)), + OMAP_DMA_CLNK_CTRL(prev_dmach)); + } + else { + /* no transfer is in progress */ + omap_start_dma(dmach); + } + } + + data->next_dmach = prev_dmach; + data->free_dmach--; + spin_unlock_irqrestore(&data->dma_lock, irqflags); + return 0; +} +int static +omap16xxcam_finish_dma(void *priv) +{ + struct omap16xxcam *data = (struct omap16xxcam *) priv; + + while (data->free_dmach < 2) + mdelay(1); + + return 0; +} + + +/* Enables the camera. Takes camera out of reset. Enables the clocks. */ +static int +omap16xxcam_enable(void *priv) +{ + struct omap16xxcam *data = (struct omap16xxcam *) priv; + + omap16xx_cam_reset(data, 1); + + /* give clock to camera_module */ + data->camera_regs->mode = (FIFO_TRIGGER_LVL << THRESHOLD_BIT); + data->camera_regs->ctrlclock = MCLK_EN | CAMEXCLK_EN; + + omap16xx_cam_clear_fifo(data); + + /* wait for camera to settle down */ + mdelay(5); + + return 0; +} + +/* Disables all the camera clocks. Put the camera interface in reset. */ +static int +omap16xxcam_disable(void *priv) +{ + struct omap16xxcam *data = (struct omap16xxcam *) priv; + + omap16xx_cam_clear_fifo(data); + + data->camera_regs->ctrlclock = 0x00000000; + data->camera_regs->mode = 0x00000000; + + omap16xx_cam_reset(data, 0); + + return 0; +} + +/* Abort the data transfer */ +static int +omap16xxcam_abort(void *priv) +{ + return omap16xxcam_disable(priv); +} + +static int +omap16xxcam_set_xclk(int xclk, void *priv) +{ + struct omap16xxcam *data = (struct omap16xxcam *) priv; + int xclk_val; + int divisor = 1; + divisor = data->ocp_clk/xclk; + if ( divisor * xclk < data->ocp_clk) + ++divisor; + + switch (divisor) { + case 1: + case 2: + xclk_val = FOSCMOD_TC2_CK2; + break; + case 3: + xclk_val = FOSCMOD_TC2_CK3; + break; + case 4: + case 5: + case 6: + case 7: + xclk_val = FOSCMOD_TC2_CK4; + break; + case 8: + case 9: + xclk_val = FOSCMOD_TC2_CK8; + break; + case 10: + case 11: + xclk_val = FOSCMOD_TC2_CK10; + break; + case 12: + case 13: + case 14: + case 15: + xclk_val = FOSCMOD_TC2_CK12; + break; + case 16: + xclk_val = FOSCMOD_TC2_CK16; + break; + default: + xclk_val = FOSCMOD_TC2_CK16; + } + + /* follow the protocol to change the XCLK clock */ + data->camera_regs->ctrlclock &= ~CAMEXCLK_EN; + data->camera_regs->ctrlclock |= xclk_val; + data->camera_regs->ctrlclock |= CAMEXCLK_EN; + + return (data->ocp_clk/divisor); +} + +static int +omap16xxcam_open(void *priv) +{ + struct omap16xxcam *data = (struct omap16xxcam *) priv; + int ret; + + if ((ret = request_irq(INT_CAMERA, omap16xx_cam_isr, SA_INTERRUPT, + "camera", data))) { + printk("FAILED to aquire irq\n"); + return ret; + } + + data->new = 1; + omap16xxcam_enable(priv); + + return omap16xx_cam_link_open(data); +} + +static int +omap16xxcam_close(void *priv) +{ + struct omap16xxcam *data = (struct omap16xxcam *) priv; + + omap16xxcam_disable(priv); + + free_irq(INT_CAMERA, data); + + return omap16xx_cam_link_close(data); +} + +static int +omap16xxcam_cleanup(void *priv) +{ + struct omap16xxcam *data = (struct omap16xxcam *) priv; + + if (machine_is_omap_h3()) { + if (data->camera_regs) { + iounmap((void *)data->camera_regs); + data->camera_regs= NULL; + } + } + + if (data->iobase_phys) { + release_mem_region(data->iobase_phys, CAMERA_IOSIZE); + data->iobase_phys = 0; + } + return 0; +} + +/* Initialise the OMAP camera interface */ +static void * +omap16xxcam_init(void) +{ + unsigned long cam_iobase; + + if (!request_region(CAMERA_BASE, CAMERA_IOSIZE, "OAMP16xx Camera")) { + printk ("OMAP16XX Parallel Camera Interface is already in use\n"); + return NULL; + } + + if (machine_is_omap_h3()) { + cam_iobase = (unsigned long) ioremap (CAMERA_BASE, CAMERA_IOSIZE); + if (!cam_iobase) { + printk("CANNOT MAP CAMERA REGISTER\n"); + return NULL; + } + } + else + cam_iobase = io_p2v(CAMERA_BASE); + + /* Set the base address of the camera registers */ + hardware_data.camera_regs = (camera_regs_t *)cam_iobase; + hardware_data.iobase_phys = (unsigned long) CAMERA_BASE; + /* get the input clock value to camera interface and store it */ + if (machine_is_omap_h3()) + hardware_data.ocp_clk = clk_get_rate(clk_get(0, "tc_ck")); + else + hardware_data.ocp_clk = clk_get_rate(clk_get(0, "mpuper_ck")); + + /* Init the camera IF */ + omap16xx_cam_init(); + /* enable it. This is needed for sensor detection */ + omap16xxcam_enable((void*)&hardware_data); + /* Init dma data */ + omap16xxcam_init_dma((void*)&hardware_data); + + init_waitqueue_head(&hardware_data.vsync_wait); + return (void*)&hardware_data; +} + +struct camera_hardware camera_hardware_if = { + version : 0x01, + name : "OMAP16xx Camera Parallel", + init : omap16xxcam_init, + cleanup : omap16xxcam_cleanup, + open : omap16xxcam_open, + close : omap16xxcam_close, + enable : omap16xxcam_enable, + disable : omap16xxcam_disable, + abort : omap16xxcam_abort, + set_xclk : omap16xxcam_set_xclk, + init_dma : omap16xxcam_init_dma, + start_dma : omap16xxcam_start_dma, + finish_dma : omap16xxcam_finish_dma, +}; + diff -Nru a/drivers/media/video/omap/omap16xxcam.h b/drivers/media/video/omap/omap16xxcam.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/video/omap/omap16xxcam.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,106 @@ +/* + * drivers/media/video/omap/omap16xxcam.h + * + * Copyright (C) 2004 Texas Instruments, Inc. + * + * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef OMAP_16XX_CAM_H +#define OMAP_16XX_CAM_H + +#define DMA_ELEM_SIZE 4 +#define FIFO_TRIGGER_LVL (32) + +/* + * --------------------------------------------------------------------------- + * OMAP1610 Camera Interface + * --------------------------------------------------------------------------- + */ + +#ifdef CONFIG_MACH_OMAP_H3 +#define CAMERA_BASE (0x2007d800) +#else +#define CAMERA_BASE (IO_PHYS + 0x6800) +#endif + +#define CAM_CTRLCLOCK_REG (CAMERA_BASE + 0x00) +#define CAM_IT_STATUS_REG (CAMERA_BASE + 0x04) +#define CAM_MODE_REG (CAMERA_BASE + 0x08) +#define CAM_STATUS_REG (CAMERA_BASE + 0x0C) +#define CAM_CAMDATA_REG (CAMERA_BASE + 0x10) +#define CAM_GPIO_REG (CAMERA_BASE + 0x14) +#define CAM_PEAK_CTR_REG (CAMERA_BASE + 0x18) +#define CAMERA_IOSIZE 0x1C + +/* CTRLCLOCK bit shifts */ +#define FOSCMOD_BIT 0 +#define FOSCMOD_MASK (0x7 << FOSCMOD_BIT) +#define FOSCMOD_12MHz 0x0 +#define FOSCMOD_6MHz 0x2 +#define FOSCMOD_9_6MHz 0x4 +#define FOSCMOD_24MHz 0x5 +#define FOSCMOD_8MHz 0x6 +#define FOSCMOD_TC2_CK2 0x3 +#define FOSCMOD_TC2_CK3 0x1 +#define FOSCMOD_TC2_CK4 0x5 +#define FOSCMOD_TC2_CK8 0x0 +#define FOSCMOD_TC2_CK10 0x4 +#define FOSCMOD_TC2_CK12 0x6 +#define FOSCMOD_TC2_CK16 0x2 +#define POLCLK (1<<3) +#define CAMEXCLK_EN (1<<4) +#define MCLK_EN (1<<5) +#define DPLL_EN (1<<6) +#define LCLK_EN (1<<7) + +/* IT_STATUS bit shifts */ +#define V_UP (1<<0) +#define V_DOWN (1<<1) +#define H_UP (1<<2) +#define H_DOWN (1<<3) +#define FIFO_FULL (1<<4) +#define DATA_XFER (1<<5) + +/* MODE bit shifts */ +#define CAMOSC (1<<0) +#define IMGSIZE_BIT 1 +#define IMGSIZE_MASK (0x3 << IMGSIZE_BIT) +#define IMGSIZE_CIF (0x0 << IMGSIZE_BIT) /* 352x288 */ +#define IMGSIZE_QCIF (0x1 << IMGSIZE_BIT) /* 176x144 */ +#define IMGSIZE_VGA (0x2 << IMGSIZE_BIT) /* 640x480 */ +#define IMGSIZE_QVGA (0x3 << IMGSIZE_BIT) /* 320x240 */ +#define ORDERCAMD (1<<3) +#define EN_V_UP (1<<4) +#define EN_V_DOWN (1<<5) +#define EN_H_UP (1<<6) +#define EN_H_DOWN (1<<7) +#define EN_DMA (1<<8) +#define THRESHOLD (1<<9) +#define THRESHOLD_BIT 9 +#define THRESHOLD_MASK (0x7f<<9) +#define EN_NIRQ (1<<16) +#define EN_FIFO_FULL (1<<17) +#define RAZ_FIFO (1<<18) + +/* STATUS bit shifts */ +#define VSTATUS (1<<0) +#define HSTATUS (1<<1) + +/* GPIO bit shifts */ +#define CAM_RST (1<<0) + + +#define XCLK_6MHZ 6000000 +#define XCLK_8MHZ 8000000 +#define XCLK_9_6MHZ 9000000 +#define XCLK_12MHZ 12000000 +#define XCLK_24MHZ 24000000 + +#endif /* OMAP_16XX_CAM_H */ diff -Nru a/drivers/media/video/omap/ov9640.h b/drivers/media/video/omap/ov9640.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/video/omap/ov9640.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,179 @@ +/* + * drivers/media/video/omap/ov9640.h + * + * Register definitions for the OmniVision OV9640 CameraChip. + * + * Author: Andy Lowe (source@mvista.com) + * + * Copyright (C) 2004 MontaVista Software, Inc. + * Copyright (C) 2004 Texas Instruments. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef OV9640_H +#define OV9640_H + +/* The OV9640 I2C sensor chip has a fixed slave address of 0x30. */ +#ifdef CONFIG_OMAP24XX_VIRTIO +#define OV9640_I2C_ADDR 0x60 +#else +#define OV9640_I2C_ADDR 0x30 +#endif + +/* define register offsets for the OV9640 sensor chip */ +#define OV9640_GAIN 0x00 +#define OV9640_BLUE 0x01 +#define OV9640_RED 0x02 +#define OV9640_VREF 0x03 +#define OV9640_COM1 0x04 +#define OV9640_BAVE 0x05 +#define OV9640_GEAVE 0x06 +#define OV9640_RAVE 0x08 +#define OV9640_COM2 0x09 +#define OV9640_PID 0x0A +#define OV9640_VER 0x0B +#define OV9640_COM3 0x0C +#define OV9640_COM4 0x0D +#define OV9640_COM5 0x0E +#define OV9640_COM6 0x0F +#define OV9640_AECH 0x10 +#define OV9640_CLKRC 0x11 +#define OV9640_COM7 0x12 +#define OV9640_COM8 0x13 +#define OV9640_COM9 0x14 +#define OV9640_COM10 0x15 +#define OV9640_HSTRT 0x17 +#define OV9640_HSTOP 0x18 +#define OV9640_VSTRT 0x19 +#define OV9640_VSTOP 0x1A +#define OV9640_PSHFT 0x1B +#define OV9640_MIDH 0x1C +#define OV9640_MIDL 0x1D +#define OV9640_MVFP 0x1E +#define OV9640_LAEC 0x1F +#define OV9640_BOS 0x20 +#define OV9640_GBOS 0x21 +#define OV9640_GROS 0x22 +#define OV9640_ROS 0x23 +#define OV9640_AEW 0x24 +#define OV9640_AEB 0x25 +#define OV9640_VPT 0x26 +#define OV9640_BBIAS 0x27 +#define OV9640_GBBIAS 0x28 +#define OV9640_EXHCH 0x2A +#define OV9640_EXHCL 0x2B +#define OV9640_RBIAS 0x2C +#define OV9640_ADVFL 0x2D +#define OV9640_ADVFH 0x2E +#define OV9640_YAVE 0x2F +#define OV9640_HSYST 0x30 +#define OV9640_HSYEN 0x31 +#define OV9640_HREF 0x32 +#define OV9640_CHLF 0x33 +#define OV9640_ARBLM 0x34 +#define OV9640_ADC 0x37 +#define OV9640_ACOM 0x38 +#define OV9640_OFON 0x39 +#define OV9640_TSLB 0x3A +#define OV9640_COM11 0x3B +#define OV9640_COM12 0x3C +#define OV9640_COM13 0x3D +#define OV9640_COM14 0x3E +#define OV9640_EDGE 0x3F +#define OV9640_COM15 0x40 +#define OV9640_COM16 0x41 +#define OV9640_COM17 0x42 +#define OV9640_MTX1 0x4F +#define OV9640_MTX2 0x50 +#define OV9640_MTX3 0x51 +#define OV9640_MTX4 0x52 +#define OV9640_MTX5 0x53 +#define OV9640_MTX6 0x54 +#define OV9640_MTX7 0x55 +#define OV9640_MTX8 0x56 +#define OV9640_MTX9 0x57 +#define OV9640_MTXS 0x58 +#define OV9640_LCC1 0x62 +#define OV9640_LCC2 0x63 +#define OV9640_LCC3 0x64 +#define OV9640_LCC4 0x65 +#define OV9640_LCC5 0x66 +#define OV9640_MANU 0x67 +#define OV9640_MANV 0x68 +#define OV9640_HV 0x69 +#define OV9640_MBD 0x6A +#define OV9640_DBLV 0x6B +#define OV9640_GSP1 0x6C +#define OV9640_GSP2 0x6D +#define OV9640_GSP3 0x6E +#define OV9640_GSP4 0x6F +#define OV9640_GSP5 0x70 +#define OV9640_GSP6 0x71 +#define OV9640_GSP7 0x72 +#define OV9640_GSP8 0x73 +#define OV9640_GSP9 0x74 +#define OV9640_GSP10 0x75 +#define OV9640_GSP11 0x76 +#define OV9640_GSP12 0x77 +#define OV9640_GSP13 0x78 +#define OV9640_GSP14 0x79 +#define OV9640_GSP15 0x7A +#define OV9640_GSP16 0x7B +#define OV9640_GST1 0x7C +#define OV9640_GST2 0x7D +#define OV9640_GST3 0x7E +#define OV9640_GST4 0x7F +#define OV9640_GST5 0x80 +#define OV9640_GST6 0x81 +#define OV9640_GST7 0x82 +#define OV9640_GST8 0x83 +#define OV9640_GST9 0x84 +#define OV9640_GST10 0x85 +#define OV9640_GST11 0x86 +#define OV9640_GST12 0x87 +#define OV9640_GST13 0x88 +#define OV9640_GST14 0x89 +#define OV9640_GST15 0x8A + +#define OV9640_NUM_REGS (OV9640_GST15 + 1) + +#define OV9640_PID_MAGIC 0x96 /* high byte of product ID number */ +#define OV9640_VER_REV2 0x48 /* low byte of product ID number */ +#define OV9640_VER_REV3 0x49 /* low byte of product ID number */ +#define OV9640_MIDH_MAGIC 0x7F /* high byte of mfg ID */ +#define OV9640_MIDL_MAGIC 0xA2 /* low byte of mfg ID */ + +/* define a structure for ov9640 register initialization values */ +struct ov9640_reg { + unsigned char reg; + unsigned char val; +}; + +enum image_size { QQCIF, QQVGA, QCIF, QVGA, CIF, VGA, SXGA }; +enum pixel_format { YUV, RGB565, RGB555 }; +#define NUM_IMAGE_SIZES 7 +#define NUM_PIXEL_FORMATS 3 + +struct capture_size { + unsigned long width; + unsigned long height; +}; + +/* Array of image sizes supported by OV9640. These must be ordered from + * smallest image size to largest. + */ +const static struct capture_size ov9640_sizes[] = { + { 88, 72 }, /* QQCIF */ + { 160, 120 }, /* QQVGA */ + { 176, 144 }, /* QCIF */ + { 320, 240 }, /* QVGA */ + { 352, 288 }, /* CIF */ + { 640, 480 }, /* VGA */ + { 1280, 960 }, /* SXGA */ +}; + +#endif /* ifndef OV9640_H */ + diff -Nru a/drivers/media/video/omap/sensor_if.h b/drivers/media/video/omap/sensor_if.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/video/omap/sensor_if.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,49 @@ + +/* + * drivers/media/video/omap/sensor_if.h + * + * Copyright (C) 2004 Texas Instruments, Inc. + * + * Sensor interface to OMAP camera capture drivers + * Sensor driver should implement this interface + * + * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef OMAP_SENSOR_IF_H +#define OMAP_SENSOR_IF_H + +#define LEN_SENSOR_NAME 31 + +struct camera_sensor { + unsigned int version; + char name[LEN_SENSOR_NAME + 1]; + + void *(*init)(struct v4l2_pix_format *); + int (*cleanup)(void *); + + int (*power_on)(void *); + int (*power_off)(void *); + + int (*enum_pixformat)(struct v4l2_fmtdesc *, void *); + int (*try_format) (struct v4l2_pix_format *, void *); + + unsigned long (*calc_xclk) (struct v4l2_pix_format *, + struct v4l2_fract *, void *); + + int (*configure) (struct v4l2_pix_format *, unsigned long, + struct v4l2_fract *, void *); + + int (*query_control) (struct v4l2_queryctrl *, void *); + int (*get_control) (struct v4l2_control *, void *); + int (*set_control) (struct v4l2_control *, void *); + +}; + +#endif diff -Nru a/drivers/media/video/omap/sensor_ov9640.c b/drivers/media/video/omap/sensor_ov9640.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/media/video/omap/sensor_ov9640.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,1216 @@ + +/* + * drivers/media/video/omap/sensor_ov9640.c + * + * Ov9640 Sensor driver for OMAP camera sensor interface + * + * Author: Andy Lowe (source@mvista.com) + * + * Copyright (C) 2004 MontaVista Software, Inc. + * Copyright (C) 2004 Texas Instruments. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include + +#include "sensor_if.h" +#include "ov9640.h" + +#define CAMERA_OV9640 +#ifdef CAMERA_OV9640 + +struct ov9640_sensor { + /* I2C parameters */ + struct i2c_client client; + struct i2c_driver driver; + int ver; /* OV9640 version */ +}; + +static struct ov9640_sensor ov9640; + +/* list of image formats supported by OV9640 sensor */ +const static struct v4l2_fmtdesc ov9640_formats[] = { + { + /* Note: V4L2 defines RGB565 as: + * + * Byte 0 Byte 1 + * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3 + * + * We interpret RGB565 as: + * + * Byte 0 Byte 1 + * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3 + */ + .description = "RGB565, le", + .pixelformat = V4L2_PIX_FMT_RGB565, + },{ + /* Note: V4L2 defines RGB565X as: + * + * Byte 0 Byte 1 + * b4 b3 b2 b1 b0 g5 g4 g3 g2 g1 g0 r4 r3 r2 r1 r0 + * + * We interpret RGB565X as: + * + * Byte 0 Byte 1 + * r4 r3 r2 r1 r0 g5 g4 g3 g2 g1 g0 b4 b3 b2 b1 b0 + */ + .description = "RGB565, be", + .pixelformat = V4L2_PIX_FMT_RGB565X, + }, + { + .description = "YUYV (YUV 4:2:2), packed", + .pixelformat = V4L2_PIX_FMT_YUYV, + },{ + .description = "UYVY, packed", + .pixelformat = V4L2_PIX_FMT_UYVY, + }, + { + /* Note: V4L2 defines RGB555 as: + * + * Byte 0 Byte 1 + * g2 g1 g0 r4 r3 r2 r1 r0 x b4 b3 b2 b1 b0 g4 g3 + * + * We interpret RGB555 as: + * + * Byte 0 Byte 1 + * g2 g1 g0 b4 b3 b2 b1 b0 x r4 r3 r2 r1 r0 g4 g3 + */ + .description = "RGB555, le", + .pixelformat = V4L2_PIX_FMT_RGB555, + },{ + /* Note: V4L2 defines RGB555X as: + * + * Byte 0 Byte 1 + * x b4 b3 b2 b1 b0 g4 g3 g2 g1 g0 r4 r3 r2 r1 r0 + * + * We interpret RGB555X as: + * + * Byte 0 Byte 1 + * x r4 r3 r2 r1 r0 g4 g3 g2 g1 g0 b4 b3 b2 b1 b0 + */ + .description = "RGB555, be", + .pixelformat = V4L2_PIX_FMT_RGB555X, + } +}; + +#define NUM_CAPTURE_FORMATS (sizeof(ov9640_formats)/sizeof(ov9640_formats[0])) +#define NUM_OVERLAY_FORMATS 2 + +/* register initialization tables for OV9640 */ + +#define OV9640_REG_TERM 0xFF /* terminating list entry for reg */ +#define OV9640_VAL_TERM 0xFF /* terminating list entry for val */ + +/* common OV9640 register initialization for all image sizes, pixel formats, + * and frame rates + */ +const static struct ov9640_reg ov9640_common[] = { + { 0x12, 0x80 }, { 0x11, 0x80 }, { 0x13, 0x88 }, /* COM7, CLKRC, COM8 */ + { 0x01, 0x58 }, { 0x02, 0x24 }, { 0x04, 0x00 }, /* BLUE, RED, COM1 */ + { 0x0E, 0x81 }, { 0x0F, 0x4F }, { 0x14, 0xcA }, /* COM5, COM6, COM9 */ + { 0x16, 0x02 }, { 0x1B, 0x01 }, { 0x24, 0x70 }, /* ?, PSHFT, AEW */ + { 0x25, 0x68 }, { 0x26, 0xD3 }, { 0x27, 0x90 }, /* AEB, VPT, BBIAS */ + { 0x2A, 0x00 }, { 0x2B, 0x00 }, { 0x32, 0x24 }, /* EXHCH, EXHCL, HREF */ + { 0x33, 0x02 }, { 0x37, 0x02 }, { 0x38, 0x13 }, /* CHLF, ADC, ACOM */ + { 0x39, 0xF0 }, { 0x3A, 0x00 }, { 0x3B, 0x01 }, /* OFON, TSLB, COM11 */ + { 0x3D, 0x90 }, { 0x3E, 0x02 }, { 0x3F, 0xF2 }, /* COM13, COM14, EDGE */ + { 0x41, 0x02 }, { 0x42, 0xC8 }, /* COM16, COM17 */ + { 0x43, 0xF0 }, { 0x44, 0x10 }, { 0x45, 0x6C }, /* ?, ?, ? */ + { 0x46, 0x6C }, { 0x47, 0x44 }, { 0x48, 0x44 }, /* ?, ?, ? */ + { 0x49, 0x03 }, { 0x59, 0x49 }, { 0x5A, 0x94 }, /* ?, ?, ? */ + { 0x5B, 0x46 }, { 0x5C, 0x84 }, { 0x5D, 0x5C }, /* ?, ?, ? */ + { 0x5E, 0x08 }, { 0x5F, 0x00 }, { 0x60, 0x14 }, /* ?, ?, ? */ + { 0x61, 0xCE }, /* ? */ + { 0x62, 0x70 }, { 0x63, 0x00 }, { 0x64, 0x04 }, /* LCC1, LCC2, LCC3 */ + { 0x65, 0x00 }, { 0x66, 0x00 }, /* LCC4, LCC5 */ + { 0x69, 0x00 }, { 0x6A, 0x3E }, { 0x6B, 0x3F }, /* HV, MBD, DBLV */ + { 0x6C, 0x40 }, { 0x6D, 0x30 }, { 0x6E, 0x4B }, /* GSP1, GSP2, GSP3 */ + { 0x6F, 0x60 }, { 0x70, 0x70 }, { 0x71, 0x70 }, /* GSP4, GSP5, GSP6 */ + { 0x72, 0x70 }, { 0x73, 0x70 }, { 0x74, 0x60 }, /* GSP7, GSP8, GSP9 */ + { 0x75, 0x60 }, { 0x76, 0x50 }, { 0x77, 0x48 }, /* GSP10,GSP11,GSP12 */ + { 0x78, 0x3A }, { 0x79, 0x2E }, { 0x7A, 0x28 }, /* GSP13,GSP14,GSP15 */ + { 0x7B, 0x22 }, { 0x7C, 0x04 }, { 0x7D, 0x07 }, /* GSP16,GST1, GST2 */ + { 0x7E, 0x10 }, { 0x7F, 0x28 }, { 0x80, 0x36 }, /* GST3, GST4, GST5 */ + { 0x81, 0x44 }, { 0x82, 0x52 }, { 0x83, 0x60 }, /* GST6, GST7, GST8 */ + { 0x84, 0x6C }, { 0x85, 0x78 }, { 0x86, 0x8C }, /* GST9, GST10,GST11 */ + { 0x87, 0x9E }, { 0x88, 0xBB }, { 0x89, 0xD2 }, /* GST12,GST13,GST14 */ + { 0x8A, 0xE6 }, { 0x13, 0xaF }, { 0x15, 0x02 }, /* GST15, COM8 */ + { 0x22, 0x8a }, /* GROS */ + { OV9640_REG_TERM, OV9640_VAL_TERM } +}; + +/* OV9640 register configuration for all combinations of pixel format and + * image size + */ + /* YUV (YCbCr) QQCIF */ +const static struct ov9640_reg qqcif_yuv[] = { + { 0x12, 0x08 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */ + { 0x04, 0x24 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */ + { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */ + { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */ + { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */ + { 0x58, 0x0F }, /* MTXS */ + { OV9640_REG_TERM, OV9640_VAL_TERM } +}; + /* YUV (YCbCr) QQVGA */ +const static struct ov9640_reg qqvga_yuv[] = { + { 0x12, 0x10 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */ + { 0x04, 0x24 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */ + { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */ + { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */ + { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */ + { 0x58, 0x0F }, /* MTXS */ + { OV9640_REG_TERM, OV9640_VAL_TERM } +}; + /* YUV (YCbCr) QCIF */ +const static struct ov9640_reg qcif_yuv[] = { + { 0x12, 0x08 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */ + { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */ + { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */ + { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */ + { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */ + { 0x58, 0x0F }, /* MTXS */ + { OV9640_REG_TERM, OV9640_VAL_TERM } +}; + /* YUV (YCbCr) QVGA */ +const static struct ov9640_reg qvga_yuv[] = { + { 0x12, 0x10 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */ + { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */ + { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */ + { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */ + { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */ + { 0x58, 0x0F }, /* MTXS */ + { OV9640_REG_TERM, OV9640_VAL_TERM } +}; + /* YUV (YCbCr) CIF */ +const static struct ov9640_reg cif_yuv[] = { + { 0x12, 0x20 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */ + { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */ + { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */ + { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */ + { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */ + { 0x58, 0x0F }, /* MTXS */ + { OV9640_REG_TERM, OV9640_VAL_TERM } +}; + /* YUV (YCbCr) VGA */ +const static struct ov9640_reg vga_yuv[] = { + { 0x12, 0x40 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */ + { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */ + { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */ + { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */ + { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */ + { 0x58, 0x0F }, /* MTXS */ + { OV9640_REG_TERM, OV9640_VAL_TERM } +}; + /* YUV (YCbCr) SXGA */ +const static struct ov9640_reg sxga_yuv[] = { + { 0x12, 0x00 }, { 0x3C, 0x46 }, { 0x40, 0xC0 }, /* COM7, COM12, COM15 */ + { 0x04, 0x00 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */ + { 0x4F, 0x50 }, { 0x50, 0x43 }, { 0x51, 0x0D }, /* MTX1, MTX2, MTX3 */ + { 0x52, 0x19 }, { 0x53, 0x4C }, { 0x54, 0x65 }, /* MTX4, MTX5, MTX6 */ + { 0x55, 0x40 }, { 0x56, 0x40 }, { 0x57, 0x40 }, /* MTX7, MTX8, MTX9 */ + { 0x58, 0x0F }, /* MTXS */ + { OV9640_REG_TERM, OV9640_VAL_TERM } +}; + /* RGB565 QQCIF */ +const static struct ov9640_reg qqcif_565[] = { + { 0x12, 0x0C }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */ + { 0x04, 0x24 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */ + { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */ + { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */ + { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */ + { 0x58, 0x65 }, /* MTXS */ + { OV9640_REG_TERM, OV9640_VAL_TERM } +}; + /* RGB565 QQVGA */ +const static struct ov9640_reg qqvga_565[] = { + { 0x12, 0x14 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */ + { 0x04, 0x24 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */ + { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */ + { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */ + { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */ + { 0x58, 0x65 }, /* MTXS */ + { OV9640_REG_TERM, OV9640_VAL_TERM } +}; + /* RGB565 QCIF */ +const static struct ov9640_reg qcif_565[] = { + { 0x12, 0x0C }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */ + { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */ + { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */ + { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */ + { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */ + { 0x58, 0x65 }, /* MTXS */ + { OV9640_REG_TERM, OV9640_VAL_TERM } +}; + /* RGB565 QVGA */ +const static struct ov9640_reg qvga_565[] = { + { 0x12, 0x14 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */ + { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */ + { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */ + { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */ + { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */ + { 0x58, 0x65 }, /* MTXS */ + { OV9640_REG_TERM, OV9640_VAL_TERM } +}; + /* RGB565 CIF */ +const static struct ov9640_reg cif_565[] = { + { 0x12, 0x24 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */ + { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */ + { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */ + { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */ + { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */ + { 0x58, 0x65 }, /* MTXS */ + { OV9640_REG_TERM, OV9640_VAL_TERM } +}; + /* RGB565 VGA */ +const static struct ov9640_reg vga_565[] = { + { 0x12, 0x44 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */ + { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */ + { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */ + { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */ + { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */ + { 0x58, 0x65 }, /* MTXS */ + { OV9640_REG_TERM, OV9640_VAL_TERM } +}; + /* RGB565 SXGA */ +const static struct ov9640_reg sxga_565[] = { + { 0x12, 0x04 }, { 0x3C, 0x40 }, { 0x40, 0x10 }, /* COM7, COM12, COM15 */ + { 0x04, 0x00 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */ + { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */ + { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */ + { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */ + { 0x58, 0x65 }, /* MTXS */ + { OV9640_REG_TERM, OV9640_VAL_TERM } +}; + /* RGB555 QQCIF */ +const static struct ov9640_reg qqcif_555[] = { + { 0x12, 0x0C }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */ + { 0x04, 0x24 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */ + { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */ + { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */ + { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */ + { 0x58, 0x65 }, /* MTXS */ + { OV9640_REG_TERM, OV9640_VAL_TERM } +}; + /* RGB555 QQVGA */ +const static struct ov9640_reg qqvga_555[] = { + { 0x12, 0x14 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */ + { 0x04, 0x24 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */ + { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */ + { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */ + { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */ + { 0x58, 0x65 }, /* MTXS */ + { OV9640_REG_TERM, OV9640_VAL_TERM } +}; + /* RGB555 QCIF */ +const static struct ov9640_reg qcif_555[] = { + { 0x12, 0x0C }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */ + { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */ + { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */ + { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */ + { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */ + { 0x58, 0x65 }, /* MTXS */ + { OV9640_REG_TERM, OV9640_VAL_TERM } +}; + /* RGB555 QVGA */ +const static struct ov9640_reg qvga_555[] = { + { 0x12, 0x14 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */ + { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */ + { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */ + { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */ + { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */ + { 0x58, 0x65 }, /* MTXS */ + { OV9640_REG_TERM, OV9640_VAL_TERM } +}; + /* RGB555 CIF */ +const static struct ov9640_reg cif_555[] = { + { 0x12, 0x24 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */ + { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */ + { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */ + { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */ + { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */ + { 0x58, 0x65 }, /* MTXS */ + { OV9640_REG_TERM, OV9640_VAL_TERM } +}; + /* RGB555 VGA */ +const static struct ov9640_reg vga_555[] = { + { 0x12, 0x44 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */ + { 0x04, 0x00 }, { 0x0C, 0x04 }, { 0x0D, 0xC0 }, /* COM1, COM3, COM4 */ + { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */ + { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */ + { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */ + { 0x58, 0x65 }, /* MTXS */ + { OV9640_REG_TERM, OV9640_VAL_TERM } +}; + /* RGB555 SXGA */ +const static struct ov9640_reg sxga_555[] = { + { 0x12, 0x04 }, { 0x3C, 0x40 }, { 0x40, 0x30 }, /* COM7, COM12, COM15 */ + { 0x04, 0x00 }, { 0x0C, 0x00 }, { 0x0D, 0x40 }, /* COM1, COM3, COM4 */ + { 0x4F, 0x71 }, { 0x50, 0x3E }, { 0x51, 0x0C }, /* MTX1, MTX2, MTX3 */ + { 0x52, 0x33 }, { 0x53, 0x72 }, { 0x54, 0x00 }, /* MTX4, MTX5, MTX6 */ + { 0x55, 0x2B }, { 0x56, 0x66 }, { 0x57, 0xD2 }, /* MTX7, MTX8, MTX9 */ + { 0x58, 0x65 }, /* MTXS */ + { OV9640_REG_TERM, OV9640_VAL_TERM } +}; + + +#define DEF_GAIN 31 +#define DEF_AUTOGAIN 1 +#define DEF_EXPOSURE 154 +#define DEF_AEC 1 +#define DEF_FREEZE_AGCAEC 0 +#define DEF_BLUE 153 +#define DEF_RED (255 - DEF_BLUE) +#define DEF_AWB 1 +#define DEF_HFLIP 0 +#define DEF_VFLIP 0 + +/* Our own specific controls */ +#define V4L2_CID_FREEZE_AGCAEC V4L2_CID_PRIVATE_BASE+0 +#define V4L2_CID_AUTOEXPOSURE V4L2_CID_PRIVATE_BASE+1 +#define V4L2_CID_LAST_PRIV V4L2_CID_AUTOEXPOSURE + +/* Video controls */ +static struct vcontrol { + struct v4l2_queryctrl qc; + int current_value; + u8 reg; + u8 mask; + u8 start_bit; +} control[] = { + { { V4L2_CID_GAIN, V4L2_CTRL_TYPE_INTEGER, "Gain", 0, 63, 1, + DEF_GAIN }, + 0, OV9640_GAIN, 0x3f, 0 }, + { { V4L2_CID_AUTOGAIN, V4L2_CTRL_TYPE_BOOLEAN, "Auto Gain", 0, 1, 0, + DEF_AUTOGAIN }, + 0, OV9640_COM8, 0x04, 2 }, + { { V4L2_CID_EXPOSURE, V4L2_CTRL_TYPE_INTEGER, "Exposure", 0, 255, 1, + DEF_EXPOSURE }, + 0, OV9640_AECH, 0xff, 0 }, + { { V4L2_CID_AUTOEXPOSURE, V4L2_CTRL_TYPE_BOOLEAN, "Auto Exposure", 0, 1, 0, + DEF_AEC }, + 0, OV9640_COM8, 0x01, 0 }, + { { V4L2_CID_FREEZE_AGCAEC, V4L2_CTRL_TYPE_BOOLEAN, "Freeze AGC/AEC", 0,1,0, + DEF_FREEZE_AGCAEC }, + 0, OV9640_COM9, 0x01, 0 }, + { { V4L2_CID_RED_BALANCE, V4L2_CTRL_TYPE_INTEGER, "Red Balance", 0, 255, 1, + DEF_RED }, + 0, OV9640_RED, 0xff, 0 }, + { { V4L2_CID_BLUE_BALANCE, V4L2_CTRL_TYPE_INTEGER, "Blue Balance", 0, 255, 1, + DEF_BLUE }, + 0, OV9640_BLUE, 0xff, 0 }, + { { V4L2_CID_AUTO_WHITE_BALANCE, V4L2_CTRL_TYPE_BOOLEAN, "Auto White Balance", 0,1,0, + DEF_AWB }, + 0, OV9640_COM8, 0x02, 1 }, + { { V4L2_CID_HFLIP, V4L2_CTRL_TYPE_BOOLEAN, "Mirror Image", 0, 1, 0, + DEF_HFLIP }, + 0, OV9640_MVFP, 0x20, 5 }, + { { V4L2_CID_VFLIP, V4L2_CTRL_TYPE_BOOLEAN, "Vertical Flip", 0, 1, 0, + DEF_VFLIP }, + 0, OV9640_MVFP, 0x10, 4 }, +}; + +#define NUM_CONTROLS (sizeof(control)/sizeof(control[0])) + +const static struct ov9640_reg * + ov9640_reg_init[NUM_PIXEL_FORMATS][NUM_IMAGE_SIZES] = +{ + { qqcif_yuv, qqvga_yuv, qcif_yuv, qvga_yuv, cif_yuv, vga_yuv, sxga_yuv }, + { qqcif_565, qqvga_565, qcif_565, qvga_565, cif_565, vga_565, sxga_565 }, + { qqcif_555, qqvga_555, qcif_555, qvga_555, cif_555, vga_555, sxga_555 }, +}; + + +/* + * Read a value from a register in an OV9640 sensor device. The value is + * returned in 'val'. + * Returns zero if successful, or non-zero otherwise. + */ +static int +ov9640_read_reg(struct i2c_client *client, u8 reg, u8 *val) +{ + int err; + struct i2c_msg msg[1]; + unsigned char data[1]; + + if (!client->adapter) + return -ENODEV; + + msg->addr = client->addr; + msg->flags = 0; + msg->len = 1; + msg->buf = data; + *data = reg; + err = i2c_transfer(client->adapter, msg, 1); + if (err >= 0) { + msg->flags = I2C_M_RD; + err = i2c_transfer(client->adapter, msg, 1); + } + if (err >= 0) { + *val = *data; + return 0; + } + return err; +} + +/* Write a value to a register in an OV9640 sensor device. + * Returns zero if successful, or non-zero otherwise. + */ +static int +ov9640_write_reg(struct i2c_client *client, u8 reg, u8 val) +{ + int err; + struct i2c_msg msg[1]; + unsigned char data[2]; + + if (!client->adapter) + return -ENODEV; + + msg->addr = client->addr; + msg->flags = 0; + msg->len = 2; + msg->buf = data; + data[0] = reg; + data[1] = val; + err = i2c_transfer(client->adapter, msg, 1); + if (err >= 0) + return 0; + return err; +} + +static int +ov9640_write_reg_mask(struct i2c_client *client, u8 reg, u8 *val, u8 mask) +{ + u8 oldval, newval; + int rc; + + if (mask == 0xff) { + newval = *val; + } else { + /* need to do read - modify - write */ + if ((rc = ov9640_read_reg(client, reg, &oldval))) + return rc; + oldval &= (~mask); /* Clear the masked bits */ + *val &= mask; /* Enforce mask on value */ + newval = oldval | *val; /* Set the desired bits */ + } + + /* write the new value to the register */ + if ((rc = ov9640_write_reg(client, reg, newval))) + return rc; + + if ((rc = ov9640_read_reg(client, reg, &newval))) + return rc; + + *val = newval & mask; + return 0; +} + +static int +ov9640_read_reg_mask(struct i2c_client *client, u8 reg, u8 *val, u8 mask) +{ + int rc; + + if ((rc = ov9640_read_reg(client, reg, val))) + return rc; + (*val) &= mask; + + return 0; +} + +/* Initialize a list of OV9640 registers. + * The list of registers is terminated by the pair of values + * { OV9640_REG_TERM, OV9640_VAL_TERM }. + * Returns zero if successful, or non-zero otherwise. + */ +static int +ov9640_write_regs(struct i2c_client *client, const struct ov9640_reg reglist[]) +{ + int err; + const struct ov9640_reg *next = reglist; + + while (!((next->reg == OV9640_REG_TERM) + && (next->val == OV9640_VAL_TERM))) + { + err = ov9640_write_reg(client, next->reg, next->val); + udelay(100); + if (err) + return err; + next++; + } + return 0; +} + +/* Returns the index of the requested ID from the control structure array */ +static int +find_vctrl(int id) +{ + int i; + + if (id < V4L2_CID_BASE) + return -EDOM; + + for (i = NUM_CONTROLS - 1; i >= 0; i--) + if (control[i].qc.id == id) + break; + if (i < 0) + i = -EINVAL; + return i; +} + +/* Calculate the internal clock divisor (value of the CLKRC register) of the + * OV9640 given the image size, the frequency (in Hz) of its XCLK input and a + * desired frame period (in seconds). The frame period 'fper' is expressed as + * a fraction. The frame period is an input/output parameter. + * Returns the value of the OV9640 CLKRC register that will yield the frame + * period returned in 'fper' at the specified xclk frequency. The + * returned period will be as close to the requested period as possible. + */ +static unsigned char +ov9640_clkrc(enum image_size isize, unsigned long xclk, struct v4l2_fract *fper) +{ + unsigned long fpm, fpm_max; /* frames per minute */ + unsigned long divisor; + const unsigned long divisor_max = 64; + const static unsigned long clks_per_frame[] = + { 200000, 200000, 200000, 200000, 400000, 800000, 3200000 }; + + if (fper->numerator > 0) + fpm = (fper->denominator*60)/fper->numerator; + else + fpm = 0xffffffff; + fpm_max = (xclk*60)/clks_per_frame[isize]; + if (fpm_max == 0) + fpm_max = 1; + if (fpm > fpm_max) + fpm = fpm_max; + if (fpm == 0) + fpm = 1; + divisor = fpm_max/fpm; + if (divisor > divisor_max) + divisor = divisor_max; + fper->numerator = divisor*60; + fper->denominator = fpm_max; + + /* try to reduce the fraction */ + while (!(fper->denominator % 5) && !(fper->numerator % 5)) { + fper->numerator /= 5; + fper->denominator /= 5; + } + while (!(fper->denominator % 3) && !(fper->numerator % 3)) { + fper->numerator /= 3; + fper->denominator /= 3; + } + while (!(fper->denominator % 2) && !(fper->numerator % 2)) { + fper->numerator /= 2; + fper->denominator /= 2; + } + if (fper->numerator < fper->denominator) { + if (!(fper->denominator % fper->numerator)) { + fper->denominator /= fper->numerator; + fper->numerator = 1; + } + } + else { + if (!(fper->numerator % fper->denominator)) { + fper->numerator /= fper->denominator; + fper->denominator = 1; + } + } + + /* we set bit 7 in CLKRC to enable the digital PLL */ + return (0x80 | (divisor - 1)); +} + +/* Configure the OV9640 for a specified image size, pixel format, and frame + * period. xclk is the frequency (in Hz) of the xclk input to the OV9640. + * fper is the frame period (in seconds) expressed as a fraction. + * Returns zero if successful, or non-zero otherwise. + * The actual frame period is returned in fper. + */ +static int +ov9640_configure(struct i2c_client *client, + enum image_size isize, + enum pixel_format pfmt, + unsigned long xclk, + struct v4l2_fract *fper) +{ + int err; + unsigned char clkrc; + + /* common register initialization */ + err = ov9640_write_regs(client, ov9640_common); + if (err) + return err; + + /* configure image size and pixel format */ + err = ov9640_write_regs(client, ov9640_reg_init[pfmt][isize]); + if (err) + return err; + + /* configure frame rate */ + clkrc = ov9640_clkrc(isize, xclk, fper); + err = ov9640_write_reg(client, OV9640_CLKRC, clkrc); + if (err) + return err; + + return 0; +} + +/* Write to GPIO EXPA on the board. + * The GPIO expanders need an independent I2C client driver. + */ +static int +write_gpio_expa(u8 val, int add) +{ + struct i2c_adapter *adap; + int err; + struct i2c_msg msg[1]; + unsigned char data[1]; + + adap = i2c_get_adapter(0); + if (!adap) + return -ENODEV; + msg->addr = add; /* I2C address of GPIO EXPA */ + msg->flags = 0; + msg->len = 1; + msg->buf = data; + data[0] = val; + err = i2c_transfer(adap, msg, 1); + if (err >= 0) + return 0; + return err; +} + +/* Read from GPIO EXPA on the board. + * The GPIO expanders need an independent I2C client driver. + */ +static int +read_gpio_expa(u8 *val, int add) +{ + struct i2c_adapter *adap; + int err; + struct i2c_msg msg[1]; + unsigned char data[1]; + + adap = i2c_get_adapter(0); + if (!adap) + return -ENODEV; + msg->addr = add; /* I2C address of GPIO EXPA */ + msg->flags = I2C_M_RD; + msg->len = 1; + msg->buf = data; + err = i2c_transfer(adap, msg, 1); + *val = data[0]; + if (err >= 0) + return 0; + return err; +} + +static int +ov9640_powerup(void) +{ + unsigned char expa; + int err; + + if (machine_is_omap_h2()) + return 0; + + /* read the current state of GPIO EXPA output */ + if (( err = read_gpio_expa(&expa, 0x27))){ + printk(KERN_ERR "Error reading GPIO EXPA \n"); + return err; + } + /* set GPIO EXPA P7 CAMERA_MOD_EN to power-up sensor */ + if ((err = write_gpio_expa(expa | 0x80, 0x27))) { + printk(KERN_ERR "Error writing to GPIO EXPA \n"); + return err; + } + + return 0; +} +static int +ov9640_powerdown(void) +{ + unsigned char expa; + int err; + + if (machine_is_omap_h2()) + return 0; + + /* read the current state of GPIO EXPA output */ + if (( err = read_gpio_expa(&expa, 0x27))){ + printk(KERN_ERR "Error reading GPIO EXPA \n"); + return err; + } + /* clear GPIO EXPA P7 CAMERA_MOD_EN to power-up sensor */ + if ((err = write_gpio_expa(expa & ~0x80, 0x27))) { + printk(KERN_ERR "Error writing to GPIO EXPA \n"); + return err; + } + return 0; +} + +/* Detect if an OV9640 is present, and if so which revision. + * A device is considered to be detected if the manufacturer ID (MIDH and MIDL) + * and the product ID (PID) registers match the expected values. + * Any value of the version ID (VER) register is accepted. + * Here are the version numbers we know about: + * 0x48 --> OV9640 Revision 1 or OV9640 Revision 2 + * 0x49 --> OV9640 Revision 3 + * Returns a negative error number if no device is detected, or the + * non-negative value of the version ID register if a device is detected. + */ +static int +ov9640_detect(struct i2c_client *client) +{ + u8 midh, midl, pid, ver; + + if (!client) + return -ENODEV; + + if (ov9640_read_reg(client, OV9640_MIDH, &midh)) + return -ENODEV; + if (ov9640_read_reg(client, OV9640_MIDL, &midl)) + return -ENODEV; + if (ov9640_read_reg(client, OV9640_PID, &pid)) + return -ENODEV; + if (ov9640_read_reg(client, OV9640_VER, &ver)) + return -ENODEV; + + if ((midh != OV9640_MIDH_MAGIC) + || (midl != OV9640_MIDL_MAGIC) + || (pid != OV9640_PID_MAGIC)) + { + /* We didn't read the values we expected, so + * this must not be an OV9640. + */ + return -ENODEV; + } + return ver; +} + +/* This function registers an I2C client via i2c_attach_client() for an OV9640 + * sensor device. If 'probe' is non-zero, then the I2C client is only + * registered if the device can be detected. If 'probe' is zero, then no + * device detection is attempted and the I2C client is always registered. + * Returns zero if an I2C client is successfully registered, or non-zero + * otherwise. + */ +static int +ov9640_i2c_attach_client(struct i2c_adapter *adap, int addr, int probe) +{ + struct ov9640_sensor *sensor = &ov9640; + struct i2c_client *client = &sensor->client; + int err; + + if (client->adapter) + return -EBUSY; /* our client is already attached */ + + client->addr = addr; + client->flags = I2C_CLIENT_ALLOW_USE; + client->driver = &sensor->driver; + client->adapter = adap; + + err = i2c_attach_client(client); + if (err) { + client->adapter = NULL; + return err; + } + + if (probe) { + err = ov9640_detect(client); + if (err < 0) { + i2c_detach_client(client); + client->adapter = NULL; + return err; + } + sensor->ver = err; + } + return 0; +} + +/* This function is called by i2c_del_adapter() and i2c_del_driver() + * if the adapter or driver with which this I2C client is associated is + * removed. This function unregisters the client via i2c_detach_client(). + * Returns zero if the client is successfully detached, or non-zero + * otherwise. + */ +static int +ov9640_i2c_detach_client(struct i2c_client *client) +{ + int err; + + if (!client->adapter) + return -ENODEV; /* our client isn't attached */ + + err = i2c_detach_client(client); + client->adapter = NULL; + + return err; +} + +/* This function will be called for each registered I2C bus adapter when our + * I2C driver is registered via i2c_add_driver(). It will also be called + * whenever a new I2C adapter is registered after our I2C driver is registered. + * This function probes the specified I2C bus adapter to determine if an + * OV9640 sensor device is present. If a device is detected, an I2C client + * is registered for it via ov9640_i2c_attach_client(). Note that we can't use + * the standard i2c_probe() function to look for the sensor because the OMAP + * I2C controller doesn't support probing. + * Returns zero if an OV9640 device is detected and an I2C client successfully + * registered for it, or non-zero otherwise. + */ +static int +ov9640_i2c_probe_adapter(struct i2c_adapter *adap) +{ + return ov9640_i2c_attach_client(adap, OV9640_I2C_ADDR, 1); +} + +/* Find the best match for a requested image capture size. The best match + * is chosen as the nearest match that has the same number or fewer pixels + * as the requested size, or the smallest image size if the requested size + * has fewer pixels than the smallest image. + */ +static enum image_size +ov9640_find_size(unsigned int width, unsigned int height) +{ + enum image_size isize; + unsigned long pixels = width*height; + + for (isize = QQCIF; isize < SXGA; isize++) { + if (ov9640_sizes[isize + 1].height* + ov9640_sizes[isize + 1].width > pixels) + { + return isize; + } + } + return SXGA; +} + +/* following are sensor interface functions implemented by + * OV9640 sensor driver. + */ +static int +ov9640sensor_query_control(struct v4l2_queryctrl *qc, void *priv) +{ + int i; + + i = find_vctrl (qc->id); + if (i == -EINVAL) { + qc->flags = V4L2_CTRL_FLAG_DISABLED; + return 0; + } + if (i < 0) + return -EINVAL; + + *qc = control[i].qc; + return 0; +} + +static int +ov9640sensor_get_control(struct v4l2_control *vc, void *priv) +{ + struct ov9640_sensor *sensor = (struct ov9640_sensor *) priv; + struct i2c_client *client = &sensor->client; + int i, val; + struct vcontrol * lvc; + + i = find_vctrl(vc->id); + if (i < 0) + return -EINVAL; + + lvc = &control[i]; + if (ov9640_read_reg_mask(client, lvc->reg, (u8 *)&val, lvc->mask)) + return -EIO; + + val = val >> lvc->start_bit; + if (val >= 0) { + vc->value = lvc->current_value = val; + return 0; + } else + return val; +} + +static int +ov9640sensor_set_control(struct v4l2_control *vc, void *priv) +{ + struct ov9640_sensor *sensor = (struct ov9640_sensor *) priv; + struct i2c_client *client = &sensor->client; + struct vcontrol *lvc; + int val = vc->value; + int i; + + i = find_vctrl(vc->id); + if (i < 0) + return -EINVAL; + + lvc = &control[i]; + val = val << lvc->start_bit; + if (ov9640_write_reg_mask(client, lvc->reg, (u8 *)&val, (u8)lvc->mask)) + return -EIO; + + val = val>> lvc->start_bit; + if (val >= 0) { + lvc->current_value = val; + return 0; + } else + return val; +} + +/* Implement the VIDIOC_ENUM_FMT ioctl for the CAPTURE buffer type. + */ +static int +ov9640sensor_enum_pixformat(struct v4l2_fmtdesc *fmt, void *priv) +{ + int index = fmt->index; + enum v4l2_buf_type type = fmt->type; + + memset(fmt, 0, sizeof(*fmt)); + fmt->index = index; + fmt->type = type; + + switch (fmt->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (index >= NUM_CAPTURE_FORMATS) + return -EINVAL; + break; + + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (index >= NUM_OVERLAY_FORMATS) + return -EINVAL; + break; + + default: + return -EINVAL; + } + + fmt->flags = ov9640_formats[index].flags; + strlcpy(fmt->description, ov9640_formats[index].description, sizeof(fmt->description)); + fmt->pixelformat = ov9640_formats[index].pixelformat; + + return 0; +} + +/* Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. This + * ioctl is used to negotiate the image capture size and pixel format + * without actually making it take effect. + */ +static int +ov9640sensor_try_format(struct v4l2_pix_format *pix, void *priv) +{ + enum image_size isize; + int ifmt; + + isize = ov9640_find_size(pix->width, pix->height); + pix->width = ov9640_sizes[isize].width; + pix->height = ov9640_sizes[isize].height; + for (ifmt = 0; ifmt < NUM_CAPTURE_FORMATS; ifmt++) { + if (pix->pixelformat == ov9640_formats[ifmt].pixelformat) + break; + } + if (ifmt == NUM_CAPTURE_FORMATS) + ifmt = 0; + pix->pixelformat = ov9640_formats[ifmt].pixelformat; + pix->field = V4L2_FIELD_NONE; + pix->bytesperline = pix->width*2; + pix->sizeimage = pix->bytesperline*pix->height; + pix->priv = 0; + switch (pix->pixelformat) { + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + default: + pix->colorspace = V4L2_COLORSPACE_JPEG; + break; + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB565X: + case V4L2_PIX_FMT_RGB555: + case V4L2_PIX_FMT_RGB555X: + pix->colorspace = V4L2_COLORSPACE_SRGB; + break; + } + return 0; +} + +/* Given the image capture format in pix, the nominal frame period in + * timeperframe, calculate the required xclk frequency + * The nominal xclk input frequency of the OV9640 is 24MHz, maximum + * frequency is 48MHz, and minimum frequency is 10MHz. + */ +static unsigned long +ov9640sensor_calc_xclk(struct v4l2_pix_format *pix, + struct v4l2_fract *timeperframe, void *priv) +{ + unsigned long tgt_xclk; /* target xclk */ + unsigned long tgt_fpm; /* target frames per minute */ + enum image_size isize; + + /* We use arbitrary rules to select the xclk frequency. If the + * capture size is VGA and the frame rate is greater than 900 + * frames per minute, or if the capture size is SXGA and the + * frame rate is greater than 450 frames per minutes, then the + * xclk frequency will be set to 48MHz. Otherwise, the xclk + * frequency will be set to 24MHz. If the mclk frequency is such that + * the target xclk frequency is not achievable, then xclk will be set + * as close as to the target as possible. + */ + if ((timeperframe->numerator == 0) + || (timeperframe->denominator == 0)) + { + /* supply a default nominal_timeperframe of 15 fps */ + timeperframe->numerator = 1; + timeperframe->denominator = 15; + } + tgt_fpm = (timeperframe->denominator*60) + / timeperframe->numerator; + tgt_xclk = 24000000; + isize = ov9640_find_size(pix->width, pix->height); + switch (isize) { + case SXGA: + if (tgt_fpm > 450) + tgt_xclk = 48000000; + break; + case VGA: + if (tgt_fpm > 900) + tgt_xclk = 48000000; + break; + default: + break; + } + return tgt_xclk; +} + +/* Given a capture format in pix, the frame period in timeperframe, and + * the xclk frequency, set the capture format of the OV9640 sensor. + * The actual frame period will be returned in timeperframe. + */ +static int +ov9640sensor_configure(struct v4l2_pix_format *pix, unsigned long xclk, + struct v4l2_fract *timeperframe, void *priv) +{ + struct ov9640_sensor *sensor = (struct ov9640_sensor *) priv; + enum pixel_format pfmt = YUV; + + switch (pix->pixelformat) { + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB565X: + pfmt = RGB565; + break; + case V4L2_PIX_FMT_RGB555: + case V4L2_PIX_FMT_RGB555X: + pfmt = RGB555; + break; + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + default: + pfmt = YUV; + } + + return ov9640_configure(&sensor->client, + ov9640_find_size(pix->width, pix->height), + pfmt, xclk, timeperframe); +} + +/* Prepare for the driver to exit. + * Balances ov9640sensor_init(). + * This function must de-initialize the sensor and its associated data + * structures. + */ +static int +ov9640sensor_cleanup(void *priv) +{ + struct ov9640_sensor *sensor = (struct ov9640_sensor *) priv; + + if (sensor) { + i2c_del_driver(&sensor->driver); + ov9640_powerdown(); + } + return 0; +} + +/* Initialize the OV9640 sensor. + * This routine allocates and initializes the data structure for the sensor, + * powers up the sensor, registers the I2C driver, and sets a default image + * capture format in pix. The capture format is not actually programmed + * into the OV9640 sensor by this routine. + * This function must return a non-NULL value to indicate that + * initialization is successful. + */ +static void * +ov9640sensor_init(struct v4l2_pix_format *pix) +{ + struct ov9640_sensor *sensor = &ov9640; + struct i2c_driver *driver = &sensor->driver; + int err; + + memset(sensor, 0, sizeof(*sensor)); + + /* power-up the sensor */ + if (ov9640_powerup()) + return NULL; + + driver->owner = THIS_MODULE; + strlcpy(driver->name, "OV9640 I2C driver", sizeof(driver->name)); + driver->id = I2C_DRIVERID_EXP0; + driver->flags = I2C_DF_NOTIFY; + driver->attach_adapter = ov9640_i2c_probe_adapter; + driver->detach_client = ov9640_i2c_detach_client; + + err = i2c_add_driver(driver); + if (err) { + printk(KERN_ERR "Failed to register OV9640 I2C client.\n"); + return NULL; + } + if (!sensor->client.adapter) { + printk(KERN_WARNING + "Failed to detect OV9640 sensor chip.\n"); + return NULL; + } + else { + printk(KERN_INFO + "OV9640 sensor chip version 0x%02x detected\n", sensor->ver); + } + + /* Make the default capture format QCIF RGB565 */ + pix->width = ov9640_sizes[QCIF].width; + pix->height = ov9640_sizes[QCIF].height; + pix->pixelformat = V4L2_PIX_FMT_RGB565; + ov9640sensor_try_format(pix, NULL); + + return (void *)sensor; +} + +struct camera_sensor camera_sensor_if = { + version: 0x01, + name: "OV9640", + init: ov9640sensor_init, + cleanup: ov9640sensor_cleanup, + enum_pixformat: ov9640sensor_enum_pixformat, + try_format: ov9640sensor_try_format, + calc_xclk: ov9640sensor_calc_xclk, + configure: ov9640sensor_configure, + query_control: ov9640sensor_query_control, + get_control: ov9640sensor_get_control, + set_control: ov9640sensor_set_control, +}; + +void print_ov9640_regs(void *priv) +{ + struct ov9640_sensor *sensor = (struct ov9640_sensor *) priv; + u8 reg, val; + for (reg=0x00; reg <=0x8A; reg++) + if (ov9640_read_reg(&sensor->client,reg,&val)) + printk("error reading %x\n", reg); + else + printk("reg %x = %x\n", reg, val); +} + +#endif /* ifdef CAMERA_OV9640 */ diff -Nru a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig --- a/drivers/mmc/Kconfig 2005-03-02 10:51:31 -08:00 +++ b/drivers/mmc/Kconfig 2005-03-02 10:51:31 -08:00 @@ -29,6 +29,14 @@ mount the filesystem. Almost everyone wishing MMC support should say Y or M here. +config MMC_BLOCK_BROKEN_RFD + boolean "Write work-around for incompatible cards" + depends on MMC_BLOCK + default n + help + Say y here if your MMC card fails write operations. Some cards + lie about being ready to receive data while they actually are not. + config MMC_ARMMMCI tristate "ARM AMBA Multimedia Card Interface support" depends on ARM_AMBA && MMC @@ -48,6 +56,36 @@ say Y or M here. If unsure, say N. + +config MMC_OMAP + tristate "TI OMAP Multimedia Card Interface support" + depends on ARCH_OMAP && MMC + select TPS65010 if MACH_OMAP_H2 + help + This selects the TI OMAP Multimedia card Interface. + If you have an OMAP board with a Multimedia Card slot, + say Y or M here. + + If unsure, say N. + +config MMC_OMAP16XX_BLOCK1 + boolean "First MMC block on OMAP16XX" + depends on ARCH_OMAP16XX && MMC_OMAP + default y if MACH_OMAP_H2 || MACH_OMAP_H3 + help + This enables the first of two MMC blocks on OMAP1610 multimedia + processor. You need to enable the correct block to activate your + MMC slot. + +config MMC_OMAP16XX_BLOCK2 + boolean "Second MMC block on OMAP16XX" + depends on ARCH_OMAP16XX && MMC_OMAP + default n if MACH_OMAP_H2 || MACH_OMAP_H3 + default y + help + This enables the second of two MMC blocks on OMAP1610 multimedia + processor. You need to enable the correct block to activate your + MMC slot. config MMC_WBSD tristate "Winbond W83L51xD SD/MMC Card Interface support" diff -Nru a/drivers/mmc/Makefile b/drivers/mmc/Makefile --- a/drivers/mmc/Makefile 2005-03-02 10:51:31 -08:00 +++ b/drivers/mmc/Makefile 2005-03-02 10:51:31 -08:00 @@ -18,5 +18,6 @@ obj-$(CONFIG_MMC_ARMMMCI) += mmci.o obj-$(CONFIG_MMC_PXA) += pxamci.o obj-$(CONFIG_MMC_WBSD) += wbsd.o +obj-$(CONFIG_MMC_OMAP) += omap.o mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o diff -Nru a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c --- a/drivers/mmc/mmc.c 2005-03-02 10:51:31 -08:00 +++ b/drivers/mmc/mmc.c 2005-03-02 10:51:31 -08:00 @@ -474,13 +474,13 @@ int bit = fls(host->ocr_avail) - 1; host->ios.vdd = bit; + host->ios.clock = host->f_min; host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; host->ios.power_mode = MMC_POWER_UP; host->ops->set_ios(host, &host->ios); mmc_delay(1); - host->ios.clock = host->f_min; host->ios.power_mode = MMC_POWER_ON; host->ops->set_ios(host, &host->ios); @@ -512,7 +512,7 @@ if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) break; - + mmc_delay(1); err = MMC_ERR_TIMEOUT; mmc_delay(10); diff -Nru a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c --- a/drivers/mmc/mmc_block.c 2005-03-02 10:51:31 -08:00 +++ b/drivers/mmc/mmc_block.c 2005-03-02 10:51:31 -08:00 @@ -54,6 +54,7 @@ unsigned int usage; unsigned int block_bits; + unsigned int suspended; }; static DECLARE_MUTEX(open_lock); @@ -158,6 +159,19 @@ stat = BLKPREP_KILL; } + if (md->suspended) { + blk_plug_device(md->queue.queue); + stat = BLKPREP_DEFER; + } + + /* + * Check for excessive requests. + */ + if (req->sector + req->nr_sectors > get_capacity(req->rq_disk)) { + printk("bad request size\n"); + stat = BLKPREP_KILL; + } + return stat; } @@ -233,6 +247,13 @@ req->rq_disk->disk_name, err); goto cmd_err; } +#ifdef CONFIG_MMC_BLOCK_BROKEN_RFD + /* Work-around for broken cards setting READY_FOR_DATA + * when not actually ready. + */ + if (R1_CURRENT_STATE(cmd.resp[0]) == 7) + cmd.resp[0] &= ~R1_READY_FOR_DATA; +#endif } while (!(cmd.resp[0] & R1_READY_FOR_DATA)); #if 0 diff -Nru a/drivers/mmc/omap.c b/drivers/mmc/omap.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mmc/omap.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,1188 @@ +/* + * linux/drivers/media/mmc/omap.c + * + * Copyright (C) 2004 Nokia Corporation + * Written by Tuukka Tikkanen and Juha Yrjölä + * Pin multiplexing and Innovator support by Tony Lindgren + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "omap.h" + +#define DRIVER_NAME "mmci-omap" + +#ifdef CONFIG_MMC_DEBUG +//#define DBG(x...) printk(KERN_DEBUG x) +#define DBG(x...) printk(x) +#else +#define DBG(x...) do { } while (0) +#endif + +/* Specifies how often in millisecs to poll for card status changes + * when the cover switch is open */ +#define OMAP_MMC_SWITCH_POLL_DELAY 500 + +static s16 mmc1_power_pin = -1, + mmc2_power_pin = -1; +static s16 mmc1_switch_pin = -1, + mmc2_switch_pin = -1; + +struct mmc_omap_host { + int initialized; + int suspended; + struct mmc_request * mrq; + struct mmc_command * cmd; + struct mmc_data * data; + struct mmc_host * mmc; + struct device * dev; + unsigned char id; /* 1610 has 2 MMC blocks */ + struct clk * clk; + u32 base; + int irq; + unsigned char bus_mode; + unsigned int dma_len; +#define OMAP_MMC_DATADIR_NONE 0 +#define OMAP_MMC_DATADIR_READ 1 +#define OMAP_MMC_DATADIR_WRITE 2 + unsigned char datadir; + u16 * buffer; + u32 bytesleft; + int power_pin; + + int use_dma, dma_ch; + struct completion dma_completion; + + int switch_pin; + struct work_struct switch_work; + struct timer_list switch_timer; + int switch_last_state; + + unsigned char sd_support; +}; + +static inline int +mmc_omap_cover_is_open(struct mmc_omap_host *host) +{ + if (host->switch_pin < 0) + return 0; + return omap_get_gpio_datain(host->switch_pin); +} + +static ssize_t +mmc_omap_show_cover_switch(struct device *dev, char *buf) +{ + struct mmc_omap_host *host = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", mmc_omap_cover_is_open(host) ? "open" : "closed"); +} + +static DEVICE_ATTR(cover_switch, S_IRUGO, mmc_omap_show_cover_switch, NULL); + +static void +mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd) +{ + u32 cmdreg; + u32 resptype; + u32 cmdtype; + + DBG("MMC%d: CMD%d, argument 0x%08x", host->id, cmd->opcode, cmd->arg); + if (cmd->flags & MMC_RSP_SHORT) + DBG(", 32-bit response"); + if (cmd->flags & MMC_RSP_LONG) + DBG(", 128-bit response"); + if (cmd->flags & MMC_RSP_CRC) + DBG(", CRC"); + if (cmd->flags & MMC_RSP_BUSY) + DBG(", busy notification"); + DBG("\n"); + + host->cmd = cmd; + + resptype = 0; + cmdtype = 0; + + /* Protocol layer does not provide response type, + * but our hardware needs to know exact type, not just size! + */ + switch (cmd->flags & MMC_RSP_MASK) { + case MMC_RSP_NONE: + /* resp 0 */ + break; + case MMC_RSP_SHORT: + /* resp 1, resp 1b */ + /* OR resp 3!! (assume this if bus is set opendrain) */ + if (host->bus_mode == MMC_BUSMODE_OPENDRAIN) + resptype = 3; + else + resptype = 1; + break; + case MMC_RSP_LONG: + /* resp 2 */ + resptype = 2; + break; + } + + /* Protocol layer does not provide command type, but our hardware + * needs it! + * any data transfer means adtc type (but that information is not + * in command structure, so we flagged it into host struct.) + * However, telling bc, bcr and ac apart based on response is + * not foolproof: + * CMD0 = bc = resp0 CMD15 = ac = resp0 + * CMD2 = bcr = resp2 CMD10 = ac = resp2 + * + * Resolve to best guess with some exception testing: + * resp0 -> bc, except CMD15 = ac + * rest are ac, except if opendrain + */ + if (host->datadir) { + cmdtype = OMAP_MMC_CMDTYPE_ADTC; + } else if (resptype == 0 && cmd->opcode != 15) { + cmdtype = OMAP_MMC_CMDTYPE_BC; + } else if (host->bus_mode == MMC_BUSMODE_OPENDRAIN) { + cmdtype = OMAP_MMC_CMDTYPE_BCR; + } else { + cmdtype = OMAP_MMC_CMDTYPE_AC; + } + + cmdreg = cmd->opcode | (resptype << 8) | (cmdtype << 12); + + if (host->bus_mode == MMC_BUSMODE_OPENDRAIN) + cmdreg |= 1 << 6; + + if (cmd->flags & MMC_RSP_BUSY) + cmdreg |= 1 << 11; + + if (host->datadir == OMAP_MMC_DATADIR_READ) + cmdreg |= 1 << 15; + + clk_enable(host->clk); + + OMAP_MMC_WRITE(host->base, CTO, 200); + OMAP_MMC_WRITE(host->base, ARGL, cmd->arg & 0xffff); + OMAP_MMC_WRITE(host->base, ARGH, cmd->arg >> 16); + OMAP_MMC_WRITE(host->base, IE, + OMAP_MMC_STAT_A_EMPTY | OMAP_MMC_STAT_A_FULL | + OMAP_MMC_STAT_CMD_CRC | OMAP_MMC_STAT_CMD_TOUT | + OMAP_MMC_STAT_DATA_CRC | OMAP_MMC_STAT_DATA_TOUT | + OMAP_MMC_STAT_END_OF_CMD | OMAP_MMC_STAT_CARD_ERR | + OMAP_MMC_STAT_END_OF_DATA); + OMAP_MMC_WRITE(host->base, CMD, cmdreg); +} + +static void +mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) +{ + host->data = NULL; + host->datadir = OMAP_MMC_DATADIR_NONE; + + if (data->error == MMC_ERR_NONE) + data->bytes_xfered += data->blocks * (1<blksz_bits); + else { + int dma_ch = host->dma_ch; + + /* We got an error, let's free the DMA channel if it's + * still allocated. */ + if (dma_ch != -1) { + host->dma_ch = -1; + omap_free_dma(dma_ch); + } + } + + dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len, + host->datadir); + host->dma_len = 0; + + clk_disable(host->clk); + + if (!data->stop) { + host->mrq = NULL; + mmc_request_done(host->mmc, data->mrq); + return; + } + + mmc_omap_start_command(host, data->stop); +} + + +static void +mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd) +{ + host->cmd = NULL; + + switch (cmd->flags & MMC_RSP_MASK) { + case MMC_RSP_NONE: + /* resp 0 */ + break; + case MMC_RSP_SHORT: + /* response types 1, 1b, 3, 4, 5, 6 */ + cmd->resp[0] = + OMAP_MMC_READ(host->base, RSP6) | + (OMAP_MMC_READ(host->base, RSP7) << 16); + DBG("MMC%d: Response %08x\n", host->id, cmd->resp[0]); + break; + case MMC_RSP_LONG: + /* response type 2 */ + cmd->resp[3] = + OMAP_MMC_READ(host->base, RSP0) | + (OMAP_MMC_READ(host->base, RSP1) << 16); + cmd->resp[2] = + OMAP_MMC_READ(host->base, RSP2) | + (OMAP_MMC_READ(host->base, RSP3) << 16); + cmd->resp[1] = + OMAP_MMC_READ(host->base, RSP4) | + (OMAP_MMC_READ(host->base, RSP5) << 16); + cmd->resp[0] = + OMAP_MMC_READ(host->base, RSP6) | + (OMAP_MMC_READ(host->base, RSP7) << 16); + DBG("MMC%d: Response %08x %08x %08x %08x\n", host->id, + cmd->resp[0], cmd->resp[1], + cmd->resp[2], cmd->resp[3]); + break; + } + + if (host->data == NULL || cmd->error != MMC_ERR_NONE) { + DBG("MMC%d: End request, err %x\n", host->id, cmd->error); + host->mrq = NULL; + clk_disable(host->clk); + mmc_request_done(host->mmc, cmd->mrq); + } +} + +static irqreturn_t mmc_omap_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct mmc_omap_host * host = (struct mmc_omap_host *)dev_id; + u16 status; + int end_command; + int end_transfer; + int ii; + + if (host->cmd == NULL && host->data == NULL) { + status = OMAP_MMC_READ(host->base, STAT); + printk(KERN_INFO "MMC%d: Spurious interrupt 0x%04x\n", host->id, status); + if (status != 0) { + OMAP_MMC_WRITE(host->base, STAT, status); + OMAP_MMC_WRITE(host->base, IE, 0); + } + return IRQ_HANDLED; + } + + end_command = 0; + end_transfer = 0; + + while ((status = OMAP_MMC_READ(host->base, STAT)) != 0) { + OMAP_MMC_WRITE(host->base, STAT, status); // Reset status bits + DBG("\tMMC IRQ %04x (cmd %d)\n", status, + host->cmd != NULL ? host->cmd->opcode : -1); + + if ((status & OMAP_MMC_STAT_A_FULL) || + ((status & OMAP_MMC_STAT_END_OF_DATA) && + (host->bytesleft > 0))) { + // Buffer almost full + ii = host->bytesleft / 2; + if (ii > 32) + ii = 32; + host->bytesleft -= ii * 2; + while (ii-- > 0) + *host->buffer++ = OMAP_MMC_READ(host->base, DATA); + } + + if (status & OMAP_MMC_STAT_A_EMPTY) { + // Buffer almost empty + ii = host->bytesleft / 2; + if (ii > 32) + ii = 32; + host->bytesleft -= ii * 2; + while (ii-- > 0) + OMAP_MMC_WRITE(host->base, DATA, *host->buffer++); + } + + if (status & OMAP_MMC_STAT_END_OF_DATA) { + // Block sent/received + end_transfer = 1; + } + + if (status & OMAP_MMC_STAT_DATA_TOUT) { + // Data timeout + printk(KERN_DEBUG "MMC%d: Data timeout\n", host->id); + if (host->data) { + host->data->error |= MMC_ERR_TIMEOUT; + end_transfer = 1; + } + } + + if (status & OMAP_MMC_STAT_DATA_CRC) { + // Data CRC error + if (host->data) { + host->data->error |= MMC_ERR_BADCRC; + printk(KERN_DEBUG "MMC%d: Data CRC error, bytes left %d\n", + host->id, host->bytesleft); + end_transfer = 1; + } else { + printk(KERN_DEBUG "MMC%d: Data CRC error\n", + host->id); + } + } + + if (status & OMAP_MMC_STAT_CMD_TOUT) { + // Command timeout + if (host->cmd) { + /* Timeouts are normal in case of MMC_SEND_STATUS */ + if (host->cmd->opcode != MMC_ALL_SEND_CID && + host->cmd->opcode != MMC_SEND_OP_COND && + !mmc_omap_cover_is_open(host)) + printk(KERN_ERR "MMC%d: Command timeout, CMD%d\n", + host->id, host->cmd->opcode); + host->cmd->error |= MMC_ERR_TIMEOUT; + end_command = 1; + } + } + + if (status & OMAP_MMC_STAT_CMD_CRC) { + // Command CRC error + printk(KERN_ERR "MMC%d: Command CRC error\n", host->id); + if (host->cmd) { + host->cmd->error |= MMC_ERR_BADCRC; + end_command = 1; + } + } + + if (status & OMAP_MMC_STAT_OCR_BUSY) { + // OCR Busy + if (host->cmd && host->cmd->opcode != MMC_SEND_OP_COND && + host->cmd->opcode != MMC_SET_RELATIVE_ADDR) { + printk(KERN_DEBUG "MMC%d: OCR busy error, CMD%d\n", + host->id, host->cmd->opcode); + } + } + + if (status & OMAP_MMC_STAT_CARD_ERR) { + // Card status error + printk(KERN_DEBUG "MMC%d: Card status error (CMD%d)\n", + host->id, host->cmd->opcode); + if (host->cmd) { + host->cmd->error |= MMC_ERR_FAILED; + end_command = 1; + } + if (host->data) { + host->data->error |= MMC_ERR_FAILED; + end_transfer = 1; + } + } + + /* + * NOTE: On 1610 the END_OF_CMD may come too early when + * starting a write + */ + if ((status & OMAP_MMC_STAT_END_OF_CMD) && + (!(status & OMAP_MMC_STAT_A_EMPTY))) { + // End of command phase + end_command = 1; + } + } + + if (end_command) { + mmc_omap_cmd_done(host, host->cmd); + } + if (end_transfer) { + mmc_omap_xfer_done(host, host->data); + } + + return IRQ_HANDLED; +} + +static irqreturn_t mmc_omap_switch_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct mmc_omap_host *host = (struct mmc_omap_host *) dev_id; + + DBG("MMC%d cover is now %s\n", host->id, + omap_get_gpio_datain(host->switch_pin) ? "open" : "closed"); + schedule_work(&host->switch_work); + + return IRQ_HANDLED; +} + +static void mmc_omap_switch_timer(unsigned long arg) +{ + struct mmc_omap_host *host = (struct mmc_omap_host *) arg; + + schedule_work(&host->switch_work); +} + +static void mmc_omap_switch_handler(void *data) +{ + struct mmc_omap_host *host = (struct mmc_omap_host *) data; + struct mmc_card *card; + static int complained = 0; + int cards = 0, cover_open; + + if (host->switch_pin == -1) + return; + cover_open = mmc_omap_cover_is_open(host); + if (cover_open != host->switch_last_state) { + kobject_uevent(&host->dev->kobj, KOBJ_CHANGE, &dev_attr_cover_switch.attr); + host->switch_last_state = cover_open; + } + DBG("MMC cover switch handler started\n"); + mmc_detect_change(host->mmc); + list_for_each_entry(card, &host->mmc->cards, node) { + if (mmc_card_present(card)) + cards++; + } + DBG("MMC%d: %d card(s) present\n", host->id, cards); + if (mmc_omap_cover_is_open(host)) { + if (!complained) { + printk(KERN_INFO "MMC%d: cover is open\n", host->id); + complained = 1; + } + mod_timer(&host->switch_timer, + jiffies + OMAP_MMC_SWITCH_POLL_DELAY * HZ / 1000); + } else { + complained = 0; + } +} + +static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data) +{ + struct mmc_omap_host *host = (struct mmc_omap_host *) data; + int dma_ch; + + /* FIXME: We ignore the possible errors for now. */ + if (host->dma_ch < 0) { + printk(KERN_ERR "MMC%d: DMA callback while DMA not enabled?\n", + host->id); + return; + } + dma_ch = host->dma_ch; + host->dma_ch = -1; + + omap_free_dma(dma_ch); + complete(&host->dma_completion); +} + +static int mmc_omap_start_dma_transfer(struct mmc_omap_host *host, struct mmc_request *req) +{ + int sync_dev, dma_ch, r; + const char *dev_name; + struct mmc_data *data = req->data; + + /* If for some reason the DMA transfer is still active, + * we wait for it to complete. This shouldn't normally happen. */ + if (host->dma_ch != -1) + wait_for_completion(&host->dma_completion); + + init_completion(&host->dma_completion); + + if (!(data->flags & MMC_DATA_WRITE)) { + if (host->id == 1) { + sync_dev = OMAP_DMA_MMC_RX; + dev_name = "MMC1 read"; + } else { + sync_dev = OMAP_DMA_MMC2_RX; + dev_name = "MMC2 read"; + } + } else { + if (host->id == 1) { + sync_dev = OMAP_DMA_MMC_TX; + dev_name = "MMC1 write"; + } else { + sync_dev = OMAP_DMA_MMC2_TX; + dev_name = "MMC2 write"; + } + } + r = omap_request_dma(sync_dev, dev_name, mmc_omap_dma_cb, host, &dma_ch); + if (r != 0) { + printk("MMC%d: omap_request_dma() failed with %d\n", host->id, r); + return r; + } + if (!(data->flags & MMC_DATA_WRITE)) { + /* 16 frames/block, 32 bytes/frame */ + omap_set_dma_src_params(dma_ch, OMAP_DMA_PORT_TIPB, + OMAP_DMA_AMODE_CONSTANT, + virt_to_phys((void *) host->base) + OMAP_MMC_REG_DATA); + omap_set_dma_dest_params(dma_ch, OMAP_DMA_PORT_EMIFF, + OMAP_DMA_AMODE_POST_INC, + data->sg->dma_address); + OMAP_MMC_WRITE(host->base, BUF, 0x8f0f); + } else { + omap_set_dma_dest_params(dma_ch, OMAP_DMA_PORT_TIPB, + OMAP_DMA_AMODE_CONSTANT, + virt_to_phys((void *) host->base) + OMAP_MMC_REG_DATA); + omap_set_dma_src_params(dma_ch, OMAP_DMA_PORT_EMIFF, + OMAP_DMA_AMODE_POST_INC, + data->sg->dma_address); + OMAP_MMC_WRITE(host->base, BUF, 0x0f8f); + } + omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S16, 16, + 16 * data->blocks, OMAP_DMA_SYNC_FRAME); + host->dma_ch = dma_ch; + omap_start_dma(dma_ch); + + return 0; +} + +static inline void set_cmd_timeout(struct mmc_omap_host *host, struct mmc_request *req) +{ + u16 reg; + + reg = OMAP_MMC_READ(host->base, SDIO); + reg &= ~(1 << 5); + OMAP_MMC_WRITE(host->base, SDIO, reg); + /* Set maximum timeout */ + OMAP_MMC_WRITE(host->base, CTO, 0xff); +} + +static inline void set_data_timeout(struct mmc_omap_host *host, struct mmc_request *req) +{ + int timeout; + u16 reg; + + /* Convert ns to clock cycles by assuming 20MHz frequency + * 1 cycle at 20MHz = 500 ns + */ + timeout = req->data->timeout_clks + req->data->timeout_ns / 500; + + /* Some cards require more time to do at least the first read operation */ + timeout = timeout << 4; + + /* Check if we need to use timeout multiplier register */ + reg = OMAP_MMC_READ(host->base, SDIO); + if (timeout > 0xffff) { + reg |= (1 << 5); + timeout /= 1024; + } else + reg &= ~(1 << 5); + OMAP_MMC_WRITE(host->base, SDIO, reg); + OMAP_MMC_WRITE(host->base, DTO, timeout); +} + +static void mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) +{ + struct mmc_data *data = req->data; + + host->data = data; + if (data == NULL) { + host->datadir = OMAP_MMC_DATADIR_NONE; + OMAP_MMC_WRITE(host->base, BLEN, 0); + OMAP_MMC_WRITE(host->base, NBLK, 0); + OMAP_MMC_WRITE(host->base, BUF, 0); + set_cmd_timeout(host, req); + return; + } + + DBG("MMC%d: Data xfer (%s %s), DTO %d cycles + %d ns, %d blocks of %d bytes\n", + host->id, (data->flags & MMC_DATA_STREAM) ? "stream" : "block", + (data->flags & MMC_DATA_WRITE) ? "write" : "read", + data->timeout_clks, data->timeout_ns, data->blocks, + 1 << data->blksz_bits); + + OMAP_MMC_WRITE(host->base, NBLK, data->blocks - 1); + OMAP_MMC_WRITE(host->base, BLEN, (1 << data->blksz_bits) - 1); + set_data_timeout(host, req); + + host->datadir = (data->flags & MMC_DATA_WRITE) ? + OMAP_MMC_DATADIR_WRITE : OMAP_MMC_DATADIR_READ; + host->dma_len = 0; + + host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, + host->datadir); + + /* No SG-DMA */ + if (unlikely(host->dma_len > 1)) + BUG(); + + if (host->use_dma) { + if (mmc_omap_start_dma_transfer(host, req) == 0) { + host->buffer = NULL; + host->bytesleft = 0; + } + } else { + /* Revert to CPU copy */ + OMAP_MMC_WRITE(host->base, BUF, 0x1f1f); + host->buffer = page_address(data->sg->page) + data->sg->offset; + host->bytesleft = data->blocks * (1 << data->blksz_bits); + host->dma_ch = -1; + } +} + +static inline int is_broken_card(struct mmc_card *card) +{ + int i; + struct mmc_cid *c = &card->cid; + static const struct broken_card_cid { + unsigned int manfid; + char prod_name[8]; + unsigned char hwrev; + unsigned char fwrev; + } broken_cards[] = { + { 0x00150000, "\x30\x30\x30\x30\x30\x30\x15\x00", 0x06, 0x03 }, + }; + + for (i = 0; i < sizeof(broken_cards)/sizeof(broken_cards[0]); i++) { + const struct broken_card_cid *b = broken_cards + i; + + if (b->manfid != c->manfid) + continue; + if (memcmp(b->prod_name, c->prod_name, sizeof(b->prod_name)) != 0) + continue; + if (b->hwrev != c->hwrev || b->fwrev != c->fwrev) + continue; + return 1; + } + return 0; +} + +static void mmc_omap_request(struct mmc_host *mmc, struct mmc_request *req) +{ + struct mmc_omap_host *host = mmc_priv(mmc); + + WARN_ON(host->mrq != NULL); + + host->mrq = req; + + /* Some cards (vendor left unnamed to protect the guilty) seem to + * require this delay after power-up. Otherwise we'll get mysterious + * data timeouts. */ + if (req->cmd->opcode == MMC_SEND_CSD) { + struct mmc_card *card; + int broken_present = 0; + + list_for_each_entry(card, &mmc->cards, node) { + if (is_broken_card(card)) { + broken_present = 1; + break; + } + } + if (broken_present) { + static int complained = 0; + + if (!complained) { + printk(KERN_WARNING "MMC%d: Broken card workaround enabled\n", + host->id); + complained = 1; + } + if (in_interrupt()) { + /* This is nasty */ + printk(KERN_ERR "Sleeping in IRQ handler, FIXME please!\n"); + dump_stack(); + mdelay(100); + } else { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(100 * HZ / 1000); + } + } + } + + mmc_omap_prepare_data(host, req); + mmc_omap_start_command(host, req->cmd); +} + +static void innovator_fpga_socket_power(int on) +{ +#if defined(CONFIG_MACH_OMAP_INNOVATOR) && defined(CONFIG_ARCH_OMAP1510) + + if (on) { + fpga_write(fpga_read(OMAP1510_FPGA_POWER) | (1 << 3), + OMAP1510_FPGA_POWER); + } else { + fpga_write(fpga_read(OMAP1510_FPGA_POWER) & ~(1 << 3), + OMAP1510_FPGA_POWER); + } +#endif +} + +/* + * Turn the socket power on/off. Innovator uses FPGA, most boards + * probably use GPIO. + */ +static void mmc_omap_power(struct mmc_omap_host *host, int on) +{ + if (on) { + if (machine_is_omap_innovator()) + innovator_fpga_socket_power(1); + else if (machine_is_omap_h2()) + tps65010_set_gpio_out_value(GPIO3, HIGH); + else if (machine_is_omap_h3()) + /* GPIO 4 of TPS65010 sends SD_EN signal */ + tps65010_set_gpio_out_value(GPIO4, HIGH); + else + if (host->power_pin >= 0) + omap_set_gpio_dataout(host->power_pin, 1); + } else { + if (machine_is_omap_innovator()) + innovator_fpga_socket_power(0); + else if (machine_is_omap_h2()) + tps65010_set_gpio_out_value(GPIO3, LOW); + else if (machine_is_omap_h3()) + tps65010_set_gpio_out_value(GPIO4, LOW); + else + if (host->power_pin >= 0) + omap_set_gpio_dataout(host->power_pin, 0); + } +} + +static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct mmc_omap_host *host = mmc_priv(mmc); + int dsor; + int realclock, i; + + DBG("MMC%d: set_ios: clock %dHz busmode %d powermode %d Vdd %d.%02d\n", + host->id, ios->clock, ios->bus_mode, ios->power_mode, + ios->vdd / 100, ios->vdd % 100); + + if (ios->power_mode == MMC_POWER_UP && ios->clock < 400000) { + /* Fix for broken stack */ + realclock = 400000; + } else { + realclock = ios->clock; + } + + if (ios->clock == 0) { + dsor = 0; + } else { + dsor = 48000000 / realclock; + if (dsor < 1) + dsor = 1; + + if (48000000 / dsor > realclock) + dsor++; + + if (dsor > 250) + dsor = 250; + } + + switch (ios->power_mode) { + case MMC_POWER_OFF: + mmc_omap_power(host, 0); + break; + case MMC_POWER_UP: + case MMC_POWER_ON: + mmc_omap_power(host, 1); + dsor |= 1<<11; + break; + } + + host->bus_mode = ios->bus_mode; + clk_enable(host->clk); + /* On insanely high arm_per frequencies something sometimes + * goes somehow out of sync, and the POW bit is not being set, + * which results in the while loop below getting stuck. + * Writing to the CON register twice seems to do the trick. */ + for (i = 0; i < 2; i++) + OMAP_MMC_WRITE(host->base, CON, dsor); + if (ios->power_mode == MMC_POWER_UP) { + /* Send clock cycles, poll completion */ + OMAP_MMC_WRITE(host->base, IE, 0); + OMAP_MMC_WRITE(host->base, STAT, 0xffff); + OMAP_MMC_WRITE(host->base, CMD, 1<<7); + while (0 == (OMAP_MMC_READ(host->base, STAT) & 1)); + OMAP_MMC_WRITE(host->base, STAT, 1); + } + clk_disable(host->clk); +} + +static struct mmc_host_ops mmc_omap_ops = { + .request = mmc_omap_request, + .set_ios = mmc_omap_set_ios, +}; + +static int mmc_omap_probe(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct mmc_host *mmc; + struct mmc_omap_host *host = NULL; + int ret = 0; + + if (pdev->resource[0].flags != IORESOURCE_MEM + || pdev->resource[1].flags != IORESOURCE_IRQ) { + printk(KERN_ERR "mmc_omap_probe: invalid resource type\n"); + return -ENODEV; + } + + if (!request_mem_region(pdev->resource[0].start, + pdev->resource[0].end - pdev->resource[0].start + 1, + pdev->name)) { + dev_dbg(&pdev->dev, "request_mem_region failed\n"); + return -EBUSY; + } + + mmc = mmc_alloc_host(sizeof(struct mmc_omap_host), dev); + if (!mmc) { + ret = -ENOMEM; + goto out; + } + + host = mmc_priv(mmc); + host->mmc = mmc; + + host->id = (pdev->resource[0].start == IO_ADDRESS(OMAP_MMC1_BASE)) ? 1 : 2; + + host->clk = clk_get(dev, (host->id == 1) ? "mmc1_ck" : "mmc2_ck"); + if (IS_ERR(host->clk)) { + ret = PTR_ERR(host->clk); + goto out; + } + + if (host->id == 1) { + omap_cfg_reg(MMC_CMD); + omap_cfg_reg(MMC_CLK); + omap_cfg_reg(MMC_DAT0); + if (cpu_is_omap1710()) { + omap_cfg_reg(M15_1710_MMC_CLKI); + omap_cfg_reg(P19_1710_MMC_CMDDIR); + omap_cfg_reg(P20_1710_MMC_DATDIR0); + } + if (host->sd_support) { + omap_cfg_reg(MMC_DAT1); + omap_cfg_reg(MMC_DAT2); + omap_cfg_reg(MMC_DAT3); + } + host->power_pin = mmc1_power_pin; + host->switch_pin = mmc1_switch_pin; + } else { + omap_cfg_reg(Y8_1610_MMC2_CMD); + omap_cfg_reg(Y10_1610_MMC2_CLK); + omap_cfg_reg(R18_1610_MMC2_CLKIN); + omap_cfg_reg(W8_1610_MMC2_DAT0); + if (host->sd_support) { + omap_cfg_reg(V8_1610_MMC2_DAT1); + omap_cfg_reg(W15_1610_MMC2_DAT2); + omap_cfg_reg(R10_1610_MMC2_DAT3); + } + + /* These are needed for the level shifter */ + omap_cfg_reg(V9_1610_MMC2_CMDDIR); + omap_cfg_reg(V5_1610_MMC2_DATDIR0); + omap_cfg_reg(W19_1610_MMC2_DATDIR1); + + host->power_pin = mmc2_power_pin; + host->switch_pin = mmc2_switch_pin; + + /* Feedback clock must be set on OMAP-1710 MMC2 */ + if (cpu_is_omap1710()) + omap_writel(omap_readl(MOD_CONF_CTRL_1) | (1 << 24), + MOD_CONF_CTRL_1); + } + + host->use_dma = 1; + host->dma_ch = -1; + + host->irq = pdev->resource[1].start; + host->base = (u32)pdev->resource[0].start; + + mmc->ops = &mmc_omap_ops; + mmc->f_min = 400000; + mmc->f_max = 24000000; + mmc->ocr_avail = MMC_VDD_33_34; + + /* No SG-DMA */ + mmc->max_phys_segs = 1; + mmc->max_seg_size = PAGE_SIZE; + + if (host->power_pin >= 0) { + if ((ret = omap_request_gpio(host->power_pin)) != 0) { + printk(KERN_ERR "MMC%d: Unable to get GPIO pin for MMC power\n", + host->id); + goto out; + } + omap_set_gpio_direction(host->power_pin, 0); + } + + ret = request_irq(host->irq, mmc_omap_irq, 0, DRIVER_NAME, host); + if (ret) + goto out; + + host->dev = dev; + dev_set_drvdata(dev, host); + + mmc_add_host(mmc); + + if (host->switch_pin >= 0) { + INIT_WORK(&host->switch_work, mmc_omap_switch_handler, host); + init_timer(&host->switch_timer); + host->switch_timer.function = mmc_omap_switch_timer; + host->switch_timer.data = (unsigned long) host; + if (omap_request_gpio(host->switch_pin) != 0) { + printk(KERN_WARNING "MMC%d: Unable to get GPIO pin for MMC cover switch\n", + host->id); + host->switch_pin = -1; + goto no_switch; + } + + omap_set_gpio_direction(host->switch_pin, 1); + omap_set_gpio_edge_ctrl(host->switch_pin, OMAP_GPIO_RISING_EDGE); + ret = request_irq(OMAP_GPIO_IRQ(host->switch_pin), + mmc_omap_switch_irq, 0, DRIVER_NAME, host); + if (ret) { + printk(KERN_WARNING "MMC%d: Unable to get IRQ for MMC cover switch\n", + host->id); + omap_free_gpio(host->switch_pin); + host->switch_pin = -1; + goto no_switch; + } + if (device_create_file(dev, &dev_attr_cover_switch) < 0) { + printk(KERN_WARNING "MMC%d: Unable to create sysfs attribute for cover switch\n", + host->id); + free_irq(OMAP_GPIO_IRQ(host->switch_pin), host); + omap_free_gpio(host->switch_pin); + host->switch_pin = -1; + goto no_switch; + } + if (mmc_omap_cover_is_open(host)) + schedule_work(&host->switch_work); + } +no_switch: + return 0; +out: + /* FIXME: Free other resources too. */ + if (host) { + if (host->clk && !IS_ERR(host->clk)) + clk_put(host->clk); + kfree(host); + } + return ret; +} + +static int mmc_omap_remove(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct mmc_omap_host *host = dev_get_drvdata(dev); + + dev_set_drvdata(dev, NULL); + + if (host) { + mmc_remove_host(host->mmc); + free_irq(host->irq, host); + mmc_omap_power(host, 0); + + if (host->power_pin >= 0) + omap_free_gpio(host->power_pin); + if (host->switch_pin >= 0) { + free_irq(OMAP_GPIO_IRQ(host->switch_pin), host); + omap_free_gpio(host->switch_pin); + host->switch_pin = -1; + del_timer_sync(&host->switch_timer); + flush_scheduled_work(); + } + if (host->clk && !IS_ERR(host->clk)) + clk_put(host->clk); + kfree(host); + } + + release_mem_region(pdev->resource[0].start, + pdev->resource[0].end - pdev->resource[0].start + 1); + + return 0; +} + +#ifdef CONFIG_PM +static int mmc_omap_suspend(struct device *dev, u32 state, u32 level) +{ + int ret = 0; + struct mmc_omap_host *host = dev_get_drvdata(dev); + + if (host && host->suspended) + return 0; + + if (!irqs_disabled()) + return -EAGAIN; + + if (host) { + ret = mmc_suspend_host(host->mmc, state); + if (ret == 0) + host->suspended = 1; + } + return ret; +} + +static int mmc_omap_resume(struct device *dev, u32 level) +{ + int ret = 0; + struct mmc_omap_host *host = dev_get_drvdata(dev); + + if (host && !host->suspended) + return 0; + + if (host) { + ret = mmc_resume_host(host->mmc); + if (ret == 0) + host->suspended = 0; + } + + return ret; +} +#else +#define mmc_omap_suspend NULL +#define mmc_omap_resume NULL +#endif + +static void mmc_release(struct device *dev) +{ + /* Nothing to release? */ +} + +static struct resource mmc1_resources[] = { + { + .start = IO_ADDRESS(OMAP_MMC1_BASE), + .end = IO_ADDRESS(OMAP_MMC1_BASE) + 0x7f, + .flags = IORESOURCE_MEM, + }, + { + .start = INT_MMC, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource mmc2_resources[] = { + { + .start = IO_ADDRESS(OMAP_MMC2_BASE), + .end = IO_ADDRESS(OMAP_MMC2_BASE) + 0x7f, + .flags = IORESOURCE_MEM, + }, + { + .start = INT_1610_MMC2, + .flags = IORESOURCE_IRQ, + }, +}; + + +static u64 mmc_dmamask = 0xffffffff; + +static struct platform_device mmc_omap_device1 = { + .name = "mmci-omap", + .id = 1, + .dev = { + .release = mmc_release, + .dma_mask = &mmc_dmamask, + }, + .num_resources = ARRAY_SIZE(&mmc1_resources), + .resource = mmc1_resources, +}; + +static struct platform_device mmc_omap_device2 = { + .name = "mmci-omap", + .id = 2, + .dev = { + .release = mmc_release, + .dma_mask = &mmc_dmamask, + }, + .num_resources = ARRAY_SIZE(&mmc2_resources), + .resource = mmc2_resources, +}; + +static struct device_driver mmc_omap_driver = { + .name = "mmci-omap", + .bus = &platform_bus_type, + .probe = mmc_omap_probe, + .remove = mmc_omap_remove, + .suspend = mmc_omap_suspend, + .resume = mmc_omap_resume, +}; + +static int enable_blocks = 0; + +static int __init mmc_omap_init(void) +{ + int ret; + const struct omap_mmc_config *minfo; + + minfo = omap_get_config(OMAP_TAG_MMC, struct omap_mmc_config); + if (minfo != NULL) { + enable_blocks = minfo->mmc_blocks; + if (enable_blocks & 1) { + mmc1_power_pin = minfo->mmc1_power_pin; + mmc1_switch_pin = minfo->mmc1_switch_pin; + } + if (enable_blocks & 2) { + mmc2_power_pin = minfo->mmc2_power_pin; + mmc2_switch_pin = minfo->mmc2_switch_pin; + } + } else { +#if defined(CONFIG_ARCH_OMAP1510) || defined(CONFIG_MMC_OMAP16XX_BLOCK1) + enable_blocks |= 1; +#endif +#if defined(CONFIG_MMC_OMAP16XX_BLOCK2) + enable_blocks |= 2; +#endif + } + if (enable_blocks == 0) { + printk(KERN_INFO "OMAP MMC driver not loaded\n"); + return -ENODEV; + } + + if (enable_blocks & 1) { + ret = platform_device_register(&mmc_omap_device1); + if (ret != 0) + return -ENODEV; + } + + if (enable_blocks & 2) { + ret = platform_device_register(&mmc_omap_device2); + if (ret != 0) + goto free1; + } + + ret = driver_register(&mmc_omap_driver); + if (ret == 0) + return 0; + + if (enable_blocks & 2) + platform_device_unregister(&mmc_omap_device2); + + free1: + if (enable_blocks & 1) + platform_device_unregister(&mmc_omap_device1); + + return -ENODEV; +} + +static void __exit mmc_omap_exit(void) +{ + driver_unregister(&mmc_omap_driver); + + if (enable_blocks & 2) + platform_device_unregister(&mmc_omap_device2); + + if (enable_blocks & 1) + platform_device_unregister(&mmc_omap_device1); +} + +module_init(mmc_omap_init); +module_exit(mmc_omap_exit); + +MODULE_DESCRIPTION("OMAP Multimedia Card driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Juha Yrjölä"); diff -Nru a/drivers/mmc/omap.h b/drivers/mmc/omap.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mmc/omap.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,58 @@ +#ifndef DRIVERS_MEDIA_MMC_OMAP_H +#define DRIVERS_MEDIA_MMC_OMAP_H + +#define OMAP_MMC1_BASE 0xfffb7800 +#define OMAP_MMC2_BASE 0xfffb7c00 + +#define OMAP_MMC_REG_CMD 0x00 +#define OMAP_MMC_REG_ARGL 0x04 +#define OMAP_MMC_REG_ARGH 0x08 +#define OMAP_MMC_REG_CON 0x0c +#define OMAP_MMC_REG_STAT 0x10 +#define OMAP_MMC_REG_IE 0x14 +#define OMAP_MMC_REG_CTO 0x18 +#define OMAP_MMC_REG_DTO 0x1c +#define OMAP_MMC_REG_DATA 0x20 +#define OMAP_MMC_REG_BLEN 0x24 +#define OMAP_MMC_REG_NBLK 0x28 +#define OMAP_MMC_REG_BUF 0x2c +#define OMAP_MMC_REG_SDIO 0x34 +#define OMAP_MMC_REG_REV 0x3c +#define OMAP_MMC_REG_RSP0 0x40 +#define OMAP_MMC_REG_RSP1 0x44 +#define OMAP_MMC_REG_RSP2 0x48 +#define OMAP_MMC_REG_RSP3 0x4c +#define OMAP_MMC_REG_RSP4 0x50 +#define OMAP_MMC_REG_RSP5 0x54 +#define OMAP_MMC_REG_RSP6 0x58 +#define OMAP_MMC_REG_RSP7 0x5c +#define OMAP_MMC_REG_IOSR 0x60 +#define OMAP_MMC_REG_SYSC 0x64 +#define OMAP_MMC_REG_SYSS 0x68 + +#define OMAP_MMC_STAT_CARD_ERR (1 << 14) +#define OMAP_MMC_STAT_CARD_IRQ (1 << 13) +#define OMAP_MMC_STAT_OCR_BUSY (1 << 12) +#define OMAP_MMC_STAT_A_EMPTY (1 << 11) +#define OMAP_MMC_STAT_A_FULL (1 << 10) +#define OMAP_MMC_STAT_CMD_CRC (1 << 8) +#define OMAP_MMC_STAT_CMD_TOUT (1 << 7) +#define OMAP_MMC_STAT_DATA_CRC (1 << 6) +#define OMAP_MMC_STAT_DATA_TOUT (1 << 5) +#define OMAP_MMC_STAT_END_BUSY (1 << 4) +#define OMAP_MMC_STAT_END_OF_DATA (1 << 3) +#define OMAP_MMC_STAT_CARD_BUSY (1 << 2) +#define OMAP_MMC_STAT_END_OF_CMD (1 << 0) + +#define OMAP_MMC_READ(base, reg) __raw_readw((base) + OMAP_MMC_REG_##reg) +#define OMAP_MMC_WRITE(base, reg, val) __raw_writew((val), (base) + OMAP_MMC_REG_##reg) + +/* + * Command types + */ +#define OMAP_MMC_CMDTYPE_BC 0 +#define OMAP_MMC_CMDTYPE_BCR 1 +#define OMAP_MMC_CMDTYPE_AC 2 +#define OMAP_MMC_CMDTYPE_ADTC 3 + +#endif diff -Nru a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig --- a/drivers/mtd/devices/Kconfig 2005-03-02 10:51:31 -08:00 +++ b/drivers/mtd/devices/Kconfig 2005-03-02 10:51:31 -08:00 @@ -73,6 +73,12 @@ not need any mapping/chip driver for LART. This one does it all for you, so go disable all of those if you enabled some of them (: +config MTD_OMAP_NOR + tristate "NOR Flash driver for OMAP" + depends on (ARCH_OMAP16XX || ARCH_OMAP24XX) && MTD + help + This enables the flash driver for OMAP 1610, OMAP1710, OMAP24XX. + config MTD_MTDRAM tristate "Test driver using RAM" depends on MTD diff -Nru a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile --- a/drivers/mtd/devices/Makefile 2005-03-02 10:51:31 -08:00 +++ b/drivers/mtd/devices/Makefile 2005-03-02 10:51:31 -08:00 @@ -23,3 +23,4 @@ obj-$(CONFIG_MTD_LART) += lart.o obj-$(CONFIG_MTD_BLKMTD) += blkmtd.o obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o +obj-$(CONFIG_MTD_OMAP_NOR) += omap-nor-flash.o diff -Nru a/drivers/mtd/devices/omap-nor-flash.c b/drivers/mtd/devices/omap-nor-flash.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mtd/devices/omap-nor-flash.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,567 @@ +/******************************************************************************* + + omap-nor-flash.c + Self-Contained MTD driver for OMAP NOR Flash + - Supports Intel 28F256L18T and Intel 28F128L18T + - Automatically detects which one of the supported flashes is used + - Automatically detects the location of the supported flashes (CS3 or CS2B) + + Author: MontaVista Software, Inc. + Copyright (c) 2003 MontaVista Software, Inc. + + The code for this driver is based on board/omap1610inn/flash.c from + U-Boot 0.4.3: + + * (C) Copyright 2001 + * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net + * + * (C) Copyright 2001 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2003 + * Texas Instruments, + * Kshitij Gupta + + The code for this driver is also based on syncflash.c: + + * MTD driver for Micron SyncFlash flash memory. + * + * Author: Jon McClintock + * + * Based loosely upon the LART flash driver, authored by + * Abraham vd Merwe + * . + * + * Copyright 2003, Blue Mug, Inc. for Motorola, Inc. + * Copyright 2003, MontaVista Software, Inc + * + * References: + * + * + * [1] MTD internal API documentation + * - http://www.linux-mtd.infradead.org/tech/ + * + + Modifications: + Feb 2004, Texas Instruments, + - Ported to 2.6 Kernel (Feb 2004) + - Added address probing (Sept 2004) + + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_MTD_PARTITIONS_MODULE +#define CONFIG_MTD_PARTITIONS 1 +#endif + +#define NB_OF(x) (sizeof (x) / sizeof (x[0])) + +/* + * General flash configuration parameters. + */ +#define OMAP_BOOTLOADER_LEN 0x20000 +#define OMAP_PARAMS_LEN 0x20000 +#define OMAP_KERNEL_LEN 0x200000 +#define BUSWIDTH 2 /*warning: this is used only in some functions, the code is specific to 16-bit data bus */ +#define INTEL_MANUFACT 0x0089 +#define INTEL_ID_28F256L18T 0x880D /* 256M = 128K x 255 + 32k x 4 */ +#define INTEL_ID_28F128L18T 0x880C /* 128M = 128K x 127 + 32k x 4 */ + +void __exit omap_flash_exit(void); +int __init omap_flash_init(void); +static int omap_flash_write(struct mtd_info *mtd, loff_t to, + size_t len, size_t * retlen, + const u_char * buf); +static int omap_flash_write_word(__u32 offset, __u16 x); +static int omap_flash_read(struct mtd_info *mtd, loff_t from, + size_t len, size_t * retlen, u_char * buf); +static int omap_flash_erase(struct mtd_info *mtd, struct erase_info *instr); +static inline int omap_flash_sector_erase(__u32 offset); +static int omap_flash_probe(void); + +static struct mtd_info mtd; + +static struct mtd_erase_region_info erase_regions[2]; + +static unsigned long omap_nor_flash_base; + +DECLARE_MUTEX(omap_flash_lock); + +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition omap_partitions[] = { + /* bootloader */ + { + name:"bootloader", + offset:0, + size:OMAP_BOOTLOADER_LEN, + mask_flags:MTD_WRITEABLE, /* force read-only */ + }, + /* bootloader params */ + { + name:"params", + offset:MTDPART_OFS_APPEND, + size:OMAP_PARAMS_LEN, + mask_flags:0, + }, + /* kernel */ + { + name:"kernel", + offset:MTDPART_OFS_APPEND, + size:OMAP_KERNEL_LEN, + mask_flags:0 + }, + /* file system */ + { + name:"file system", + offset:MTDPART_OFS_APPEND, + size:MTDPART_SIZ_FULL, + mask_flags:0 + } +}; +#endif + +static char module_name[] = "OMAP NOR FLASH"; + +#define omap_flash_inw(o) readw((omap_nor_flash_base+(__u32)o)) +#define omap_flash_outw(o,d) writew((__u16)(d),(omap_nor_flash_base+(__u32)o)) + +/* Probe for NOR Flash on OMAP board at address omap_nor_flash_base */ +static int +omap_flash_probe(void) +{ + __u16 mfgid, devid; + __u32 offset; + int i, j; + + memset(&mtd, 0, sizeof (mtd)); + down(&omap_flash_lock); + /* Write auto select command: read Manufacturer ID */ + omap_flash_outw(0, 0x0090); + + mfgid = omap_flash_inw(0); /*manufacturer ID */ + + switch (mfgid) { + + case INTEL_MANUFACT: + break; + default: + omap_flash_outw(0, 0x00FF); /* restore read mode */ + up(&omap_flash_lock); + printk(KERN_ERR + "%s ERROR: no supported Flash device found\n", + module_name); + return -ENXIO; /* no or unknown flash */ + } + + devid = omap_flash_inw(2); /* device ID */ + + switch (devid) { + + case INTEL_ID_28F256L18T: + erase_regions[0].offset = 0; + erase_regions[0].erasesize = 128 * 1024; + erase_regions[0].numblocks = 255; + erase_regions[1].offset = + erase_regions[0].erasesize * erase_regions[0].numblocks; + erase_regions[1].erasesize = 32 * 1024; + erase_regions[1].numblocks = 4; + printk(KERN_INFO "%s: Intel 28F256L18T found at 0x%lx\n", module_name, omap_nor_flash_base); + break; + + case INTEL_ID_28F128L18T: + erase_regions[0].offset = 0; + erase_regions[0].erasesize = 128 * 1024; + erase_regions[0].numblocks = 127; + erase_regions[1].offset = + erase_regions[0].erasesize * erase_regions[0].numblocks; + erase_regions[1].erasesize = 32 * 1024; + erase_regions[1].numblocks = 4; + printk(KERN_INFO "%s: Intel 28F128L18T found at 0x%lx\n", module_name, omap_nor_flash_base); + break; + + default: + omap_flash_outw(0, 0x00FF); /* restore read mode */ + up(&omap_flash_lock); + printk(KERN_ERR + "%s ERROR: no supported Flash device found\n", + module_name); + return -ENXIO; /* no or unknown flash */ + } + omap_flash_outw(0, 0x00FF); /* restore read mode */ + + mtd.name = module_name; + mtd.type = MTD_NORFLASH; + mtd.flags = MTD_CAP_NORFLASH; + + mtd.erasesize = 128 * 1024; + mtd.numeraseregions = NB_OF(erase_regions); + mtd.eraseregions = erase_regions; + for (i = 0; i < NB_OF(erase_regions); i++) { + mtd.size += + erase_regions[i].erasesize * erase_regions[i].numblocks; + offset = erase_regions[i].offset; + for (j = 0; j < erase_regions[i].numblocks; j++) { + + /* this sends the clear lock bit command */ + omap_flash_outw(offset, 0x0060); + omap_flash_outw(offset, 0x00D0); + omap_flash_outw(offset, 0x00FF);/* reset to read mode */ + offset += erase_regions[i].erasesize; + } + } + + up(&omap_flash_lock); + + mtd.owner = THIS_MODULE; + + mtd.erase = omap_flash_erase; + mtd.read = omap_flash_read; + mtd.write = omap_flash_write; + + return 0; +} + +/* Erase a flash sector */ +static inline int +omap_flash_sector_erase(__u32 offset) +{ + __u16 status; + + down(&omap_flash_lock); + /*erase sector */ + omap_flash_outw(offset, 0x0050); /* clear status register */ + omap_flash_outw(offset, 0x0020); /* erase setup */ + omap_flash_outw(offset, 0x00D0); /* erase confirm */ + + /* wait for erase complete while polling the status register */ + while (((status = omap_flash_inw(offset)) & 0x0080) != 0x0080) + schedule_timeout(1); + + omap_flash_outw(offset, 0x0050); /* clear status register */ + omap_flash_outw(offset, 0x00FF); /* reset to read mode */ + up(&omap_flash_lock); + + /* process status register */ + if (status & (1 << 3)) { + printk(KERN_ERR + "%s ERROR: erasing at address 0x%.8x: Vpp range error \n", + module_name, offset); + return -EPERM; + } + if ((status & (3 << 4)) == (3 << 4)) { + printk(KERN_ERR + "%s ERROR: erasing at address 0x%.8x: command sequence error\n", + module_name, offset); + return -EPERM; + } + if (status & (1 << 5)) { + printk(KERN_ERR + "%s ERROR: erasing at address 0x%.8x: block erase error\n", + module_name, offset); + return -ETIMEDOUT; + } + if (status & (1 << 1)) { + printk(KERN_ERR + "%s ERROR: erasing at address 0x%.8x: block locked error\n", + module_name, offset); + return -EPERM; + } + + return 0; +} + +/* Pick the proper sector addresses for erasing */ +static int +omap_flash_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + __u32 addr, len; + int i, first; + + /* sanity checks */ + if (instr->addr + instr->len > mtd->size) + return (-EINVAL); + + /* + * check that both start and end of the requested erase are + * aligned with the erasesize at the appropriate addresses. + * + * skip all erase regions which are ended before the start of + * the requested erase. Actually, to save on the calculations, + * we skip to the first erase region which starts after the + * start of the requested erase, and then go back one. + */ + for (i = 0; (i < mtd->numeraseregions) && + (instr->addr >= mtd->eraseregions[i].offset); i++) ; + i--; + + /* + * ok, now i is pointing at the erase region in which this + * erase request starts. Check the start of the requested + * erase range is aligned with the erase size which is in + * effect here. + */ + if (instr->addr & (mtd->eraseregions[i].erasesize - 1)) + return (-EINVAL); + + /* Remember the erase region we start on */ + first = i; + + /* + * next, check that the end of the requested erase is aligned + * with the erase region at that address. + * + * as before, drop back one to point at the region in which + * the address actually falls + */ + for (; + (i < mtd->numeraseregions) && + ((instr->addr + instr->len) >= mtd->eraseregions[i].offset); i++) ; + i--; + + /* is the end aligned on a block boundary? */ + if ((instr->addr + instr->len) & (mtd->eraseregions[i].erasesize - 1)) + return (-EINVAL); + + addr = instr->addr; + len = instr->len; + + i = first; + + /* now erase those blocks */ + while (len) { + if (omap_flash_sector_erase(addr)) { + instr->state = MTD_ERASE_FAILED; + return (-EIO); + } + + addr += mtd->eraseregions[i].erasesize; + len -= mtd->eraseregions[i].erasesize; + + if (addr == (mtd->eraseregions[i].offset + + (mtd->eraseregions[i].erasesize * + mtd->eraseregions[i].numblocks))) + i++; + } + + instr->state = MTD_ERASE_DONE; + if (instr->callback) + instr->callback(instr); + + return (0); +} + +/* Read a block of data from flash */ +static int +omap_flash_read(struct mtd_info *mtd, loff_t from, + size_t len, size_t * retlen, u_char * buf) +{ + /* Sanity checks. */ + if (!len) + return (0); + if (from + len > mtd->size) + return (-EINVAL); + + /* We always read len bytes. */ + *retlen = len; + down(&omap_flash_lock); + memcpy(buf, (void *) (omap_nor_flash_base + (__u32) from), len); + up(&omap_flash_lock); + + return (0); +} + +/* Write a flash word. The offset must be on a word boudary */ +static int +omap_flash_write_word(__u32 offset, __u16 x) +{ + __u16 status; + + down(&omap_flash_lock); + /* Check if Flash is (sufficiently) erased */ + if ((omap_flash_inw(offset) & x) != x) { + printk(KERN_ERR + "%s ERROR: cannot write, flash not erased at address 0x%.8x.\n", + module_name, offset); + up(&omap_flash_lock); + return -EIO; /*flash not erased */ + } + + omap_flash_outw(offset, 0x0050); /* clear status register */ + omap_flash_outw(offset, 0x0040); /* write setup */ + omap_flash_outw(offset, x); + + /* wait for program complete while polling the status register */ + while (((status = omap_flash_inw(offset)) & 0x0080) != 0x0080) + schedule_timeout(1); + + omap_flash_outw(offset, 0x0050); /* clear status register */ + omap_flash_outw(offset, 0x00FF); /* restore read mode */ + up(&omap_flash_lock); + + /* process status register */ + if (status & (1 << 3)) { + printk(KERN_ERR + "%s ERROR: writing at address 0x%.8x: Vpp range error \n", + module_name, offset); + return -EPERM; + } + if (status & (1 << 4)) { + printk(KERN_ERR + "%s ERROR: writing at address 0x%.8x: program error \n", + module_name, offset); + return -ETIMEDOUT; + } + if (status & (1 << 1)) { + printk(KERN_ERR + "%s ERROR: writing at address 0x%.8x: device protect error\n", + module_name, offset); + return -EPERM; + } + + return 0; +} + +/* Write a block of data to flash. Takes care of the word boundaries */ +static int +omap_flash_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t * retlen, const u_char * buf) +{ + __u8 tmp[BUSWIDTH]; + int i, n; + + *retlen = 0; + + /* Sanity checks */ + if (!len) + return (0); + if (to + len > mtd->size) + return (-EINVAL); + + /* First, we write a byte padded with original data until we reach a + * word boundary. */ + if (to & (BUSWIDTH - 1)) { + __u32 aligned = to & ~(BUSWIDTH - 1); + i = to - aligned; + + n = 0; + down(&omap_flash_lock); + *((__u16 *) tmp) = omap_flash_inw(aligned); + up(&omap_flash_lock); + + while (len && i < BUSWIDTH) + tmp[i++] = buf[n++], len--; + + if (omap_flash_write_word(aligned, *((__u16 *) tmp))) + return (-EIO); + + to += n; + buf += n; + *retlen += n; + } + + /* Now we write words until we reach a non-word boundary. */ + while (len >= BUSWIDTH) { + if (omap_flash_write_word(to, *((__u16 *) buf))) + return (-EIO); + + to += BUSWIDTH; + buf += BUSWIDTH; + *retlen += BUSWIDTH; + len -= BUSWIDTH; + } + + /* Top up the last unaligned bytes, padded with original data.... */ + if (len & (BUSWIDTH - 1)) { + i = n = 0; + + down(&omap_flash_lock); + *((__u16 *) tmp) = omap_flash_inw(to); + up(&omap_flash_lock); + + while (len--) + tmp[i++] = buf[n++]; + + if (omap_flash_write_word(to, *((__u16 *) tmp))) + return (-EIO); + + *retlen += n; + } + + return 0; +} + +int __init +omap_flash_init(void) +{ + int result; + + printk("%s: MTD Self-Contained Driver ver. 1.0 size=0x%lx\n", module_name, OMAP_NOR_FLASH_SIZE); + + omap_nor_flash_base = (unsigned long) ioremap(OMAP_NOR_FLASH_START1, OMAP_NOR_FLASH_SIZE); + result = omap_flash_probe(); + if (result < 0) { + iounmap((void *) omap_nor_flash_base); + omap_nor_flash_base = (unsigned long) ioremap(OMAP_NOR_FLASH_START2, OMAP_NOR_FLASH_SIZE); + result = omap_flash_probe(); + if (result < 0) { + iounmap((void *) omap_nor_flash_base); + return (-ENXIO); + } + } +#ifndef CONFIG_MTD_PARTITIONS + result = add_mtd_device(&mtd); +#else + result = add_mtd_partitions(&mtd, + omap_partitions, + NB_OF(omap_partitions)); +#endif + + /* check result */ + if (result) + iounmap((void *) omap_nor_flash_base); + + return (result); +} + +void __exit +omap_flash_exit(void) +{ +#ifndef CONFIG_MTD_PARTITIONS + del_mtd_device(&mtd); +#else + del_mtd_partitions(&mtd); +#endif + iounmap((void *) omap_nor_flash_base); +} + +module_init(omap_flash_init); +module_exit(omap_flash_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("MontaVista Software Inc."); +MODULE_DESCRIPTION("Self-Contained MTD driver for NOR Flash on OMAP board"); diff -Nru a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig --- a/drivers/mtd/maps/Kconfig 2005-03-02 10:51:31 -08:00 +++ b/drivers/mtd/maps/Kconfig 2005-03-02 10:51:31 -08:00 @@ -596,6 +596,16 @@ This enables access to the flash chips on the Interface MPC-1211(CTP/PCI/MPC-SH02). If you have such a board, say 'Y'. +config MTD_OMAP_NORv2 + tristate "TI OMAP Development board mappings" + depends on MTD_CFI && ARCH_OMAP + select MTD_CONCAT if MACH_OMAP_INNOVATOR + help + This enables access to the NOR flash chips on several TI OMAP + development boards, or others using the same NOR chipselects. + These boards include the Innovator, H2, H3, OSK, Perseus2, and + more. If you have such a board, say 'Y'. + # This needs CFI or JEDEC, depending on the cards found. config MTD_PCI tristate "PCI MTD driver" diff -Nru a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile --- a/drivers/mtd/maps/Makefile 2005-03-02 10:51:31 -08:00 +++ b/drivers/mtd/maps/Makefile 2005-03-02 10:51:31 -08:00 @@ -72,3 +72,4 @@ obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o obj-$(CONFIG_MTD_DMV182) += dmv182.o obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o +obj-$(CONFIG_MTD_OMAP_NORv2) += omap_nor.o diff -Nru a/drivers/mtd/maps/omap_nor.c b/drivers/mtd/maps/omap_nor.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mtd/maps/omap_nor.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,196 @@ +/* + * Flash memory support for various TI OMAP boards + * + * Copyright (C) 2001-2002 MontaVista Software Inc. + * Copyright (C) 2003-2004 Texas Instruments + * Copyright (C) 2004 Nokia Corporation + * + * Assembled using driver code copyright the companies above + * and written by David Brownell, Jian Zhang , + * Tony Lindgren and others. + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MODULE_NAME "omap_nor" + + +#ifdef CONFIG_MTD_PARTITIONS + +/* only bootable devices have a default partitioning */ +static struct mtd_partition boot_partitions[] = { + /* bootloader (U-Boot, etc) in first sector */ + { + .name = "bootloader", + .offset = 0, + .size = SZ_128K, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + /* bootloader params in the next sector */ + { + .name = "params", + .offset = MTDPART_OFS_APPEND, + .size = SZ_128K, + .mask_flags = 0, + }, + /* kernel */ + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = SZ_2M, + .mask_flags = 0 + }, +#ifdef CONFIG_MACH_OMAP_INNOVATOR + /* rest of flash1 is a file system */ + { + .name = "rootfs", + .offset = MTDPART_OFS_APPEND, + .size = SZ_16M - SZ_2M - 2 * SZ_128K, + .mask_flags = 0 + }, +#endif + /* file system */ + { + .name = "filesystem", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + .mask_flags = 0 + } +}; + +static const char *part_probes[] = { /* "RedBoot", */ "cmdlinepart", NULL }; +static struct mtd_partition *parts; + +#endif + +static void omap_set_vpp(struct map_info *map, int enable) +{ + static int count; + + if (enable) { + if (count++ == 0) + OMAP_EMIFS_CONFIG_REG |= OMAP_EMIFS_CONFIG_WP; + } else { + if (count && (--count == 0)) + OMAP_EMIFS_CONFIG_REG &= ~OMAP_EMIFS_CONFIG_WP; + } +} + +static struct map_info omap_map = { + .bankwidth = 2, + .set_vpp = omap_set_vpp, +}; + +static struct mtd_info *mymtd; + +static int __init probe_nor(char *name, u32 phys, u32 size, int bootable) +{ + int tmp = -EBUSY; + + if (!request_mem_region(phys, size, name)) + return tmp; + + omap_map.name = name; + omap_map.phys = phys; + omap_map.size = size; + omap_map.virt = ioremap(phys, size); + + simple_map_init(&omap_map); + mymtd = do_map_probe("cfi_probe", &omap_map); + if (!mymtd) { + release_mem_region(phys, size); + iounmap(omap_map.virt); + return -EIO; + } + mymtd->owner = THIS_MODULE; + +#ifdef CONFIG_MTD_PARTITIONS + tmp = parse_mtd_partitions(mymtd, part_probes, &parts, 0); + if (tmp > 0) + add_mtd_partitions(mymtd, parts, tmp); + else if (tmp < 0 && bootable) + add_mtd_partitions(mymtd, boot_partitions, + ARRAY_SIZE(boot_partitions)); + else +#endif + add_mtd_device(mymtd); + + return 0; +} + +static int __init init_omap_nor(void) +{ + int ret = -ENODEV; + + /* external CS3 flash might be mapped to address 0 ... */ + if (machine_is_omap_innovator() || machine_is_voiceblue() || + machine_is_netstar()) + ret = probe_nor(MODULE_NAME "_cs0", 0, SZ_32M, 1); + else + ret = probe_nor(MODULE_NAME "_cs3", + omap_cs3_phys(), OMAP_CS3_SIZE, 1); + + /* H2/H3 "NAND boot" puts NOR at CS2B, NAND at CS3 */ + if (ret < 0 && (machine_is_omap_h2() || machine_is_omap_h3())) + ret = probe_nor(MODULE_NAME "_cs2b", + OMAP_CS2B_PHYS, OMAP_CS2B_SIZE, 0); + + return ret; +} + +static void __exit cleanup_omap_nor(void) +{ +#ifdef CONFIG_MTD_PARTITIONS + if (parts) + del_mtd_partitions(mymtd); + else +#endif + del_mtd_device(mymtd); + map_destroy(mymtd); + release_mem_region(omap_map.phys, omap_map.size); + iounmap((void *) omap_map.virt); + +#ifdef CONFIG_MTD_PARTITIONS + if (parts) + kfree(parts); +#endif +} + +module_init(init_omap_nor); +module_exit(cleanup_omap_nor); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MTD NOR map driver for TI OMAP boards"); + diff -Nru a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig --- a/drivers/mtd/nand/Kconfig 2005-03-02 10:51:31 -08:00 +++ b/drivers/mtd/nand/Kconfig 2005-03-02 10:51:31 -08:00 @@ -49,6 +49,12 @@ help If you had to ask, you don't have one. Say 'N'. +config MTD_NAND_OMAP + tristate "NAND Flash device on OMAP H3/H2 board" + depends on ARM && ARCH_OMAP && MTD_NAND && (MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_NETSTAR) + help + Support for NAND flash on Texas Instruments H3/H2 platform. + config MTD_NAND_TOTO tristate "NAND Flash device on TOTO board" depends on ARM && ARCH_OMAP && MTD_NAND @@ -203,5 +209,12 @@ help The simulator may simulate verious NAND flash chips for the MTD nand layer. - + +config MTD_NAND_OMAP_HW + bool "OMAP HW NAND Flash controller support" + depends on ARM && ARCH_OMAP && MTD_NAND + + help + Driver for TI Omap 1710 hardware nand flash controller. + endmenu diff -Nru a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile --- a/drivers/mtd/nand/Makefile 2005-03-02 10:51:31 -08:00 +++ b/drivers/mtd/nand/Makefile 2005-03-02 10:51:31 -08:00 @@ -20,5 +20,7 @@ obj-$(CONFIG_MTD_NAND_RTC_FROM4) += rtc_from4.o obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o +obj-$(CONFIG_MTD_NAND_OMAP) += omap-nand-flash.o +obj-$(CONFIG_MTD_NAND_OMAP_HW) += omap-hw.o nand-objs = nand_base.o nand_bbt.o diff -Nru a/drivers/mtd/nand/omap-hw.c b/drivers/mtd/nand/omap-hw.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mtd/nand/omap-hw.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,843 @@ +/* + * drivers/mtd/nand/omap-hw.c + * + * This is the MTD driver for OMAP 1710 internal HW nand controller. + * + * Copyright (C) 2004 Nokia Corporation + * + * Author: Jarkko Lavinen + * + * Dma patches by Juha Yrjölä + * + * $Id: omap-hw.c,v 1.1 2004/12/08 00:00:01 jlavi Exp $ + * + * 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 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; see the file COPYING. If not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#define NAND_BASE 0xfffbcc00 +#define NND_REVISION 0x00 +#define NND_ACCESS 0x04 +#define NND_ADDR_SRC 0x08 +#define NND_CTRL 0x10 +#define NND_MASK 0x14 +#define NND_STATUS 0x18 +#define NND_READY 0x1c +#define NND_COMMAND 0x20 +#define NND_COMMAND_SEC 0x24 +#define NND_ECC_SELECT 0x28 +#define NND_ECC_START 0x2c +#define NND_ECC_9 0x4c +#define NND_RESET 0x50 +#define NND_FIFO 0x54 +#define NND_FIFOCTRL 0x58 +#define NND_PSC_CLK 0x5c +#define NND_SYSTEST 0x60 +#define NND_SYSCFG 0x64 +#define NND_SYSSTATUS 0x68 +#define NND_FIFOTEST1 0x6c +#define NND_FIFOTEST2 0x70 +#define NND_FIFOTEST3 0x74 +#define NND_FIFOTEST4 0x78 +#define NND_PSC1_CLK 0x8c +#define NND_PSC2_CLK 0x90 + + +#define NND_CMD_READ1_LOWER 0x00 +#define NND_CMD_WRITE1_LOWER 0x00 +#define NND_CMD_READ1_UPPER 0x01 +#define NND_CMD_WRITE1_UPPER 0x01 +#define NND_CMD_PROGRAM_END 0x10 +#define NND_CMD_READ2_SPARE 0x50 +#define NND_CMD_WRITE2_SPARE 0x50 +#define NND_CMD_ERASE 0x60 +#define NND_CMD_STATUS 0x70 +#define NND_CMD_PROGRAM 0x80 +#define NND_CMD_READ_ID 0x90 +#define NND_CMD_ERASE_END 0xD0 +#define NND_CMD_RESET 0xFF + + +#define NAND_Ecc_P1e (1 << 0) +#define NAND_Ecc_P2e (1 << 1) +#define NAND_Ecc_P4e (1 << 2) +#define NAND_Ecc_P8e (1 << 3) +#define NAND_Ecc_P16e (1 << 4) +#define NAND_Ecc_P32e (1 << 5) +#define NAND_Ecc_P64e (1 << 6) +#define NAND_Ecc_P128e (1 << 7) +#define NAND_Ecc_P256e (1 << 8) +#define NAND_Ecc_P512e (1 << 9) +#define NAND_Ecc_P1024e (1 << 10) +#define NAND_Ecc_P2048e (1 << 11) + +#define NAND_Ecc_P1o (1 << 16) +#define NAND_Ecc_P2o (1 << 17) +#define NAND_Ecc_P4o (1 << 18) +#define NAND_Ecc_P8o (1 << 19) +#define NAND_Ecc_P16o (1 << 20) +#define NAND_Ecc_P32o (1 << 21) +#define NAND_Ecc_P64o (1 << 22) +#define NAND_Ecc_P128o (1 << 23) +#define NAND_Ecc_P256o (1 << 24) +#define NAND_Ecc_P512o (1 << 25) +#define NAND_Ecc_P1024o (1 << 26) +#define NAND_Ecc_P2048o (1 << 27) + +#define TF(value) (value ? 1 : 0) + +#define P2048e(a) (TF(a & NAND_Ecc_P2048e) << 0 ) +#define P2048o(a) (TF(a & NAND_Ecc_P2048o) << 1 ) +#define P1e(a) (TF(a & NAND_Ecc_P1e) << 2 ) +#define P1o(a) (TF(a & NAND_Ecc_P1o) << 3 ) +#define P2e(a) (TF(a & NAND_Ecc_P2e) << 4 ) +#define P2o(a) (TF(a & NAND_Ecc_P2o) << 5 ) +#define P4e(a) (TF(a & NAND_Ecc_P4e) << 6 ) +#define P4o(a) (TF(a & NAND_Ecc_P4o) << 7 ) + +#define P8e(a) (TF(a & NAND_Ecc_P8e) << 0 ) +#define P8o(a) (TF(a & NAND_Ecc_P8o) << 1 ) +#define P16e(a) (TF(a & NAND_Ecc_P16e) << 2 ) +#define P16o(a) (TF(a & NAND_Ecc_P16o) << 3 ) +#define P32e(a) (TF(a & NAND_Ecc_P32e) << 4 ) +#define P32o(a) (TF(a & NAND_Ecc_P32o) << 5 ) +#define P64e(a) (TF(a & NAND_Ecc_P64e) << 6 ) +#define P64o(a) (TF(a & NAND_Ecc_P64o) << 7 ) + +#define P128e(a) (TF(a & NAND_Ecc_P128e) << 0 ) +#define P128o(a) (TF(a & NAND_Ecc_P128o) << 1 ) +#define P256e(a) (TF(a & NAND_Ecc_P256e) << 2 ) +#define P256o(a) (TF(a & NAND_Ecc_P256o) << 3 ) +#define P512e(a) (TF(a & NAND_Ecc_P512e) << 4 ) +#define P512o(a) (TF(a & NAND_Ecc_P512o) << 5 ) +#define P1024e(a) (TF(a & NAND_Ecc_P1024e) << 6 ) +#define P1024o(a) (TF(a & NAND_Ecc_P1024o) << 7 ) + +#define P8e_s(a) (TF(a & NAND_Ecc_P8e) << 0 ) +#define P8o_s(a) (TF(a & NAND_Ecc_P8o) << 1 ) +#define P16e_s(a) (TF(a & NAND_Ecc_P16e) << 2 ) +#define P16o_s(a) (TF(a & NAND_Ecc_P16o) << 3 ) +#define P1e_s(a) (TF(a & NAND_Ecc_P1e) << 4 ) +#define P1o_s(a) (TF(a & NAND_Ecc_P1o) << 5 ) +#define P2e_s(a) (TF(a & NAND_Ecc_P2e) << 6 ) +#define P2o_s(a) (TF(a & NAND_Ecc_P2o) << 7 ) + +#define P4e_s(a) (TF(a & NAND_Ecc_P4e) << 0 ) +#define P4o_s(a) (TF(a & NAND_Ecc_P4o) << 1 ) + +extern struct nand_oobinfo jffs2_oobinfo; + +/* + * MTD structure for OMAP board + */ +static struct mtd_info *omap_mtd; +static struct clk *omap_nand_clk; +static unsigned long omap_nand_base = io_p2v(NAND_BASE); + + +static inline u32 nand_read_reg(int idx) +{ + return __raw_readl(omap_nand_base + idx); +} + +static inline void nand_write_reg(int idx, u32 val) +{ + __raw_writel(val, omap_nand_base + idx); +} + +static inline u8 nand_read_reg8(int idx) +{ + return __raw_readb(omap_nand_base + idx); +} + +static inline void nand_write_reg8(int idx, u8 val) +{ + __raw_writeb(val, omap_nand_base + idx); +} + +static void omap_nand_select_chip(struct mtd_info *mtd, int chip) +{ + u32 l; + + switch(chip) { + case -1: + l = nand_read_reg(NND_CTRL); + l |= (1 << 8) | (1 << 10) | (1 << 12) | (1 << 14); + nand_write_reg(NND_CTRL, l); + break; + case 0: + /* Also CS1, CS2, CS4 would be available */ + l = nand_read_reg(NND_CTRL); + l &= ~(1 << 8); + nand_write_reg(NND_CTRL, l); + break; + default: + BUG(); + } +} + +static void nand_dma_cb(int lch, u16 ch_status, void *data) +{ + complete((struct completion *) data); +} + +static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr, + unsigned int u32_count, int is_write) +{ + const int block_size = 16; + unsigned int block_count, len; + int r, dma_ch; + struct completion comp; + unsigned long fifo_reg; + + r = omap_request_dma(OMAP_DMA_NAND, "NAND", nand_dma_cb, &comp, &dma_ch); + if (r < 0) + return r; + block_count = u32_count * 4 / block_size; + nand_write_reg(NND_FIFOCTRL, (block_size << 24) | block_count); + fifo_reg = NAND_BASE + NND_FIFO; + if (is_write) { + omap_set_dma_dest_params(dma_ch, OMAP_DMA_PORT_TIPB, + OMAP_DMA_AMODE_CONSTANT, fifo_reg); + omap_set_dma_src_params(dma_ch, OMAP_DMA_PORT_EMIFF, + OMAP_DMA_AMODE_POST_INC, + virt_to_phys(addr)); +// omap_set_dma_src_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4); + /* Set POSTWRITE bit */ + nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) | (1 << 16)); + } else { + omap_set_dma_src_params(dma_ch, OMAP_DMA_PORT_TIPB, + OMAP_DMA_AMODE_CONSTANT, fifo_reg); + omap_set_dma_dest_params(dma_ch, OMAP_DMA_PORT_EMIFF, + OMAP_DMA_AMODE_POST_INC, + virt_to_phys(addr)); +// omap_set_dma_dest_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_8); + /* Set PREFETCH bit */ + nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) | (1 << 17)); + } + omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S32, block_size / 4, + block_count, OMAP_DMA_SYNC_FRAME); + init_completion(&comp); + + len = u32_count << 2; + consistent_sync(addr, len, DMA_TO_DEVICE); + omap_start_dma(dma_ch); + wait_for_completion(&comp); + omap_free_dma(dma_ch); + if (!is_write) + consistent_sync(addr, len, DMA_FROM_DEVICE); + + nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) & ~((1 << 16) | (1 << 17))); + return 0; +} + +static void fifo_read(u32 *out, unsigned int len) +{ + const int block_size = 16; + unsigned long status_reg, fifo_reg; + int c; + + status_reg = omap_nand_base + NND_STATUS; + fifo_reg = omap_nand_base + NND_FIFO; + len = len * 4 / block_size; + nand_write_reg(NND_FIFOCTRL, (block_size << 24) | len); + nand_write_reg(NND_STATUS, 0x0f); + nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) | (1 << 17)); + c = block_size / 4; + while (len--) { + int i; + + while ((__raw_readl(status_reg) & (1 << 2)) == 0); + __raw_writel(0x0f, status_reg); + for (i = 0; i < c; i++) { + u32 l = __raw_readl(fifo_reg); + *out++ = l; + } + } + nand_write_reg(NND_CTRL, nand_read_reg(NND_CTRL) & ~(1 << 17)); + nand_write_reg(NND_STATUS, 0x0f); +} + +static void omap_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +{ + unsigned long access_reg; + + if (likely(((unsigned long) buf & 3) == 0 && (len & 3) == 0)) { + int u32_count = len >> 2; + u32 *dest = (u32 *) buf; + /* If the transfer is big enough and the length divisible by + * 16, we try to use DMA transfer, or FIFO copy in case of + * DMA failure (e.g. all channels busy) */ + if (u32_count > 64 && (u32_count & 3) == 0) { +#if 1 + if (omap_nand_dma_transfer(mtd, buf, u32_count, 0) == 0) + return; +#endif + /* In case of an error, fallback to FIFO copy */ + fifo_read((u32 *) buf, u32_count); + return; + } + access_reg = omap_nand_base + NND_ACCESS; + /* Small buffers we just read directly */ + while (u32_count--) + *dest++ = __raw_readl(access_reg); + } else { + /* If we're not word-aligned, we use byte copy */ + access_reg = omap_nand_base + NND_ACCESS; + while (len--) + *buf++ = __raw_readb(access_reg); + } +} + +static void omap_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) +{ + if (likely(((unsigned long) buf & 3) == 0 && (len & 3) == 0)) { + const u32 *src = (const u32 *) buf; + + len >>= 2; +#if 0 + /* If the transfer is big enough and length divisible by 16, + * we try to use DMA transfer. */ + if (len > 256 / 4 && (len & 3) == 0) { + if (omap_nand_dma_transfer(mtd, (void *) buf, len, 1) == 0) + return; + /* In case of an error, fallback to CPU copy */ + } +#endif + while (len--) + nand_write_reg(NND_ACCESS, *src++); + } else { + while (len--) + nand_write_reg8(NND_ACCESS, *buf++); + } +} + +static int omap_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) +{ + if (likely(((unsigned long) buf & 3) == 0 && (len & 3) == 0)) { + const u32 *dest = (const u32 *) buf; + len >>= 2; + while (len--) + if (*dest++ != nand_read_reg(NND_ACCESS)) + return -EFAULT; + } else { + while (len--) + if (*buf++ != nand_read_reg8(NND_ACCESS)) + return -EFAULT; + } + return 0; +} + +static u_char omap_nand_read_byte(struct mtd_info *mtd) +{ + return nand_read_reg8(NND_ACCESS); +} + +static void omap_nand_write_byte(struct mtd_info *mtd, u_char byte) +{ + nand_write_reg8(NND_ACCESS, byte); +} + +static int omap_nand_dev_ready(struct mtd_info *mtd) +{ + u32 l; + + l = nand_read_reg(NND_READY); + return l & 0x01; +} + +static int nand_write_command(u8 cmd, u32 addr, int addr_valid) +{ + if (addr_valid) { + nand_write_reg(NND_ADDR_SRC, addr); + nand_write_reg8(NND_COMMAND, cmd); + } else { + nand_write_reg(NND_ADDR_SRC, 0); + nand_write_reg8(NND_COMMAND_SEC, cmd); + } + while (!omap_nand_dev_ready(NULL)); + return 0; +} + +/* + * Send command to NAND device + */ +static void omap_nand_command(struct mtd_info *mtd, unsigned command, int column, int page_addr) +{ + struct nand_chip *this = mtd->priv; + + /* + * Write out the command to the device. + */ + if (command == NAND_CMD_SEQIN) { + int readcmd; + + if (column >= mtd->oobblock) { + /* OOB area */ + column -= mtd->oobblock; + readcmd = NAND_CMD_READOOB; + } else if (column < 256) { + /* First 256 bytes --> READ0 */ + readcmd = NAND_CMD_READ0; + } else { + column -= 256; + readcmd = NAND_CMD_READ1; + } + nand_write_command(readcmd, 0, 0); + } + + switch (command) { + case NAND_CMD_RESET: + case NAND_CMD_PAGEPROG: + case NAND_CMD_STATUS: + case NAND_CMD_ERASE2: + nand_write_command(command, 0, 0); + break; + + case NAND_CMD_ERASE1: + nand_write_command(command, ((page_addr & 0xFFFFFF00) << 1) | (page_addr & 0XFF), 1); + break; + + default: + nand_write_command(command, (page_addr << this->page_shift) | column, 1); + } +} + +static void omap_nand_command_lp(struct mtd_info *mtd, unsigned command, int column, int page_addr) +{ + struct nand_chip *this = mtd->priv; + + if (command == NAND_CMD_READOOB) { + column += mtd->oobblock; + command = NAND_CMD_READ0; + } + switch (command) { + case NAND_CMD_RESET: + case NAND_CMD_PAGEPROG: + case NAND_CMD_STATUS: + case NAND_CMD_ERASE2: + nand_write_command(command, 0, 0); + break; + case NAND_CMD_ERASE1: + nand_write_command(command, page_addr << this->page_shift >> 11, 1); + break; + default: + nand_write_command(command, (page_addr << 16) | column, 1); + } + if (command == NAND_CMD_READ0) + nand_write_command(NAND_CMD_READSTART, 0, 0); +} + +/* + * Generate non-inverted ECC bytes. + * + * Using noninverted ECC can be considered ugly since writing a blank + * page ie. padding will clear the ECC bytes. This is no problem as long + * nobody is trying to write data on the seemingly unused page. + * + * Reading an erased page will produce an ECC mismatch between + * generated and read ECC bytes that has to be dealt with separately. + */ +static int omap_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) +{ + u32 l; + int reg; + int n; + struct nand_chip *this = mtd->priv; + + if (this->eccmode == NAND_ECC_HW12_2048) + n = 4; + else + n = 1; + reg = NND_ECC_START; + while (n--) { + l = nand_read_reg(reg); + *ecc_code++ = l; // P128e, ..., P1e + *ecc_code++ = l >> 16; // P128o, ..., P1o + // P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e + *ecc_code++ = ((l >> 8) & 0x0f) | ((l >> 20) & 0xf0); + reg += 4; + } + return 0; +} + +/* + * This function will generate true ECC value, which can be used + * when correcting data read from NAND flash memory core + */ +static void gen_true_ecc(u8 *ecc_buf) +{ + u32 tmp = ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xF0) << 20) | ((ecc_buf[2] & 0x0F) << 8); + + ecc_buf[0] = ~(P64o(tmp) | P64e(tmp) | P32o(tmp) | P32e(tmp) | P16o(tmp) | P16e(tmp) | P8o(tmp) | P8e(tmp) ); + ecc_buf[1] = ~(P1024o(tmp) | P1024e(tmp) | P512o(tmp) | P512e(tmp) | P256o(tmp) | P256e(tmp) | P128o(tmp) | P128e(tmp)); + ecc_buf[2] = ~( P4o(tmp) | P4e(tmp) | P2o(tmp) | P2e(tmp) | P1o(tmp) | P1e(tmp) | P2048o(tmp) | P2048e(tmp)); +} + +/* + * This function compares two ECC's and indicates if there is an error. + * If the error can be corrected it will be corrected to the buffer + */ +static int omap_nand_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ + u8 *ecc_data2, /* read from register */ + u8 *page_data) +{ + uint i; + u8 tmp0_bit[8], tmp1_bit[8], tmp2_bit[8]; + u8 comp0_bit[8], comp1_bit[8], comp2_bit[8]; + u8 ecc_bit[24]; + u8 ecc_sum = 0; + u8 find_bit = 0; + uint find_byte = 0; + int isEccFF; + + isEccFF = ((*(u32 *)ecc_data1 & 0xFFFFFF) == 0xFFFFFF); + + gen_true_ecc(ecc_data1); + gen_true_ecc(ecc_data2); + + for (i = 0; i <= 2; i++) { + *(ecc_data1 + i) = ~(*(ecc_data1 + i)); + *(ecc_data2 + i) = ~(*(ecc_data2 + i)); + } + + for (i = 0; i < 8; i++) { + tmp0_bit[i] = *ecc_data1 % 2; + *ecc_data1 = *ecc_data1 / 2; + } + + for (i = 0; i < 8; i++) { + tmp1_bit[i] = *(ecc_data1 + 1) % 2; + *(ecc_data1 + 1) = *(ecc_data1 + 1) / 2; + } + + for (i = 0; i < 8; i++) { + tmp2_bit[i] = *(ecc_data1 + 2) % 2; + *(ecc_data1 + 2) = *(ecc_data1 + 2) / 2; + } + + for (i = 0; i < 8; i++) { + comp0_bit[i] = *ecc_data2 % 2; + *ecc_data2 = *ecc_data2 / 2; + } + + for (i = 0; i < 8; i++) { + comp1_bit[i] = *(ecc_data2 + 1) % 2; + *(ecc_data2 + 1) = *(ecc_data2 + 1) / 2; + } + + for (i = 0; i < 8; i++) { + comp2_bit[i] = *(ecc_data2 + 2) % 2; + *(ecc_data2 + 2) = *(ecc_data2 + 2) / 2; + } + + for (i = 0; i< 6; i++ ) + ecc_bit[i] = tmp2_bit[i + 2] ^ comp2_bit[i + 2]; + + for (i = 0; i < 8; i++) + ecc_bit[i + 6] = tmp0_bit[i] ^ comp0_bit[i]; + + for (i = 0; i < 8; i++) + ecc_bit[i + 14] = tmp1_bit[i] ^ comp1_bit[i]; + + ecc_bit[22] = tmp2_bit[0] ^ comp2_bit[0]; + ecc_bit[23] = tmp2_bit[1] ^ comp2_bit[1]; + + for (i = 0; i < 24; i++) + ecc_sum += ecc_bit[i]; + + switch (ecc_sum) { + case 0: + /* Not reached because this function is not called if + ECC values are equal */ + return 0; + + case 1: + /* Uncorrectable error */ + DEBUG (MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR 1\n"); + return -1; + + case 12: + /* Correctable error */ + find_byte = (ecc_bit[23] << 8) + + (ecc_bit[21] << 7) + + (ecc_bit[19] << 6) + + (ecc_bit[17] << 5) + + (ecc_bit[15] << 4) + + (ecc_bit[13] << 3) + + (ecc_bit[11] << 2) + + (ecc_bit[9] << 1) + + ecc_bit[7]; + + find_bit = (ecc_bit[5] << 2) + (ecc_bit[3] << 1) + ecc_bit[1]; + + DEBUG (MTD_DEBUG_LEVEL0, "Correcting single bit ECC error at offset: %d, bit: %d\n", find_byte, find_bit); + + page_data[find_byte] ^= (1 << find_bit); + + return 0; + default: + if (isEccFF) { + if (ecc_data2[0] == 0 && ecc_data2[1] == 0 && ecc_data2[2] == 0) + return 0; + } + DEBUG (MTD_DEBUG_LEVEL0, "UNCORRECTED_ERROR default\n"); + return -1; + } +} + +static int omap_nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) +{ + struct nand_chip *this; + int block_count = 0, i, r; + + this = mtd->priv; + if (this->eccmode == NAND_ECC_HW12_2048) + block_count = 4; + else + block_count = 1; + for (i = 0; i < block_count; i++) { + if (memcmp(read_ecc, calc_ecc, 3) != 0) { + r = omap_nand_compare_ecc(read_ecc, calc_ecc, dat); + if (r < 0) + return r; + } + read_ecc += 3; + calc_ecc += 3; + dat += 512; + } + return 0; +} + +static void omap_nand_enable_hwecc(struct mtd_info *mtd, int mode) +{ + nand_write_reg(NND_RESET, 0x01); +} + +static int omap_nand_scan_bbt(struct mtd_info *mtd) +{ + return 0; +} + +#ifdef CONFIG_MTD_CMDLINE_PARTS + +extern int mtdpart_setup(char *); + +static int __init add_dynamic_parts(struct mtd_info *mtd) +{ + static const char *part_parsers[] = { "cmdlinepart", NULL }; + struct mtd_partition *parts; + const struct omap_flash_part_config *cfg; + char *part_str = NULL; + size_t part_str_len; + int c; + + cfg = omap_get_var_config(OMAP_TAG_FLASH_PART, &part_str_len); + if (cfg != NULL) { + part_str = kmalloc(part_str_len + 1, GFP_KERNEL); + if (part_str == NULL) + return -ENOMEM; + memcpy(part_str, cfg->part_table, part_str_len); + part_str[part_str_len] = '\0'; + mtdpart_setup(part_str); + } + c = parse_mtd_partitions(omap_mtd, part_parsers, &parts, 0); + if (part_str != NULL) { + mtdpart_setup(NULL); + kfree(part_str); + } + if (c <= 0) + return -1; + + add_mtd_partitions(mtd, parts, c); + + return 0; +} + +#else + +static inline int add_dynamic_parts(struct mtd_info *mtd) +{ + return -1; +} + +#endif + +static inline int calc_psc(int ns, int cycle_ps) +{ + return (ns * 1000 + (cycle_ps - 1)) / cycle_ps; +} + +static void set_psc_regs(int psc_ns, int psc1_ns, int psc2_ns) +{ + int psc[3], i; + unsigned long rate, ps; + + rate = clk_get_rate(omap_nand_clk); + ps = 1000000000 / (rate / 1000); + psc[0] = calc_psc(psc_ns, ps); + psc[1] = calc_psc(psc1_ns, ps); + psc[2] = calc_psc(psc2_ns, ps); + for (i = 0; i < 3; i++) { + if (psc[i] == 0) + psc[i] = 1; + else if (psc[i] > 256) + psc[i] = 256; + } + nand_write_reg(NND_PSC_CLK, psc[0] - 1); + nand_write_reg(NND_PSC1_CLK, psc[1] - 1); + nand_write_reg(NND_PSC2_CLK, psc[2] - 1); + printk(KERN_INFO "omap-hw-nand: using PSC values %d, %d, %d\n", psc[0], psc[1], psc[2]); +} + +/* + * Main initialization routine + */ +static int __init omap_nand_init(void) +{ + struct nand_chip *this; + int err = 0; + u32 l; + + omap_nand_clk = clk_get(NULL, "armper_ck"); + BUG_ON(omap_nand_clk == NULL); + clk_use(omap_nand_clk); + + l = nand_read_reg(NND_REVISION); + printk(KERN_INFO "omap-hw-nand: OMAP NAND Controller rev. %d.%d\n", l>>4, l & 0xf); + + /* Reset the NAND Controller */ + nand_write_reg(NND_SYSCFG, 0x02); + while ((nand_read_reg(NND_SYSSTATUS) & 0x01) == 0); + + /* No Prefetch, no postwrite, write prot & enable pairs disabled, + addres counter set to send 4 byte addresses to flash, + A8 is set not to be sent to flash (erase addre needs formatting), + choose little endian, enable 512 byte ECC logic, + */ + nand_write_reg(NND_CTRL, 0xFF01); + + /* Allocate memory for MTD device structure and private data */ + omap_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); + if (!omap_mtd) { + printk(KERN_WARNING "omap-hw-nand: Unable to allocate OMAP NAND MTD device structure.\n"); + err = -ENOMEM; + goto free_clock; + } + + /* Get pointer to private data */ + this = (struct nand_chip *) (&omap_mtd[1]); + + /* Initialize structures */ + memset((char *) omap_mtd, 0, sizeof(struct mtd_info)); + memset((char *) this, 0, sizeof(struct nand_chip)); + + /* Link the private data with the MTD structure */ + omap_mtd->priv = this; + omap_mtd->name = "omap-nand"; + + /* Used from chip select and nand_command() */ + this->read_byte = omap_nand_read_byte; + this->write_byte = omap_nand_write_byte; + + this->select_chip = omap_nand_select_chip; + this->dev_ready = omap_nand_dev_ready; + this->chip_delay = 0; + this->eccmode = NAND_ECC_HW3_512; + this->cmdfunc = omap_nand_command; + this->write_buf = omap_nand_write_buf; + this->read_buf = omap_nand_read_buf; + this->verify_buf = omap_nand_verify_buf; + this->calculate_ecc = omap_nand_calculate_ecc; + this->correct_data = omap_nand_correct_data; + this->enable_hwecc = omap_nand_enable_hwecc; + this->scan_bbt = omap_nand_scan_bbt; + + nand_write_reg(NND_PSC_CLK, 10); + /* Scan to find existance of the device */ + if (nand_scan(omap_mtd, 1)) { + err = -ENXIO; + goto out_mtd; + } + + set_psc_regs(25, 15, 35); + if (this->page_shift == 11) { + this->cmdfunc = omap_nand_command_lp; + l = nand_read_reg(NND_CTRL); + l |= 1 << 4; /* Set the A8 bit in CTRL reg */ + nand_write_reg(NND_CTRL, l); + this->eccmode = NAND_ECC_HW12_2048; + this->eccsteps = 1; + this->eccsize = 2048; + this->eccbytes = 12; + omap_mtd->eccsize = 2048; + nand_write_reg(NND_ECC_SELECT, 6); + } + + this->options |= NAND_NO_AUTOINCR; + + err = add_dynamic_parts(omap_mtd); + if (err < 0) { + printk(KERN_ERR "omap-hw-nand: no partitions defined\n"); + err = -ENODEV; + nand_release(omap_mtd); + goto out_mtd; + } + /* init completed */ + return 0; +out_mtd: + kfree(omap_mtd); +free_clock: + clk_put(omap_nand_clk); + return err; +} + +module_init(omap_nand_init); + +/* + * Clean up routine + */ +static void __exit omap_nand_cleanup (void) +{ + clk_unuse(omap_nand_clk); + clk_put(omap_nand_clk); + nand_release(omap_mtd); + kfree(omap_mtd); +} + +module_exit(omap_nand_cleanup); + diff -Nru a/drivers/mtd/nand/omap-nand-flash.c b/drivers/mtd/nand/omap-nand-flash.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mtd/nand/omap-nand-flash.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,308 @@ +/* + * drivers/mtd/nand/omap-nand-flash.c + * + * Copyright (c) 2004 Texas Instruments + * Jian Zhang + * Copyright (c) 2004 David Brownell + * + * Derived from drivers/mtd/autcpu12.c + * + * Copyright (c) 2002 Thomas Gleixner + * + * 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. + * + * Overview: + * This is a device driver for the NAND flash device found on the + * TI H3/H2 boards. It supports 16-bit 32MiB Samsung k9f5616 chip. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define H3_NAND_RB_GPIO_PIN 10 +#define H2_NAND_RB_GPIO_PIN 62 +#define NETSTAR_NAND_RB_GPIO_PIN 1 +/* + * MTD structure for H3 board + */ +static struct mtd_info *omap_nand_mtd = NULL; + +static void __iomem *omap_nand_flash_base; + +/* + * Define partitions for flash devices + */ + +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition static_partition[] = { + { .name = "Booting Image", + .offset = 0, + .size = 64 * 1024, + .mask_flags = MTD_WRITEABLE /* force read-only */ + }, + { .name = "U-Boot", + .offset = MTDPART_OFS_APPEND, + .size = 256 * 1024, + .mask_flags = MTD_WRITEABLE /* force read-only */ + }, + { .name = "U-Boot Environment", + .offset = MTDPART_OFS_APPEND, + .size = 192 * 1024 + }, + { .name = "Kernel", + .offset = MTDPART_OFS_APPEND, + .size = 2 * SZ_1M + }, + { .name = "File System", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, + }, +}; + +const char *part_probes[] = { "cmdlinepart", NULL, }; + +#endif + +/* H2/H3 maps two address LSBs to CLE and ALE; MSBs make CS_2B */ +#define MASK_CLE 0x02 +#define MASK_ALE 0x04 + + +/* + * hardware specific access to control-lines +*/ +static void omap_nand_hwcontrol(struct mtd_info *mtd, int cmd) +{ + struct nand_chip *this = mtd->priv; + u32 IO_ADDR_W = (u32) this->IO_ADDR_W; + + IO_ADDR_W &= ~(MASK_ALE|MASK_CLE); + switch(cmd){ + case NAND_CTL_SETCLE: IO_ADDR_W |= MASK_CLE; break; + case NAND_CTL_SETALE: IO_ADDR_W |= MASK_ALE; break; + } + this->IO_ADDR_W = (void __iomem *) IO_ADDR_W; +} + +/* + * chip busy R/B detection + */ +static int omap_nand_ready(struct mtd_info *mtd) +{ + if (machine_is_omap_h3()) + return omap_get_gpio_datain(H3_NAND_RB_GPIO_PIN); + if (machine_is_omap_h2()) + return omap_get_gpio_datain(H2_NAND_RB_GPIO_PIN); + if (machine_is_netstar()) + return omap_get_gpio_datain(NETSTAR_NAND_RB_GPIO_PIN); +} + +/* Scan to find existance of the device at omap_nand_flash_base. + This also allocates oob and data internal buffers */ +static int probe_nand_chip(void) +{ + struct nand_chip *this; + + this = (struct nand_chip *) (&omap_nand_mtd[1]); + + /* Initialize structures */ + memset((char *) this, 0, sizeof(struct nand_chip)); + + this->IO_ADDR_R = omap_nand_flash_base; + this->IO_ADDR_W = omap_nand_flash_base; + this->options = NAND_SAMSUNG_LP_OPTIONS; + this->hwcontrol = omap_nand_hwcontrol; + this->eccmode = NAND_ECC_SOFT; + + /* try 16-bit chip first */ + this->options |= NAND_BUSWIDTH_16; + if (nand_scan (omap_nand_mtd, 1)) { + if (machine_is_omap_h3()) + return -ENXIO; + + /* then try 8-bit chip for H2 */ + memset((char *) this, 0, sizeof(struct nand_chip)); + this->IO_ADDR_R = omap_nand_flash_base; + this->IO_ADDR_W = omap_nand_flash_base; + this->options = NAND_SAMSUNG_LP_OPTIONS; + this->hwcontrol = omap_nand_hwcontrol; + this->eccmode = NAND_ECC_SOFT; + if (nand_scan (omap_nand_mtd, 1)) { + return -ENXIO; + } + } + + return 0; +} + +/* + * Main initialization routine + */ +int __init omap_nand_init (void) +{ + struct nand_chip *this; + struct mtd_partition *dynamic_partition = 0; + int err = 0; + int nandboot = 0; + + if (!(machine_is_omap_h2() || machine_is_omap_h3() || machine_is_netstar())) + return -ENODEV; + + /* Allocate memory for MTD device structure and private data */ + omap_nand_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), + GFP_KERNEL); + if (!omap_nand_mtd) { + printk (KERN_WARNING "Unable to allocate NAND MTD device structure.\n"); + err = -ENOMEM; + goto out; + } + + /* Get pointer to private data */ + this = (struct nand_chip *) (&omap_nand_mtd[1]); + + /* Initialize structures */ + memset((char *) omap_nand_mtd, 0, sizeof(struct mtd_info) + sizeof(struct nand_chip)); + + /* Link the private data with the MTD structure */ + omap_nand_mtd->priv = this; + + if (machine_is_omap_h2()) { + /* FIXME on H2, R/B needs M7_1610_GPIO62 ... */ + this->chip_delay = 15; + omap_cfg_reg(L3_1610_FLASH_CS2B_OE); + omap_cfg_reg(M8_1610_FLASH_CS2B_WE); + } else if (machine_is_omap_h3()) { + if (omap_request_gpio(H3_NAND_RB_GPIO_PIN) != 0) { + printk(KERN_ERR "NAND: Unable to get GPIO pin for R/B, use delay\n"); + /* 15 us command delay time */ + this->chip_delay = 15; + } else { + /* GPIO10 for input. it is in GPIO1 module */ + omap_set_gpio_direction(H3_NAND_RB_GPIO_PIN, 1); + + /* GPIO10 Func_MUX_CTRL reg bit 29:27, Configure V2 to mode1 as GPIO */ + /* GPIO10 pullup/down register, Enable pullup on GPIO10 */ + omap_cfg_reg(V2_1710_GPIO10); + + this->dev_ready = omap_nand_ready; + } + } else if (machine_is_netstar()) { + if (omap_request_gpio(NETSTAR_NAND_RB_GPIO_PIN) != 0) { + printk(KERN_ERR "NAND: Unable to get GPIO pin for R/B, use delay\n"); + /* 15 us command delay time */ + this->chip_delay = 15; + } else { + omap_set_gpio_direction(NETSTAR_NAND_RB_GPIO_PIN, 1); + this->dev_ready = omap_nand_ready; + } + } + + /* try the first address */ + omap_nand_flash_base = ioremap(OMAP_NAND_FLASH_START1, SZ_4K); + if (probe_nand_chip()){ + nandboot = 1; + /* try the second address */ + iounmap(omap_nand_flash_base); + omap_nand_flash_base = ioremap(OMAP_NAND_FLASH_START2, SZ_4K); + if (probe_nand_chip()){ + iounmap(omap_nand_flash_base); + err = -ENXIO; + goto out_mtd; + } + } + + /* Register the partitions */ + switch(omap_nand_mtd->size) { + case SZ_128M: + if (!(machine_is_netstar())) + goto out_unsupported; + /* fall through */ + case SZ_32M: +#ifdef CONFIG_MTD_PARTITIONS + err = parse_mtd_partitions(omap_nand_mtd, part_probes, + &dynamic_partition, 0); + if (err > 0) + err = add_mtd_partitions(omap_nand_mtd, + dynamic_partition, err); + else if (nandboot) + err = add_mtd_partitions(omap_nand_mtd, + static_partition, + ARRAY_SIZE(static_partition)); + else +#endif + err = add_mtd_device(omap_nand_mtd); + if (err) + goto out_buf; + break; +out_unsupported: + default: + printk(KERN_WARNING "Unsupported NAND device\n"); + err = -ENXIO; + goto out_buf; + } + + goto out; + +out_buf: + nand_release (omap_nand_mtd); + if (this->dev_ready) { + if (machine_is_omap_h2()) + omap_free_gpio(H2_NAND_RB_GPIO_PIN); + else if (machine_is_omap_h3()) + omap_free_gpio(H3_NAND_RB_GPIO_PIN); + else if (machine_is_netstar()) + omap_free_gpio(NETSTAR_NAND_RB_GPIO_PIN); + } + iounmap(omap_nand_flash_base); + +out_mtd: + kfree (omap_nand_mtd); +out: + return err; +} + +module_init(omap_nand_init); + +/* + * Clean up routine + */ +static void __exit omap_nand_cleanup (void) +{ + struct nand_chip *this = omap_nand_mtd->priv; + if (this->dev_ready) { + if (machine_is_omap_h2()) + omap_free_gpio(H2_NAND_RB_GPIO_PIN); + else if (machine_is_omap_h3()) + omap_free_gpio(H3_NAND_RB_GPIO_PIN); + else if (machine_is_netstar()) + omap_free_gpio(NETSTAR_NAND_RB_GPIO_PIN); + } + + /* nand_release frees MTD partitions, MTD structure + and nand internal buffers*/ + nand_release (omap_nand_mtd); + kfree (omap_nand_mtd); + + iounmap(omap_nand_flash_base); +} + +module_exit(omap_nand_cleanup); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jian Zhang "); +MODULE_DESCRIPTION("Glue layer for NAND flash on H2/H3 boards"); diff -Nru a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig --- a/drivers/net/irda/Kconfig 2005-03-02 10:51:31 -08:00 +++ b/drivers/net/irda/Kconfig 2005-03-02 10:51:31 -08:00 @@ -341,6 +341,12 @@ To compile it as a module, choose M here: the module will be called donauboe. +config OMAP1610_IR + tristate "OMAP1610 IrDA(SIR/MIR/FIR)" + depends on IRDA + help + Say Y here if you want to build support for the Omap1610 IR. + config AU1000_FIR tristate "Alchemy Au1000 SIR/FIR" depends on MIPS_AU1000 && IRDA diff -Nru a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile --- a/drivers/net/irda/Makefile 2005-03-02 10:51:31 -08:00 +++ b/drivers/net/irda/Makefile 2005-03-02 10:51:31 -08:00 @@ -42,6 +42,8 @@ obj-$(CONFIG_MCP2120_DONGLE) += mcp2120-sir.o obj-$(CONFIG_ACT200L_DONGLE) += act200l-sir.o obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o +obj-$(CONFIG_OMAP1610_IR) += omap1610-ir.o + # The SIR helper module sir-dev-objs := sir_core.o sir_dev.o sir_dongle.o sir_kthread.o diff -Nru a/drivers/net/irda/omap1610-ir.c b/drivers/net/irda/omap1610-ir.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/net/irda/omap1610-ir.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,1017 @@ +/* + * BRIEF MODULE DESCRIPTION + * + * Infra-red driver for the OMAP1610-H2 and OMAP1710-H3 Platforms + * (SIR/MIR/FIR modes) + * (based on omap-sir.c) + * + * Copyright 2003 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * source@mvista.com + * + * Copyright 2004 Texas Instruments. + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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. + * + Modifications: + Feb 2004, Texas Instruments + - Ported to 2.6 kernel (Feb 2004). + * + Apr 2004, Texas Instruments + - Added support for H3 (Apr 2004). + Nov 2004, Texas Instruments + - Added support for Power Management. + + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_MACH_OMAP_H3 +#include +#endif + +#define SIR_MODE 0 +#define MIR_MODE 1 +#define FIR_MODE 2 + +#define OMAP1610_H2_FIRSEL_GPIO 17 + +static int rx_state = 0; /* RX state for IOCTL */ + +struct omap1610_irda { + unsigned char open; + int speed; /* Current IrDA speed */ + int newspeed; + + struct net_device_stats stats; + struct irlap_cb *irlap; + struct qos_info qos; + + int rx_dma_channel; + int tx_dma_channel; + + dma_addr_t rx_buf_dma_phys; /* Physical adress of RX DMA buffer */ + dma_addr_t tx_buf_dma_phys; /* Physical adress of TX DMA buffer */ + + void *rx_buf_dma_virt; /* Virtual adress of RX DMA buffer */ + void *tx_buf_dma_virt; /* Virtual adress of TX DMA buffer */ + + struct device *dev; +}; + +#define OMAP_IRDA_DEBUG 0 + +#if (OMAP_IRDA_DEBUG > 0) +#define DBG(format, args...) printk(KERN_ERR "%s(): " format, __FUNCTION__, ## args); +#define DBG_IRQ(format, args...) printk(KERN_ERR "%s(): " format, __FUNCTION__, ## args); +#else +#define DBG(format, args...) +#define DBG_IRQ(format, args...) +#endif + +#if (OMAP_IRDA_DEBUG > 1) +#define __ECHO_IN printk(KERN_ERR "%s: enter\n",__FUNCTION__); +#define __ECHO_OUT printk(KERN_ERR "%s: exit\n",__FUNCTION__); +#else +#define __ECHO_IN +#define __ECHO_OUT +#endif + +#ifdef OMAP1610_IR_HARDWARE_DEBUG_ENABLE +#define HDBG_DELAY 200 + +void hard_debug1(u16 i) +{ + for (; i; i--) { + omap_writew(0x2000, + OMAP1610_GPIO1_BASE + OMAP1610_GPIO_CLEAR_DATAOUT); + udelay(HDBG_DELAY); + + omap_writew(0x2000, + OMAP1610_GPIO1_BASE + OMAP1610_GPIO_SET_DATAOUT); + udelay(HDBG_DELAY); + } +} + +void hard_debug2(u16 i) +{ + for (; i; i--) { + omap_writew(0x8000, + OMAP1610_GPIO1_BASE + OMAP1610_GPIO_CLEAR_DATAOUT); + udelay(HDBG_DELAY); + + omap_writew(0x8000, + OMAP1610_GPIO1_BASE + OMAP1610_GPIO_SET_DATAOUT); + udelay(HDBG_DELAY); + } +} + +#define HDBG1(i) hard_debug1(i) +#define HDBG2(i) hard_debug2(i) +#else +#define HDBG1(i) +#define HDBG2(i) +#endif + +/* forward declarations */ + +extern void irda_device_setup(struct net_device *dev); +extern void omap_stop_dma(int lch); +static int omap1610_irda_set_speed(struct net_device *dev, int speed); + +static void omap1610_irda_start_rx_dma(struct omap1610_irda *si) +{ + /* Configure DMA */ + omap_set_dma_src_params(si->rx_dma_channel, 0x3, 0x0, (unsigned long)UART3_RHR); + + omap_enable_dma_irq(si->rx_dma_channel, 0x01); + + omap_set_dma_dest_params(si->rx_dma_channel, 0x0, 0x1, + si->rx_buf_dma_phys); + + omap_set_dma_transfer_params(si->rx_dma_channel, 0x0, 4096, 0x1, 0x0); + + omap_start_dma(si->rx_dma_channel); +} + +static void omap1610_start_tx_dma(struct omap1610_irda *si, int size) +{ + __ECHO_IN; + + /* Configure DMA */ + omap_set_dma_dest_params(si->tx_dma_channel, 0x03, 0x0, (unsigned long)UART3_THR); + + omap_enable_dma_irq(si->tx_dma_channel, 0x01); + + omap_set_dma_src_params(si->tx_dma_channel, 0x0, 0x1, + si->tx_buf_dma_phys); + + omap_set_dma_transfer_params(si->tx_dma_channel, 0x0, size, 0x1, 0x0); + + HDBG1(1); + + /* Start DMA */ + omap_start_dma(si->tx_dma_channel); + + HDBG1(1); + + __ECHO_OUT; +} + +/* DMA RX callback - normally, we should not go here, + it calls only if something is going wrong + */ + +static void omap1610_irda_rx_dma_callback(int lch, u16 ch_status, void *data) +{ + struct net_device *dev = data; + struct omap1610_irda *si = dev->priv; + + printk(KERN_ERR "RX Transfer error or very big frame \n"); + + /* Clear interrupts */ + omap_readb(UART3_IIR); + + si->stats.rx_frame_errors++; + + omap_readb(UART3_RESUME); + + /* Re-init RX DMA */ + omap1610_irda_start_rx_dma(si); + +} + +/* DMA TX callback - calling when frame transfer has been finished */ + +static void omap1610_irda_tx_dma_callback(int lch, u16 ch_status, void *data) +{ + struct net_device *dev = data; + struct omap1610_irda *si = dev->priv; + + __ECHO_IN; + + /*Stop DMA controller */ + omap_stop_dma(si->tx_dma_channel); + + __ECHO_OUT; + +} + +/* + * Set the IrDA communications speed. + * Interrupt have to be disabled here. + */ + +static int omap1610_irda_startup(struct net_device *dev) +{ + __ECHO_IN; + + /* Enable UART3 clock and set UART3 to IrDA mode */ + omap_writel(omap_readl(MOD_CONF_CTRL_0) | (1 << 31) | (1 << 15), + MOD_CONF_CTRL_0); + + if (machine_is_omap_h2()) { +// omap_cfg_reg(Y15_1610_GPIO17); + omap_writel(omap_readl(FUNC_MUX_CTRL_A) | 7, FUNC_MUX_CTRL_A); + + omap_set_gpio_direction(OMAP1610_H2_FIRSEL_GPIO, 0); + omap_set_gpio_dataout(OMAP1610_H2_FIRSEL_GPIO, 0); + } + + omap_writeb(0x07, UART3_MDR1); /* Put UART3 in reset mode */ + + /* Clear DLH and DLL */ + omap_writeb(1 << 7, UART3_LCR); + + omap_writeb(0, UART3_DLL); + omap_writeb(0, UART3_DLH); + + omap_writeb(0xbf, UART3_LCR); + + omap_writeb(1 << 4, UART3_EFR); + + omap_writeb(1 << 7, UART3_LCR); + + /* Enable access to UART3_TLR and UART3_TCR registers */ + omap_writeb(1 << 6, UART3_MCR); + + omap_writeb(0, UART3_SCR); + + /* Set Rx trigger to 1 and Tx trigger to 1 */ + omap_writeb(0, UART3_TLR); + + /* Set LCR to 8 bits and 1 stop bit */ + omap_writeb(0x03, UART3_LCR); + + /* Clear RX and TX FIFO and enable FIFO */ + /* Use DMA Req for transfers */ + + omap_writeb((1 << 2) | (1 << 1) | (1 << 3) | (1 << 4) | (1 << 6) | 1, + UART3_FCR); + + omap_writeb(0, UART3_MCR); + + omap_writeb((1 << 7) | (1 << 6), UART3_SCR); + + /* Enable UART3 SIR Mode,(Frame-length method to end frames) */ + omap_writeb(1, UART3_MDR1); + + /* Set Status FIFO trig to 1 */ + omap_writeb(0, UART3_MDR2); + + /* Enables RXIR input */ + /* and disable TX underrun */ + /* SEND_SIP pulse */ + + // omap_writeb((1 << 7) | (1 << 6) | (1 << 4), UART3_ACREG); + omap_writeb((1 << 6) | (1 << 4), UART3_ACREG); + + /* Enable EOF Interrupt only */ + omap_writeb((1 << 7) | (1 << 5), UART3_IER); + + /* Set Maximum Received Frame size to 2048 bytes */ + omap_writeb(0x00, UART3_RXFLL); + omap_writeb(0x08, UART3_RXFLH); + + omap_readb(UART3_RESUME); + + __ECHO_OUT; + + return 0; + +} + +static int omap1610_irda_shutdown(struct omap1610_irda *si) +{ + /* Disable all UART3 Interrupts */ + omap_writeb(0, UART3_IER); + + /* Disable UART3 and disable baud rate generator */ + omap_writeb(0x07, UART3_MDR1); /* Put UART3 in reset mode */ + + omap_writeb((1 << 5), UART3_ACREG); /* set SD_MODE pin to high and Disable RX IR */ + + /* Clear DLH and DLL */ + omap_writeb(1 << 7, UART3_LCR); + omap_writeb(0, UART3_DLL); + omap_writeb(0, UART3_DLH); + + return 0; +} + +static irqreturn_t +omap1610_irda_irq(int irq, void *dev_id, struct pt_regs *hw_regs) +{ + struct net_device *dev = dev_id; + struct omap1610_irda *si = dev->priv; + struct sk_buff *skb; + + u8 status; + int w = 0; + + __ECHO_IN; + + /* Clear EOF interrupt */ + status = omap_readb(UART3_IIR); + + if (status & (1 << 5)) { + u8 mdr2 = omap_readb(UART3_MDR2); + HDBG1(2); + if (mdr2 & 1) + printk(KERN_ERR "IRDA Buffer underrun error"); + + si->stats.tx_packets++; + + if (si->newspeed) { + omap1610_irda_set_speed(dev, si->newspeed); + si->newspeed = 0; + } + + netif_wake_queue(dev); + + if (!(status & 0x80)) + return IRQ_HANDLED; + } + + /* Stop DMA and if there are no errors, send frame to upper layer */ + + omap_stop_dma(si->rx_dma_channel); + + status = omap_readb(UART3_SFLSR); /* Take a frame status */ + + if (status != 0) { /* Bad frame? */ + si->stats.rx_frame_errors++; + omap_readb(UART3_RESUME); + } else { + /* We got a frame! */ + skb = alloc_skb(4096, GFP_ATOMIC); + + if (!skb) { + printk(KERN_ERR "omap_sir: out of memory for RX SKB\n"); + return IRQ_HANDLED; + } + /* + * Align any IP headers that may be contained + * within the frame. + */ + + skb_reserve(skb, 1); + + w = omap_readw(OMAP_DMA_CDAC(si->rx_dma_channel)); + w -= omap_readw(OMAP_DMA_CDSA_L(si->rx_dma_channel)); + + if (si->speed != 4000000) { + memcpy(skb_put(skb, w - 2), si->rx_buf_dma_virt, w - 2); /* Copy DMA buffer to skb */ + } else { + memcpy(skb_put(skb, w - 4), si->rx_buf_dma_virt, w - 4); /* Copy DMA buffer to skb */ + } + + skb->dev = dev; + skb->mac.raw = skb->data; + skb->protocol = htons(ETH_P_IRDA); + si->stats.rx_packets++; + si->stats.rx_bytes += skb->len; + netif_receive_skb(skb); /* Send data to upper level */ + } + + /* Re-init RX DMA */ + omap1610_irda_start_rx_dma(si); + + dev->last_rx = jiffies; + + __ECHO_OUT; + + return IRQ_HANDLED; +} + +static int omap1610_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct omap1610_irda *si = dev->priv; + int speed = irda_get_next_speed(skb); + int mtt = irda_get_mtt(skb); + int xbofs = irda_get_next_xbofs(skb); + + __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 (xbofs) { + /* Set number of addtional BOFS */ + omap_writeb(xbofs + 1, UART3_EBLR); + } + + /* + * If this is an empty frame, we can bypass a lot. + */ + if (skb->len == 0) { + if (si->newspeed) { + si->newspeed = 0; + omap1610_irda_set_speed(dev, speed); + } + dev_kfree_skb(skb); + return 0; + } + + netif_stop_queue(dev); + + /* Copy skb data to DMA buffer */ + + memcpy(si->tx_buf_dma_virt, skb->data, skb->len); + + si->stats.tx_bytes += skb->len; + + /* Set frame length */ + + omap_writeb((skb->len & 0xff), UART3_TXFLL); + omap_writeb((skb->len >> 8), UART3_TXFLH); + + if (mtt > 1000) + mdelay(mtt / 1000); + else + udelay(mtt); + + /* Start TX DMA transfer */ + + omap1610_start_tx_dma(si, skb->len); + + /* We can free skb now because it's already in DMA buffer */ + + dev_kfree_skb(skb); + + dev->trans_start = jiffies; + + __ECHO_OUT; + + return 0; +} + +static int +omap1610_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) +{ + struct if_irda_req *rq = (struct if_irda_req *)ifreq; + struct omap1610_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 = + omap1610_irda_set_speed(dev, + rq->ifr_baudrate); + } else { + printk + (KERN_ERR + "omap_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 = rx_state; + break; + + default: + break; + } + + __ECHO_OUT; + + return ret; +} + +static struct net_device_stats *omap1610_irda_stats(struct net_device *dev) +{ + struct omap1610_irda *si = dev->priv; + return &si->stats; +} + +static int omap1610_irda_start(struct net_device *dev) +{ + struct omap1610_irda *si = dev->priv; + int err; + unsigned long flags = 0; + +#ifdef CONFIG_MACH_OMAP_H3 + u8 ioExpanderVal = 0; +#endif + + __ECHO_IN; + si->speed = 9600; + + err = request_irq(dev->irq, omap1610_irda_irq, 0, dev->name, dev); + if (err) + goto err_irq; + + /* + * The interrupt must remain disabled for now. + */ + + disable_irq(dev->irq); + + /* Request DMA channels for IrDA hardware */ + + if (omap_request_dma(OMAP_DMA_UART3_RX, "IrDA Rx DMA", + (void *)omap1610_irda_rx_dma_callback, + dev, &(si->rx_dma_channel))) { + printk(KERN_ERR "Failed to request IrDA Rx DMA \n"); + goto err_irq; + } + + if (omap_request_dma(OMAP_DMA_UART3_TX, "IrDA Tx DMA", + (void *)omap1610_irda_tx_dma_callback, + dev, &(si->tx_dma_channel))) { + printk(KERN_ERR "Failed to request IrDA Tx DMA \n"); + goto err_irq; + } + + /* Allocate TX and RX buffers for DMA channels */ + + si->rx_buf_dma_virt = + dma_alloc_coherent(NULL, 4096, &(si->rx_buf_dma_phys), flags); + + si->tx_buf_dma_virt = + dma_alloc_coherent(NULL, 4096, &(si->tx_buf_dma_phys), flags); + + /* + * Setup the serial port for the specified config. + */ + +#if CONFIG_MACH_OMAP_H3 + + if ((err = read_gpio_expa(&ioExpanderVal, 0x26))) { + printk(KERN_ERR "Error reading from I/O EXPANDER \n"); + return err; + } + + ioExpanderVal |= 0x40; /* 'P6' Enable IRDA_TX and IRDA_RX */ + + if ((err = write_gpio_expa(ioExpanderVal, 0x26))) { + printk(KERN_ERR "Error writing to I/O EXPANDER \n"); + return err; + } +#endif + err = omap1610_irda_startup(dev); + + if (err) + goto err_startup; + + omap1610_irda_set_speed(dev, si->speed = 9600); + + /* + * Open a new IrLAP layer instance. + */ + + si->irlap = irlap_open(dev, &si->qos, "omap_sir"); + + err = -ENOMEM; + if (!si->irlap) + goto err_irlap; + + /* Now enable the interrupt and start the queue */ + si->open = 1; + + /* Start RX DMA */ + + omap1610_irda_start_rx_dma(si); + + enable_irq(dev->irq); + netif_start_queue(dev); + + __ECHO_OUT; + + return 0; + + err_irlap: + si->open = 0; + omap1610_irda_shutdown(si); + err_startup: + err_irq: + free_irq(dev->irq, dev); + return err; +} + +static int omap1610_irda_stop(struct net_device *dev) +{ + struct omap1610_irda *si = dev->priv; + + __ECHO_IN; + + disable_irq(dev->irq); + + netif_stop_queue(dev); + + omap_free_dma(si->rx_dma_channel); + omap_free_dma(si->tx_dma_channel); + + dma_free_coherent(NULL, 4096, si->rx_buf_dma_virt, si->rx_buf_dma_phys); + dma_free_coherent(NULL, 4096, si->tx_buf_dma_virt, si->tx_buf_dma_phys); + + omap1610_irda_shutdown(si); + + /* Stop IrLAP */ + if (si->irlap) { + irlap_close(si->irlap); + si->irlap = NULL; + } + + si->open = 0; + + /* + * Free resources + */ + + free_irq(dev->irq, dev); + + __ECHO_OUT; + + return 0; +} + +#ifdef CONFIG_MACH_OMAP_H3 + +static void set_h3_gpio_expa(u8 FIR_SEL, u8 IrDA_INVSEL) +{ + u8 ioExpanderVal = 0; + + if (read_gpio_expa(&ioExpanderVal, 0x27) != 0) { + printk(KERN_ERR "Error reading from I/O EXPANDER \n"); + return; + } + + ioExpanderVal &= ~0x03; + ioExpanderVal |= FIR_SEL << 1; + ioExpanderVal |= IrDA_INVSEL << 0; + + if (write_gpio_expa(ioExpanderVal, 0x27) != 0) { + printk(KERN_ERR "Error writing to I/O EXPANDER \n"); + return; + } + if (read_gpio_expa(&ioExpanderVal, 0x27) != 0) { + printk(KERN_ERR "Error reading from I/O EXPANDER \n"); + return; + } +} + +int which_speed; + +static void set_h3_gpio_expa_handler(void *data) +{ + int *mode = data; + + if (*mode == SIR_MODE) + set_h3_gpio_expa(0, 1); + else if (*mode == MIR_MODE) + set_h3_gpio_expa(1, 1); + else if (*mode == FIR_MODE) + set_h3_gpio_expa(1, 1); +} + +DECLARE_WORK(set_h3_gpio_expa_work, &set_h3_gpio_expa_handler, &which_speed); + +static inline void set_h3_irda_mode(int mode) +{ + cancel_delayed_work(&set_h3_gpio_expa_work); + which_speed = mode; + schedule_work(&set_h3_gpio_expa_work); +} +#else +#define set_h3_irda_mode(x) +#endif + +static int omap1610_irda_set_speed(struct net_device *dev, int speed) +{ + struct omap1610_irda *si = dev->priv; + int divisor; + + __ECHO_IN; + + /* Set IrDA speed */ + if (speed <= 115200) { + /* SIR mode */ + if (machine_is_omap_h2()) { + omap_set_gpio_dataout(OMAP1610_H2_FIRSEL_GPIO, 0); + } + + if (machine_is_omap_h3()) + set_h3_irda_mode(SIR_MODE); + + printk("Set SIR Mode! Speed: %d\n", speed); + + omap_writeb(1, UART3_MDR1); /* Set SIR mode */ + + omap_writeb(1, UART3_EBLR); + + divisor = 48000000 / (16 * speed); /* Base clock 48 MHz */ + + HDBG2(1); + omap_writeb(1 << 7, UART3_LCR); + + omap_writeb((divisor & 0xFF), UART3_DLL); + + omap_writeb((divisor >> 8), UART3_DLH); + + omap_writeb(0x03, UART3_LCR); + + omap_writeb(0, UART3_MCR); + + HDBG2(1); + + } else if (speed <= 1152000) { + /* MIR mode */ + printk("Set MIR Mode! Speed: %d\n", speed); + + omap_writeb((1 << 2) | (1 << 6), UART3_MDR1); /* Set MIR mode with + SIP after each frame */ + + omap_writeb(2, UART3_EBLR); + + divisor = 48000000 / (41 * speed); /* Base clock 48 MHz */ + + omap_writeb(1 << 7, UART3_LCR); + + omap_writeb((divisor & 0xFF), UART3_DLL); + + omap_writeb((divisor >> 8), UART3_DLH); + + omap_writeb(0x03, UART3_LCR); + + if (machine_is_omap_h2()) + omap_set_gpio_dataout(OMAP1610_H2_FIRSEL_GPIO, 1); + + if (machine_is_omap_h3()) + set_h3_irda_mode(MIR_MODE); + + } else { + /* FIR mode */ + + printk("Set FIR Mode! Speed: %d\n", speed); + + omap_writeb((1 << 2) | (1 << 6) | 1, UART3_MDR1); /* Set FIR mode + with SIP after each frame */ + if (machine_is_omap_h2()) + omap_set_gpio_dataout(OMAP1610_H2_FIRSEL_GPIO, 1); + + if (machine_is_omap_h3()) + set_h3_irda_mode(FIR_MODE); + } + + si->speed = speed; + + __ECHO_OUT; + + return 0; + +} + +#ifdef CONFIG_PM +/* + * Suspend the IrDA interface. + */ +static int omap1610_irda_suspend(struct device *_dev, u32 state, u32 level) +{ + struct net_device *dev = dev_get_drvdata(_dev); + struct omap1610_irda *si; + + if (!dev || level != SUSPEND_DISABLE) + return 0; + + si = (struct omap1610_irda *)&dev->priv; + if (si->open) { + /* + * Stop the transmit queue + */ + netif_device_detach(dev); + disable_irq(dev->irq); + omap1610_irda_shutdown(si); + } + return 0; +} + +/* + * Resume the IrDA interface. + */ +static int omap1610_irda_resume(struct device *_dev, u32 level) +{ + struct net_device *dev = dev_get_drvdata(_dev); + struct omap1610_irda *si; + + if (!dev || level != RESUME_ENABLE) + return 0; + + si = (struct omap1610_irda *)&dev->priv; + if (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; + } + + omap1610_irda_startup(dev); + enable_irq(dev->irq); + + /* + * This automatically wakes up the queue + */ + netif_device_attach(dev); + } + + return 0; +} +#else +#define omap1610_irda_suspend NULL +#define omap1610_irda_resume NULL +#endif + +static int omap1610_irda_probe(struct device *_dev) +{ + struct platform_device *pdev = to_platform_device(_dev); + struct net_device *dev; + struct omap1610_irda *si; + unsigned int baudrate_mask; + int err = 0; + + dev = alloc_irdadev(sizeof(struct omap1610_irda)); + if (!dev) + goto err_mem_1; + + si = dev->priv; + si->dev = &pdev->dev; + dev->hard_start_xmit = omap1610_irda_hard_xmit; + dev->open = omap1610_irda_start; + dev->stop = omap1610_irda_stop; + dev->do_ioctl = omap1610_irda_ioctl; + dev->get_stats = omap1610_irda_stats; + dev->irq = INT_UART3; + + irda_init_max_qos_capabilies(&si->qos); + + /* + * OMAP1610 supports SIR, MIR, FIR modes, + * but actualy supported modes depend on hardware implementation. + * OMAP1610 Innovator supports only SIR and + * OMAP1610 H2 supports both SIR and FIR + */ + + baudrate_mask = + IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200 | IR_576000 | + IR_1152000; + + if (machine_is_omap_h2() || machine_is_omap_h3()) { + + 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); + + err = register_netdev(dev); + if (!err) + dev_set_drvdata(&pdev->dev, dev); + else + free_netdev(dev); + + err_mem_1: + return err; +} + +static int omap1610_irda_remove(struct device *_dev) +{ + struct net_device *dev = dev_get_drvdata(_dev); + +#ifdef CONFIG_MACH_OMAP_H3 + if (machine_is_omap_h3()) + cancel_delayed_work(&set_h3_gpio_expa_work); +#endif + if (dev) { + unregister_netdev(dev); + free_netdev(dev); + } + return 0; +} + +static void irda_dummy_release(struct device *dev) +{ + /* Dummy function to keep the platform driver happy */ +} + +static struct device_driver omap1610ir_driver = { + .name = "omap1610-ir", + .bus = &platform_bus_type, + .probe = omap1610_irda_probe, + .remove = omap1610_irda_remove, + .suspend = omap1610_irda_suspend, + .resume = omap1610_irda_resume, +}; + +static struct platform_device omap1610ir_device = { + .name = "omap1610-ir", + .dev.release = irda_dummy_release, + .id = 0, +}; + +#ifdef MODULE +static +#endif +int __init omap1610_irda_init(void) +{ + int ret; + ret = driver_register(&omap1610ir_driver); + if (ret == 0) { + ret = platform_device_register(&omap1610ir_device); + if (ret) + driver_unregister(&omap1610ir_driver); + } + return ret; + +} + +#ifdef MODULE +static +#endif +void __exit omap1610_irda_exit(void) +{ + driver_unregister(&omap1610ir_driver); + platform_device_unregister(&omap1610ir_device); +} + +module_init(omap1610_irda_init); +module_exit(omap1610_irda_exit); + +MODULE_AUTHOR("MontaVista"); +MODULE_DESCRIPTION("OMAP IrDA Driver"); +MODULE_LICENSE("GPL"); + diff -Nru a/drivers/net/smc91x.c b/drivers/net/smc91x.c --- a/drivers/net/smc91x.c 2005-03-02 10:51:31 -08:00 +++ b/drivers/net/smc91x.c 2005-03-02 10:51:31 -08:00 @@ -483,6 +483,11 @@ dev->name, packet_number, status, packet_len, packet_len); + if (unlikely(packet_len == 0 && !(status & RS_ERRORS))) { + printk(KERN_ERR "%s: bad memory timings: rxlen %u status %x\n", + dev->name, packet_len, status); + status |= RS_TOOSHORT; + } if (unlikely(status & RS_ERRORS)) { SMC_WAIT_MMU_BUSY(); SMC_SET_MMU_CMD(MC_RELEASE); diff -Nru a/drivers/net/smc91x.h b/drivers/net/smc91x.h --- a/drivers/net/smc91x.h 2005-03-02 10:51:31 -08:00 +++ b/drivers/net/smc91x.h 2005-03-02 10:51:31 -08:00 @@ -162,6 +162,26 @@ } } +#elif defined(CONFIG_ARCH_OMAP) + +/* 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_IO_SHIFT 0 +#define SMC_NOWAIT 1 + +#define SMC_inb(a, r) readb((a) + (r)) +#define SMC_outb(v, a, r) writeb(v, (a) + (r)) +#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) readsw((void __iomem *)(a) + (r), p, l) +#define SMC_outsw(a, r, p, l) writesw((void __iomem *)(a) + (r), p, l) +#define SMC_inl(a, r) readl((a) + (r)) +#define SMC_outl(v, a, r) writel(v, (a) + (r)) +#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) +#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) + #elif defined(CONFIG_ISA) #define SMC_CAN_USE_8BIT 1 diff -Nru a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig --- a/drivers/pcmcia/Kconfig 2005-03-02 10:51:31 -08:00 +++ b/drivers/pcmcia/Kconfig 2005-03-02 10:51:31 -08:00 @@ -195,6 +195,13 @@ tristate "NEC VRC4173 CARDU support" depends on CPU_VR41XX && PCI && PCMCIA +config OMAP_CF + tristate "OMAP CompactFlash Controller" + depends on PCMCIA && ARCH_OMAP16XX + help + Say Y here to support the CompactFlash controller on OMAP. + Note that this doesn't support "True IDE" mode. + config PCCARD_NONSTATIC tristate depends on PCCARD diff -Nru a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile --- a/drivers/pcmcia/Makefile 2005-03-02 10:51:31 -08:00 +++ b/drivers/pcmcia/Makefile 2005-03-02 10:51:31 -08:00 @@ -33,6 +33,7 @@ obj-$(CONFIG_PCMCIA_AU1X00) += au1x00_ss.o obj-$(CONFIG_PCMCIA_VRC4171) += vrc4171_card.o obj-$(CONFIG_PCMCIA_VRC4173) += vrc4173_cardu.o +obj-$(CONFIG_OMAP_CF) += omap_cf.o sa11xx_core-y += soc_common.o sa11xx_base.o pxa2xx_core-y += soc_common.o pxa2xx_base.o diff -Nru a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/pcmcia/omap_cf.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,372 @@ +/* + * omap_cf.c -- OMAP 16xx CompactFlash controller driver + * + * Copyright (c) 2005 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + + +/* NOTE: don't expect this to support many I/O cards. The 16xx chips have + * hard-wired timings to support Compact Flash memory cards; they won't work + * with various other devices (like WLAN adapters) without some external + * logic to help out. + * + * Also: CF controller docs disagree with address space docs as to where + * CF_BASE really lives. + */ +#define CF_BASE 0xfffe2800 + +/* status; read after IRQ */ +#define CF_STATUS_REG __REG16(CF_BASE + 0x00) +# define CF_STATUS_BAD_READ (1 << 2) +# define CF_STATUS_BAD_WRITE (1 << 1) +# define CF_STATUS_CARD_DETECT (1 << 0) + +/* which chipselect (CS0..CS3) is used for CF (active low) */ +#define CF_CFG_REG __REG16(CF_BASE + 0x02) + +/* card reset */ +#define CF_CONTROL_REG __REG16(CF_BASE + 0x04) +# define CF_CONTROL_RESET (1 << 0) + +#define omap_cf_present() (!(CF_STATUS_REG & CF_STATUS_CARD_DETECT)) + +/*--------------------------------------------------------------------------*/ + +static const char driver_name[] = "omap_cf"; + +struct omap_cf_socket { + struct pcmcia_socket socket; + + struct timer_list timer; + unsigned present:1; + unsigned active:1; + + struct platform_device *pdev; + unsigned long phys_cf; + u_int irq; +}; + +#define POLL_INTERVAL (2 * HZ) + +#define SZ_2K (2 * SZ_1K) + +/*--------------------------------------------------------------------------*/ + +static int omap_cf_ss_init(struct pcmcia_socket *s) +{ + return 0; +} + +/* the timer is primarily to kick this socket's pccardd */ +static void omap_cf_timer(unsigned long _cf) +{ + struct omap_cf_socket *cf = (void *) _cf; + unsigned present = omap_cf_present(); + + if (present != cf->present) { + cf->present = present; + pr_debug("%s: card %s\n", driver_name, + present ? "present" : "gone"); + pcmcia_parse_events(&cf->socket, SS_DETECT); + } + + if (cf->active) + mod_timer(&cf->timer, jiffies + POLL_INTERVAL); +} + +/* This irq handler prevents "irqNNN: nobody cared" messages as drivers + * claim the card's IRQ. It may also detect some card insertions, but + * not removals; it can't always eliminate timer irqs. + */ +static irqreturn_t omap_cf_irq(int irq, void *_cf, struct pt_regs *r) +{ + omap_cf_timer((unsigned long)_cf); + return IRQ_HANDLED; +} + +static int omap_cf_get_status(struct pcmcia_socket *s, u_int *sp) +{ + if (!sp) + return -EINVAL; + + /* FIXME power management should probably be board-specific: + * - 3VCARD vs XVCARD (OSK only handles 3VCARD) + * - POWERON (switched on/off by set_socket) + */ + if (omap_cf_present()) { + struct omap_cf_socket *cf; + + *sp = SS_READY | SS_DETECT | SS_POWERON | SS_3VCARD; + cf = container_of(s, struct omap_cf_socket, socket); + s->irq.AssignedIRQ = cf->irq; + } else + *sp = 0; + return 0; +} + +static int +omap_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s) +{ + u16 control; + + /* FIXME some non-OSK boards will support power switching */ + switch (s->Vcc) { + case 0: + case 33: + break; + default: + return -EINVAL; + } + + control = CF_CONTROL_REG; + if (s->flags & SS_RESET) + CF_CONTROL_REG = CF_CONTROL_RESET; + else + CF_CONTROL_REG = 0; + + pr_debug("%s: Vcc %d, io_irq %d, flags %04x csc %04x\n", + driver_name, s->Vcc, s->io_irq, s->flags, s->csc_mask); + + return 0; +} + +static int omap_cf_ss_suspend(struct pcmcia_socket *s) +{ + pr_debug("%s: %s\n", driver_name, __FUNCTION__); + return omap_cf_set_socket(s, &dead_socket); +} + +/* regions are 2K each: mem, attrib, io (and reserved-for-ide) */ + +static int +omap_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io) +{ + struct omap_cf_socket *cf; + + cf = container_of(s, struct omap_cf_socket, socket); + io->flags &= MAP_ACTIVE|MAP_ATTRIB|MAP_16BIT; + io->start = cf->phys_cf + SZ_4K; + io->stop = io->start + SZ_2K - 1; + return 0; +} + +static int +omap_cf_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *map) +{ + struct omap_cf_socket *cf; + + if (map->card_start) + return -EINVAL; + cf = container_of(s, struct omap_cf_socket, socket); + map->static_start = cf->phys_cf; + map->flags &= MAP_ACTIVE|MAP_ATTRIB|MAP_16BIT; + if (map->flags & MAP_ATTRIB) + map->static_start += SZ_2K; + return 0; +} + +static struct pccard_operations omap_cf_ops = { + .init = omap_cf_ss_init, + .suspend = omap_cf_ss_suspend, + .get_status = omap_cf_get_status, + .set_socket = omap_cf_set_socket, + .set_io_map = omap_cf_set_io_map, + .set_mem_map = omap_cf_set_mem_map, +}; + +/*--------------------------------------------------------------------------*/ + +/* + * NOTE: right now the only board-specific platform_data is + * "what chipselect is used". Boards could want more. + */ + +static int __init omap_cf_probe(struct device *dev) +{ + unsigned seg; + struct omap_cf_socket *cf; + struct platform_dev *pdev = to_platform_device(dev); + int irq; + int status; + + seg = (int) dev->platform_data; + if (seg == 0 || seg > 3) + return -ENODEV; + + /* either CFLASH.IREQ (INT_1610_CF) or some GPIO */ + irq = platform_get_irq(pdev, 0); + if (!irq) + return -EINVAL; + + cf = kcalloc(1, sizeof *cf, GFP_KERNEL); + if (!cf) + return -ENOMEM; + init_timer(&cf->timer); + cf->timer.function = omap_cf_timer; + cf->timer.data = (unsigned long) cf; + + cf->pdev = pdev; + dev_set_drvdata(dev, cf); + + /* this primarily just shuts up irq handling noise */ + status = request_irq(irq, omap_cf_irq, SA_SHIRQ, + driver_name, cf); + if (status < 0) + goto fail0; + cf->irq = irq; + cf->socket.pci_irq = irq; + + switch (seg) { + /* NOTE: CS0 could be configured too ... */ + case 1: + cf->phys_cf = OMAP_CS1_PHYS; + break; + case 2: + cf->phys_cf = OMAP_CS2_PHYS; + break; + case 3: + cf->phys_cf = omap_cs3_phys(); + break; + default: + goto fail1; + } + + /* pcmcia layer only remaps "real" memory */ + cf->socket.io_offset = (unsigned long) + ioremap(cf->phys_cf + SZ_4K, SZ_2K); + if (!cf->socket.io_offset) + goto fail1; + + if (!request_mem_region(cf->phys_cf, SZ_8K, driver_name)) + goto fail1; + + /* NOTE: CF conflicts with MMC1 */ + omap_cfg_reg(W11_1610_CF_CD1); + omap_cfg_reg(P11_1610_CF_CD2); + omap_cfg_reg(R11_1610_CF_IOIS16); + omap_cfg_reg(V10_1610_CF_IREQ); + omap_cfg_reg(W10_1610_CF_RESET); + + CF_CFG_REG = ~(1 << seg); + + pr_info("%s: cs%d on irq %d\n", driver_name, seg, irq); + + /* NOTE: better EMIFS setup might support more cards; but the + * TRM only shows how to affect regular flash signals, not their + * CF/PCMCIA variants... + */ + pr_debug("%s: cs%d, previous ccs %08x acs %08x\n", driver_name, + seg, EMIFS_CCS(seg), EMIFS_ACS(seg)); + EMIFS_CCS(seg) = 0x0004a1b3; /* synch mode 4 etc */ + EMIFS_ACS(seg) = 0x00000000; /* OE hold/setup */ + + /* CF uses armxor_ck, which is "always" available */ + + pr_debug("%s: sts %04x cfg %04x control %04x %s\n", driver_name, + CF_STATUS_REG, CF_CFG_REG, CF_CONTROL_REG, + omap_cf_present() ? "present" : "(not present)"); + + cf->socket.owner = THIS_MODULE; + cf->socket.dev.dev = dev; + cf->socket.ops = &omap_cf_ops; + cf->socket.resource_ops = &pccard_static_ops; + cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP + | SS_CAP_MEM_ALIGN; + cf->socket.map_size = SZ_2K; + + status = pcmcia_register_socket(&cf->socket); + if (status < 0) + goto fail2; + + cf->active = 1; + mod_timer(&cf->timer, jiffies + POLL_INTERVAL); + return 0; + +fail2: + iounmap((void __iomem *) cf->socket.io_offset); + release_mem_region(cf->phys_cf, SZ_8K); +fail1: + free_irq(irq, cf); +fail0: + kfree(cf); + return status; +} + +static int __devexit omap_cf_remove(struct device *dev) +{ + struct omap_cf_socket *cf = dev_get_drvdata(dev); + + cf->active = 0; + del_timer_sync(&cf->timer); + iounmap((void __iomem *) cf->socket.io_offset); + release_mem_region(cf->phys_cf, SZ_8K); + free_irq(cf->irq, cf); + kfree(cf); + return 0; +} + +static int omap_cf_suspend(struct device *dev, u32 state, u32 level) +{ + if (level != SUSPEND_SAVE_STATE) + return 0; + return pcmcia_socket_dev_suspend(dev, state); +} + +static int omap_cf_resume(struct device *dev, u32 level) +{ + if (level != RESUME_RESTORE_STATE) + return 0; + return pcmcia_socket_dev_resume(dev); +} + +static struct device_driver omap_cf_driver = { + .name = (char *) driver_name, + .bus = &platform_bus_type, + .probe = omap_cf_probe, + .remove = __devexit_p(omap_cf_remove), + .suspend = omap_cf_suspend, + .resume = omap_cf_resume, +}; + +static int __init omap_cf_init(void) +{ + if (cpu_is_omap16xx()) + driver_register(&omap_cf_driver); + return 0; +} + +static void __exit omap_cf_exit(void) +{ + if (cpu_is_omap16xx()) + driver_register(&omap_cf_driver); +} + +module_init(omap_cf_init); +module_exit(omap_cf_exit); + +MODULE_DESCRIPTION("OMAP CF Driver"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/serial/8250.c b/drivers/serial/8250.c --- a/drivers/serial/8250.c 2005-03-02 10:51:31 -08:00 +++ b/drivers/serial/8250.c 2005-03-02 10:51:31 -08:00 @@ -1233,7 +1233,8 @@ DEBUG_INTR("end.\n"); - return IRQ_RETVAL(handled); + //return IRQ_RETVAL(handled); + return IRQ_HANDLED; /* FIXME: iir status not ready on 1510 */ } /* @@ -1733,6 +1734,17 @@ serial_outp(up, UART_EFR, efr); } +#ifdef CONFIG_ARCH_OMAP1510 + /* Workaround to enable 115200 baud on OMAP1510 internal ports */ + if (cpu_is_omap1510() && is_omap_port(up->port.membase)) { + if (baud == 115200) { + quot = 1; + serial_out(up, UART_OMAP_OSC_12M_SEL, 1); + } else + serial_out(up, UART_OMAP_OSC_12M_SEL, 0); + } +#endif + if (up->capabilities & UART_NATSEMI) { /* Switch to bank 2 not bank 1, to avoid resetting EXCR2 */ serial_outp(up, UART_LCR, 0xe0); @@ -1782,6 +1794,11 @@ { unsigned int size = 8 << up->port.regshift; int ret = 0; + +#ifdef CONFIG_ARCH_OMAP + if (is_omap_port(up->port.membase)) + size = 0x16 << up->port.regshift; +#endif switch (up->port.iotype) { case UPIO_MEM: diff -Nru a/drivers/ssi/Kconfig b/drivers/ssi/Kconfig --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/ssi/Kconfig 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,17 @@ +menu "Synchronous Serial Interfaces (SSI)" + +config OMAP_UWIRE + depends on ARCH_OMAP + tristate "MicroWire support on OMAP" + ---help--- + Say Y here if you want support for the MicroWire interface + on an OMAP processor. + +config OMAP_TSC2101 + depends on ARCH_OMAP || ARCH_OMAP24XX + tristate "TSC2101 codec support for Touchscreen and audio" + select OMAP_UWIRE if MACH_OMAP_H3 || MACH_OMAP_H2 + ---help--- + Say Y here if you want support for the TSC2101 codec. It is + needed for touchscreen and audio on OMAP1610 and 1710. +endmenu diff -Nru a/drivers/ssi/Makefile b/drivers/ssi/Makefile --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/ssi/Makefile 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,6 @@ +# +# Makefile for the SSI drivers +# + +obj-$(CONFIG_OMAP_UWIRE) += omap-uwire.o +obj-$(CONFIG_OMAP_TSC2101) += omap-tsc2101.o diff -Nru a/drivers/ssi/omap-tsc2101.c b/drivers/ssi/omap-tsc2101.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/ssi/omap-tsc2101.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,244 @@ +/* + * linux/drivers/ssi/omap-tsc2101.c + * + * TSC2101 codec interface driver for the OMAP platform + * + * Copyright (C) 2004 Texas Instruments, Inc. + * + * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * History: + * + * 2004/11/07 Nishanth Menon - Modified for common hooks for Audio and Touchscreen + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "omap-tsc2101.h" + +#if CONFIG_ARCH_OMAP16XX +#include <../drivers/ssi/omap-uwire.h> +#else +#error "Unsupported configuration" +#endif + +#define SPIO 1 + +static int count; +static spinlock_t tsc2101_lock = SPIN_LOCK_UNLOCKED; +static struct clk * tsc2101_mclk_ck; + +static int omap_tsc2101_configure(void); + +/* FIXME: add driver model usage to powerdown the tsc2101 on suspend */ +/* Clock -Hard coding for the time being */ +#define CLK_SOFT_REQ_REG_BASE (0xFFFE0800+0x34) +#define SOFT_COM_MCK0_REQ_MASK (0x1<<6) + +int omap_tsc2101_enable(void) +{ + int ret = 0; + + spin_lock(&tsc2101_lock); + if (count++ == 0) { + int ret = 0; + /* set the Mux to provide MCLK to TSC2101 */ + if (machine_is_omap_h3()) { + ret = omap_cfg_reg(V5_1710_MCLK_ON); + } else { + if (machine_is_omap_h2()) { + ret = omap_cfg_reg(R10_1610_MCLK_ON); + } + } + + /* Get the MCLK */ + tsc2101_mclk_ck = clk_get(0, "mclk"); + if (NULL == tsc2101_mclk_ck) { + printk(KERN_ERR "Unable to get the clock MCLK!!!\n");; + return -EPERM; + } + if (clk_set_rate(tsc2101_mclk_ck, 12000000)) { + printk(KERN_ERR "Unable to set rate to the MCLK!!!\n");; + return -EPERM; + } + clk_enable(tsc2101_mclk_ck); + + ret = omap_tsc2101_configure(); + + /* Lock the module */ + if (!ret && !try_module_get(THIS_MODULE)) { + printk(KERN_CRIT "Failed to get TSC module\n"); + ret = -ESTALE; + } + } + + spin_unlock(&tsc2101_lock); + return ret; +} + +void omap_tsc2101_disable(void) +{ + spin_lock(&tsc2101_lock); + if (--count == 0) { + int ret = 0; + /* Remove the Mux to Stop MCLK to TSC2101 */ + if (machine_is_omap_h3()) { + ret = omap_cfg_reg(V5_1710_MCLK_OFF); + } else { + if (machine_is_omap_h2()) { + ret = omap_cfg_reg(R10_1610_MCLK_OFF); + } + } + + /* Release the MCLK */ + clk_disable(tsc2101_mclk_ck); + clk_put(tsc2101_mclk_ck); + tsc2101_mclk_ck = NULL; + + module_put(THIS_MODULE); + } + spin_unlock(&tsc2101_lock); +} + +void omap_tsc2101_write(int page, u8 address, u16 data) +{ + + int ret = 0; + + if (machine_is_omap_h2()) { + ret = + omap_uwire_data_transfer(1, + (((page) << 11) | (address << 5)), + 16, 0, NULL, 1); + if (ret) { + printk(KERN_ERR + "uwire-write returned error for address %x\n", + address); + return; + } + ret = omap_uwire_data_transfer(1, data, 16, 0, NULL, 0); + if (ret) { + printk(KERN_ERR + "uwire-write returned error for address %x\n", + address); + return; + } + } + if (machine_is_omap_h3()) { + + ret = + omap_uwire_data_transfer(0, ((page << 11) | (address << 5)), + 16, 0, NULL, 1); + if (ret) { + printk(KERN_ERR + "uwire-write returned error for address %x\n", + address); + return; + } + ret = omap_uwire_data_transfer(0, data, 16, 0, NULL, 0); + if (ret) { + printk(KERN_ERR + "uwire-write returned error for address %x\n", + address); + return; + } + } + +} + +void omap_tsc2101_reads(int page, u8 startaddress, u16 * data, int numregs) +{ + int cs = 0, i; + if (machine_is_omap_h2()) { + cs = 1; + } + if (machine_is_omap_h3()) { + cs = 0; + } + (void)omap_uwire_data_transfer(cs, (0x8000 | (page << 11) + | (startaddress << 5)), + 16, 0, NULL, 1); + for (i = 0; i < (numregs - 1); i++, data++) { + omap_uwire_data_transfer(cs, 0, 0, 16, data, 1); + } + omap_uwire_data_transfer(cs, 0, 0, 16, data, 0); +} + +u16 omap_tsc2101_read(int page, u8 address) +{ + u16 ret; + omap_tsc2101_reads(page, address, &ret, 1); + return ret; +} + +/* FIXME: adapt clock divisors for uwire to current ARM xor clock rate */ +static int omap_tsc2101_configure(void) +{ + unsigned long uwire_flags = 0; + +#if CONFIG_MACH_OMAP_H3 + int err = 0; + u8 ioExpanderVal = 0; + + if ((err = read_gpio_expa(&ioExpanderVal, 0x24))) { + printk(" Error reading from I/O EXPANDER \n"); + return err; + } + ioExpanderVal |= 0x8; + + if ((err = write_gpio_expa(ioExpanderVal, 0x24))) { + printk(KERN_ERR ": Error writing to I/O EXPANDER \n"); + return err; + } +#endif + + if (machine_is_omap_h2()) { + uwire_flags = UWIRE_READ_RISING_EDGE | UWIRE_WRITE_RISING_EDGE; + omap_cfg_reg(N15_1610_UWIRE_CS1); + omap_uwire_configure_mode(1, uwire_flags); + } + if (machine_is_omap_h3()) { + uwire_flags = UWIRE_READ_RISING_EDGE | UWIRE_WRITE_RISING_EDGE; + omap_cfg_reg(N14_1610_UWIRE_CS0); + omap_uwire_configure_mode(0, uwire_flags); + } + + /* Configure MCLK enable */ + omap_writel(omap_readl(PU_PD_SEL_2) | (1 << 22), PU_PD_SEL_2); + + return 0; +} + +EXPORT_SYMBOL(omap_tsc2101_enable); +EXPORT_SYMBOL(omap_tsc2101_read); +EXPORT_SYMBOL(omap_tsc2101_reads); +EXPORT_SYMBOL(omap_tsc2101_write); +EXPORT_SYMBOL(omap_tsc2101_disable); + +MODULE_AUTHOR("Texas Instruments"); +MODULE_DESCRIPTION + ("Glue audio driver for the TI OMAP1610/OMAP1710 TSC2101 codec."); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/ssi/omap-tsc2101.h b/drivers/ssi/omap-tsc2101.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/ssi/omap-tsc2101.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,32 @@ +/* + * linux/drivers/ssi/omap-tsc2101.h + * + * TSC2101 codec interface driver for the OMAP platform + * + * Copyright (C) 2004 Texas Instruments, Inc. + * + * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * History: + * + * 2004/11/07 Nishanth Menon - Provided common hooks for Audio and Touchscreen + */ + +#ifndef __OMAP_TSC2101_H +#define __OMAP_TSC2101_H + +extern u16 omap_tsc2101_read(int page, u8 address); +extern void omap_tsc2101_reads(int page, u8 startaddress, u16 * data, + int numregs); +extern void omap_tsc2101_write(int page, u8 address, u16 data); + +extern void omap_tsc2101_disable(void); +extern int omap_tsc2101_enable(void); + +#endif diff -Nru a/drivers/ssi/omap-uwire.c b/drivers/ssi/omap-uwire.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/ssi/omap-uwire.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,226 @@ +/* + * BRIEF MODULE DESCRIPTION + * + * uWire interface driver for the OMAP Platform + * + * Copyright 2003 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * source@mvista.com + * + * Ported to 2.6 uwire interface. + * Copyright (C) 2004 Texas Instruments. + * + * Generalization patches by Juha Yrjölä + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include /* OMAP730_IO_CONF registers */ + +#include "omap-uwire.h" + +/* uWire Registers: */ +#define UWIRE_BASE 0xFFFB3000 +#define UWIRE_IO_SIZE 0x20 +#define UWIRE_TDR 0x00 +#define UWIRE_RDR 0x00 +#define UWIRE_CSR 0x01 +#define UWIRE_SR1 0x02 +#define UWIRE_SR2 0x03 +#define UWIRE_SR3 0x04 +#define UWIRE_SR4 0x05 +#define UWIRE_SR5 0x06 + +static unsigned short uwire_flags[4]; +static unsigned long uwire_base = io_p2v(UWIRE_BASE); +static spinlock_t uwire_lock; +static unsigned int uwire_idx_shift; + +static inline void uwire_write_reg(int idx, u16 val) +{ + __raw_writew(val, uwire_base + (idx << uwire_idx_shift)); +} + +static inline u16 uwire_read_reg(int idx) +{ + return __raw_readw(uwire_base + (idx << uwire_idx_shift)); +} + +void omap_uwire_configure_mode(int cs, unsigned long flags) +{ + u16 w, val = 0; + int shift, reg; + + BUG_ON(cs > 3); + + val = flags & 0x3f; + if (flags & UWIRE_CLK_INVERTED) + val ^= 0x03; + if (cs & 1) + shift = 6; + else + shift = 0; + if (cs <= 1) + reg = UWIRE_SR1; + else + reg = UWIRE_SR2; + spin_lock(&uwire_lock); + w = uwire_read_reg(reg); + w &= ~(0x3f << shift); + w |= val << shift; + uwire_write_reg(reg, w); + spin_unlock(&uwire_lock); + + uwire_flags[cs] = flags; +} + +static int wait_uwire_csr_flag(u16 mask, u16 val, int might_not_catch) +{ + u16 w; + int c = 0; + unsigned long max_jiffies = jiffies + HZ; + + for (;;) { + w = uwire_read_reg(UWIRE_CSR); + if ((w & mask) == val) + break; + if (time_after(jiffies, max_jiffies)) { + printk(KERN_ERR "%s: timeout. reg=%#06x mask=%#06x val=%#06x\n", + __FUNCTION__, w, mask, val); + return -1; + } + c++; + if (might_not_catch && c > 64) + break; + } + return 0; +} + +int omap_uwire_data_transfer(int cs, u16 tx_data, int tx_size, int rx_size, + u16 *rx_buf, int leave_cs_active) +{ + u16 ret = -1, w; + u16 mask; + + BUG_ON(cs > 3); + BUG_ON(rx_size && !rx_buf); + + spin_lock(&uwire_lock); + + if (wait_uwire_csr_flag(1 << 14, 0, 0)) + goto exit; + + if (uwire_flags[cs] & UWIRE_CLK_INVERTED) + uwire_write_reg(UWIRE_SR4, 1); + else + uwire_write_reg(UWIRE_SR4, 0); + + w = cs << 10; + w |= 1 << 12; /* CS_CMD : activate CS */ + uwire_write_reg(UWIRE_CSR, w); + + /* Shift data to 16bit MSb and place it in TX register. */ + uwire_write_reg(UWIRE_TDR, tx_data << (16 - tx_size)); + + if (wait_uwire_csr_flag(1 << 14, 0, 0)) + goto exit; + + w = rx_size | (tx_size << 5) | (cs << 10); + w |= (1 << 12) | (1 << 13); + /* Start uWire read/write */ + uwire_write_reg(UWIRE_CSR, w); + + /* Wait till read/write actually starts. + * This is needed at high (>=60MHz) MPU frequencies + * REVISIT: But occasionally we won't have time to catch it + */ + if (wait_uwire_csr_flag(1 << 14, 1 << 14, 1)) + goto exit; + + /* Wait for both transfers to be completed */ + mask = 1 << 14; /* CSRB : reg busy */ + w = 0; + if (rx_size) { + mask |= 1 << 15; /* RDRB : reg busy */ + w |= 1 << 15; + } + + if (wait_uwire_csr_flag(mask, w, 0)) + goto exit; + + if (rx_size) + *rx_buf = uwire_read_reg(UWIRE_RDR); + + if (!leave_cs_active) + uwire_write_reg(UWIRE_CSR, cs << 10); + + ret = 0; + +exit: + spin_unlock(&uwire_lock); + return ret; +} + +static int __init omap_uwire_init(void) +{ + spin_lock_init(&uwire_lock); + if (cpu_is_omap730()) + uwire_idx_shift = 1; + else + uwire_idx_shift = 2; + + uwire_write_reg(UWIRE_SR3, 1); + if (machine_is_omap_h2() || machine_is_omap_osk()) { + /* defaults: W21 SDO, U18 SDI, V19 SCL */ + omap_cfg_reg(N14_1610_UWIRE_CS0); + omap_cfg_reg(N15_1610_UWIRE_CS1); + } + if (machine_is_omap_perseus2()) { + /* configure pins: MPU_UW_nSCS1, MPU_UW_SDO, MPU_UW_SCLK */ + int val = omap_readl(OMAP730_IO_CONF_9) & ~0x00EEE000; + omap_writel(val | 0x00AAA000, OMAP730_IO_CONF_9); + } + return 0; +} + +static void __exit omap_uwire_exit(void) +{ +} + +subsys_initcall(omap_uwire_init); +module_exit(omap_uwire_exit); + +EXPORT_SYMBOL(omap_uwire_configure_mode); +EXPORT_SYMBOL(omap_uwire_data_transfer); + +MODULE_LICENSE("GPL"); diff -Nru a/drivers/ssi/omap-uwire.h b/drivers/ssi/omap-uwire.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/ssi/omap-uwire.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,26 @@ +#ifndef __ARCH_OMAP_UWIRE_H +#define __ARCH_OMAP_UWIRE_H + +#define UWIRE_READ_FALLING_EDGE 0x0000 +#define UWIRE_READ_RISING_EDGE 0x0001 +#define UWIRE_WRITE_FALLING_EDGE 0x0000 +#define UWIRE_WRITE_RISING_EDGE 0x0002 +#define UWIRE_CS_ACTIVE_LOW 0x0000 +#define UWIRE_CS_ACTIVE_HIGH 0x0004 +#define UWIRE_FREQ_DIV_2 0x0000 +#define UWIRE_FREQ_DIV_4 0x0008 +#define UWIRE_FREQ_DIV_8 0x0010 +#define UWIRE_CHK_READY 0x0020 +#define UWIRE_CLK_INVERTED 0x0040 + +/* + * uWire for OMAP declarations + */ +extern void omap_uwire_configure_mode(int cs, unsigned long flags); + +/* NOTE: Make sure you don't call this from an interrupt handler! */ +extern int omap_uwire_data_transfer(int cs, u16 tx_data, int tx_size, + int rx_size, u16 *rx_buf, + int leave_cs_active); + +#endif diff -Nru a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig --- a/drivers/usb/gadget/Kconfig 2005-03-02 10:51:31 -08:00 +++ b/drivers/usb/gadget/Kconfig 2005-03-02 10:51:31 -08:00 @@ -194,7 +194,7 @@ config USB_GADGET_OMAP boolean "OMAP USB Device Controller" depends on ARCH_OMAP - select ISP1301_OMAP if MACH_OMAP_H2 + select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 help Many Texas Instruments OMAP processors have flexible full speed USB device controllers, with support for up to 30 diff -Nru a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c --- a/drivers/usb/gadget/omap_udc.c 2005-03-02 10:51:31 -08:00 +++ b/drivers/usb/gadget/omap_udc.c 2005-03-02 10:51:31 -08:00 @@ -2,7 +2,7 @@ * omap_udc.c -- for OMAP full speed udc; most chips support OTG. * * Copyright (C) 2004 Texas Instruments, Inc. - * Copyright (C) 2004 David Brownell + * Copyright (C) 2004-2005 David Brownell * * 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 @@ -2046,7 +2046,10 @@ pullup_disable (udc); } - if (machine_is_omap_innovator()) + /* boards that don't have VBUS sensing can't autogate 48MHz; + * can't enter deep sleep while a gadget driver is active. + */ + if (machine_is_omap_innovator() || machine_is_omap_osk()) omap_vbus_session(&udc->gadget, 1); done: @@ -2064,7 +2067,7 @@ if (!driver || driver != udc->driver) return -EINVAL; - if (machine_is_omap_innovator()) + if (machine_is_omap_innovator() || machine_is_omap_osk()) omap_vbus_session(&udc->gadget, 0); if (udc->transceiver) @@ -2157,13 +2160,13 @@ } } -static char *trx_mode(unsigned m) +static char *trx_mode(unsigned m, int enabled) { switch (m) { - case 3: - case 0: return "6wire"; + case 0: return enabled ? "*6wire" : "unused"; case 1: return "4wire"; case 2: return "3wire"; + case 3: return "6wire"; default: return "unknown"; } } @@ -2171,17 +2174,20 @@ static int proc_otg_show(struct seq_file *s) { u32 tmp; + u32 trans; tmp = OTG_REV_REG; - seq_printf(s, "OTG rev %d.%d, transceiver_ctrl %08x\n", - tmp >> 4, tmp & 0xf, - USB_TRANSCEIVER_CTRL_REG); + trans = USB_TRANSCEIVER_CTRL_REG; + seq_printf(s, "OTG rev %d.%d, transceiver_ctrl %03x\n", + tmp >> 4, tmp & 0xf, trans); tmp = OTG_SYSCON_1_REG; seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s," FOURBITS "\n", tmp, - trx_mode(USB2_TRX_MODE(tmp)), - trx_mode(USB1_TRX_MODE(tmp)), - trx_mode(USB0_TRX_MODE(tmp)), + trx_mode(USB2_TRX_MODE(tmp), trans & CONF_USB2_UNI_R), + trx_mode(USB1_TRX_MODE(tmp), trans & CONF_USB1_UNI_R), + (USB0_TRX_MODE(tmp) == 0) + ? "internal" + : trx_mode(USB0_TRX_MODE(tmp), 1), (tmp & OTG_IDLE_EN) ? " !otg" : "", (tmp & HST_IDLE_EN) ? " !host" : "", (tmp & DEV_IDLE_EN) ? " !dev" : "", diff -Nru a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c --- a/drivers/usb/host/ohci-omap.c 2005-03-02 10:51:31 -08:00 +++ b/drivers/usb/host/ohci-omap.c 2005-03-02 10:51:31 -08:00 @@ -26,6 +26,7 @@ #include #include #include +#include #include "ohci-omap.h" @@ -33,52 +34,60 @@ #error "This file is OMAP bus glue. CONFIG_OMAP must be defined." #endif +#ifdef CONFIG_TPS65010 +#include +#else + +#define LOW 0 +#define HIGH 1 + +#define GPIO1 1 + +static inline int tps65010_set_gpio_out_value(unsigned gpio, unsigned value) +{ + return 0; +} + +#endif + extern int usb_disabled(void); extern int ocpi_enable(void); /* - * OHCI clock initialization for OMAP-1510 and 1610 + * OHCI clock initialization for OMAP-1510 and 16xx */ static int omap_ohci_clock_power(int on) { - if (on) { - /* for 1510, 48MHz DPLL is set up in usb init */ - - if (cpu_is_omap16xx()) { - /* Enable OHCI */ - omap_writel(omap_readl(ULPD_SOFT_REQ) | SOFT_USB_OTG_REQ, - ULPD_SOFT_REQ); - - /* USB host clock request if not using OTG */ - omap_writel(omap_readl(ULPD_SOFT_REQ) | SOFT_USB_REQ, - ULPD_SOFT_REQ); - - omap_writel(omap_readl(ULPD_STATUS_REQ) | USB_HOST_DPLL_REQ, - ULPD_STATUS_REQ); - } - - /* Enable 48MHz clock to USB */ - omap_writel(omap_readl(ULPD_CLOCK_CTRL) | USB_MCLK_EN, - ULPD_CLOCK_CTRL); + struct clk *usb_ck; + struct clk *usb_host_ck; - omap_writel(omap_readl(ARM_IDLECT2) | (1 << EN_LBFREECK) | (1 << EN_LBCK), - ARM_IDLECT2); + usb_ck = clk_get(0, "usb_ck"); + if (IS_ERR(usb_ck)) + return PTR_ERR(usb_ck); + + usb_host_ck = clk_get(0, "usb_hhc_ck"); + if (IS_ERR(usb_host_ck)) { + clk_put(usb_ck); + return PTR_ERR(usb_host_ck); + } - omap_writel(omap_readl(MOD_CONF_CTRL_0) | USB_HOST_HHC_UHOST_EN, - MOD_CONF_CTRL_0); + if (on) { + clk_enable(usb_ck); + clk_enable(usb_host_ck); } else { - /* Disable 48MHz clock to USB */ - omap_writel(omap_readl(ULPD_CLOCK_CTRL) & ~USB_MCLK_EN, - ULPD_CLOCK_CTRL); - - /* FIXME: The DPLL stays on for now */ + clk_disable(usb_ck); + clk_disable(usb_host_ck); } + clk_put(usb_host_ck); + clk_put(usb_ck); + return 0; } /* - * Hardware specific transceiver power on/off + * Board specific gang-switched transceiver power on/off. + * NOTE: OSK supplies power from DC, not battery. */ static int omap_ohci_transceiver_power(int on) { @@ -87,17 +96,15 @@ fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL) | ((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), INNOVATOR_FPGA_CAM_USB_CONTROL); - else if (machine_is_omap_osk()) { - /* FIXME: GPIO1 -> 1 on the TPS65010 I2C chip */ - } + else if (machine_is_omap_osk()) + tps65010_set_gpio_out_value(GPIO1, LOW); } else { if (machine_is_omap_innovator() && cpu_is_omap1510()) fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL) & ~((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), INNOVATOR_FPGA_CAM_USB_CONTROL); - else if (machine_is_omap_osk()) { - /* FIXME: GPIO1 -> 0 on the TPS65010 I2C chip */ - } + else if (machine_is_omap_osk()) + tps65010_set_gpio_out_value(GPIO1, HIGH); } return 0; @@ -177,6 +184,7 @@ { struct omap_usb_config *config = pdev->dev.platform_data; int need_transceiver = (config->otg != 0); + int ret; dev_dbg(&pdev->dev, "starting USB Controller\n"); @@ -188,7 +196,7 @@ /* boards can use OTG transceivers in non-OTG modes */ need_transceiver = need_transceiver - || machine_is_omap_h2(); + || machine_is_omap_h2() || machine_is_omap_h3(); if (cpu_is_omap16xx()) ocpi_enable(); @@ -213,21 +221,44 @@ } #endif - if (machine_is_omap_osk()) { - omap_request_gpio(9); - omap_set_gpio_direction(9, 1); - omap_set_gpio_dataout(9, 1); - } - omap_ohci_clock_power(1); - omap_ohci_transceiver_power(1); - if (cpu_is_omap1510()) { omap_1510_local_bus_power(1); omap_1510_local_bus_init(); } + if ((ret = ohci_init(ohci)) < 0) + return ret; + + /* board-specific power switching and overcurrent support */ + if (machine_is_omap_osk() || machine_is_omap_innovator()) { + u32 rh = roothub_a (ohci); + + /* power switching (ganged by default) */ + rh &= ~RH_A_NPS; + + /* TPS2045 switch for internal transceiver (port 1) */ + if (machine_is_omap_osk()) { + ohci->power_budget = 250; + + rh &= ~RH_A_NOCP; + + /* gpio9 for overcurrent detction */ + omap_cfg_reg(W8_1610_GPIO9); + omap_request_gpio(9); + omap_set_gpio_direction(9, 1 /* IN */); + + /* for paranoia's sake: disable USB.PUEN */ + omap_cfg_reg(W4_USB_HIGHZ); + } + ohci_writel(ohci, rh, &ohci->regs->roothub.a); + // distrust_firmware = 0; + } + + /* FIXME khubd hub requests should manage power switching */ + omap_ohci_transceiver_power(1); + /* board init will have already handled HMC and mux setup. * any external transceiver should already be initialized * too, so all configured ports use the right signaling now. @@ -288,7 +319,8 @@ } if (!request_mem_region(pdev->resource[0].start, - pdev->resource[0].end - pdev->resource[0].start + 1, hcd_name)) { + pdev->resource[0].end - pdev->resource[0].start + 1, + hcd_name)) { dev_dbg(&pdev->dev, "request_mem_region failed\n"); return -EBUSY; } @@ -307,31 +339,31 @@ hcd->regs = (void *)pdev->resource[0].start; hcd->self.controller = &pdev->dev; - retval = omap_start_hc(ohci, pdev); - if (retval < 0) - goto err2; - retval = hcd_buffer_create (hcd); if (retval != 0) { dev_dbg(&pdev->dev, "pool alloc fail\n"); goto err2; } + retval = omap_start_hc(ohci, pdev); + if (retval < 0) + goto err2; + retval = request_irq (hcd->irq, usb_hcd_irq, - SA_INTERRUPT, hcd->driver->description, hcd); + SA_INTERRUPT, hcd_name, hcd); if (retval != 0) { dev_dbg(&pdev->dev, "request_irq failed\n"); retval = -EBUSY; goto err3; } - dev_info(&pdev->dev, "at 0x%p, irq %d\n", hcd->regs, hcd->irq); + dev_info(&pdev->dev, "%s at 0x%p, irq %d\n", + hcd->product_desc, hcd->regs, hcd->irq); hcd->self.bus_name = pdev->dev.bus_id; usb_register_bus (&hcd->self); - if ((retval = driver->start (hcd)) < 0) - { + if ((retval = driver->start (hcd)) < 0) { usb_hcd_omap_remove(hcd, pdev); return retval; } @@ -404,9 +436,6 @@ struct ohci_hcd *ohci = hcd_to_ohci (hcd); int ret; - if ((ret = ohci_init(ohci)) < 0) - return ret; - config = hcd->self.controller->platform_data; if (config->otg || config->rwc) writel(OHCI_CTRL_RWC, &ohci->regs->control); @@ -499,6 +528,8 @@ struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev)); int status = -EINVAL; + if (level != SUSPEND_POWER_DOWN) + return 0; if (state <= dev->power.power_state) return 0; @@ -524,6 +555,9 @@ { struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev)); int status = 0; + + if (level != RESUME_POWER_ON) + return 0; switch (dev->power.power_state) { case 0: diff -Nru a/drivers/usb/host/ohci-omap.h b/drivers/usb/host/ohci-omap.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/usb/host/ohci-omap.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,40 @@ +/* + * linux/drivers/usb/host/ohci-omap.h + * + * OMAP OHCI USB controller specific defines + */ + +/* OMAP USB OHCI common defines */ +#define OMAP_OHCI_NAME "omap-ohci" +#define OMAP_OHCI_BASE 0xfffba000 +#define OMAP_OHCI_SIZE 4096 + +#define HMC_CLEAR (0x3f << 1) +#define APLL_NDPLL_SWITCH 0x0001 +#define DPLL_PLL_ENABLE 0x0010 +#define DPLL_LOCK 0x0001 +#define SOFT_REQ_REG_REQ 0x0001 +#define USB_MCLK_EN 0x0010 +#define USB_HOST_HHC_UHOST_EN 0x00000200 +#define SOFT_USB_OTG_REQ (1 << 8) +#define SOFT_USB_REQ (1 << 3) +#define STATUS_REQ_REG 0xfffe0840 +#define USB_HOST_DPLL_REQ (1 << 8) +#define SOFT_DPLL_REQ (1 << 0) + +/* OMAP-1510 USB OHCI defines */ +#define OMAP1510_LB_MEMSIZE 32 /* Should be same as SDRAM size */ +#define OMAP1510_LB_CLOCK_DIV 0xfffec10c +#define OMAP1510_LB_MMU_CTL 0xfffec208 +#define OMAP1510_LB_MMU_LCK 0xfffec224 +#define OMAP1510_LB_MMU_LD_TLB 0xfffec228 +#define OMAP1510_LB_MMU_CAM_H 0xfffec22c +#define OMAP1510_LB_MMU_CAM_L 0xfffec230 +#define OMAP1510_LB_MMU_RAM_H 0xfffec234 +#define OMAP1510_LB_MMU_RAM_L 0xfffec238 + + +// #define HMC_1510 ((MOD_CONF_CTRL_0_REG >> 1) & 0x3f) +#define HMC_1610 (OTG_SYSCON_2_REG & 0x3f) +#define HMC HMC_1610 + diff -Nru a/drivers/video/Kconfig b/drivers/video/Kconfig --- a/drivers/video/Kconfig 2005-03-02 10:51:31 -08:00 +++ b/drivers/video/Kconfig 2005-03-02 10:51:31 -08:00 @@ -1111,6 +1111,47 @@ describes the available parameters. +config FB_OMAP + tristate "OMAP frame buffer support (EXPERIMENTAL)" + depends on FB && ARCH_OMAP + help + This is the new frame buffer device driver with 2D acceleration + for OMAP boards. + +config FB_OMAP_INTERNAL_LCDC + bool "OMAP internal LCD controller support" + depends on FB_OMAP + default y + help + Say Y here, if you want to have support for the internal OMAP + LCD controller. If unsure, say Y. + +config FB_OMAP_EXTERNAL_LCDC + bool "OMAP external LCD controller support" + depends on FB_OMAP + help + Say Y here, if you want to have support for boards with an + external LCD controller connected to the SoSSI interface. + +config FB_OMAP_MANUAL_UPDATE + bool "Default to manual update mode" + depends on FB_OMAP_EXTERNAL_LCDC + help + Say Y here, if your user-space applications are capable of + notifying the frame buffer driver when a change has occured in + the frame buffer content and thus a reload of the image data is + required. If unsure, say N. + +config FB_OMAP_DMA_TUNE + bool "Set DMA SDRAM access priority high" + depends on FB_OMAP + help + On systems in which video memory is in system memory + (SDRAM) this will speed up graphics DMA operations. + If you have such a system and want to use rotation + answer yes. Answer no if you have a dedicated video + memory, or don't use any of the accelerated features. + config FB_VIRTUAL tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" depends on FB diff -Nru a/drivers/video/Makefile b/drivers/video/Makefile --- a/drivers/video/Makefile 2005-03-02 10:51:31 -08:00 +++ b/drivers/video/Makefile 2005-03-02 10:51:31 -08:00 @@ -104,6 +104,7 @@ obj-$(CONFIG_FB_VGA16) += vga16fb.o cfbfillrect.o cfbcopyarea.o \ cfbimgblt.o vgastate.o obj-$(CONFIG_FB_OF) += offb.o cfbfillrect.o cfbimgblt.o cfbcopyarea.o +obj-$(CONFIG_FB_OMAP) += omap/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o # the test framebuffer is last obj-$(CONFIG_FB_VIRTUAL) += vfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o diff -Nru a/drivers/video/omap/Makefile b/drivers/video/omap/Makefile --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/video/omap/Makefile 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,18 @@ +# +# Makefile for the new OMAP framebuffer device driver +# + +obj-$(CONFIG_FB_OMAP) += omapfb.o + +objs-yy := omapfb_main.o +objs-y$(CONFIG_FB_OMAP_INTERNAL_LCDC) += omap_lcdc.o +objs-y$(CONFIG_FB_OMAP_EXTERNAL_LCDC) += sossi.o +objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_H3) += lcd_h3.o +objs-y$(CONFIG_MACH_OMAP_H2) += lcd_h2.o +objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1610.o +objs-$(CONFIG_ARCH_OMAP1510)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1510.o +objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o +objs-$(CONFIG_ARCH_OMAP730)$(CONFIG_MACH_OMAP_PERSEUS2) += lcd_p2.o + +omapfb-objs := $(objs-yy) + diff -Nru a/drivers/video/omap/debug.h b/drivers/video/omap/debug.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/video/omap/debug.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,106 @@ +/* + * File: drivers/video/omap_new/debug.c + * + * Debug support for the omapfb driver + * + * Copyright (C) 2004 Nokia Corporation + * Author: Imre Deak + * + * 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. + */ + +#ifndef __OMAPFB_DEBUG_H +#define __OMAPFB_DEBUG_H + +#ifdef OMAPFB_DBG + +#define DBG_BUF_SIZE 2048 +#define MAX_DBG_INDENT_LEVEL 5 +#define DBG_INDENT_SIZE 3 +#define MAX_DBG_MESSAGES 0 + +static int dbg_indent; +static int dbg_cnt; +static char dbg_buf[DBG_BUF_SIZE]; +static spinlock_t dbg_spinlock = SPIN_LOCK_UNLOCKED; + +static inline void dbg_print(int level, const char *fmt, ...) +{ + if (level <= OMAPFB_DBG) { + if (!MAX_DBG_MESSAGES || dbg_cnt < MAX_DBG_MESSAGES) { + va_list args; + int ind = dbg_indent; + unsigned long flags; + + spin_lock_irqsave(&dbg_spinlock, flags); + dbg_cnt++; + if (ind > MAX_DBG_INDENT_LEVEL) + ind = MAX_DBG_INDENT_LEVEL; + + printk("%*s", ind * DBG_INDENT_SIZE, ""); + va_start(args, fmt); + vsnprintf(dbg_buf, sizeof(dbg_buf), fmt, args); + printk(dbg_buf); + va_end(args); + spin_unlock_irqrestore(&dbg_spinlock, flags); + } + } +} + +#define DBGPRINT dbg_print + +#define DBGENTER(level) do { \ + dbg_print(level, "%s: Enter\n", __FUNCTION__); \ + dbg_indent++; \ + } while (0) + +#define DBGLEAVE(level) do { \ + dbg_indent--; \ + dbg_print(level, "%s: Leave\n", __FUNCTION__); \ + } while (0) + +static inline void dump_dma_regs(int lch) +{ +#define _R(x) __REG16(OMAP_DMA_##x(lch)) + + dbg_print(4, "\nCSDP :%#06x CCR :%#06x CSSA_U :%#06x " + "\nCDSA_L:%#06x CDSA_U :%#06x CEN :%#06x " + "\nCFN :%#06x CSFI :%#06x CSEI :%#06x " + "\nCSAC :%#06x CICR :%#06x CSR :%04x " + "\nCSSA_L:%#06x CDAC :%#06x CDEI :%#06x " + "\nCDFI :%#06x COLOR_L :%#06x COLOR_U :%#06x " + "\nCCR2 :%#06x CLNK_CTRL:%#06x LCH_CTRL:%#06x\n", + _R(CSDP), _R(CCR), _R(CSSA_U), + _R(CDSA_L), _R(CDSA_U), _R(CEN), + _R(CFN), _R(CSFI), _R(CSEI), + _R(CSAC), _R(CICR), 0, /* _R(CSR), */ + _R(CSSA_L), _R(CDAC), _R(CDEI), + _R(CDFI), _R(COLOR_L), _R(COLOR_U), + _R(CCR2), _R(CLNK_CTRL), _R(LCH_CTRL)); +#undef _R +} + +#define DUMP_DMA_REGS(lch) dump_dma_regs(lch) + +#else /* OMAPFB_DBG */ + +#define DBGPRINT(level, format, ...) +#define DBGENTER(level) +#define DBGLEAVE(level) +#define DUMP_DMA_REGS(lch) + +#endif /* OMAPFB_DBG */ + +#endif /* __OMAPFB_DEBUG_H */ diff -Nru a/drivers/video/omap/lcd_h2.c b/drivers/video/omap/lcd_h2.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/video/omap/lcd_h2.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,133 @@ +/* + * File: drivers/video/omap_new/lcd-h2.c + * + * LCD panel support for the TI OMAP H2 board + * + * Copyright (C) 2004 Nokia Corporation + * Author: Imre Deak + * + * 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 + +#include + +#include "omapfb.h" + +// #define OMAPFB_DBG 1 + +#include "debug.h" +#include "../drivers/ssi/omap-uwire.h" + +#define TSC2101_UWIRE_CS 1 + +static int tsc2101_write_reg(int page, int reg, u16 data) +{ + u16 cmd; + int r; + + DBGENTER(1); + + cmd = ((page & 3) << 11) | ((reg & 0x3f) << 5); + if (omap_uwire_data_transfer(TSC2101_UWIRE_CS, cmd, 16, 0, NULL, 1)) + r = -1; + else + r = omap_uwire_data_transfer(TSC2101_UWIRE_CS, data, 16, 0, NULL, 0); + + DBGLEAVE(1); + return r; +} + +static int h2_panel_init(struct lcd_panel *panel) +{ + unsigned long uwire_flags; + DBGENTER(1); + + /* Configure N15 pin to be uWire CS1 */ + omap_cfg_reg(N15_1610_UWIRE_CS1); + uwire_flags = UWIRE_READ_RISING_EDGE | UWIRE_WRITE_RISING_EDGE; + uwire_flags |= UWIRE_FREQ_DIV_8; + omap_uwire_configure_mode(TSC2101_UWIRE_CS, uwire_flags); + + DBGLEAVE(1); + return 0; +} + +static void h2_panel_cleanup(struct lcd_panel *panel) +{ + DBGENTER(1); + DBGLEAVE(1); +} + +static int h2_panel_enable(struct lcd_panel *panel) +{ + int r; + + DBGENTER(1); + + /* Assert LCD_EN, BKLIGHT_EN pins on LCD panel + * page2, GPIO config reg, GPIO(0,1) to out and asserted + */ + r = tsc2101_write_reg(2, 0x23, 0xCC00) ? -1 : 0; + + DBGLEAVE(1); + return r; +} + +static void h2_panel_disable(struct lcd_panel *panel) +{ + DBGENTER(1); + + /* Deassert LCD_EN and BKLIGHT_EN pins on LCD panel + * page2, GPIO config reg, GPIO(0,1) to out and deasserted + */ + if (tsc2101_write_reg(2, 0x23, 0x8800)) + PRNERR("failed to disable LCD panel\n"); + + DBGLEAVE(1); +} + +static unsigned long h2_panel_get_caps(struct lcd_panel *panel) +{ + return 0; +} + +static struct lcdc_video_mode mode240x320 = { + .x_res = 240, + .y_res = 320, + .pixel_clock = 12500, + .bpp = 16, + .hsw = 12, + .hfp = 14, + .hbp = 72 - 12, + .vsw = 1, + .vfp = 1, + .vbp = 0, + .pcd = 12, +}; + +struct lcd_panel h2_panel = { + .name = "h2", + .config = LCD_PANEL_TFT, + .video_mode = &mode240x320, + + .init = h2_panel_init, + .cleanup = h2_panel_cleanup, + .enable = h2_panel_enable, + .disable = h2_panel_disable, + .get_caps= h2_panel_get_caps, +}; + diff -Nru a/drivers/video/omap/lcd_h3.c b/drivers/video/omap/lcd_h3.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/video/omap/lcd_h3.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,111 @@ +/* + * File: drivers/video/omap_new/lcd-h3.c + * + * LCD panel support for the TI OMAP H3 board + * + * Copyright (C) 2004 Nokia Corporation + * Author: Imre Deak + * + * 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 + +#include +#include + +#include "omapfb.h" + +// #define OMAPFB_DBG 1 + +#include "debug.h" + +static int h3_panel_init(struct lcd_panel *panel) +{ + DBGENTER(1); + DBGLEAVE(1); + return 0; +} + +static void h3_panel_cleanup(struct lcd_panel *panel) +{ + DBGENTER(1); + DBGLEAVE(1); +} + +static int h3_panel_enable(struct lcd_panel *panel) +{ + int r = 0; + + DBGENTER(1); + + /* GPIO1 and GPIO2 of TPS65010 send LCD_ENBKL and LCD_ENVDD signals */ + r = tps65010_set_gpio_out_value(GPIO1, HIGH); + if (!r) + r = tps65010_set_gpio_out_value(GPIO2, HIGH); + if (r) + PRNERR("Unable to turn on LCD panel\n"); + + DBGLEAVE(1); + return r; +} + +static void h3_panel_disable(struct lcd_panel *panel) +{ + int r = 0; + + DBGENTER(1); + + /* GPIO1 and GPIO2 of TPS65010 send LCD_ENBKL and LCD_ENVDD signals */ + r = tps65010_set_gpio_out_value(GPIO1, LOW); + if (!r) + tps65010_set_gpio_out_value(GPIO2, LOW); + if (r) + PRNERR("Unable to turn off LCD panel\n"); + + DBGLEAVE(1); +} + +static unsigned long h3_panel_get_caps(struct lcd_panel *panel) +{ + return 0; +} + +static struct lcdc_video_mode mode240x320 = { + .x_res = 240, + .y_res = 320, + .pixel_clock = 12500, + .bpp = 16, + .hsw = 12, + .hfp = 14, + .hbp = 72 - 12, + .vsw = 1, + .vfp = 1, + .vbp = 0, + .pcd = 4, +}; + +struct lcd_panel h3_panel = { + .name = "h3", + .config = LCD_PANEL_TFT, + .video_mode = &mode240x320, + + .init = h3_panel_init, + .cleanup = h3_panel_cleanup, + .enable = h3_panel_enable, + .disable = h3_panel_disable, + .get_caps= h3_panel_get_caps, +}; + diff -Nru a/drivers/video/omap/lcd_inn1510.c b/drivers/video/omap/lcd_inn1510.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/video/omap/lcd_inn1510.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,98 @@ +/* + * File: drivers/video/omap_new/lcd-inn1510.c + * + * LCD panel support for the TI OMAP1510 Innovator board + * + * Copyright (C) 2004 Nokia Corporation + * Author: Imre Deak + * + * 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 + +#include + +#include + +#include "omapfb.h" + +// #define OMAPFB_DBG 1 + +#include "debug.h" + +static int innovator1510_panel_init(struct lcd_panel *panel) +{ + DBGENTER(1); + DBGLEAVE(1); + return 0; +} + +static void innovator1510_panel_cleanup(struct lcd_panel *panel) +{ + DBGENTER(1); + DBGLEAVE(1); +} + +static int innovator1510_panel_enable(struct lcd_panel *panel) +{ + DBGENTER(1); + + fpga_write(0x7, OMAP1510_FPGA_LCD_PANEL_CONTROL); + + DBGLEAVE(1); + return 0; +} + +static void innovator1510_panel_disable(struct lcd_panel *panel) +{ + DBGENTER(1); + + fpga_write(0x0, OMAP1510_FPGA_LCD_PANEL_CONTROL); + + DBGLEAVE(1); +} + +static unsigned long innovator1510_panel_get_caps(struct lcd_panel *panel) +{ + return 0; +} + +static struct lcdc_video_mode mode240x320 = { + .x_res = 240, + .y_res = 320, + .pixel_clock = 12500, + .bpp = 16, + .hsw = 12, + .hfp = 14, + .hbp = 72 - 12, + .vsw = 1, + .vfp = 1, + .vbp = 0, + .pcd = 4, +}; + +struct lcd_panel innovator1510_panel = { + .name = "inn1510", + .config = LCD_PANEL_TFT, + .video_mode = &mode240x320, + + .init = innovator1510_panel_init, + .cleanup = innovator1510_panel_cleanup, + .enable = innovator1510_panel_enable, + .disable = innovator1510_panel_disable, + .get_caps= innovator1510_panel_get_caps, +}; + diff -Nru a/drivers/video/omap/lcd_inn1610.c b/drivers/video/omap/lcd_inn1610.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/video/omap/lcd_inn1610.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,122 @@ +/* + * File: drivers/video/omap_new/lcd-inn1610.c + * + * LCD panel support for the TI OMAP1610 Innovator board + * + * Copyright (C) 2004 Nokia Corporation + * Author: Imre Deak + * + * 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 + +#include + +#include "omapfb.h" + +// #define OMAPFB_DBG 1 + +#include "debug.h" + +static int innovator1610_panel_init(struct lcd_panel *panel) +{ + int r = 0; + + DBGENTER(1); + + if (omap_request_gpio(14)) { + PRNERR("can't request GPIO 14\n"); + r = -1; + goto exit; + } + if (omap_request_gpio(15)) { + PRNERR("can't request GPIO 15\n"); + omap_free_gpio(14); + r = -1; + goto exit; + } + /* configure GPIO(14, 15) as outputs */ + omap_set_gpio_direction(14, 0); + omap_set_gpio_direction(15, 0); +exit: + DBGLEAVE(1); + return r; +} + +static void innovator1610_panel_cleanup(struct lcd_panel *panel) +{ + DBGENTER(1); + + omap_free_gpio(15); + omap_free_gpio(14); + + DBGLEAVE(1); +} + +static int innovator1610_panel_enable(struct lcd_panel *panel) +{ + DBGENTER(1); + + /* set GPIO14 and GPIO15 high */ + omap_set_gpio_dataout(14, 1); + omap_set_gpio_dataout(15, 1); + + DBGLEAVE(1); + return 0; +} + +static void innovator1610_panel_disable(struct lcd_panel *panel) +{ + DBGENTER(1); + + /* set GPIO13, GPIO14 and GPIO15 low */ + omap_set_gpio_dataout(14, 0); + omap_set_gpio_dataout(15, 0); + + DBGLEAVE(1); +} + +static unsigned long innovator1610_panel_get_caps(struct lcd_panel *panel) +{ + return 0; +} + +static struct lcdc_video_mode mode320x240 = { + .x_res = 320, + .y_res = 240, + .pixel_clock = 12500, + .bpp = 16, + .hsw = 12, + .hfp = 14, + .hbp = 72 - 12, + .vsw = 1, + .vfp = 1, + .vbp = 0, + .pcd = 4, +}; + +struct lcd_panel innovator1610_panel = { + .name = "inn1610", + .config = LCD_PANEL_TFT, + .video_mode = &mode320x240, + + .init = innovator1610_panel_init, + .cleanup = innovator1610_panel_cleanup, + .enable = innovator1610_panel_enable, + .disable = innovator1610_panel_disable, + .get_caps= innovator1610_panel_get_caps, +}; + diff -Nru a/drivers/video/omap/lcd_osk.c b/drivers/video/omap/lcd_osk.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/video/omap/lcd_osk.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,117 @@ +/* + * File: drivers/video/omap_new/lcd-osk.c + * + * LCD panel support for the TI OMAP OSK board + * + * Copyright (C) 2004 Nokia Corporation + * Author: Imre Deak + * Adapted for OSK by + * + * 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 +#include +#include + +#include "omapfb.h" + +// #define OMAPFB_DBG 1 + +#include "debug.h" + +static int osk_panel_init(struct lcd_panel *panel) +{ + DBGENTER(1); + DBGLEAVE(1); + return 0; +} + +static void osk_panel_cleanup(struct lcd_panel *panel) +{ + DBGENTER(1); + DBGLEAVE(1); +} + +static int osk_panel_enable(struct lcd_panel *panel) +{ + DBGENTER(1); + + /* configure PWL pin */ + omap_cfg_reg(PWL); + + /* Enable PWL unit */ + omap_writeb(0x01, OMAP16XX_PWL_CLK_ENABLE); + + /* Set PWL level */ + omap_writeb(0xFF, OMAP16XX_PWL_ENABLE); + + /* configure GPIO2 as output */ + omap_set_gpio_direction(2, 0); + + /* set GPIO2 high */ + omap_set_gpio_dataout(2, 1); + + DBGLEAVE(1); + return 0; +} + +static void osk_panel_disable(struct lcd_panel *panel) +{ + DBGENTER(1); + + /* Set PWL level to zero */ + omap_writeb(0x00, OMAP16XX_PWL_ENABLE); + + /* Disable PWL unit */ + omap_writeb(0x00, OMAP16XX_PWL_CLK_ENABLE); + + /* set GPIO2 low */ + omap_set_gpio_dataout(2, 0); + + DBGLEAVE(1); +} + +static unsigned long osk_panel_get_caps(struct lcd_panel *panel) +{ + return 0; +} + +static struct lcdc_video_mode mode240x320 = { + .x_res = 240, + .y_res = 320, + .pixel_clock = 12500, + .bpp = 16, + .hsw = 40, + .hfp = 40, + .hbp = 72, + .vsw = 1, + .vfp = 1, + .vbp = 0, + .pcd = 12, +}; + +struct lcd_panel osk_panel = { + .name = "osk", + .config = LCD_PANEL_TFT, + .video_mode = &mode240x320, + + .init = osk_panel_init, + .cleanup = osk_panel_cleanup, + .enable = osk_panel_enable, + .disable = osk_panel_disable, + .get_caps= osk_panel_get_caps, +}; + diff -Nru a/drivers/video/omap/lcd_p2.c b/drivers/video/omap/lcd_p2.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/video/omap/lcd_p2.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,311 @@ +/* + * File: drivers/video/omap_new/lcd-p2.c + * + * LCD panel support for the TI OMAP P2 board + * + * Authors: + * jekyll + * B Jp + * Brian Swetland + * + * 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 +#include +#include +#include + +#include "omapfb.h" + +/* + * File: epson-md-tft.h + * + * This file contains definitions for Epsons MD-TF LCD Module + * + * Copyright (C) 2004 MPC-Data Limited (http://www.mpc-data.co.uk) + * Author: Dave Peverley + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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. + * + * Please report all bugs and problems to the author. + * + */ + +/* LCD uWire commands & params + * All values from Epson + */ +#define LCD_DISON 0xAF +#define LCD_DISOFF 0xAE +#define LCD_DISNOR 0xA6 +#define LCD_DISINV 0xA7 +#define LCD_DISCTL 0xCA +#define LCD_GCP64 0xCB +#define LCD_GCP16 0xCC +#define LCD_GSSET 0xCD +#define LCD_SLPIN 0x95 +#define LCD_SLPOUT 0x94 +#define LCD_SD_PSET 0x75 +#define LCD_MD_PSET 0x76 +#define LCD_SD_CSET 0x15 +#define LCD_MD_CSET 0x16 +#define LCD_DATCTL 0xBC +#define LCD_RAMWR 0x5C +#define LCD_RAMRD 0x5D +#define LCD_PTLIN 0xA8 +#define LCD_PTLOUT 0xA9 +#define LCD_ASCSET 0xAA +#define LCD_SCSTART 0xAB +#define LCD_VOLCTL 0xC6 +#define LCD_NOP 0x25 +#define LCD_OSCISEL 0x7 +#define LCD_3500KSET 0xD1 +#define LCD_3500KEND 0xD2 +#define LCD_14MSET 0xD3 +#define LCD_14MEND 0xD4 + +#define INIT_3500KSET 0x45 +#define INIT_14MSET 0x4B +#define INIT_DATCTL 0x08 /* 6.6.6 bits for D-Sample */ + +#define INIT_OSCISEL 0x05 + +#define INIT_VOLCTL 0x77 /* Nominel "volume" */ + +#define INIT_VOLCTL_Ton 0x98 /* Activate power-IC timer */ +#define INIT_GSSET 0x00 + +const unsigned short INIT_DISCTL[11] = +{ + 0xDE, 0x01, 0x64, 0x00, 0x1B, 0xF4, 0x00, 0xDC, 0x00, 0x02, 0x00 +}; + +const unsigned short INIT_GCP64[126] = +{ + 0x3B,0x00,0x42,0x00,0x4A,0x00,0x51,0x00, + 0x58,0x00,0x5F,0x00,0x66,0x00,0x6E,0x00, + 0x75,0x00,0x7C,0x00,0x83,0x00,0x8A,0x00, + 0x92,0x00,0x99,0x00,0xA0,0x00,0xA7,0x00, + 0xAE,0x00,0xB6,0x00,0xBD,0x00,0xC4,0x00, + 0xCB,0x00,0xD2,0x00,0xDA,0x00,0xE1,0x00, + 0xE8,0x00,0xEF,0x00,0xF6,0x00,0xFE,0x00, + 0x05,0x01,0x0C,0x01,0x13,0x01,0x1A,0x01, + 0x22,0x01,0x29,0x01,0x30,0x01,0x37,0x01, + 0x3E,0x01,0x46,0x01,0x4D,0x01,0x54,0x01, + 0x5B,0x01,0x62,0x01,0x6A,0x01,0x71,0x01, + 0x78,0x01,0x7F,0x01,0x86,0x01,0x8E,0x01, + 0x95,0x01,0x9C,0x01,0xA3,0x01,0xAA,0x01, + 0xB2,0x01,0xB9,0x01,0xC0,0x01,0xC7,0x01, + 0xCE,0x01,0xD6,0x01,0xDD,0x01,0xE4,0x01, + 0xEB,0x01,0xF2,0x01,0xFA,0x01 +}; + +const unsigned short INIT_GCP16[15] = +{ + 0x1A,0x31,0x48,0x54,0x5F,0x67,0x70,0x76,0x7C,0x80,0x83,0x84,0x85,0x87,0x96 +}; + +const unsigned short INIT_MD_PSET[4] = { 0, 0, 219, 0 }; +const unsigned short INIT_MD_CSET[4] = { 2, 0, 177, 0 }; + +const unsigned short INIT_SD_PSET[4] = { 0x00, 0x01, 0x00, 0x01 }; +const unsigned short INIT_SD_CSET[4] = { 0x00, 0x02, 0x00, 0x02 }; + +const unsigned short INIT_ASCSET[7] = { 0x00, 0x00, 0xDB, 0x00, 0xDC, 0x00, 0x01 }; +const unsigned short INIT_SCSTART[2] = { 0x00, 0x00 }; + +/* ----- end of epson_md_tft.h ----- */ + + +#include "debug.h" +#include "../drivers/ssi/omap-uwire.h" + +#define LCD_UWIRE_CS 0 + +static int p2_panel_init(struct lcd_panel *panel) +{ + DBGENTER(1); + DBGLEAVE(1); + return 0; +} + +static void p2_panel_cleanup(struct lcd_panel *panel) +{ + DBGENTER(1); + DBGLEAVE(1); +} + +static int p2_panel_enable(struct lcd_panel *panel) +{ + int i; + unsigned long value; + DBGENTER(1); + + /* thwack the reset line */ + omap_set_gpio_direction(19, 0); + omap_set_gpio_dataout(19, 0); + mdelay(2); + omap_set_gpio_dataout(19, 1); + + /* bits 31:28 -> 0 LCD_PXL_15 .. 12 */ + value = omap_readl(OMAP730_IO_CONF_3) & 0x0FFFFFFF; + omap_writel(value, OMAP730_IO_CONF_3); + + /* bits 19:0 -> 0 LCD_VSYNC, AC, PXL_0, PCLK, HSYNC, + ** PXL_9..1, PXL_10, PXL_11 + */ + value = omap_readl(OMAP730_IO_CONF_4) & 0xFFF00000; + omap_writel(value, OMAP730_IO_CONF_4); + + omap_uwire_configure_mode(0,16); + + omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_DISOFF, 9, 0,NULL,1); + omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_SLPIN, 9, 0,NULL,1); + omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_DISNOR, 9, 0,NULL,1); + omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_GSSET, 9, 0,NULL,1); + omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_GSSET | 0x100), 9, 0,NULL,1); + + /* DISCTL */ + omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_DISCTL, 9, 0,NULL,1); + for (i = 0; i < (sizeof(INIT_DISCTL)/sizeof(unsigned short)); i++) + omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_DISCTL[i] | 0x100), 9, 0,NULL,1); + + /* GCP64 */ + omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_GCP64, 9, 0,NULL,1); + for (i = 0; i < (sizeof(INIT_GCP64)/sizeof(unsigned short)); i++) + omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_GCP64[i] | 0x100), 9, 0,NULL,1); + + /* GCP16 */ + omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_GCP16, 9, 0,NULL,1); + for (i = 0; i < (sizeof(INIT_GCP16)/sizeof(unsigned short)); i++) + omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_GCP16[i] | 0x100), 9, 0,NULL,1); + + /* MD_CSET */ + omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_MD_CSET, 9, 0,NULL,1); + for (i = 0; i < (sizeof(INIT_MD_CSET)/sizeof(unsigned short)); i++) + omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_MD_CSET[i] | 0x100), 9, 0,NULL,1); + + /* MD_PSET */ + omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_MD_PSET, 9, 0,NULL,1); + for (i = 0; i < (sizeof(INIT_MD_PSET)/sizeof(unsigned short)); i++) + omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_MD_PSET[i] | 0x100), 9, 0,NULL,1); + + /* SD_CSET */ + omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_SD_CSET, 9, 0,NULL,1); + for (i = 0; i < (sizeof(INIT_SD_CSET)/sizeof(unsigned short)); i++) + omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_SD_CSET[i] | 0x100), 9, 0,NULL,1); + + /* SD_PSET */ + omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_SD_PSET, 9, 0,NULL,1); + for (i = 0; i < (sizeof(INIT_SD_PSET)/sizeof(unsigned short)); i++) + omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_SD_PSET[i] | 0x100), 9, 0,NULL,1); + + /* DATCTL */ + omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_DATCTL, 9, 0,NULL,1); + omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_DATCTL | 0x100), 9, 0,NULL,1); + + /* OSSISEL = d'5 */ + omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_OSCISEL, 9, 0,NULL,1); + omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_OSCISEL | 0x100), 9, 0,NULL,1); + + /* 14MSET = d'74 */ + omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_14MSET, 9, 0,NULL,1); + omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_14MSET | 0x100), 9, 0,NULL,1); + + /* 14MEND */ + omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_14MEND, 9, 0,NULL,1); + + /* 3500KSET = d'69 */ + omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_3500KSET, 9, 0,NULL,1); + omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_3500KSET | 0x100), 9, 0,NULL,1); + + /* 3500KEND */ + omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_3500KEND, 9, 0,NULL,1); + + omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_SLPOUT, 9, 0,NULL,1); + + omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_VOLCTL, 9, 0,NULL,1); + omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_VOLCTL_Ton | 0x100), 9, 0,NULL,1); + + omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_VOLCTL, 9, 0,NULL,1); + + omap_uwire_data_transfer(LCD_UWIRE_CS, (INIT_VOLCTL | 0x100), 9, 0,NULL,1); + + omap_uwire_data_transfer(LCD_UWIRE_CS, LCD_DISON, 9, 0,NULL,1); + + /* enable backlight */ + omap_set_gpio_direction(134, 0); + omap_set_gpio_dataout(134, 1); + + DBGLEAVE(1); + return 0; +} + +static void p2_panel_disable(struct lcd_panel *panel) +{ + DBGENTER(1); + DBGLEAVE(1); +} + +static unsigned long p2_panel_get_caps(struct lcd_panel *panel) +{ + return 0; +} + +static struct lcdc_video_mode mode176x220 = { + .x_res = 176, + .y_res = 220, + .pixel_clock = 12500, + .bpp = 16, + .hsw = 5, + .hfp = 1, + .hbp = 1, + .vsw = 2, + .vfp = 12, + .vbp = 1, + .pcd = 4, + .flags = OMAP_LCDC_INV_PIX_CLOCK, +}; + +struct lcd_panel p2_panel = { + .name = "p2", + .config = LCD_PANEL_TFT, + .video_mode = &mode176x220, + + .init = p2_panel_init, + .cleanup = p2_panel_cleanup, + .enable = p2_panel_enable, + .disable = p2_panel_disable, + .get_caps= p2_panel_get_caps, +}; + diff -Nru a/drivers/video/omap/omap_lcdc.c b/drivers/video/omap/omap_lcdc.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/video/omap/omap_lcdc.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,599 @@ +/* + * linux/arch/arm/mach-omap/omap_lcdc.c + * + * OMAP internal LCD controller + * + * Copyright (C) 2004 Nokia Corporation + * Author: Imre Deak + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "omapfb.h" +#include "debug.h" + +#define OMAP_LCDC_BASE 0xfffec000 +#define OMAP_LCDC_SIZE 256 +#define OMAP_LCDC_IRQ INT_LCD_CTRL + +#define OMAP_LCDC_CONTROL (OMAP_LCDC_BASE + 0x00) +#define OMAP_LCDC_TIMING0 (OMAP_LCDC_BASE + 0x04) +#define OMAP_LCDC_TIMING1 (OMAP_LCDC_BASE + 0x08) +#define OMAP_LCDC_TIMING2 (OMAP_LCDC_BASE + 0x0c) +#define OMAP_LCDC_STATUS (OMAP_LCDC_BASE + 0x10) +#define OMAP_LCDC_SUBPANEL (OMAP_LCDC_BASE + 0x14) +#define OMAP_LCDC_LINE_INT (OMAP_LCDC_BASE + 0x18) +#define OMAP_LCDC_DISPLAY_STATUS (OMAP_LCDC_BASE + 0x1c) + +#define OMAP_LCDC_STAT_DONE (1 << 0) +#define OMAP_LCDC_STAT_VSYNC (1 << 1) +#define OMAP_LCDC_STAT_SYNC_LOST (1 << 2) +#define OMAP_LCDC_STAT_ABC (1 << 3) +#define OMAP_LCDC_STAT_LINE_INT (1 << 4) +#define OMAP_LCDC_STAT_FUF (1 << 5) +#define OMAP_LCDC_STAT_LOADED_PALETTE (1 << 6) + +#define OMAP_LCDC_CTRL_LCD_EN (1 << 0) +#define OMAP_LCDC_CTRL_LCD_TFT (1 << 7) +#define OMAP_LCDC_CTRL_LINE_IRQ_CLR_SEL (1 << 10) + +#define OMAP_LCDC_IRQ_VSYNC (1 << 2) +#define OMAP_LCDC_IRQ_DONE (1 << 3) +#define OMAP_LCDC_IRQ_LOADED_PALETTE (1 << 4) +#define OMAP_LCDC_IRQ_LINE_NIRQ (1 << 5) +#define OMAP_LCDC_IRQ_LINE (1 << 6) +#define OMAP_LCDC_IRQ_MASK (((1 << 5) - 1) << 2) + +#define MAX_PALETTE_SIZE PAGE_SIZE + +enum lcdc_load_mode { + OMAP_LCDC_LOAD_PALETTE, + OMAP_LCDC_LOAD_FRAME, + OMAP_LCDC_LOAD_PALETTE_AND_FRAME +}; + +struct omap_lcd_controller { + enum fb_update_mode update_mode; + unsigned int irq_mask; + struct completion last_frame_complete; + struct completion palette_load_complete; + struct clk *lcd_ck; +} omap_lcdc; + +static void inline enable_irqs(int mask) +{ + omap_lcdc.irq_mask |= mask; +} + +static void inline disable_irqs(int mask) +{ + omap_lcdc.irq_mask &= ~mask; +} + +static void set_load_mode(enum lcdc_load_mode mode) +{ + u32 l; + + l = omap_readl(OMAP_LCDC_CONTROL); + l &= ~(3 << 20); + switch (mode) { + case OMAP_LCDC_LOAD_PALETTE: + l |= 1 << 20; + break; + case OMAP_LCDC_LOAD_FRAME: + l |= 2 << 20; + break; + case OMAP_LCDC_LOAD_PALETTE_AND_FRAME: + break; + default: + BUG(); + } + omap_writel(l, OMAP_LCDC_CONTROL); +} + +static void enable_controller(void) +{ + u32 l; + + l = omap_readl(OMAP_LCDC_CONTROL); + l |= OMAP_LCDC_CTRL_LCD_EN; + l &= ~OMAP_LCDC_IRQ_MASK; + l |= omap_lcdc.irq_mask | OMAP_LCDC_IRQ_DONE; /* enabled IRQs */ + omap_writel(l, OMAP_LCDC_CONTROL); +} + +static void disable_controller_async(void) +{ + u32 l; + u32 mask; + + init_completion(&omap_lcdc.last_frame_complete); + l = omap_readl(OMAP_LCDC_CONTROL); + mask = OMAP_LCDC_CTRL_LCD_EN | OMAP_LCDC_IRQ_MASK; + /* Preserve the DONE mask, since we still want to get the + * final DONE irq. It will be disabled in the IRQ handler. + */ + mask &= ~OMAP_LCDC_IRQ_DONE; + l &= ~mask; + omap_writel(l, OMAP_LCDC_CONTROL); +} + +static void last_frame_timeout(unsigned long data) +{ + printk(KERN_ERR "omap_lcdc: timeout waiting for DONE flag\n"); + complete(&omap_lcdc.last_frame_complete); +} + +static void inline wait_for_frame_done(void) +{ + struct timer_list timeout; + + init_timer(&timeout); + timeout.function = last_frame_timeout; + timeout.expires = jiffies + msecs_to_jiffies(500); + add_timer(&timeout); + wait_for_completion(&omap_lcdc.last_frame_complete); + del_timer_sync(&timeout); +} + +static void disable_controller(void) +{ + disable_controller_async(); + wait_for_frame_done(); +} + +static void reset_controller(u32 status) +{ + static unsigned long reset_count = 0; + static unsigned long last_jiffies = 0; + + disable_controller_async(); + reset_count++; + if (reset_count == 1 || + time_after(jiffies, last_jiffies + HZ)) { + printk(KERN_ERR "omap_lcdc: resetting " + "(status %#010x,reset count %lu)\n", + status, reset_count); + last_jiffies = jiffies; + } + if (reset_count < 100) { + enable_controller(); + } else { + reset_count = 0; + printk(KERN_ERR "omap_lcdc: too many reset attempts, " + "giving up.\n"); + } +} + +/* Configure the LCD DMA according to the current mode specified by parameters + * in fbdev and fbdev->var. + */ +static void setup_lcd_dma(struct omapfb_device *fbdev) +{ + static const int dma_elem_type[] = { + 0, + OMAP_DMA_DATA_TYPE_S8, + OMAP_DMA_DATA_TYPE_S16, + 0, + OMAP_DMA_DATA_TYPE_S32, + }; + struct fb_var_screeninfo *var = &fbdev->fb_info->var; + unsigned long src; + int esize, xelem, yelem; + + src = fbdev->lcddma_handle + fbdev->vis_frame_org + fbdev->view_org; + switch (var->rotate) { + case 0: + esize = fbdev->mirror || (src & 3) ? 2 : 4; + xelem = var->xres * var->bits_per_pixel / 8 / esize; + yelem = var->yres; + break; + case 90: + case 180: + case 270: + esize = 2; + xelem = var->xres * var->bits_per_pixel / 16; + yelem = var->yres; + break; + default: + BUG(); + return; + } + DBGPRINT(1, "setup_dma: src=%#010x esize=%d xelem=%d yelem=%d\n", + src, esize, xelem, yelem); + omap_set_lcd_dma_b1(src, xelem, yelem, dma_elem_type[esize]); + omap_set_lcd_dma_single_transfer(0); + if (!cpu_is_omap1510()) { + /* Set virtual xres elem size */ + omap_set_lcd_dma_b1_vxres( + fbdev->fb_info->fix.line_length / esize); + /* Setup transformations */ + omap_set_lcd_dma_b1_rotation(var->rotate); + omap_set_lcd_dma_b1_mirror(fbdev->mirror); + omap_set_lcd_dma_b1_scale(fbdev->xscale, fbdev->yscale); + } + omap_setup_lcd_dma(); +} + +static irqreturn_t lcdc_irq_handler(int irq, void *dev_id, + struct pt_regs *fp) +{ + u32 status; + + status = omap_readl(OMAP_LCDC_STATUS); + + if (status & (OMAP_LCDC_STAT_FUF | OMAP_LCDC_STAT_SYNC_LOST)) + reset_controller(status); + else { + if (status & OMAP_LCDC_STAT_DONE) { + u32 l; + + /* Disable IRQ_DONE. The status bit will be cleared + * only when the controller is reenabled and we don't + * want to get more interrupts. + */ + l = omap_readl(OMAP_LCDC_CONTROL); + l &= ~OMAP_LCDC_IRQ_DONE; + omap_writel(l, OMAP_LCDC_CONTROL); + complete(&omap_lcdc.last_frame_complete); + } + if (status & OMAP_LCDC_STAT_LOADED_PALETTE) { + disable_controller_async(); + complete(&omap_lcdc.palette_load_complete); + } + } + + /* Clear these interrupt status bits. + * Sync_lost, FUF bits were cleared by disabling the LCD controller + * LOADED_PALETTE can be cleared this way only in palette only + * load mode. In other load modes it's cleared by disabling the + * controller. + */ + status &= ~(OMAP_LCDC_STAT_VSYNC | + OMAP_LCDC_STAT_LOADED_PALETTE | + OMAP_LCDC_STAT_ABC | + OMAP_LCDC_STAT_LINE_INT); + omap_writel(status, OMAP_LCDC_STATUS); + return IRQ_HANDLED; +} + +/* Change to a new video mode. We defer this to a later time to avoid any + * flicker and not to mess up the current LCD DMA context. For this we disable + * the LCD controler, which will generate a DONE irq after the last frame has + * been transferred. Then it'll be safe to reconfigure both the LCD controller + * as well as the LCD DMA. + */ +static void omap_lcdc_change_mode(struct omapfb_device *fbdev) +{ + DBGENTER(1); + + omap_stop_lcd_dma(); + disable_controller(); + setup_lcd_dma(fbdev); + enable_controller(); + + DBGLEAVE(1); +} + +/* Configure the LCD DMA for a palette load operation and do the palette + * downloading synchronously. We don't use the frame+palette load mode of + * the controller, since the palette can always be downloaded seperately. + */ +static void load_palette(struct omapfb_device *fbdev) +{ + u8 *palette; + u32 code; + unsigned long size; + unsigned long palette_org; + + DBGENTER(1); + + switch (fbdev->panel->video_mode->bpp) { + case 1: + /* 0 is already set */ + code = 0; + size = 256; + break; + case 2: + code = 0x1000; + size = 256; + break; + case 4: + code = 0x2000; + size = 256; + break; + case 8: + code = 0x3000; + size = 256; + break; + case 12: + case 16: + code = 0x4000; + size = 32; + break; + default: + BUG(); + return; + } + palette_org = MAX_PALETTE_SIZE - size; + palette = fbdev->lcddma_base + palette_org; + memset(palette, 0, size); + *(u32 *)palette = code; + + omap_set_lcd_dma_b1(fbdev->lcddma_handle + palette_org, + size / 4 + 1, 1, OMAP_DMA_DATA_TYPE_S32); + omap_set_lcd_dma_single_transfer(1); + omap_setup_lcd_dma(); + + init_completion(&omap_lcdc.palette_load_complete); + enable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE); + set_load_mode(OMAP_LCDC_LOAD_PALETTE); + enable_controller(); + wait_for_completion(&omap_lcdc.palette_load_complete); + /* The controller gets disabled in the irq handler */ + disable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE); + omap_stop_lcd_dma(); + + DBGLEAVE(1); +} + +static void inline setup_regs(struct omapfb_device *fbdev) +{ + u32 l; + struct lcdc_video_mode *mode = fbdev->panel->video_mode; + int tft = fbdev->panel->config & LCD_PANEL_TFT; + int signal_levels = fbdev->panel->signals; + + l = omap_readl(OMAP_LCDC_CONTROL); + l &= ~OMAP_LCDC_CTRL_LCD_TFT; + l |= tft ? OMAP_LCDC_CTRL_LCD_TFT : 0; + omap_writel(l, OMAP_LCDC_CONTROL); + + l = omap_readl(OMAP_LCDC_TIMING2); + l &= ~(((1 << 6) - 1) << 20); + l |= signal_levels << 20; + omap_writel(l, OMAP_LCDC_TIMING2); + + l = mode->x_res - 1; + l |= (mode->hsw - 1) << 10; + l |= (mode->hfp - 1) << 16; + l |= (mode->hbp - 1) << 24; + omap_writel(l, OMAP_LCDC_TIMING0); + + l = mode->y_res - 1; + l |= (mode->vsw - 1) << 10; + l |= mode->vfp << 16; + l |= mode->vbp << 24; + omap_writel(l, OMAP_LCDC_TIMING1); + + l = omap_readl(OMAP_LCDC_TIMING2); + l &= ~0xff; + + if (!cpu_is_omap730()) + l |= mode->pcd; + + if (machine_is_omap_perseus2()) { + u32 clock1, clock2; + int pcd; + + clock1 = mode->pixel_clock * 1000; + clock2 = clk_get_rate(omap_lcdc.lcd_ck); + + if (clock1 != 0) { + pcd = clock2 / clock1; + if (pcd > 255) + pcd = 0; + } else { + pcd = 0; + } + + if (pcd == 0) + l |= mode->pcd; + else + l |= pcd; + +// printk("%% ck1: %d ck2: %d pcd: %d %%\n",clock1, clock2, pcd); + } + + l |= mode->acb << 8; + if (mode->flags & OMAP_LCDC_INV_PIX_CLOCK) + l |= 1 << 22; + omap_writel(l, OMAP_LCDC_TIMING2); +} + +/* Configure the LCD controller, download the color palette and start a looped + * DMA transfer of the frame image data. */ +static int omap_lcdc_set_update_mode(struct omapfb_device *fbdev, + enum fb_update_mode mode) +{ + int r = 0; + + DBGENTER(1); + + if (mode != omap_lcdc.update_mode) { + switch (mode) { + case FB_AUTO_UPDATE: + setup_regs(fbdev); + load_palette(fbdev); + + /* Setup and start LCD DMA */ + setup_lcd_dma(fbdev); + + set_load_mode(OMAP_LCDC_LOAD_FRAME); + enable_irqs(OMAP_LCDC_IRQ_DONE); + /* This will start the actual DMA transfer */ + enable_controller(); + omap_lcdc.update_mode = mode; + break; + case FB_UPDATE_DISABLED: + disable_controller(); + omap_stop_lcd_dma(); + omap_lcdc.update_mode = mode; + break; + default: + r = -EINVAL; + } + } + + DBGLEAVE(1); + return r; +} + +static enum fb_update_mode omap_lcdc_get_update_mode(struct omapfb_device *fbdev) +{ + return omap_lcdc.update_mode; +} + +static void omap_lcdc_suspend(struct omapfb_device *fbdev) +{ + if (omap_lcdc.update_mode == FB_AUTO_UPDATE) { + disable_controller(); + omap_stop_lcd_dma(); + } +} + +static void omap_lcdc_resume(struct omapfb_device *fbdev) +{ + if (omap_lcdc.update_mode == FB_AUTO_UPDATE) { + setup_regs(fbdev); + load_palette(fbdev); + setup_lcd_dma(fbdev); + set_load_mode(OMAP_LCDC_LOAD_FRAME); + enable_irqs(OMAP_LCDC_IRQ_DONE); + enable_controller(); + } +} + +static int omap_lcdc_init(struct omapfb_device *fbdev) +{ + int r; + u32 l; + int rate; + struct clk *tc_ck; + + DBGENTER(1); + + omap_lcdc.irq_mask = 0; + + l = 0; + omap_writel(l, OMAP_LCDC_CONTROL); + + /* FIXME: + * According to errata some platforms have a clock rate limitiation + */ + omap_lcdc.lcd_ck = clk_get(0, "lcd_ck"); + if (IS_ERR(omap_lcdc.lcd_ck)) { + printk(KERN_ERR "omap_lcdc: unable to access LCD clock\n"); + r = PTR_ERR(omap_lcdc.lcd_ck); + goto fail0; + } + + tc_ck = clk_get(0, "tc_ck"); + if (IS_ERR(tc_ck)) { + printk(KERN_ERR "omap_lcdc: unable to access TC clock\n"); + r = PTR_ERR(tc_ck); + goto fail1; + } + + rate = clk_get_rate(tc_ck); + clk_put(tc_ck); + + if (machine_is_omap_innovator() || machine_is_omap_h3()) + rate /= 3; + r = clk_set_rate(omap_lcdc.lcd_ck, rate); + if (r) { + printk(KERN_ERR "omap_lcdc: failed to adjust LCD rate\n"); + goto fail1; + } + clk_use(omap_lcdc.lcd_ck); + + r = request_irq(OMAP_LCDC_IRQ, lcdc_irq_handler, 0, "omap-lcdc", fbdev); + if (r) { + printk(KERN_ERR "omap_lcdc: unable to get IRQ\n"); + goto fail2; + } + + r = omap_request_lcd_dma(NULL, NULL); + if (r) { + printk(KERN_ERR "omap_lcdc: unable to get LCD DMA\n"); + goto fail3; + } + + printk(KERN_INFO "OMAP LCD controller initialized.\n"); + DBGLEAVE(1); + return 0; +fail3: + free_irq(OMAP_LCDC_IRQ, fbdev); +fail2: + clk_unuse(omap_lcdc.lcd_ck); +fail1: + clk_put(omap_lcdc.lcd_ck); +fail0: + DBGLEAVE(1); + return r; +} + +static void omap_lcdc_cleanup(struct omapfb_device *fbdev) +{ + omap_free_lcd_dma(); + free_irq(OMAP_LCDC_IRQ, fbdev); + clk_unuse(omap_lcdc.lcd_ck); + clk_put(omap_lcdc.lcd_ck); +} + +static void omap_lcdc_get_mem_layout(struct omapfb_device *fbdev, + unsigned long *size, unsigned long *fb_org) +{ + struct lcdc_video_mode *mode = fbdev->panel->video_mode; + + *size = MAX_PALETTE_SIZE; + *fb_org = *size; + *size += mode->x_res * mode->bpp / 8 * mode->y_res; +} + +static unsigned long omap_lcdc_get_caps(struct omapfb_device *fbdev) +{ + return 0; +} + +struct lcd_ctrl omapfb_lcdc_ctrl = { + .name = "internal", + .init = omap_lcdc_init, + .cleanup = omap_lcdc_cleanup, + .get_mem_layout = omap_lcdc_get_mem_layout, + .get_caps = omap_lcdc_get_caps, + .set_update_mode = omap_lcdc_set_update_mode, + .get_update_mode = omap_lcdc_get_update_mode, + .update_window = NULL, + .suspend = omap_lcdc_suspend, + .resume = omap_lcdc_resume, + .change_mode = omap_lcdc_change_mode, +}; + +MODULE_DESCRIPTION("TI OMAP LCDC controller"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/video/omap/omapfb.h b/drivers/video/omap/omapfb.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/video/omap/omapfb.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,236 @@ +/* + * File: drivers/video/omap_new/omapfb.c + * + * Framebuffer driver for TI OMAP boards + * + * Copyright (C) 2004 Nokia Corporation + * Author: Imre Deak + * + * 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. + */ + +#ifndef __OMAPFB_H +#define __OMAPFB_H + +/* IOCTL commands. */ + +#define OMAP_IOW(num, dtype) _IOW('O', num, dtype) +#define OMAP_IOR(num, dtype) _IOR('O', num, dtype) +#define OMAP_IOWR(num, dtype) _IOWR('O', num, dtype) +#define OMAP_IO(num) _IO('O', num) + +#define OMAPFB_FILLRECT OMAP_IOW(0, struct fb_fillrect) +#define OMAPFB_COPYAREA OMAP_IOW(1, struct fb_copyarea) +#define OMAPFB_IMAGEBLIT OMAP_IOW(2, struct fb_image) + +#define OMAPFB_TRANSPARENT_BLIT OMAP_IOW(30, struct fb_image) +#define OMAPFB_MIRROR OMAP_IOW(31, int) +#define OMAPFB_SCALE OMAP_IOW(32, struct fb_scale) +#define OMAPFB_SELECT_VIS_FRAME OMAP_IOW(33, int) +#define OMAPFB_SELECT_SRC_FRAME OMAP_IOW(34, int) +#define OMAPFB_SELECT_DST_FRAME OMAP_IOW(35, int) +#define OMAPFB_GET_FRAME_OFFSET OMAP_IOWR(36, struct fb_frame_offset) +#define OMAPFB_SYNC_GFX OMAP_IO(37) +#define OMAPFB_VSYNC OMAP_IO(38) +#define OMAPFB_LATE_ACTIVATE OMAP_IO(39) +#define OMAPFB_SET_UPDATE_MODE OMAP_IOW(40, enum fb_update_mode) +#define OMAPFB_UPDATE_WINDOW OMAP_IOW(41, struct fb_update_window) +#define OMAPFB_GET_CAPS OMAP_IOR(42, unsigned long) +#define OMAPFB_GET_UPDATE_MODE OMAP_IOW(43, enum fb_update_mode) + +#define FBCAPS_GENERIC_MASK 0x00000fff +#define FBCAPS_LCDC_MASK 0x00fff000 +#define FBCAPS_PANEL_MASK 0xff000000 + +#define FBCAPS_MANUAL_UPDATE 0x00001000 +#define FBCAPS_SET_BACKLIGHT 0x01000000 + +struct fb_scale { + unsigned int xscale, yscale; +}; + +struct fb_frame_offset { + unsigned int idx; + unsigned long offset; +}; + +struct fb_update_window { + unsigned int x, y; + unsigned int width, height; +}; + +enum fb_update_mode { + FB_UPDATE_DISABLED = 0, + FB_AUTO_UPDATE, + FB_MANUAL_UPDATE +}; + +#ifdef __KERNEL__ + +#include +#include + +#define OMAPFB_DEVICE "omapfb" +#define OMAPFB_DRIVER "omapfb" + +#define PRNERR(fmt, args...) printk(KERN_ERR OMAPFB_DRIVER ": " fmt, ## args) + +#define GFX_FIFO_SIZE 2 + +#define LCD_PANEL_TFT 0x01 + +#define OMAP_LCDC_INV_VSYNC 0x01 +#define OMAP_LCDC_INV_HSYNC 0x02 +#define OMAP_LCDC_INV_PIX_CLOCK 0x04 +#define OMAP_LCDC_INV_OUTPUT_EN 0x08 +#define OMAP_LCDC_HSVS_RISING_EDGE 0x10 +#define OMAP_LCDC_HSVS_OPPOSITE 0x20 + +struct lcdc_video_mode { + u16 x_res, y_res; + u32 pixel_clock; /* In kHz */ + int bpp; + u8 hsw; /* Horizontal synchronization pulse width */ + u8 hfp; /* Horizontal front porch */ + u8 hbp; /* Horizontal back porch */ + u8 vsw; /* Vertical synchronization pulse width */ + u8 vfp; /* Vertical front porch */ + u8 vbp; /* Vertical back porch */ + u8 acb; /* ac-bias pin frequency */ + u8 pcd; /* Pixel clock divider (this will change) */ + u8 flags; +}; + +struct lcd_panel { + const char *name; + int config; + int signals; + struct lcdc_video_mode *video_mode; + + int (*init) (struct lcd_panel *panel); + void (*cleanup) (struct lcd_panel *panel); + int (*enable) (struct lcd_panel *panel); + void (*disable) (struct lcd_panel *panel); + unsigned long (*get_caps)(struct lcd_panel *panel); + int (*set_bklight_level)(struct lcd_panel *panel, + unsigned int level); + unsigned int (*get_bklight_level)(struct lcd_panel *panel); + unsigned int (*get_bklight_max) (struct lcd_panel *panel); +}; + +struct omapfb_device; + +struct lcd_ctrl { + const char *name; + void *data; + int (*init) (struct omapfb_device *fbdev); + void (*cleanup) (struct omapfb_device *fbdev); + void (*get_mem_layout) (struct omapfb_device *fbdev, + unsigned long *size, + unsigned long *fb_org); + unsigned long (*get_caps) (struct omapfb_device *fbdev); + int (*set_update_mode)(struct omapfb_device *fbdev, + enum fb_update_mode mode); + enum fb_update_mode (*get_update_mode)(struct omapfb_device *fbdev); + int (*update_window) (struct omapfb_device *fbdev, + struct fb_update_window *win); + void (*suspend) (struct omapfb_device *fbdev); + void (*resume) (struct omapfb_device *fbdev); + void (*change_mode) (struct omapfb_device *fbdev); +}; + +enum omapfb_state { + OMAPFB_DISABLED = 0, + OMAPFB_SUSPENDED= 99, + OMAPFB_ACTIVE = 100 +}; + +struct gfx_lchannel { + int lch_num; + struct gfx_lchannel *next, *prev; +}; + +struct gfx_dma { + spinlock_t spinlock; + + struct completion sync_complete; /* Signalled when the + fifo gets empty */ + volatile int done; /* Indicates the + end of a DMA chain + transfer */ + struct gfx_lchannel fifo[GFX_FIFO_SIZE]; + struct gfx_lchannel *f_head, *f_tail; /* Process and insert + points on the + fifo */ + struct gfx_lchannel *f_chain_end; /* Points to the new + chain end */ + struct semaphore f_free; /* # of free lch-s */ + int f_run; /* # of active lch-s */ + int f_wait; /* # of lch-s + waiting */ + struct tasklet_struct dequeue_tasklet; /* Processes new DMA + chain transfers on + the fifo */ +}; + +struct omapfb_device { + int state; + int ext_lcdc; /* Using external + LCD controller */ + void *lcddma_base; /* MPU virtual + address */ + dma_addr_t lcddma_handle; /* Bus physical + address */ + unsigned long lcddma_mem_size; + unsigned long palette_org; /* Palette offset into + lcddma_base/handle */ + unsigned long frame0_org, frame1_org; /* Frame offsets for + back and front + frame buffers into + lcddma_base/handle */ + unsigned long vis_frame_org; /* Offset of visible + frame buffer. + = frame0/1_org */ + unsigned long src_frame_org; /* Offset of source + frame for drawing + operations. + = frame0/1_org */ + unsigned long dst_frame_org; /* Offset of dest + frame for drawing + operations. + = frame0/1_org */ + unsigned long view_org; /* View offset into + lcddma_base/handle+ + vis_frame_org. + Used for panning */ + unsigned long palette_size; + int xscale, yscale, mirror; /* transformations. + rotate is stored in + fb_info->var */ + + u32 pseudo_palette[17]; + + struct gfx_dma gfx; /* Accelerator */ + struct lcd_panel *panel; /* LCD panel */ + struct lcd_ctrl *ctrl; /* LCD controller */ + + struct fb_info *fb_info; /* Linux fbdev + framework data */ + struct device *dev; +}; + +#endif /* __KERNEL__ */ + +#endif /* __OMAPFB_H */ diff -Nru a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/video/omap/omapfb_main.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,2116 @@ +/* + * File: drivers/video/omap/omapfb_main.c + * + * Framebuffer driver for TI OMAP boards + * + * Copyright (C) 2004 Nokia Corporation + * Author: Imre Deak + * + * Acknowledgements: + * Alex McMains - Original driver + * Juha Yrjola - Original driver and improvements + * Dirk Behme - changes for 2.6 kernel API + * Texas Instruments - H3 support + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "omapfb.h" + +// #define OMAPFB_DBG_FIFO 1 +// #define OMAPFB_DBG 1 + +#include "debug.h" + +#define COPY_MODE_REV_DIR 0x01 +#define COPY_MODE_TRANSPARENT 0x02 +#define COPY_MODE_IMAGE 0x04 + +#ifdef OMAPFB_DBG_FIFO +struct gfx_stat { + unsigned long f_run[GFX_FIFO_SIZE]; +} stat; +#endif + +static unsigned int def_accel; +static unsigned long def_vram; +static long def_vxres; +static long def_vyres; +static unsigned int def_rotate; +static unsigned int def_mirror; + +#ifdef CONFIG_FB_OMAP_MANUAL_UPDATE +static int manual_update = 1; +#else +static int manual_update; +#endif + +static struct caps_table_struct { + unsigned long flag; + const char *name; +} omapfb_caps_table[] = { + { FBCAPS_MANUAL_UPDATE, "manual update" }, + { FBCAPS_SET_BACKLIGHT, "backlight setting" }, +}; + +/* + * --------------------------------------------------------------------------- + * LCD panel + * --------------------------------------------------------------------------- + */ +extern struct lcd_panel h3_panel; +extern struct lcd_panel h2_panel; +extern struct lcd_panel p2_panel; +extern struct lcd_panel osk_panel; +extern struct lcd_panel innovator1610_panel; +extern struct lcd_panel innovator1510_panel; + +static struct lcd_panel *panels[] = { +#ifdef CONFIG_MACH_OMAP_H2 + &h2_panel, +#endif +#ifdef CONFIG_MACH_OMAP_H3 + &h3_panel, +#endif +#ifdef CONFIG_MACH_OMAP_PERSEUS2 + &p2_panel, +#endif +#ifdef CONFIG_MACH_OMAP_OSK + &osk_panel, +#endif +#ifdef CONFIG_MACH_OMAP_INNOVATOR +#ifdef CONFIG_ARCH_OMAP1510 + &innovator1510_panel, +#endif +#ifdef CONFIG_ARCH_OMAP16XX + &innovator1610_panel, +#endif +#endif +}; + +extern struct lcd_ctrl omapfb_lcdc_ctrl; + +static struct lcd_ctrl *ctrls[] = { +#ifdef CONFIG_FB_OMAP_INTERNAL_LCDC + &omapfb_lcdc_ctrl, +#endif +}; + +/* + * --------------------------------------------------------------------------- + * gfx DMA + * --------------------------------------------------------------------------- + */ +/* Get a new logical channel from the gfx fifo. */ +static void inline gfxdma_get_lch(struct gfx_dma *gfx, int *lch) +{ + DBGENTER(3); + + down(&gfx->f_free); + + spin_lock_bh(&gfx->spinlock); + + *lch = gfx->f_tail->lch_num; + gfx->f_tail = gfx->f_tail->next; + + spin_unlock_bh(&gfx->spinlock); + + DBGLEAVE(3); +} + +/* Set basic transfer params for the logical channel */ +static inline void gfxdma_set_lch_params(int lch, int data_type, + int enumber, int fnumber, + unsigned long src_start, int src_amode, + unsigned long dst_start, int dst_amode) +{ + omap_set_dma_transfer_params(lch, data_type, enumber, fnumber, 0); + omap_set_dma_src_params(lch, OMAP_DMA_PORT_EMIFF, + src_amode, src_start); + omap_set_dma_dest_params(lch, OMAP_DMA_PORT_EMIFF, + dst_amode, dst_start); +} + +/* Set element and frame indexes for the logical channel, to support + * image transformations + */ +static inline void gfxdma_set_lch_index(int lch, int src_eidx, int src_fidx, + int dst_eidx, int dst_fidx) +{ + omap_set_dma_src_index(lch, src_eidx, src_fidx); + omap_set_dma_dest_index(lch, dst_eidx, dst_fidx); +} + +/* Set color parameter for the logical channel, to support constant fill and + * transparent copy operations + */ +static inline void gfxdma_set_lch_color(int lch, u32 color, + enum omap_dma_color_mode mode) +{ + omap_set_dma_color_mode(lch, mode, color); +} + + +/* Start a new transfer consisting of a single DMA logical channel, + * or a chain (f_run > 1). Can be called in interrupt context. + * gfx->spinlock must be held. + */ +static void inline gfxdma_start_chain(struct gfx_dma *gfx) +{ + DBGENTER(3); + + gfx->f_run = gfx->f_wait; +#ifdef OMAPFB_DBG_FIFO + stat.f_run[gfx->f_run - 1]++; +#endif + gfx->f_wait = 0; + omap_enable_dma_irq(gfx->f_chain_end->lch_num, OMAP_DMA_BLOCK_IRQ); + /* Let it go */ + DBGPRINT(1, "start %d\n", gfx->f_head->lch_num); + omap_start_dma(gfx->f_head->lch_num); + gfx->f_chain_end = gfx->f_chain_end->next; + + DBGLEAVE(3); +} + +/* Enqueue a logical channel, that has been set up. If no other transfers + * are pending start this new one right away. */ +static void inline gfxdma_enqueue(struct gfx_dma *gfx, int lch) +{ + DBGENTER(3); + + spin_lock_bh(&gfx->spinlock); + DBGPRINT(3, "run:%d wait:%d\n", gfx->f_run, gfx->f_wait); + if (gfx->f_wait) { + DBGPRINT(1, "link %d, %d\n", gfx->f_chain_end->lch_num, lch); + omap_dma_link_lch(gfx->f_chain_end->lch_num, lch); + gfx->f_chain_end = gfx->f_chain_end->next; + } + omap_disable_dma_irq(lch, OMAP_DMA_BLOCK_IRQ); + + gfx->f_wait++; + + if (!gfx->f_run) + gfxdma_start_chain(gfx); + spin_unlock_bh(&gfx->spinlock); + + DBGLEAVE(3); +} + +/* Called by DMA core when the last transfer ended, or there is an error + * condition. We dispatch handling of the end of transfer case to a tasklet. + * Called in interrupt context. + */ +static void gfxdma_handler(int lch, u16 ch_status, void *data) +{ + struct gfx_dma *gfx = (struct gfx_dma *)data; + int done = 0; + + DBGENTER(3); + + DBGPRINT(4, "lch=%d status=%#010x\n", lch, ch_status); + if (unlikely(ch_status & (OMAP_DMA_TOUT_IRQ | OMAP_DMA_DROP_IRQ))) { + PRNERR("gfx DMA error. status=%#010x\n", ch_status); + done = 1; + } else if (likely(ch_status & OMAP_DMA_BLOCK_IRQ)) + done = 1; + if (likely(done)) { + gfx->done = 1; + tasklet_schedule(&gfx->dequeue_tasklet); + } + + DBGLEAVE(3); +} + +/* Let the DMA core know that the last transfer has ended. If there are + * pending transfers in the fifo start them now. + * Called in interrupt context. + */ +static void gfxdma_dequeue_tasklet(unsigned long data) +{ + struct gfx_dma *gfx = (struct gfx_dma *)data; + struct gfx_lchannel *f_chain; + + DBGENTER(3); + + /* start an already programmed transfer + */ + while (likely(gfx->done)) { + gfx->done = 0; + spin_lock(&gfx->spinlock); + f_chain = gfx->f_head; + omap_stop_dma(f_chain->lch_num); + /* Would be better w/o a loop.. */ + while (gfx->f_run--) { + if (gfx->f_run) + omap_dma_unlink_lch(f_chain->lch_num, + f_chain->next->lch_num); + f_chain = f_chain->next; + up(&gfx->f_free); + } + gfx->f_run = 0; + gfx->f_head = f_chain; + if (likely(gfx->f_wait)) + gfxdma_start_chain(gfx); + else + complete(&gfx->sync_complete); + spin_unlock(&gfx->spinlock); + } + + DBGLEAVE(3); +} + +/* Wait till any pending transfers end. */ +static void gfxdma_sync(struct gfx_dma *gfx) +{ + int wait = 0; + + DBGENTER(1); + + for (;;) { + spin_lock_bh(&gfx->spinlock); + if (gfx->f_run + gfx->f_wait) { + wait = 1; + init_completion(&gfx->sync_complete); + } + spin_unlock_bh(&gfx->spinlock); + if (wait) { + wait_for_completion(&gfx->sync_complete); + wait = 0; + } else + break; + } + + DBGLEAVE(1); +} + +/* Initialize the gfx DMA object. + * Allocate DMA logical channels according to the fifo size. + * Set the channel parameters that will be the same for all transfers. + */ +static int gfxdma_init(struct gfx_dma *gfx) +{ + int r = 0; + int i; + + DBGENTER(1); + + for (i = 0; i < GFX_FIFO_SIZE; i++) { + int next_idx; + int lch_num; + + r = omap_request_dma(0, OMAPFB_DRIVER, + gfxdma_handler, gfx, &lch_num); + if (r) { + int j; + + PRNERR("unable to get GFX DMA %d\n", i); + for (j = 0; j < i; j++) + omap_free_dma(lch_num); + r = -1; + goto exit; + } + omap_set_dma_src_data_pack(lch_num, 1); + omap_set_dma_src_burst_mode(lch_num, OMAP_DMA_DATA_BURST_4); + omap_set_dma_dest_data_pack(lch_num, 1); + omap_set_dma_dest_burst_mode(lch_num, OMAP_DMA_DATA_BURST_4); + + gfx->fifo[i].lch_num = lch_num; + + next_idx = i < GFX_FIFO_SIZE - 1 ? i + 1 : 0; + gfx->fifo[next_idx].prev = &gfx->fifo[i]; + gfx->fifo[i].next = &gfx->fifo[next_idx]; + } + gfx->f_head = gfx->f_tail = gfx->f_chain_end = &gfx->fifo[0]; + sema_init(&gfx->f_free, GFX_FIFO_SIZE); + + spin_lock_init(&gfx->spinlock); + + tasklet_init(&gfx->dequeue_tasklet, gfxdma_dequeue_tasklet, + (unsigned long)gfx); + + init_completion(&gfx->sync_complete); +exit: + DBGLEAVE(1); + return r; +} + +/* Clean up the gfx DMA object */ +static void gfxdma_cleanup(struct gfx_dma *gfx) +{ + int i; + + DBGENTER(1); + + for (i = 0; i < GFX_FIFO_SIZE; i++) + omap_free_dma(gfx->fifo[i].lch_num); + + DBGLEAVE(1); +} + +/* + * --------------------------------------------------------------------------- + * LCD controller and LCD DMA + * --------------------------------------------------------------------------- + */ +/* Lookup table to map elem size to elem type. */ +static const int dma_elem_type[] = { + 0, + OMAP_DMA_DATA_TYPE_S8, + OMAP_DMA_DATA_TYPE_S16, + 0, + OMAP_DMA_DATA_TYPE_S32, +}; + +/* Allocate resources needed for LCD controller and LCD DMA operations. Video + * memory is allocated from system memory according to the virtual display + * size, except if a bigger memory size is specified explicitly as a kernel + * parameter. + */ +static int ctrl_init(struct omapfb_device *fbdev) +{ + unsigned long mem_size; + int r; + + DBGENTER(1); + + r = fbdev->ctrl->init(fbdev); + if (r < 0) + goto exit; + fbdev->ctrl->get_mem_layout(fbdev, &mem_size, &fbdev->frame0_org); + + if (def_vram) { + if (mem_size > def_vram) { + PRNERR("specified frame buffer memory too small\n"); + r = -ENOMEM; + goto cleanup_ctrl; + } + mem_size = def_vram; + } + fbdev->lcddma_mem_size = PAGE_SIZE << get_order(mem_size); + fbdev->lcddma_base = dma_alloc_writecombine(fbdev->dev, + fbdev->lcddma_mem_size, + &fbdev->lcddma_handle, + GFP_KERNEL); + if (fbdev->lcddma_base == NULL) { + PRNERR("unable to allocate fb DMA memory\n"); + r = -ENOMEM; + goto cleanup_ctrl; + } + + memset(fbdev->lcddma_base, 0, fbdev->lcddma_mem_size); + + DBGPRINT(1, "lcddma_base=%#10x lcddma_handle=%#10x lcddma_mem_size=%d" + "palette_size=%d frame0_org=%d palette_org=%d\n", + fbdev->lcddma_base, fbdev->lcddma_handle, + fbdev->lcddma_mem_size, + fbdev->palette_size, + fbdev->frame0_org, fbdev->palette_org); + + DBGLEAVE(1); + return 0; +cleanup_ctrl: + fbdev->ctrl->cleanup(fbdev); +exit: + DBGLEAVE(1); + return r; +} + +static void ctrl_cleanup(struct omapfb_device *fbdev) +{ + fbdev->ctrl->cleanup(fbdev); + dma_free_writecombine(fbdev->dev, fbdev->lcddma_mem_size, + fbdev->lcddma_base, fbdev->lcddma_handle); +} + +static void ctrl_change_mode(struct omapfb_device *fbdev) +{ + fbdev->ctrl->change_mode(fbdev); +} + +/* + * --------------------------------------------------------------------------- + * fbdev framework callbacks and the ioctl interface + * --------------------------------------------------------------------------- + */ +/* Called each time the omapfb device is opened */ +static int omapfb_open(struct fb_info *info, int user) +{ + DBGENTER(1); + +#ifdef OMAPFB_DBG_FIFO + memset(&stat, 0, sizeof(stat)); +#endif + + DBGLEAVE(1); + return 0; +} + +/* Called when the omapfb device is closed. We make sure that any pending + * gfx DMA operations are ended, before we return. */ +static int omapfb_release(struct fb_info *info, int user) +{ + struct omapfb_device *dev = (struct omapfb_device *)info->par; + int sync = 0; + + DBGENTER(1); + + spin_lock_bh(&dev->gfx.spinlock); + if (dev->gfx.f_run) + sync = 1; + spin_unlock_bh(&dev->gfx.spinlock); + if (sync) { + gfxdma_sync(&dev->gfx); + } +#ifdef OMAPFB_DBG_FIFO + { + int i; + for (i = 0; i < GFX_FIFO_SIZE; i++) + printk(KERN_INFO "f_run[%d]=%lu\n", i + 1, + stat.f_run[i]); + } +#endif + + DBGLEAVE(1); + return 0; +} + +/* Store a single color palette entry into a pseudo palette or the hardware + * palette if one is available. For now we support only 16bpp and thus store + * the entry only to the pseudo palette. + */ +static int omapfb_setcolreg(u_int regno, u_int red, u_int green, + u_int blue, u_int transp, + struct fb_info *info) +{ + u16 pal; + int r = 0; + + DBGENTER(2); + + if (regno >= 16) { + r = -1; + goto exit; + } + pal = ((red >> 11) << 11) | ((green >> 10) << 5) | (blue >> 11); + ((u32 *)(info->pseudo_palette))[regno] = pal; + +exit: + DBGLEAVE(2); + return r; +} + +static int omapfb_suspend(struct device *dev, u32 state, u32 level); +static int omapfb_resume(struct device *dev, u32 level); + +static int omapfb_blank(int blank, struct fb_info *info) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)info->par; + int r = 0; + + DBGENTER(1); + switch (blank) { + case VESA_NO_BLANKING: + omapfb_resume(fbdev->dev, 0); + break; + case VESA_POWERDOWN: + omapfb_suspend(fbdev->dev, 0, 0); + break; + default: + r = -EINVAL; + } + + DBGLEAVE(1); + return r; +} + +/* Setup a constant fill DMA transfer. Destination must be elem size aligned. */ +static inline void fill_block(struct omapfb_device *fbdev, + unsigned long dst, unsigned long enumber, + unsigned long height, int esize, u32 color) +{ + unsigned long fidx; + int lch; + + DBGPRINT(2, "dst:%#010x enumber:%d height:%d esize:%d color:%#010x\n", + dst, enumber, height, esize, color); + fidx = fbdev->fb_info->fix.line_length - enumber * esize + 1; + gfxdma_get_lch(&fbdev->gfx, &lch); + gfxdma_set_lch_params(lch, dma_elem_type[esize], enumber, height, + 0, OMAP_DMA_AMODE_CONSTANT, + dst, OMAP_DMA_AMODE_DOUBLE_IDX); + gfxdma_set_lch_index(lch, 0, 0, 1, fidx); + gfxdma_set_lch_color(lch, color, OMAP_DMA_CONSTANT_FILL); + gfxdma_enqueue(&fbdev->gfx, lch); + + DUMP_DMA_REGS(lch); +} + +/* Fill the specified rectangle with a solid color. + * ROP_XOR and bpp<8 is passed to the unaccelerated function as these cases + * can't be handled by the DMA hardware. + * When frame flipping is in effect use the destination frame. + * We'll make our best to use the largest possible elem size, doing the fill + * in more parts if alignment requires us to do so. + */ +static void omapfb_fillrect(struct fb_info *fbi, + const struct fb_fillrect *rect) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par; + + int dx = rect->dx, dy = rect->dy; + int vxres = fbi->var.xres_virtual; + int vyres = fbi->var.yres_virtual; + int width = rect->width, height = rect->height; + unsigned long dst; + u32 color; + int bpp; + int enumber, esize; + + DBGENTER(2); + + bpp = fbi->var.bits_per_pixel; + /* bpp < 8 is tbd. + * We can't do ROP_XOR with DMA + * If IRQs are disabled we can't use DMA + */ + if (rect->rop == ROP_XOR || irqs_disabled()) { + cfb_fillrect(fbi, rect); + return; + } + /* Clipping */ + if (!width || !height || dx > vxres || dy > vyres) + return; + if (dx + width > vxres) + width = vxres - dx; + if (dy + height > vyres) + height = vyres - dy; + + if (bpp == 12) + bpp = 16; + width = width * bpp / 8; + + dst = fbdev->lcddma_handle + fbdev->dst_frame_org; + dst += dx * bpp / 8 + dy * fbi->fix.line_length; + + if (fbi->fix.visual == FB_VISUAL_TRUECOLOR || + fbi->fix.visual == FB_VISUAL_DIRECTCOLOR ) + color = ((u32 *) (fbi->pseudo_palette))[rect->color]; + else + color = rect->color; + switch (bpp) { + case 8: + color |= color << 8; + /* Fall through */ + case 16: + color |= color << 16; + } + + if ((dst & 3) || width < 4) { + if (!(dst & 1) && width > 1) { + esize = 2; + enumber = 1; + width -= 2; + } else { + esize = 1; + enumber = 4 - (esize & 3); + if (enumber > width) + enumber = width; + width -= enumber; + } + fill_block(fbdev, dst, enumber, height, esize, color); + dst = (dst + 3) & ~3; + } + if (width) { + enumber = width / 4; + fill_block(fbdev, dst, enumber, height, 4, color); + dst += enumber * 4; + width -= enumber * 4; + } + if (width) { + if (width == 2) { + esize = 2; + enumber = 1; + } else { + esize = 1; + enumber = width; + } + fill_block(fbdev, dst, enumber, height, esize, color); + } + + DBGLEAVE(2); + return; +} + +/* Setup a gfx DMA transfer to a rectangular area. + * A color parameter can be specified for transparent copy. + * Transfer direction can be setup to use either incremental or decremental + * addresses. + * Source and destination must be elem size aligned. + */ +static inline void transfer_block(struct omapfb_device *fbdev, + unsigned long src, unsigned long dst, + unsigned long img_width, + unsigned long enumber, unsigned long height, + int esize, u32 bg_color, int flags) +{ + s16 eidx; + s16 s_fidx, d_fidx; + int lch; + + eidx = 1; + s_fidx = img_width - enumber * esize + 1; + d_fidx = fbdev->fb_info->fix.line_length - enumber * esize + 1; + if (flags & COPY_MODE_REV_DIR) { + eidx = -2 * esize + 1; + s_fidx = -s_fidx + eidx + 1; + d_fidx = -d_fidx + eidx + 1; + } + + DBGPRINT(2, "src:%#010x dst:%#010x enumber:%d height:%d " + "esize:%d eidx:%d s_fidx:%d d_fidx bg_color:%#010x flags:%d\n", + src, dst, enumber, height, esize, eidx, s_fidx, d_fidx, + bg_color, flags); + + gfxdma_get_lch(&fbdev->gfx, &lch); + gfxdma_set_lch_params(lch, dma_elem_type[esize], enumber, height, + src, OMAP_DMA_AMODE_DOUBLE_IDX, + dst, OMAP_DMA_AMODE_DOUBLE_IDX); + gfxdma_set_lch_index(lch, eidx, s_fidx, eidx, d_fidx); + if (flags & COPY_MODE_TRANSPARENT) + gfxdma_set_lch_color(lch, bg_color, OMAP_DMA_TRANSPARENT_COPY); + else + gfxdma_set_lch_color(lch, 0, OMAP_DMA_COLOR_DIS); + gfxdma_enqueue(&fbdev->gfx, lch); + + DUMP_DMA_REGS(lch); +} + +/* Copy a rectangular area or an image to another rectangular area. + * A color parameter can be specified for transparent copy. + * Transfer direction can be setup to use either incremental or decremental + * addresses. + * Currently both source and destination area must be entirely contained in + * frame buffer memory. + * The largest possible transfer elem size will be determined according to + * source and destination address alignment, dividing the transfer into more + * parts if necessary. + */ +static inline void copy_data(struct omapfb_device *fbdev, + unsigned long src, unsigned long dst, + unsigned long width, unsigned long height, + u32 bg_color, int flags) +{ + struct fb_info *fbi = fbdev->fb_info; + int esize, stripe_esize; + int step, rest, enumber; + unsigned long img_width; + static const int esize_arr[] = {4, 1, 2, 1}; + int rev; + + /* Check alignment constraints */ + esize = esize_arr[(src ^ dst) & 3]; + + rev = flags & COPY_MODE_REV_DIR; + if (rev) { + rest = src & (esize - 1); + if (rest > width) + rest = width; + src -= rest ? rest : esize; + dst -= rest ? rest : esize; + } else { + rest = esize - (src & (esize - 1)); + if (rest > width) + rest = width; + } + if (width < esize) + rest = width; + + img_width = flags & COPY_MODE_IMAGE ? width : fbi->fix.line_length; + + DBGPRINT(2, "\nrev=%d src=%#010lx dst=%#010lx \n" + "esize=%d width=%d rest=%d\n", + rev, src, dst, esize, width, rest); + if (rest) { + /* Transfer this unaligned stripe, so that afterwards + * we have both src and dst 16bit or 32bit aligned. + */ + if (rest == 2) { + /* Area body is 32bit aligned */ + stripe_esize = 2; + enumber = 1; + step = rev ? -esize : 2; + width -= 2; + } else { + stripe_esize = 1; + enumber = rest; + step = rev ? -esize : rest; + } + transfer_block(fbdev, src, dst, img_width, enumber, height, + stripe_esize, bg_color, flags); + src += step; + dst += step; + } + if (width) { + /* Transfer area body */ + enumber = (width & ~(esize - 1)) / esize; + transfer_block(fbdev, src, dst, img_width, enumber, height, + esize, bg_color, flags); + step = enumber * esize; + width -= step; + if (rev) + step = -step + esize - width; + src += step; + dst += step; + } + if (width) { + /* Transfer the remaining unaligned stripe */ + if (width == 2) { + stripe_esize = 2; + enumber = 1; + } else { + stripe_esize = 1; + enumber = width; + } + transfer_block(fbdev, src, dst, img_width, enumber, height, + stripe_esize, bg_color, flags); + } + + DBGLEAVE(2); +} + +/* Copy a rectangular area in the frame buffer to another rectangular area. + * Calculate the source and destination addresses. + * Transfer direction will be determined taking care of possible area + * overlapping. + * Currently both source and destination area must be entirely contained in + * frame buffer memory, in case of frame flipping source and destination frame + * respectively. + */ +static void omapfb_copyarea(struct fb_info *fbi, + const struct fb_copyarea *area) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par; + + int width = area->width, height = area->height; + int sx = area->sx, sy = area->sy; + int dx = area->dx, dy = area->dy; + unsigned long dst, dst_ofs, src, src_ofs; + unsigned long end_ofs; + int bpp = fbi->var.bits_per_pixel; + int flags; + + DBGENTER(2); + + if (!width || !height) + goto exit; + + /* If IRQs are disabled we can't use DMA */ + if (irqs_disabled()) { + cfb_copyarea(fbi, area); + goto exit; + } + + src = fbdev->lcddma_handle; + dst = src; + src_ofs = fbdev->src_frame_org + sx * bpp / 8 + + sy * fbi->fix.line_length; + dst_ofs = fbdev->dst_frame_org + dx * bpp / 8 + + dy * fbi->fix.line_length; + end_ofs = (height - 1) * fbi->fix.line_length + width * bpp / 8; + src += src_ofs; + dst += dst_ofs; + + DBGPRINT(2, "src:%#010lx dst:%#010lx end_ofs:%#010lx\n", + src, dst, end_ofs); + + /* Currently we support only transfers where both source and destination + * area is contained entirely in fbmem. This is because of DMA memory + * constraints. + */ + if (src_ofs + end_ofs > fbdev->lcddma_mem_size || + dst_ofs + end_ofs > fbdev->lcddma_mem_size) + goto exit; + + flags = 0; + if ((dy == sy && dx > sx) || (dy > sy)) { + flags = COPY_MODE_REV_DIR; + src += end_ofs; + dst += end_ofs; + } + + width = width * bpp / 8; + copy_data(fbdev, src, dst, width, height, 0, flags); +exit: + DBGLEAVE(2); +} + +/* Copy an image to a rectangular area in the frame buffer. + * A color parameter can be specified for transparent copy. + * Calculate the source and destination addresses. + * Transfer direction will be determined taking care of possible area + * overlapping. + * Currently both source and destination area must be entirely contained in + * frame buffer memory, in case of frame flipping source and destination frame + * respectively. + */ +static void do_imageblit(struct fb_info *fbi, const struct fb_image *image, + int flags) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par; + + int width = image->width, height = image->height; + int dx = image->dx, dy = image->dy; + unsigned long dst, dst_ofs; + unsigned long dst_end_ofs; + int bpp = fbi->var.bits_per_pixel; + u32 bg_color; + + DBGENTER(2); + + if (!width || !height) + goto exit; + + /* bpp conversion is not supported, let the default function handle it. + * Note that image->depth is either 1 for monochrome image, or equals + * bpp of the current video mode, so we can't rely on it. + * If IRQs are disabled we can't use DMA. + */ + if (image->depth != bpp || irqs_disabled()) { + if (!(flags & COPY_MODE_TRANSPARENT)) + cfb_imageblit(fbi, image); + goto exit; + } + + dst = fbdev->lcddma_handle; + dst_ofs = fbdev->dst_frame_org + + dx * bpp / 8 + dy * fbi->fix.line_length; + dst_end_ofs = (height - 1) * fbi->fix.line_length + width * bpp / 8; + dst += dst_ofs; + + DBGPRINT(2, "data:%#010lx dst:%#010lx dst_end_ofs:%#010lx\n", + image->data, dst, dst_end_ofs); + + /* Check that both source and destination is DMA -able */ + if (dst_ofs + dst_end_ofs > fbdev->lcddma_mem_size) + goto exit; + + if (((unsigned long)image->data < (unsigned long)fbdev->lcddma_base) || + ((unsigned long)image->data + width * bpp / 8 * height > + (unsigned long)fbdev->lcddma_base + fbdev->lcddma_mem_size)) { + if (!(flags & COPY_MODE_TRANSPARENT)) + cfb_imageblit(fbi, image); + goto exit; + } + + bg_color = image->bg_color; + if (flags & COPY_MODE_TRANSPARENT) { + switch (bpp) { + case 8: + bg_color |= bg_color << 8; + /* Fall through */ + case 16: + bg_color |= bg_color << 16; + } + } + + width = width * bpp / 8; + flags |= COPY_MODE_IMAGE; + copy_data(fbdev, (unsigned long)image->data, dst, width, height, + bg_color, flags); +exit: + DBGLEAVE(2); +} + +/* Normal image blit */ +static void omapfb_imageblit(struct fb_info *fbi, const struct fb_image *image) +{ + do_imageblit(fbi, image, 0); +} + +/* Transparent image blit, using image->bg_color as the color key */ +static void omapfb_transparent_blit(struct fb_info *fbi, + const struct fb_image *image) +{ + do_imageblit(fbi, image, COPY_MODE_TRANSPARENT); +} + +/* Set fb_info.fix fields and also updates fbdev. + * When calling this fb_info.var must be set up already. + */ +static void set_fb_fix(struct omapfb_device *fbdev) +{ + struct fb_info *fbi = fbdev->fb_info; + struct fb_fix_screeninfo *fix = &fbi->fix; + struct fb_var_screeninfo *var = &fbi->var; + struct fb_ops *fbops = fbi->fbops; + int frame_size; + + strncpy(fix->id, OMAPFB_DRIVER, sizeof(fix->id)); + fix->type = FB_TYPE_PACKED_PIXELS; + switch (var->bits_per_pixel) { + case 16: + fix->visual = FB_VISUAL_TRUECOLOR; + break; + case 1: + case 2: + case 4: + case 8: + fix->visual = FB_VISUAL_PSEUDOCOLOR; + break; + } + fix->accel = FB_ACCEL_OMAP1610; + fix->line_length = var->xres_virtual * var->bits_per_pixel / 8; + fix->smem_len = fbdev->lcddma_mem_size - fbdev->frame0_org; + fix->smem_start = fbdev->lcddma_handle + fbdev->frame0_org; + + if (var->accel_flags == FB_ACCELF_TEXT && var->bits_per_pixel >= 8) { + fbops->fb_fillrect = omapfb_fillrect; + fbops->fb_copyarea = omapfb_copyarea; + fbops->fb_imageblit = omapfb_imageblit; + } else { + fbops->fb_fillrect = cfb_fillrect; + fbops->fb_copyarea = cfb_copyarea; + fbops->fb_imageblit = cfb_imageblit; + } + + /* Set the second frame buffer offset for flipping if there is + * room for it. */ + frame_size = fix->line_length * var->yres; + fbdev->frame1_org = fbdev->frame0_org + frame_size; + if (fbdev->frame1_org + frame_size > fbdev->lcddma_mem_size) + fbdev->frame1_org = 0; + fbdev->vis_frame_org = fbdev->src_frame_org = fbdev->dst_frame_org = + fbdev->frame0_org; + + fbdev->view_org = var->yoffset * fix->line_length + + var->xoffset * var->bits_per_pixel / 8; +} + +/* Check the values in var against our capabilities and in case of out of + * bound values try to adjust them. + */ +static int set_fb_var(struct omapfb_device *fbdev, + struct fb_var_screeninfo *var) +{ + int bpp; + unsigned long max_frame_size; + unsigned long line_size; + + bpp = var->bits_per_pixel = fbdev->panel->video_mode->bpp; + if (bpp != 16) + /* Not yet supported */ + return -1; + switch (var->rotate) { + case 0: + case 180: + var->xres = fbdev->panel->video_mode->x_res; + var->yres = fbdev->panel->video_mode->y_res; + break; + case 90: + case 270: + var->xres = fbdev->panel->video_mode->y_res; + var->yres = fbdev->panel->video_mode->x_res; + break; + default: + return -1; + } + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + max_frame_size = fbdev->lcddma_mem_size - fbdev->frame0_org; + line_size = var->xres_virtual * bpp / 8; + if (line_size * var->yres_virtual > max_frame_size) { + /* Try to keep yres_virtual first */ + line_size = max_frame_size / var->yres_virtual; + var->xres_virtual = line_size * 8 / bpp; + if (var->xres_virtual < var->xres) { + /* Still doesn't fit. Shrink yres_virtual too */ + var->xres_virtual = var->xres; + line_size = var->xres * bpp / 8; + var->yres_virtual = max_frame_size / line_size; + } + } + if (var->xres + var->xoffset > var->xres_virtual) + var->xoffset = var->xres_virtual - var->xres; + if (var->yres + var->yoffset > var->yres_virtual) + var->yoffset = var->yres_virtual - var->yres; + line_size = var->xres * bpp / 8; + + var->red.offset = 11; var->red.length = 5; var->red.msb_right = 0; + var->green.offset= 5; var->green.length = 6; var->green.msb_right = 0; + var->blue.offset = 0; var->blue.length = 5; var->blue.msb_right = 0; + + var->height = -1; + var->width = -1; + var->grayscale = 0; + var->nonstd = 0; + + /* TODO: video timing params, sync */ + var->pixclock = -1; + var->left_margin = -1; + var->right_margin = -1; + var->upper_margin = -1; + var->lower_margin = -1; + var->hsync_len = -1; + var->vsync_len = -1; + + var->vmode = FB_VMODE_NONINTERLACED; + var->sync = 0; + + return 0; +} + +static struct fb_var_screeninfo new_var; + +/* Set rotation (0, 90, 180, 270 degree), and switch to the new mode. */ +static void omapfb_rotate(struct fb_info *fbi, int rotate) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par; + + DBGENTER(1); + + if (cpu_is_omap1510() && rotate != fbdev->fb_info->var.rotate) { + memcpy(&new_var, &fbi->var, sizeof(new_var)); + new_var.rotate = rotate; + if (set_fb_var(fbdev, &new_var) == 0 && + memcmp(&new_var, &fbi->var, sizeof(new_var))) { + memcpy(&fbi->var, &new_var, sizeof(new_var)); + set_fb_fix(fbdev); + ctrl_change_mode(fbdev); + } + } + + DBGLEAVE(1); +} + +/* Set new x,y offsets in the virtual display for the visible area and switch + * to the new mode. + */ +static int omapfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *fbi) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par; + int r = 0; + + DBGENTER(1); + + if (var->xoffset != fbi->var.xoffset || + var->yoffset != fbi->var.yoffset) { + memcpy(&new_var, &fbi->var, sizeof(new_var)); + new_var.xoffset = var->xoffset; + new_var.yoffset = var->yoffset; + if (set_fb_var(fbdev, &new_var)) + r = -EINVAL; + else { + memcpy(&fbi->var, &new_var, sizeof(new_var)); + set_fb_fix(fbdev); + ctrl_change_mode(fbdev); + } + } + + DBGLEAVE(1); + return r; +} + +/* Set mirror to vertical axis and switch to the new mode. */ +static int omapfb_mirror(struct fb_info *fbi, int mirror) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par; + int r = 0; + + DBGENTER(1); + + mirror = mirror ? 1 : 0; + if (cpu_is_omap1510()) + r = -EINVAL; + else if (mirror != fbdev->mirror) { + fbdev->mirror = mirror; + ctrl_change_mode(fbdev); + } + + DBGLEAVE(1); + return r; +} + +/* Set x,y scale and switch to the new mode */ +static int omapfb_scale(struct fb_info *fbi, + unsigned int xscale, unsigned int yscale) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par; + int r = 0; + + DBGENTER(1); + + if (cpu_is_omap1510()) + r = -EINVAL; + else if (xscale != fbdev->xscale || yscale != fbdev->yscale) { + if (fbi->var.xres * xscale > fbi->var.xres_virtual || + fbi->var.yres * yscale > fbi->var.yres_virtual) + r = -EINVAL; + else { + fbdev->xscale = xscale; + fbdev->yscale = yscale; + ctrl_change_mode(fbdev); + } + } + + DBGLEAVE(1); + return r; +} + +/* Check values in var, try to adjust them in case of out of bound values if + * possible, or return error. + */ +static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par; + int r; + + DBGENTER(1); + + r = set_fb_var(fbdev, var); + + DBGLEAVE(1); + return r; +} + +/* Switch to a new mode. The parameters for it has been check already by + * omapfb_check_var. + */ +static int omapfb_set_par(struct fb_info *fbi) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par; + + DBGENTER(1); + + set_fb_fix(fbdev); + ctrl_change_mode(fbdev); + + DBGLEAVE(1); + return 0; +} + +/* Frame flipping support. Assign the primary or the secondary frame to the + * visible frame, as well as the source and destination frames for graphics + * operations like rectangle fill and area copy. Flipping is only possible + * if we have enough video memory for the secondary frame. + */ +static int omapfb_select_vis_frame(struct fb_info *fbi, unsigned int vis_idx) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par; + + if (vis_idx > 1 || (vis_idx == 1 && !fbdev->frame1_org)) + return -EINVAL; + fbdev->vis_frame_org = vis_idx ? fbdev->frame1_org : fbdev->frame0_org; + ctrl_change_mode(fbdev); + return 0; +} + +static int omapfb_select_src_frame(struct fb_info *fbi, unsigned int src_idx) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par; + + if (src_idx > 1 || (src_idx == 1 && !fbdev->frame1_org)) + return -EINVAL; + fbdev->src_frame_org = src_idx ? fbdev->frame1_org : fbdev->frame0_org; + return 0; +} + +static int omapfb_select_dst_frame(struct fb_info *fbi, unsigned int dst_idx) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par; + + if (dst_idx > 1 || (dst_idx == 1 && !fbdev->frame1_org)) + return -EINVAL; + fbdev->dst_frame_org = dst_idx ? fbdev->frame1_org : fbdev->frame0_org; + DBGPRINT(1, "dst_frame_org=%#010x\n", fbdev->dst_frame_org); + return 0; +} + +/* Get the address of the primary and secondary frames */ +static int omapfb_get_frame_offset(struct fb_info *fbi, + struct fb_frame_offset *fb_offset) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par; + + if (fb_offset->idx > 1) + return -EINVAL; + if (fb_offset->idx == 1 && !fbdev->frame1_org) + return -EINVAL; + fb_offset->offset = fb_offset->idx ? fbdev->frame1_org : + fbdev->frame0_org; + return 0; +} + +static int omapfb_update_window(struct fb_info *fbi, + struct fb_update_window *win) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par; + + if (!fbdev->ctrl->update_window || + win->x >= fbi->var.xres || win->y >= fbi->var.yres) + return -EINVAL; + if (win->x + win->width >= fbi->var.xres) + win->width = fbi->var.xres - win->x; + if (win->y + win->height >= fbi->var.yres) + win->height = fbi->var.yres - win->y; + if (!win->width || !win->height) + return 0; + return fbdev->ctrl->update_window(fbdev, win); +} + +static unsigned long omapfb_get_caps(struct fb_info *fbi) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par; + unsigned long caps; + + caps = 0; + caps |= fbdev->panel->get_caps(fbdev->panel); + caps |= fbdev->ctrl->get_caps(fbdev); + return caps; +} + +static int omapfb_set_update_mode(struct omapfb_device *fbdev, + enum fb_update_mode new_mode); + +static enum fb_update_mode omapfb_get_update_mode(struct omapfb_device *fbdev); + +/* Ioctl interface. Part of the kernel mode frame buffer API is duplicated + * here to be accessible by user mode code. In addition transparent copy + * graphics transformations, frame flipping support is provided through this + * interface. + */ +static int omapfb_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, + struct fb_info *fbi) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)fbi->par; + struct fb_ops *ops = fbi->fbops; + union { + struct fb_fillrect rect; + struct fb_copyarea area; + struct fb_image image; + struct fb_scale scale; + struct fb_frame_offset frame_offset; + struct fb_update_window update_window; + unsigned int frame_idx; + unsigned int mirror; + enum fb_update_mode update_mode; + unsigned long caps; + } p; + int r = 0; + + DBGENTER(2); + + BUG_ON(!ops); + DBGPRINT(2, "cmd=%010x\n", cmd); + switch (cmd) + { + case OMAPFB_FILLRECT: + if (copy_from_user(&p.rect, (void *)arg, sizeof(p.rect))) + r = -EFAULT; + else + ops->fb_fillrect(fbi, &p.rect); + break; + case OMAPFB_COPYAREA: + if (copy_from_user(&p.area, (void *)arg, sizeof(p.area))) + r = -EFAULT; + else + ops->fb_copyarea(fbi, &p.area); + break; + case OMAPFB_IMAGEBLIT: + if (copy_from_user(&p.image, (void *)arg, sizeof(p.image))) + r = -EFAULT; + else + ops->fb_imageblit(fbi, &p.image); + break; + case OMAPFB_TRANSPARENT_BLIT: + if (copy_from_user(&p.image, (void *)arg, sizeof(p.image))) + r = -EFAULT; + else + omapfb_transparent_blit(fbi, &p.image); + break; + case OMAPFB_MIRROR: + if (get_user(p.mirror, (int *)arg)) + r = -EFAULT; + else + omapfb_mirror(fbi, p.mirror); + break; + case OMAPFB_SCALE: + if (copy_from_user(&p.scale, (void *)arg, sizeof(p.scale))) + r = -EFAULT; + else + r = omapfb_scale(fbi, p.scale.xscale, p.scale.yscale); + break; + case OMAPFB_SELECT_VIS_FRAME: + if (get_user(p.frame_idx, (int *)arg)) + r = -EFAULT; + else + r = omapfb_select_vis_frame(fbi, p.frame_idx); + break; + case OMAPFB_SELECT_SRC_FRAME: + if (get_user(p.frame_idx, (int *)arg)) + r = - EFAULT; + else + r = omapfb_select_src_frame(fbi, p.frame_idx); + break; + case OMAPFB_SELECT_DST_FRAME: + if (get_user(p.frame_idx, (int *)arg)) + r = -EFAULT; + else + r = omapfb_select_dst_frame(fbi, p.frame_idx); + break; + case OMAPFB_GET_FRAME_OFFSET: + if (copy_from_user(&p.frame_offset, (void *)arg, + sizeof(p.frame_offset))) + r = -EFAULT; + else { + r = omapfb_get_frame_offset(fbi, &p.frame_offset); + if (copy_to_user((void *)arg, &p.frame_offset, + sizeof(p.frame_offset))) + r = -EFAULT; + } + break; + case OMAPFB_SYNC_GFX: + gfxdma_sync(&fbdev->gfx); + break; + case OMAPFB_VSYNC: + break; + case OMAPFB_LATE_ACTIVATE: + printk(KERN_WARNING OMAPFB_DRIVER + ": LATE_ACTIVATE obsoleted by SET_UPDATE_MODE.\n"); +// r = -EINVAL; + break; + case OMAPFB_SET_UPDATE_MODE: + if (get_user(p.update_mode, (int *)arg)) + r = -EFAULT; + else + r = omapfb_set_update_mode(fbdev, p.update_mode); + break; + case OMAPFB_GET_UPDATE_MODE: + p.update_mode = omapfb_get_update_mode(fbdev); + if (put_user(p.update_mode, (enum fb_update_mode *)arg)) + r = -EFAULT; + break; + case OMAPFB_UPDATE_WINDOW: + if (copy_from_user(&p.update_window, (void *)arg, + sizeof(p.update_window))) + r = -EFAULT; + else + r = omapfb_update_window(fbi, &p.update_window); + break; + case OMAPFB_GET_CAPS: + p.caps = omapfb_get_caps(fbi); + if (put_user(p.caps, (unsigned long *)arg)) + r = -EFAULT; + break; + default: + r = -EINVAL; + } + + DBGLEAVE(2); + return r; +} + +/* Callback table for the frame buffer framework. Some of these pointers + * will be changed according to the current setting of fb_info->accel_flags. + */ +static struct fb_ops omapfb_ops = { + .owner = THIS_MODULE, + .fb_open = omapfb_open, + .fb_release = omapfb_release, + .fb_setcolreg = omapfb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, + .fb_blank = omapfb_blank, + .fb_ioctl = omapfb_ioctl, + .fb_check_var = omapfb_check_var, + .fb_set_par = omapfb_set_par, + .fb_rotate = omapfb_rotate, + .fb_pan_display = omapfb_pan_display, +}; + +/* + * --------------------------------------------------------------------------- + * Sysfs interface + * --------------------------------------------------------------------------- + */ +/* omapfbX sysfs entries */ +static ssize_t omapfb_show_caps_num(struct device *dev, char *buf) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; + + return snprintf(buf, PAGE_SIZE, "%#010lx\n", + omapfb_get_caps(fbdev->fb_info)); +} + +static ssize_t omapfb_show_caps_text(struct device *dev, char *buf) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; + int pos = 0; + int i; + unsigned long caps; + + caps = omapfb_get_caps(fbdev->fb_info); + for (i = 0; i < ARRAY_SIZE(omapfb_caps_table) && pos < PAGE_SIZE; i++) { + if (omapfb_caps_table[i].flag & caps) { + pos += snprintf(&buf[pos], PAGE_SIZE - pos, "%s\n", + omapfb_caps_table[i].name); + } + } + return min((int)PAGE_SIZE, pos); +} + +static DEVICE_ATTR(caps_num, 0444, omapfb_show_caps_num, NULL); +static DEVICE_ATTR(caps_text, 0444, omapfb_show_caps_text, NULL); + +/* panel sysfs entries */ +static ssize_t omapfb_show_panel_name(struct device *dev, char *buf) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; + + return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->panel->name); +} + +static ssize_t omapfb_show_bklight_level(struct device *dev, char *buf) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; + int r; + + if (fbdev->panel->get_bklight_level) { + r = snprintf(buf, PAGE_SIZE, "%d\n", + fbdev->panel->get_bklight_level(fbdev->panel)); + } else + r = -ENODEV; + return r; +} + +static ssize_t omapfb_store_bklight_level(struct device *dev, const char *buf, + size_t size) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; + int r; + + if (fbdev->panel->set_bklight_level) { + unsigned int level; + + if (sscanf(buf, "%10d", &level) == 1) { + r = fbdev->panel->set_bklight_level(fbdev->panel, + level); + } else + r = -EINVAL; + } else + r = -ENODEV; + return r ? r : size; +} + +static ssize_t omapfb_show_bklight_max(struct device *dev, char *buf) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; + int r; + + if (fbdev->panel->get_bklight_level) { + r = snprintf(buf, PAGE_SIZE, "%d\n", + fbdev->panel->get_bklight_max(fbdev->panel)); + } else + r = -ENODEV; + return r; +} + +static struct device_attribute dev_attr_panel_name = + __ATTR(name, 0444, omapfb_show_panel_name, NULL); +static DEVICE_ATTR(backlight_level, 0664, + omapfb_show_bklight_level, omapfb_store_bklight_level); +static DEVICE_ATTR(backlight_max, 0444, omapfb_show_bklight_max, NULL); + +static struct attribute *panel_attrs[] = { + &dev_attr_panel_name.attr, + &dev_attr_backlight_level.attr, + &dev_attr_backlight_max.attr, + NULL, +}; + +static struct attribute_group panel_attr_grp = { + .name = "panel", + .attrs = panel_attrs, +}; + +/* ctrl sysfs entries */ +static ssize_t omapfb_show_ctrl_name(struct device *dev, char *buf) +{ + struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data; + + return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->ctrl->name); +} + +static struct device_attribute dev_attr_ctrl_name = + __ATTR(name, 0444, omapfb_show_ctrl_name, NULL); + +static struct attribute *ctrl_attrs[] = { + &dev_attr_ctrl_name.attr, + NULL, +}; + +static struct attribute_group ctrl_attr_grp = { + .name = "ctrl", + .attrs = ctrl_attrs, +}; + +static int omapfb_register_sysfs(struct omapfb_device *fbdev) +{ + int r; + + if ((r = device_create_file(fbdev->dev, &dev_attr_caps_num))) + goto fail0; + + if ((r = device_create_file(fbdev->dev, &dev_attr_caps_text))) + goto fail1; + + if ((r = sysfs_create_group(&fbdev->dev->kobj, &panel_attr_grp))) + goto fail2; + + if ((r = sysfs_create_group(&fbdev->dev->kobj, &ctrl_attr_grp))) + goto fail3; + + return 0; +fail3: + sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp); +fail2: + device_remove_file(fbdev->dev, &dev_attr_caps_text); +fail1: + device_remove_file(fbdev->dev, &dev_attr_caps_num); +fail0: + PRNERR("unable to register sysfs interface\n"); + return r; +} + +static void omapfb_unregister_sysfs(struct omapfb_device *fbdev) +{ + sysfs_remove_group(&fbdev->dev->kobj, &ctrl_attr_grp); + sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp); + device_remove_file(fbdev->dev, &dev_attr_caps_num); + device_remove_file(fbdev->dev, &dev_attr_caps_text); +} + +/* + * --------------------------------------------------------------------------- + * LDM callbacks + * --------------------------------------------------------------------------- + */ +/* Initialize system fb_info object and set the default video mode. + * The frame buffer memory already allocated by lcddma_init + */ +static int fbinfo_init(struct omapfb_device *fbdev) +{ + struct fb_info *info = fbdev->fb_info; + struct fb_var_screeninfo *var = &info->var; + int r = 0; + + DBGENTER(1); + + BUG_ON(!fbdev->lcddma_base); + info->fbops = &omapfb_ops; + info->flags = FBINFO_FLAG_DEFAULT; + info->screen_base = (char *) fbdev->lcddma_base + fbdev->frame0_org; + info->pseudo_palette = fbdev->pseudo_palette; + + var->accel_flags = def_accel ? FB_ACCELF_TEXT : 0; + var->xres_virtual = def_vxres; + var->yres_virtual = def_vyres; + var->rotate = def_rotate; + + fbdev->mirror = def_mirror; + + set_fb_var(fbdev, var); + set_fb_fix(fbdev); + + r = fb_alloc_cmap(&info->cmap, 16, 0); + if (r != 0) + PRNERR("unable to allocate color map memory\n"); + + DBGLEAVE(1); + return r; +} + +/* Release the fb_info object */ +static void fbinfo_cleanup(struct omapfb_device *fbdev) +{ + DBGENTER(1); + + fb_dealloc_cmap(&fbdev->fb_info->cmap); + + DBGLEAVE(1); +} + +/* Free driver resources. Can be called to rollback an aborted initialization + * sequence. + */ +static void omapfb_free_resources(struct omapfb_device *fbdev, int state) +{ + switch (state) { + case OMAPFB_ACTIVE: + unregister_framebuffer(fbdev->fb_info); + case 8: + omapfb_unregister_sysfs(fbdev); + case 7: + omapfb_set_update_mode(fbdev, FB_UPDATE_DISABLED); + case 6: + fbdev->panel->disable(fbdev->panel); + case 5: + gfxdma_cleanup(&fbdev->gfx); + case 4: + fbinfo_cleanup(fbdev); + case 3: + ctrl_cleanup(fbdev); + case 2: + fbdev->panel->cleanup(fbdev->panel); + case 1: + dev_set_drvdata(fbdev->dev, NULL); + framebuffer_release(fbdev->fb_info); + case 0: + /* nothing to free */ + break; + default: + BUG(); + } +} + +static int omapfb_find_panel(struct omapfb_device *fbdev) +{ + const struct omap_lcd_config *cfg; + char name[17]; + int i; + + fbdev->panel = NULL; + cfg = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config); + if (cfg == NULL) { + const char *def_name = NULL; + + if (machine_is_omap_h2()) + def_name = "h2"; + if (machine_is_omap_h3()) + def_name = "h3"; + if (machine_is_omap_perseus2()) + def_name = "p2"; + if (machine_is_omap_osk()) + def_name = "osk"; + if (machine_is_omap_innovator() && cpu_is_omap1610()) + def_name = "inn1610"; + if (machine_is_omap_innovator() && cpu_is_omap1510()) + def_name = "inn1510"; + if (def_name == NULL) + return -1; + strncpy(name, def_name, sizeof(name) - 1); + } else + strncpy(name, cfg->panel_name, sizeof(name) - 1); + name[sizeof(name) - 1] = 0; + for (i = 0; i < ARRAY_SIZE(panels); i++) { + if (strcmp(panels[i]->name, name) == 0) { + fbdev->panel = panels[i]; + break; + } + } + if (fbdev->panel == NULL) + return -1; + return 0; +} + +static int omapfb_find_ctrl(struct omapfb_device *fbdev) +{ + const struct omap_lcd_config *cfg; + char name[17]; + int i; + + fbdev->ctrl = NULL; + cfg = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config); + if (cfg == NULL) { + strcpy(name, "internal"); + } else + strncpy(name, cfg->ctrl_name, sizeof(name) - 1); + name[sizeof(name) - 1] = 0; + for (i = 0; i < ARRAY_SIZE(ctrls); i++) { + if (strcmp(ctrls[i]->name, name) == 0) { + fbdev->ctrl = ctrls[i]; + break; + } + } + if (fbdev->ctrl == NULL) + return -1; + return 0; +} + +static void check_required_callbacks(struct omapfb_device *fbdev) +{ +#define _C(x) (fbdev->ctrl->x) +#define _P(x) (fbdev->panel->x) + BUG_ON(!(_C(init) && _C(cleanup) && _C(get_caps) && + _C(get_mem_layout) && _C(set_update_mode) && _C(change_mode) && + _P(init) && _P(cleanup) && _P(enable) && _P(disable) && + _P(get_caps))); +#undef _P +#undef _C +} + +static int omapfb_set_update_mode(struct omapfb_device *fbdev, + enum fb_update_mode mode) +{ + return fbdev->ctrl->set_update_mode(fbdev, mode); +} + +static enum fb_update_mode omapfb_get_update_mode(struct omapfb_device *fbdev) +{ + return fbdev->ctrl->get_update_mode(fbdev); +} + +/* Called by LDM binding to probe and attach a new device. + * Initialization sequence: + * 1. allocate system fb_info structure + * select panel type according to machine type + * 2. init LCD panel + * 3. init LCD controller and LCD DMA + * 4. init system fb_info structure + * 5. init gfx DMA + * 6. enable LCD panel + * start LCD frame transfer + * 7. register system fb_info structure + */ +static int omapfb_probe(struct device *dev) +{ + struct platform_device *pdev; + struct omapfb_device *fbdev = NULL; + struct fb_info *fbi; + int init_state; + int r = 0; + + DBGENTER(1); + + init_state = 0; + + pdev = to_platform_device(dev); + if (pdev->num_resources != 0) { + PRNERR("probed for an unknown device\n"); + r = -ENODEV; + goto cleanup; + } + + fbi = framebuffer_alloc(sizeof(struct omapfb_device), dev); + if (!fbi) { + PRNERR("unable to allocate memory for device info\n"); + r = -ENOMEM; + goto cleanup; + } + + fbdev = (struct omapfb_device *)fbi->par; + fbdev->fb_info = fbi; + fbdev->dev = dev; + dev_set_drvdata(dev, fbdev); + + init_state++; + if (omapfb_find_ctrl(fbdev) < 0) { + PRNERR("LCD controller not found, board not supported\n"); + r = -ENODEV; + goto cleanup; + } + if (omapfb_find_panel(fbdev) < 0) { + PRNERR("LCD panel not found, board not supported\n"); + r = -ENODEV; + goto cleanup; + } + + check_required_callbacks(fbdev); + + printk(KERN_INFO OMAPFB_DRIVER ": configured for panel %s\n", + fbdev->panel->name); + + r = fbdev->panel->init(fbdev->panel); + if (r) + goto cleanup; + init_state++; + + r = ctrl_init(fbdev); + if (r) + goto cleanup; + init_state++; + + r = fbinfo_init(fbdev); + if (r) + goto cleanup; + init_state++; + + r = gfxdma_init(&fbdev->gfx); + if (r) + goto cleanup; + init_state++; + +#ifdef CONFIG_FB_OMAP_DMA_TUNE + /* Set DMA priority for EMIFF access to highest */ + omap_set_dma_priority(OMAP_DMA_PORT_EMIFF, 15); +#endif + + r = fbdev->panel->enable(fbdev->panel); + if (r) + goto cleanup; + init_state++; + + r = omapfb_set_update_mode(fbdev, manual_update ? + FB_MANUAL_UPDATE : FB_AUTO_UPDATE); + if (r) + goto cleanup; + init_state++; + + r = omapfb_register_sysfs(fbdev); + if (r) + goto cleanup; + init_state++; + + r = register_framebuffer(fbdev->fb_info); + if (r != 0) { + PRNERR("register_framebuffer failed\n"); + goto cleanup; + } + + fbdev->state = OMAPFB_ACTIVE; + + printk(KERN_INFO "OMAP framebuffer initialized vram=%lu\n", + fbdev->lcddma_mem_size); + + DBGLEAVE(1); + return 0; + +cleanup: + omapfb_free_resources(fbdev, init_state); + + DBGLEAVE(1); + return r; +} + +/* Called when the device is being detached from the driver */ +static int omapfb_remove(struct device *dev) +{ + struct omapfb_device *fbdev = dev_get_drvdata(dev); + enum omapfb_state saved_state = fbdev->state; + + DBGENTER(1); + /* FIXME: wait till completion of pending events */ + + fbdev->state = OMAPFB_DISABLED; + omapfb_free_resources(fbdev, saved_state); + + DBGLEAVE(1); + return 0; +} + +/* PM suspend */ +static int omapfb_suspend(struct device *dev, u32 state, u32 level) +{ + struct omapfb_device *fbdev = dev_get_drvdata(dev); + + DBGENTER(1); + + if (fbdev->state == OMAPFB_ACTIVE) { + if (fbdev->ctrl->suspend) + fbdev->ctrl->suspend(fbdev); + fbdev->panel->disable(fbdev->panel); + fbdev->state = OMAPFB_SUSPENDED; + } + + DBGLEAVE(1); + return 0; +} + +/* PM resume */ +static int omapfb_resume(struct device *dev, u32 level) +{ + struct omapfb_device *fbdev = dev_get_drvdata(dev); + + DBGENTER(1); + + if (fbdev->state == OMAPFB_SUSPENDED) { + fbdev->panel->enable(fbdev->panel); + if (fbdev->ctrl->resume) + fbdev->ctrl->resume(fbdev); + fbdev->state = OMAPFB_ACTIVE; + } + + DBGLEAVE(1); + return 0; +} + +static void omapfb_release_dev(struct device *dev) +{ + DBGENTER(1); + DBGLEAVE(1); +} + +static u64 omapfb_dmamask = ~(u32)0; + +static struct platform_device omapfb_device = { + .name = OMAPFB_DEVICE, + .id = 0, + .dev = { + .release = omapfb_release_dev, + .dma_mask = &omapfb_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = 0, +}; + +static struct device_driver omapfb_driver = { + .name = OMAPFB_DRIVER, + .bus = &platform_bus_type, + .probe = omapfb_probe, + .remove = omapfb_remove, + .suspend = omapfb_suspend, + .resume = omapfb_resume +}; + +#ifndef MODULE + +/* Process kernel command line parameters */ +int __init omapfb_setup(char *options) +{ + char *this_opt = NULL; + int r = 0; + + DBGENTER(1); + + if (!options || !*options) + goto exit; + + while (!r && (this_opt = strsep(&options, ",")) != NULL) { + if (!strncmp(this_opt, "accel", 5)) + def_accel = 1; + else if (!strncmp(this_opt, "vram:", 5)) { + char *suffix; + def_vram = (simple_strtoul(this_opt + 5, &suffix, 0)); + switch (suffix[0]) { + case 'm': + case 'M': + def_vram *= 1024 * 1024; + break; + case 'k': + case 'K': + def_vram *= 1024; + break; + default: + PRNERR("invalid vram suffix\n"); + r = -1; + } + } + else if (!strncmp(this_opt, "vxres:", 6)) + def_vxres = simple_strtoul(this_opt + 6, NULL, 0); + else if (!strncmp(this_opt, "vyres:", 6)) + def_vyres = simple_strtoul(this_opt + 6, NULL, 0); + else if (!strncmp(this_opt, "rotate:", 7)) + def_rotate = (simple_strtoul(this_opt + 7, NULL, 0)); + else if (!strncmp(this_opt, "mirror:", 7)) + def_mirror = (simple_strtoul(this_opt + 7, NULL, 0)); + else if (!strncmp(this_opt, "manual_update", 13)) + manual_update = 1; + else { + PRNERR("invalid option\n"); + r = -1; + } + } +exit: + DBGLEAVE(1); + return r; +} + +#endif + +/* Register both the driver and the device */ +int __init omapfb_init(void) +{ + int r = 0; + + DBGENTER(1); + +#ifndef MODULE + { + char *option; + + if (fb_get_options("omapfb", &option)) { + r = -ENODEV; + goto exit; + } + omapfb_setup(option); + } +#endif + /* Register the device with LDM */ + if (platform_device_register(&omapfb_device)) { + PRNERR("failed to register omapfb device\n"); + r = -ENODEV; + goto exit; + } + /* Register the driver with LDM */ + if (driver_register(&omapfb_driver)) { + PRNERR("failed to register omapfb driver\n"); + platform_device_unregister(&omapfb_device); + r = -ENODEV; + goto exit; + } + +exit: + DBGLEAVE(1); + return r; +} + +static void __exit omapfb_cleanup(void) +{ + DBGENTER(1); + + driver_unregister(&omapfb_driver); + platform_device_unregister(&omapfb_device); + + DBGLEAVE(1); +} + +module_param_named(accel, def_accel, uint, 0664); +module_param_named(vram, def_vram, ulong, 0664); +module_param_named(vxres, def_vxres, long, 0664); +module_param_named(vyres, def_vyres, long, 0664); +module_param_named(rotate, def_rotate, uint, 0664); +module_param_named(mirror, def_mirror, uint, 0664); +module_param_named(manual_update, manual_update, bool, 0664); + +module_init(omapfb_init); +module_exit(omapfb_cleanup); + +MODULE_DESCRIPTION("TI OMAP framebuffer driver"); +MODULE_AUTHOR("Imre Deak "); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/video/omap/sossi.c b/drivers/video/omap/sossi.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/video/omap/sossi.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,302 @@ +/* + * File: drivers/video/omap_new/omapfb_main.c + * + * Special optimiSed Screen Interface driver for TI OMAP boards + * + * Copyright (C) 2004 Nokia Corporation + * Author: Juha Yrjölä + * + * 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 +#include +#include +#include + +#include "sossi.h" + +#define OMAP_SOSSI_BASE 0xfffbac00 +#define SOSSI_ID_REG 0x00 +#define SOSSI_INIT1_REG 0x04 +#define SOSSI_INIT2_REG 0x08 +#define SOSSI_INIT3_REG 0x0c +#define SOSSI_FIFO_REG 0x10 +#define SOSSI_REOTABLE_REG 0x14 +#define SOSSI_TEARING_REG 0x18 +#define SOSSI_INIT1B_REG 0x1c +#define SOSSI_FIFOB_REG 0x20 + +#define DMA_GSCR 0xfffedc04 +#define DMA_LCD_CCR 0xfffee3c2 +#define DMA_LCD_CTRL 0xfffee3c4 +#define DMA_LCD_LCH_CTRL 0xfffee3ea + +static int sossi_base = IO_ADDRESS(OMAP_SOSSI_BASE); + +static inline u32 sossi_read_reg(int reg) +{ + return readl(sossi_base + reg); +} + +static inline u16 sossi_read_reg16(int reg) +{ + return readw(sossi_base + reg); +} + +static inline u8 sossi_read_reg8(int reg) +{ + return readb(sossi_base + reg); +} + +static inline void sossi_write_reg(int reg, u32 value) +{ + writel(value, sossi_base + reg); +} + +static inline void sossi_write_reg16(int reg, u16 value) +{ + writew(value, sossi_base + reg); +} + +static inline void sossi_write_reg8(int reg, u8 value) +{ + writeb(value, sossi_base + reg); +} + +static void sossi_set_bits(int reg, u32 bits) +{ + sossi_write_reg(reg, sossi_read_reg(reg) | bits); +} + +static void sossi_clear_bits(int reg, u32 bits) +{ + sossi_write_reg(reg, sossi_read_reg(reg) & ~bits); +} + +#if 1 +void sossi_dump(void) +{ + printk(" INIT1: 0x%08x\n", sossi_read_reg(SOSSI_INIT1_REG)); + printk(" INIT2: 0x%08x\n", sossi_read_reg(SOSSI_INIT2_REG)); + printk(" INIT3: 0x%08x\n", sossi_read_reg(SOSSI_INIT3_REG)); + printk(" TEARING: 0x%08x\n", sossi_read_reg(SOSSI_TEARING_REG)); + printk(" INIT1B: 0x%08x\n", sossi_read_reg(SOSSI_INIT1B_REG)); +} +#endif + +static void sossi_dma_init(void) +{ + /* OMAP3.1 mapping disable */ + omap_writel(omap_readl(DMA_GSCR) | (1 << 3), DMA_GSCR); + /* Logical channel type to b0100 */ + omap_writew(omap_readw(DMA_LCD_LCH_CTRL) | (1 << 2), DMA_LCD_LCH_CTRL); + /* LCD_DMA dest port to 1 */ + omap_writew(omap_readw(DMA_LCD_CTRL) | (1 << 8), DMA_LCD_CTRL); + /* LCD_CCR OMAP31 comp mode */ + omap_writew(omap_readw(DMA_LCD_CCR) | (1 << 10), DMA_LCD_CCR); +} + +#define MOD_CONF_CTRL_1 0xfffe1110 +#define CONF_SOSSI_RESET_R (1 << 23) +#define CONF_MOD_SOSSI_CLK_EN_R (1 << 16) + +int sossi_init(void) +{ + u32 l, k; + + /* Reset and enable the SoSSI module */ + l = omap_readl(MOD_CONF_CTRL_1); + l |= CONF_SOSSI_RESET_R; + omap_writel(l, MOD_CONF_CTRL_1); + l &= ~CONF_SOSSI_RESET_R; + omap_writel(l, MOD_CONF_CTRL_1); + + l |= CONF_MOD_SOSSI_CLK_EN_R; + /* FIXME: Hardcode divide ratio 3 */ + l |= 2 << 17; + omap_writel(l, MOD_CONF_CTRL_1); + + omap_writel(omap_readl(ARM_IDLECT2) | (1 << 11), ARM_IDLECT2); + omap_writel(omap_readl(ARM_IDLECT1) | (1 << 6), ARM_IDLECT1); + + sossi_dma_init(); + + l = sossi_read_reg(SOSSI_INIT2_REG); + /* Enable and reset the SoSSI block */ + l |= (1 << 0) | (1 << 1); + sossi_write_reg(SOSSI_INIT2_REG, l); + /* Take SoSSI out of reset */ + l &= ~(1 << 1); + sossi_write_reg(SOSSI_INIT2_REG, l); + + sossi_write_reg(SOSSI_ID_REG, 0); + l = sossi_read_reg(SOSSI_ID_REG); + k = sossi_read_reg(SOSSI_ID_REG); + + if (l != 0x55555555 || k != 0xaaaaaaaa) { + printk(KERN_ERR "Invalid SoSSI sync pattern: %08x, %08x\n", l, k); + return -ENODEV; + } + l = sossi_read_reg(SOSSI_ID_REG); /* Component code */ + l = sossi_read_reg(SOSSI_ID_REG); + printk(KERN_INFO "SoSSI rev. %d.%d initialized\n", l >> 16, l & 0xffff); + + l = sossi_read_reg(SOSSI_INIT1_REG); + l |= (1 << 19); /* DMA_MODE */ + l &= ~(1 << 31); /* REORDERING */ + sossi_write_reg(SOSSI_INIT1_REG, l); + + return 0; +} + +static void set_timings(int tw0, int tw1) +{ + u32 l; + + l = sossi_read_reg(SOSSI_INIT1_REG); + l &= ~((0x0f << 20) | (0x3f << 24)); + l |= ((tw0 & 0x0f) << 20) | ((tw1 & 0x3f) << 24); + sossi_write_reg(SOSSI_INIT1_REG, l); +} + +static struct sossi { + int bus_pick_width; +} sossi; + +void sossi_set_xfer_params(int tw0, int tw1, int bus_pick_count, int bus_pick_width) +{ + u32 l; + + set_timings(tw0, tw1); + sossi.bus_pick_width = bus_pick_width; + l = ((bus_pick_count - 1) << 5) | ((bus_pick_width - 1) & 0x1f); + sossi_write_reg(SOSSI_INIT3_REG, l); +} + +void sossi_start_transfer(void) +{ + /* WE */ + sossi_clear_bits(SOSSI_INIT2_REG, 1 << 4); + /* CS active low */ + sossi_clear_bits(SOSSI_INIT1_REG, 1 << 30); + /* FIXME: locking? */ +} + +void sossi_stop_transfer(void) +{ + /* WE */ + sossi_set_bits(SOSSI_INIT2_REG, 1 << 4); + /* CS active low */ + sossi_set_bits(SOSSI_INIT1_REG, 1 << 30); + /* FIXME: locking? */ +} + +static void send_data(const void *data, unsigned int len) +{ + while (len >= 4) { + sossi_write_reg(SOSSI_FIFO_REG, *(const u32 *) data); + len -= 4; + data += 4; + } + while (len >= 2) { + sossi_write_reg16(SOSSI_FIFO_REG, *(const u16 *) data); + len -= 2; + data += 2; + } + while (len) { + sossi_write_reg8(SOSSI_FIFO_REG, *(const u8 *) data); + len--; + data++; + } +} + +static void set_cycles(unsigned int len) +{ + int nr_cycles = len / (sossi.bus_pick_width / 8); + + sossi_clear_bits(SOSSI_INIT1_REG, 0x3ffff); + sossi_set_bits(SOSSI_INIT1_REG, (nr_cycles - 1) & 0x3ffff); +} + +void sossi_send_cmd(const void *data, unsigned int len) +{ + sossi_clear_bits(SOSSI_INIT1_REG, 1 << 18); + set_cycles(len); + send_data(data, len); +} + +void sossi_send_data(const void *data, unsigned int len) +{ + sossi_set_bits(SOSSI_INIT1_REG, 1 << 18); + set_cycles(len); + send_data(data, len); +} + +void sossi_prepare_dma_transfer(unsigned int count) +{ + sossi_set_bits(SOSSI_INIT1_REG, 1 << 18); + set_cycles(count); +} + +void sossi_send_data_const32(u32 data, unsigned int count) +{ + sossi_set_bits(SOSSI_INIT1_REG, 1 << 18); + set_cycles(count * 4); + while (count > 0) { + sossi_write_reg(SOSSI_FIFO_REG, data); + count--; + } +} + +void sossi_set_tearing(int mode, int hs_counter, int detect_limit, + int vs_counter, int vs_detect_limit, int flags) +{ + u32 l = 0; + + l |= vs_counter << 30; + if (flags & SOSSI_FLAG_HS_INVERTED) + l |= 1 << 29; + if (flags & SOSSI_FLAG_VS_INVERTED) + l |= 1 << 28; + l |= mode << 26; + l |= hs_counter << 15; + l |= vs_detect_limit << 3; + l |= detect_limit; + sossi_write_reg(SOSSI_TEARING_REG, l); +} + +void sossi_read_data(void *data, unsigned int len) +{ + /* Before reading we must check if some writings are going on */ + while (!(sossi_read_reg(SOSSI_INIT2_REG) & (1 << 3))); + sossi_set_bits(SOSSI_INIT1_REG, 1 << 18); + set_cycles(len); + while (len >= 4) { + *(u32 *) data = sossi_read_reg(SOSSI_FIFO_REG); + len -= 4; + data += 4; + } + while (len >= 2) { + *(u16 *) data = sossi_read_reg16(SOSSI_FIFO_REG); + len -= 2; + data += 2; + } + while (len) { + *(u8 *) data = sossi_read_reg8(SOSSI_FIFO_REG); + len--; + data++; + } +} diff -Nru a/drivers/video/omap/sossi.h b/drivers/video/omap/sossi.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/video/omap/sossi.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,19 @@ +#ifndef DRIVERS_VIDEO_OMAP_SOSSI_H +#define DRIVERS_VIDEO_OMAP_SOSSI_H + +#define SOSSI_FLAG_HS_INVERTED 0x01 +#define SOSSI_FLAG_VS_INVERTED 0x02 + +extern int sossi_init(void); +extern void sossi_set_xfer_params(int tw0, int tw1, int bus_pick_count, int bus_pick_width); +extern void sossi_start_transfer(void); +extern void sossi_stop_transfer(void); +extern void sossi_send_cmd(const void *data, unsigned int len); +extern void sossi_send_data(const void *data, unsigned int len); +extern void sossi_send_data_const32(u32 data, unsigned int count); +extern void sossi_prepare_dma_transfer(unsigned int count); +extern void sossi_read_data(void *data, unsigned int len); +extern void sossi_set_tearing(int mode, int hs_counter, int detect_limit, + int vs_counter, int vs_detect_limit, int flags); + +#endif diff -Nru a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c --- a/fs/jffs2/nodelist.c 2005-03-02 10:51:31 -08:00 +++ b/fs/jffs2/nodelist.c 2005-03-02 10:51:31 -08:00 @@ -127,7 +127,7 @@ valid_ref = jffs2_first_valid_node(f->inocache->nodes); - if (!valid_ref) + if (!valid_ref && (f->inocache->ino != 1)) printk(KERN_WARNING "Eep. No valid nodes for ino #%u\n", f->inocache->ino); while (valid_ref) { diff -Nru a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c --- a/fs/jffs2/wbuf.c 2005-03-02 10:51:31 -08:00 +++ b/fs/jffs2/wbuf.c 2005-03-02 10:51:31 -08:00 @@ -532,6 +532,9 @@ D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() called for ino #%u...\n", ino)); + if (!c->wbuf) + return 0; + down(&c->alloc_sem); if (!jffs2_wbuf_pending_for_ino(c, ino)) { D1(printk(KERN_DEBUG "Ino #%d not pending in wbuf. Returning\n", ino)); @@ -577,6 +580,9 @@ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c) { int ret; + + if (!c->wbuf) + return 0; down_write(&c->wbuf_sem); ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); diff -Nru a/include/asm-arm/arch-omap/aic23.h b/include/asm-arm/arch-omap/aic23.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/include/asm-arm/arch-omap/aic23.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,112 @@ +/* + * linux/include/asm-arm/arch-omap/aic23.h + * + * Hardware definitions for TI TLV320AIC23 audio codec + * + * Copyright (C) 2002 RidgeRun, Inc. + * Author: Steve Johnson + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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. + */ + +#ifndef __ASM_ARCH_AIC23_H +#define __ASM_ARCH_AIC23_H + +// Codec TLV320AIC23 +#define LEFT_LINE_VOLUME_ADDR 0x00 +#define RIGHT_LINE_VOLUME_ADDR 0x01 +#define LEFT_CHANNEL_VOLUME_ADDR 0x02 +#define RIGHT_CHANNEL_VOLUME_ADDR 0x03 +#define ANALOG_AUDIO_CONTROL_ADDR 0x04 +#define DIGITAL_AUDIO_CONTROL_ADDR 0x05 +#define POWER_DOWN_CONTROL_ADDR 0x06 +#define DIGITAL_AUDIO_FORMAT_ADDR 0x07 +#define SAMPLE_RATE_CONTROL_ADDR 0x08 +#define DIGITAL_INTERFACE_ACT_ADDR 0x09 +#define RESET_CONTROL_ADDR 0x0F + +// Left (right) line input volume control register +#define LRS_ENABLED 0x0100 +#define LIM_MUTED 0x0080 +#define LIV_DEFAULT 0x0017 +#define LIV_MAX 0x001f +#define LIV_MIN 0x0000 + +// Left (right) channel headphone volume control register +#define LZC_ON 0x0080 +#define LHV_DEFAULT 0x0079 +#define LHV_MAX 0x007f +#define LHV_MIN 0x0000 + +// Analog audio path control register +#define STE_ENABLED 0x0020 +#define DAC_SELECTED 0x0010 +#define BYPASS_ON 0x0008 +#define INSEL_MIC 0x0004 +#define MICM_MUTED 0x0002 +#define MICB_20DB 0x0001 + +// Digital audio path control register +#define DACM_MUTE 0x0008 +#define DEEMP_32K 0x0002 +#define DEEMP_44K 0x0004 +#define DEEMP_48K 0x0006 +#define ADCHP_ON 0x0001 + +// Power control down register +#define DEVICE_POWER_OFF 0x0080 +#define CLK_OFF 0x0040 +#define OSC_OFF 0x0020 +#define OUT_OFF 0x0010 +#define DAC_OFF 0x0008 +#define ADC_OFF 0x0004 +#define MIC_OFF 0x0002 +#define LINE_OFF 0x0001 + +// Digital audio interface register +#define MS_MASTER 0x0040 +#define LRSWAP_ON 0x0020 +#define LRP_ON 0x0010 +#define IWL_16 0x0000 +#define IWL_20 0x0004 +#define IWL_24 0x0008 +#define IWL_32 0x000C +#define FOR_I2S 0x0002 +#define FOR_DSP 0x0003 + +// Sample rate control register +#define CLKOUT_HALF 0x0080 +#define CLKIN_HALF 0x0040 +#define BOSR_384fs 0x0002 // BOSR_272fs when in USB mode +#define USB_CLK_ON 0x0001 +#define SR_MASK 0xf +#define CLKOUT_SHIFT 7 +#define CLKIN_SHIFT 6 +#define SR_SHIFT 2 +#define BOSR_SHIFT 1 + +// Digital interface register +#define ACT_ON 0x0001 + +#define TLV320AIC23ID1 (0x1a) // cs low +#define TLV320AIC23ID2 (0x1b) // cs high + +#endif /* __ASM_ARCH_AIC23_H */ diff -Nru a/include/asm-arm/arch-omap/board-h2.h b/include/asm-arm/arch-omap/board-h2.h --- a/include/asm-arm/arch-omap/board-h2.h 2005-03-02 10:51:31 -08:00 +++ b/include/asm-arm/arch-omap/board-h2.h 2005-03-02 10:51:31 -08:00 @@ -21,8 +21,8 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * 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., + * 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. */ @@ -32,9 +32,7 @@ /* Placeholder for H2 specific defines */ /* At OMAP1610 Innovator the Ethernet is directly connected to CS1 */ -#define OMAP1610_ETHR_BASE 0xE8000000 -#define OMAP1610_ETHR_SIZE SZ_4K -#define OMAP1610_ETHR_START 0x04000000 +#define OMAP1610_ETHR_START 0x04000300 /* Intel STRATA NOR flash at CS3 or CS2B(NAND Boot) */ #define OMAP_NOR_FLASH_SIZE SZ_32M diff -Nru a/include/asm-arm/arch-omap/board-h3.h b/include/asm-arm/arch-omap/board-h3.h --- a/include/asm-arm/arch-omap/board-h3.h 2005-03-02 10:51:31 -08:00 +++ b/include/asm-arm/arch-omap/board-h3.h 2005-03-02 10:51:31 -08:00 @@ -28,9 +28,7 @@ #define __ASM_ARCH_OMAP_H3_H /* In OMAP1710 H3 the Ethernet is directly connected to CS1 */ -#define OMAP1710_ETHR_BASE 0xE8000000 -#define OMAP1710_ETHR_SIZE SZ_4K -#define OMAP1710_ETHR_START 0x04000000 +#define OMAP1710_ETHR_START 0x04000300 /* Intel STRATA NOR flash at CS3 or CS2B(NAND Boot) */ #define OMAP_NOR_FLASH_SIZE SZ_32M diff -Nru a/include/asm-arm/arch-omap/board-h4.h b/include/asm-arm/arch-omap/board-h4.h --- a/include/asm-arm/arch-omap/board-h4.h 2005-03-02 10:51:31 -08:00 +++ b/include/asm-arm/arch-omap/board-h4.h 2005-03-02 10:51:31 -08:00 @@ -21,8 +21,8 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * 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., + * 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. */ diff -Nru a/include/asm-arm/arch-omap/board-innovator.h b/include/asm-arm/arch-omap/board-innovator.h --- a/include/asm-arm/arch-omap/board-innovator.h 2005-03-02 10:51:31 -08:00 +++ b/include/asm-arm/arch-omap/board-innovator.h 2005-03-02 10:51:31 -08:00 @@ -19,8 +19,8 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * 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., + * 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. */ #ifndef __ASM_ARCH_OMAP_INNOVATOR_H @@ -74,8 +74,7 @@ #if defined (CONFIG_ARCH_OMAP16XX) /* At OMAP1610 Innovator the Ethernet is directly connected to CS1 */ -#define INNOVATOR1610_ETHR_START 0x04000000 -#define INNOVATOR1610_ETHR_SIZE SZ_4K +#define INNOVATOR1610_ETHR_START 0x04000300 #endif /* CONFIG_ARCH_OMAP1610 */ #endif /* __ASM_ARCH_OMAP_INNOVATOR_H */ diff -Nru a/include/asm-arm/arch-omap/board-netstar.h b/include/asm-arm/arch-omap/board-netstar.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/include/asm-arm/arch-omap/board-netstar.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2004 2N Telekomunikace, Ladislav Michl + * + * Hardware definitions for OMAP5910 based NetStar board. + * + * 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_NETSTAR_H +#define __ASM_ARCH_NETSTAR_H + +#include + +#define OMAP_NAND_FLASH_START1 OMAP_CS1_PHYS + (1 << 23) +#define OMAP_NAND_FLASH_START2 OMAP_CS1_PHYS + (2 << 23) + +#endif /* __ASM_ARCH_NETSTAR_H */ diff -Nru a/include/asm-arm/arch-omap/board-osk.h b/include/asm-arm/arch-omap/board-osk.h --- a/include/asm-arm/arch-omap/board-osk.h 2005-03-02 10:51:31 -08:00 +++ b/include/asm-arm/arch-omap/board-osk.h 2005-03-02 10:51:31 -08:00 @@ -21,8 +21,8 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * 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., + * 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. */ @@ -30,9 +30,7 @@ #define __ASM_ARCH_OMAP_OSK_H /* At OMAP5912 OSK the Ethernet is directly connected to CS1 */ -#define OMAP_OSK_ETHR_BASE 0xE8800000 -#define OMAP_OSK_ETHR_SIZE SZ_4K -#define OMAP_OSK_ETHR_START 0x04800000 +#define OMAP_OSK_ETHR_START 0x04800300 /* Micron NOR flash at CS3 mapped to address 0x0 if BM bit is 1 */ #define OMAP_OSK_NOR_FLASH_BASE 0xD8000000 diff -Nru a/include/asm-arm/arch-omap/board-voiceblue.h b/include/asm-arm/arch-omap/board-voiceblue.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/include/asm-arm/arch-omap/board-voiceblue.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2004 2N Telekomunikace, Ladislav Michl + * + * Hardware definitions for OMAP5910 based VoiceBlue board. + * + * 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_VOICEBLUE_H +#define __ASM_ARCH_VOICEBLUE_H + +#if (EXTERNAL_MAX_NR_PORTS < 4) +#undef EXTERNAL_MAX_NR_PORTS +#define EXTERNAL_MAX_NR_PORTS 4 +#endif + +extern void voiceblue_wdt_enable(void); +extern void voiceblue_wdt_disable(void); +extern void voiceblue_wdt_ping(void); +extern void voiceblue_reset(void); + +#endif /* __ASM_ARCH_VOICEBLUE_H */ + diff -Nru a/include/asm-arm/arch-omap/camera.h b/include/asm-arm/arch-omap/camera.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/include/asm-arm/arch-omap/camera.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,75 @@ +/* + * OMAP-1510 camera interface + * + * FIXME: This will go to same directory with the camera driver + */ +#define CAMERA_BASE 0xfffb6800 +#define CAM_CTRLCLOCK_REG (CAMERA_BASE + 0x00) +#define CAM_IT_STATUS_REG (CAMERA_BASE + 0x04) +#define CAM_MODE_REG (CAMERA_BASE + 0x08) +#define CAM_STATUS_REG (CAMERA_BASE + 0x0C) +#define CAM_CAMDATA_REG (CAMERA_BASE + 0x10) +#define CAM_GPIO_REG (CAMERA_BASE + 0x14) +#define CAM_PEAK_CTR_REG (CAMERA_BASE + 0x18) + +#ifndef __ASSEMBLY__ +typedef struct { + __u32 ctrlclock; /* 00 */ + __u32 it_status; /* 04 */ + __u32 mode; /* 08 */ + __u32 status; /* 0C */ + __u32 camdata; /* 10 */ + __u32 gpio; /* 14 */ + __u32 peak_counter; /* 18 */ +} camera_regs_t; +#endif + +/* CTRLCLOCK bit shifts */ +#define FOSCMOD_BIT 0 +#define FOSCMOD_MASK (0x7 << FOSCMOD_BIT) +#define FOSCMOD_12MHz 0x0 +#define FOSCMOD_6MHz 0x2 +#define FOSCMOD_9_6MHz 0x4 +#define FOSCMOD_24MHz 0x5 +#define FOSCMOD_8MHz 0x6 +#define POLCLK (1<<3) +#define CAMEXCLK_EN (1<<4) +#define MCLK_EN (1<<5) +#define DPLL_EN (1<<6) +#define LCLK_EN (1<<7) + +/* IT_STATUS bit shifts */ +#define V_UP (1<<0) +#define V_DOWN (1<<1) +#define H_UP (1<<2) +#define H_DOWN (1<<3) +#define FIFO_FULL (1<<4) +#define DATA_XFER (1<<5) + +/* MODE bit shifts */ +#define CAMOSC (1<<0) +#define IMGSIZE_BIT 1 +#define IMGSIZE_MASK (0x3 << IMGSIZE_BIT) +#define IMGSIZE_CIF (0x0 << IMGSIZE_BIT) /* 352x288 */ +#define IMGSIZE_QCIF (0x1 << IMGSIZE_BIT) /* 176x144 */ +#define IMGSIZE_VGA (0x2 << IMGSIZE_BIT) /* 640x480 */ +#define IMGSIZE_QVGA (0x3 << IMGSIZE_BIT) /* 320x240 */ +#define ORDERCAMD (1<<3) +#define EN_V_UP (1<<4) +#define EN_V_DOWN (1<<5) +#define EN_H_UP (1<<6) +#define EN_H_DOWN (1<<7) +#define EN_DMA (1<<8) +#define THRESHOLD (1<<9) +#define THRESHOLD_BIT 9 +#define THRESHOLD_MASK (0x7f<<9) +#define EN_NIRQ (1<<16) +#define EN_FIFO_FULL (1<<17) +#define RAZ_FIFO (1<<18) + +/* STATUS bit shifts */ +#define VSTATUS (1<<0) +#define HSTATUS (1<<1) + +/* GPIO bit shifts */ +#define CAM_RST (1<<0) diff -Nru a/include/asm-arm/arch-omap/clocks.h b/include/asm-arm/arch-omap/clocks.h --- a/include/asm-arm/arch-omap/clocks.h 2005-03-02 10:51:31 -08:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,216 +0,0 @@ -/* - * OMAP clock interface - * - * Copyright (C) 2001 RidgeRun, Inc - * Written by Gordon McNutt - * Updated 2004 for Linux 2.6 by Tony Lindgren - * - * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * 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. - */ - -#ifndef __ASM_ARM_CLOCKS_H -#define __ASM_ARM_CLOCKS_H - -#include - -/* ARM_CKCTL bit shifts */ -#define PERDIV 0 -#define LCDDIV 2 -#define ARMDIV 4 -#define DSPDIV 6 -#define TCDIV 8 -#define DSPMMUDIV 10 -#define ARM_TIMXO 12 -#define EN_DSPCK 13 -#define ARM_INTHCK_SEL 14 /* REVISIT: Where is this used? */ - -/* ARM_IDLECT1 bit shifts */ -#define IDLWDT_ARM 0 -#define IDLXORP_ARM 1 -#define IDLPER_ARM 2 -#define IDLLCD_ARM 3 -#define IDLLB_ARM 4 -#define IDLHSAB_ARM 5 -#define IDLIF_ARM 6 -#define IDLDPLL_ARM 7 -#define IDLAPI_ARM 8 -#define IDLTIM_ARM 9 -#define SETARM_IDLE 11 - -/* ARM_IDLECT2 bit shifts */ -#define EN_WDTCK 0 -#define EN_XORPCK 1 -#define EN_PERCK 2 -#define EN_LCDCK 3 -#define EN_LBCK 4 -#define EN_HSABCK 5 -#define EN_APICK 6 -#define EN_TIMCK 7 -#define DMACK_REQ 8 -#define EN_GPIOCK 9 -#define EN_LBFREECK 10 - -/* - * OMAP clocks - */ -typedef enum { - /* Fixed system clock */ - OMAP_CLKIN = 0, - - /* DPLL1 */ - OMAP_CK_GEN1, OMAP_CK_GEN2, OMAP_CK_GEN3, - - /* TC usually needs to be checked before anything else */ - OMAP_TC_CK, - - /* CLKM1 */ - OMAP_ARM_CK, OMAP_MPUPER_CK, OMAP_ARM_GPIO_CK, OMAP_MPUXOR_CK, - OMAP_MPUTIM_CK, OMAP_MPUWD_CK, - - /* CLKM2 */ - OMAP_DSP_CK, OMAP_DSPMMU_CK, -#if 0 - /* Accessible only from the dsp */ - OMAP_DSPPER_CK, OMAP_GPIO_CK, OMAP_DSPXOR_CK, OMAP_DSPTIM_CK, - OMAP_DSPWD_CK, OMAP_UART_CK, -#endif - /* CLKM3 */ - OMAP_DMA_CK, OMAP_API_CK, OMAP_HSAB_CK, OMAP_LBFREE_CK, - OMAP_LB_CK, OMAP_LCD_CK -} ck_t; - -typedef enum { - /* Reset the MPU */ - OMAP_ARM_RST, - - /* Reset the DSP */ - OMAP_DSP_RST, - - /* Reset priority registers, EMIF config, and MPUI control logic */ - OMAP_API_RST, - - /* Reset DSP, MPU, and Peripherals */ - OMAP_SW_RST, -} reset_t; - -#define OMAP_CK_MIN OMAP_CLKIN -#define OMAP_CK_MAX OMAP_LCD_CK - -#if defined(CONFIG_OMAP_ARM_30MHZ) -#define OMAP_CK_MAX_RATE 30 -#elif defined(CONFIG_OMAP_ARM_60MHZ) -#define OMAP_CK_MAX_RATE 60 -#elif defined(CONFIG_OMAP_ARM_96MHZ) -#define OMAP_CK_MAX_RATE 96 -#elif defined(CONFIG_OMAP_ARM_120MHZ) -#define OMAP_CK_MAX_RATE 120 -#elif defined(CONFIG_OMAP_ARM_168MHZ) -#define OMAP_CK_MAX_RATE 168 -#elif defined(CONFIG_OMAP_ARM_182MHZ) -#define OMAP_CK_MAX_RATE 182 -#elif defined(CONFIG_OMAP_ARM_192MHZ) -#define OMAP_CK_MAX_RATE 192 -#elif defined(CONFIG_OMAP_ARM_195MHZ) -#define OMAP_CK_MAX_RATE 195 -#endif - -#define CK_DPLL_MASK 0x0fe0 - -/* Shared by CK and DSPC */ -#define MPUI_STROBE_MAX_1509 24 -#define MPUI_STROBE_MAX_1510 30 - -/* - * ---------------------------------------------------------------------------- - * Clock interface functions - * ---------------------------------------------------------------------------- - */ - -/* Clock initialization. */ -int init_ck(void); - -/* - * For some clocks you have a choice of which "parent" clocks they are derived - * from. Use this to select a "parent". See the platform documentation for - * valid combinations. - */ -int ck_can_set_input(ck_t); -int ck_set_input(ck_t ck, ck_t input); -int ck_get_input(ck_t ck, ck_t *input); - -/* - * Use this to set a clock rate. If other clocks are derived from this one, - * their rates will all change too. If this is a derived clock and I can't - * change it to match your request unless I also change the parent clock, then - * tough luck -- I won't change the parent automatically. I'll return an error - * if I can't get the clock within 10% of what you want. Otherwise I'll return - * the value I actually set it to. If I have to switch parents to get the rate - * then I will do this automatically (since it only affects this clock and its - * descendants). - */ -int ck_can_set_rate(ck_t); -int ck_set_rate(ck_t ck, int val_in_mhz); -int ck_get_rate(ck_t ck); - -/* - * Use this to get a bitmap of available rates for the clock. Caller allocates - * the buffer and passes in the length. Clock module fills up to len bytes of - * the buffer & passes back actual bytes used. - */ -int ck_get_rates(ck_t ck, void *buf, int len); -int ck_valid_rate(int rate); - -/* - * Idle a clock. What happens next depends on the clock ;). For example, if - * you idle the ARM_CK you might well end up in sleep mode on some platforms. - * If you try to idle a clock that doesn't support it I'll return an error. - * Note that idling a clock does not always take affect until certain h/w - * conditions are met. Consult the platform specs to learn more. - */ -int ck_can_idle(ck_t); -int ck_idle(ck_t); -int ck_activate(ck_t); -int ck_is_idle(ck_t); - -/* - * Enable/disable a clock. I'll return an error if the h/w doesn't support it. - * If you disable a clock being used by an active device then you probably - * just screwed it. YOU are responsible for making sure this doesn't happen. - */ -int ck_can_disable(ck_t); -int ck_enable(ck_t); -int ck_disable(ck_t); -int ck_is_enabled(ck_t); - -/* Enable/reset ARM peripherals (remove/set reset signal) */ -void ck_enable_peripherals(void); -void ck_reset_peripherals(void); - -/* Generate/clear a MPU or DSP reset */ -void ck_generate_reset(reset_t reset); -void ck_release_from_reset(reset_t reset); - -/* This gets a string representation of the clock's name. Useful for proc. */ -char *ck_get_name(ck_t); - -extern void start_mputimer1(unsigned long); - -#endif diff -Nru a/include/asm-arm/arch-omap/dmtimer.h b/include/asm-arm/arch-omap/dmtimer.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/include/asm-arm/arch-omap/dmtimer.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,90 @@ +/* + * linux/include/asm-arm/arm/arch-omap/dmtimer.h + * + * OMAP Dual-Mode Timers + * + * Copyright (C) 2005 Nokia Corporation + * Author: Lauri Leukkunen + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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. + */ + +#ifndef __ASM_ARCH_TIMER_H +#define __ASM_ARCH_TIMER_H + +#include + +#define OMAP_TIMER_SRC_ARMXOR 0x00 +#define OMAP_TIMER_SRC_32_KHZ 0x01 +#define OMAP_TIMER_SRC_EXT_CLK 0x02 + +/* timer control reg bits */ +#define OMAP_TIMER_CTRL_CAPTMODE (1 << 13) +#define OMAP_TIMER_CTRL_PT (1 << 12) +#define OMAP_TIMER_CTRL_TRG_OVERFLOW (0x1 << 10) +#define OMAP_TIMER_CTRL_TRG_OFANDMATCH (0x2 << 10) +#define OMAP_TIMER_CTRL_TCM_LOWTOHIGH (0x1 << 8) +#define OMAP_TIMER_CTRL_TCM_HIGHTOLOW (0x2 << 8) +#define OMAP_TIMER_CTRL_TCM_BOTHEDGES (0x3 << 8) +#define OMAP_TIMER_CTRL_SCPWM (1 << 7) +#define OMAP_TIMER_CTRL_CE (1 << 6) /* compare enable */ +#define OMAP_TIMER_CTRL_PRE (1 << 5) /* prescaler enable */ +#define OMAP_TIMER_CTRL_PTV_SHIFT 2 /* how much to shift the prescaler value */ +#define OMAP_TIMER_CTRL_AR (1 << 1) /* auto-reload enable */ +#define OMAP_TIMER_CTRL_ST (1 << 0) /* start timer */ + +/* timer interrupt enable bits */ +#define OMAP_TIMER_INT_CAPTURE (1 << 2) +#define OMAP_TIMER_INT_OVERFLOW (1 << 1) +#define OMAP_TIMER_INT_MATCH (1 << 0) + + +struct omap_dm_timer { + struct list_head timer_list; + + u32 base; + unsigned int irq; +}; + +inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg); +inline void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value); + +struct omap_dm_timer * omap_dm_timer_request(void); +void omap_dm_timer_free(struct omap_dm_timer *timer); +void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source); + +void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value); +void omap_dm_timer_set_trigger(struct omap_dm_timer *timer, unsigned int value); +void omap_dm_timer_enable_compare(struct omap_dm_timer *timer); +void omap_dm_timer_enable_autoreload(struct omap_dm_timer *timer); + +void omap_dm_timer_trigger(struct omap_dm_timer *timer); +void omap_dm_timer_start(struct omap_dm_timer *timer); +void omap_dm_timer_stop(struct omap_dm_timer *timer); + +void omap_dm_timer_set_load(struct omap_dm_timer *timer, unsigned int load); +void omap_dm_timer_set_match(struct omap_dm_timer *timer, unsigned int match); + +unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer); +void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value); + +unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer); +void omap_dm_timer_reset_counter(struct omap_dm_timer *timer); + +#endif /* __ASM_ARCH_TIMER_H */ diff -Nru a/include/asm-arm/arch-omap/dsp.h b/include/asm-arm/arch-omap/dsp.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/include/asm-arm/arch-omap/dsp.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,225 @@ +/* + * linux/include/asm-arm/arch-omap/dsp.h + * + * Header for OMAP DSP driver + * + * Copyright (C) 2002-2004 Nokia Corporation + * + * Written by Toshihiro Kobayashi + * + * 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 + * + * 2004/11/16: DSP Gateway version 3.1 + */ + +#ifndef ASM_ARCH_DSP_H +#define ASM_ARCH_DSP_H + + +/* + * for /dev/dspctl/ctl + */ +#define OMAP_DSP_IOCTL_RESET 1 +#define OMAP_DSP_IOCTL_RUN 2 +#define OMAP_DSP_IOCTL_SETRSTVECT 3 +#define OMAP_DSP_IOCTL_IDLE 4 +#define OMAP_DSP_IOCTL_MPUI_WORDSWAP_ON 5 +#define OMAP_DSP_IOCTL_MPUI_WORDSWAP_OFF 6 +#define OMAP_DSP_IOCTL_MPUI_BYTESWAP_ON 7 +#define OMAP_DSP_IOCTL_MPUI_BYTESWAP_OFF 8 +#define OMAP_DSP_IOCTL_DSPCFG 10 +#define OMAP_DSP_IOCTL_DSPUNCFG 11 +#define OMAP_DSP_IOCTL_TASKCNT 12 +#define OMAP_DSP_IOCTL_REGMEMR 40 +#define OMAP_DSP_IOCTL_REGMEMW 41 +#define OMAP_DSP_IOCTL_REGIOR 42 +#define OMAP_DSP_IOCTL_REGIOW 43 +#define OMAP_DSP_IOCTL_GETVAR 44 +#define OMAP_DSP_IOCTL_SETVAR 45 +#define OMAP_DSP_IOCTL_RUNLEVEL 50 +#define OMAP_DSP_IOCTL_SUSPEND 51 +#define OMAP_DSP_IOCTL_RESUME 52 +#define OMAP_DSP_IOCTL_MBSEND 99 + +/* + * for taskdev + * (ioctls below should be >= 0x10000) + */ +#define OMAP_DSP_TASK_IOCTL_BFLSH 0x10000 +#define OMAP_DSP_TASK_IOCTL_SETBSZ 0x10001 +#define OMAP_DSP_TASK_IOCTL_LOCK 0x10002 +#define OMAP_DSP_TASK_IOCTL_UNLOCK 0x10003 +#define OMAP_DSP_TASK_IOCTL_GETNAME 0x10004 + +/* + * for /dev/dspctl/mem + */ +#define OMAP_DSP_MEM_IOCTL_EXMAP 1 +#define OMAP_DSP_MEM_IOCTL_EXUNMAP 2 +#define OMAP_DSP_MEM_IOCTL_EXMAP_FLUSH 3 +#define OMAP_DSP_MEM_IOCTL_FBEXPORT 5 +#define OMAP_DSP_MEM_IOCTL_MMUITACK 7 +#define OMAP_DSP_MEM_IOCTL_MMUINIT 9 + +struct omap_dsp_mapinfo { + unsigned long dspadr; + unsigned long size; +}; + +/* + * for /dev/dspctl/twch + */ +#define OMAP_DSP_TWCH_IOCTL_MKDEV 1 +#define OMAP_DSP_TWCH_IOCTL_RMDEV 2 +#define OMAP_DSP_TWCH_IOCTL_TADD 11 +#define OMAP_DSP_TWCH_IOCTL_TDEL 12 +#define OMAP_DSP_TWCH_IOCTL_TKILL 13 + +#define OMAP_DSP_DEVSTATE_NOTASK 0x00000001 +#define OMAP_DSP_DEVSTATE_ATTACHED 0x00000002 +#define OMAP_DSP_DEVSTATE_GARBAGE 0x00000004 +#define OMAP_DSP_DEVSTATE_ADDREQ 0x00000100 +#define OMAP_DSP_DEVSTATE_DELREQ 0x00000200 +#define OMAP_DSP_DEVSTATE_KILLREQ 0x00000400 +#define OMAP_DSP_DEVSTATE_ADDFAIL 0x00001000 + +struct omap_dsp_taddinfo { + unsigned char minor; + unsigned long taskadr; +}; +#define OMAP_DSP_TADD_ABORTADR 0xffffffff + + +/* + * error cause definition (for error detection device) + */ +#define OMAP_DSP_ERRDT_WDT 0x00000001 +#define OMAP_DSP_ERRDT_MMU 0x00000002 + + +/* + * mailbox protocol definitions + */ + +struct omap_dsp_mailbox_cmd { + unsigned short cmd; + unsigned short data; +}; + +struct omap_dsp_reginfo { + unsigned short adr; + unsigned short val; +}; + +struct omap_dsp_varinfo { + unsigned char varid; + unsigned short val[0]; +}; + +#define OMAP_DSP_MBPROT_REVISION 0x0018 + +#define OMAP_DSP_MBCMD_WDSND 0x10 +#define OMAP_DSP_MBCMD_WDREQ 0x11 +#define OMAP_DSP_MBCMD_BKSND 0x20 +#define OMAP_DSP_MBCMD_BKREQ 0x21 +#define OMAP_DSP_MBCMD_BKYLD 0x23 +#define OMAP_DSP_MBCMD_BKSNDP 0x24 +#define OMAP_DSP_MBCMD_BKREQP 0x25 +#define OMAP_DSP_MBCMD_TCTL 0x30 +#define OMAP_DSP_MBCMD_TCTLDATA 0x31 +#define OMAP_DSP_MBCMD_WDT 0x50 +#define OMAP_DSP_MBCMD_RUNLEVEL 0x51 +#define OMAP_DSP_MBCMD_PM 0x52 +#define OMAP_DSP_MBCMD_SUSPEND 0x53 +#define OMAP_DSP_MBCMD_TCFG 0x60 +#define OMAP_DSP_MBCMD_TADD 0x62 +#define OMAP_DSP_MBCMD_TDEL 0x63 +#define OMAP_DSP_MBCMD_TSTOP 0x65 +#define OMAP_DSP_MBCMD_DSPCFG 0x70 +#define OMAP_DSP_MBCMD_REGRW 0x72 +#define OMAP_DSP_MBCMD_GETVAR 0x74 +#define OMAP_DSP_MBCMD_SETVAR 0x75 +#define OMAP_DSP_MBCMD_ERR 0x78 +#define OMAP_DSP_MBCMD_DBG 0x79 + +#define OMAP_DSP_MBCMD_TCTL_TINIT 0x0000 +#define OMAP_DSP_MBCMD_TCTL_TEN 0x0001 +#define OMAP_DSP_MBCMD_TCTL_TDIS 0x0002 +#define OMAP_DSP_MBCMD_TCTL_TCLR 0x0003 +#define OMAP_DSP_MBCMD_TCTL_TCLR_FORCE 0x0004 + +#define OMAP_DSP_MBCMD_RUNLEVEL_USER 0x01 +#define OMAP_DSP_MBCMD_RUNLEVEL_SUPER 0x0e +#define OMAP_DSP_MBCMD_RUNLEVEL_RECOVERY 0x10 + +#define OMAP_DSP_MBCMD_PM_DISABLE 0x00 +#define OMAP_DSP_MBCMD_PM_ENABLE 0x01 + +#define OMAP_DSP_MBCMD_TDEL_SAFE 0x0000 +#define OMAP_DSP_MBCMD_TDEL_KILL 0x0001 + +#define OMAP_DSP_MBCMD_DSPCFG_REQ 0x00 +#define OMAP_DSP_MBCMD_DSPCFG_SYSADRH 0x28 +#define OMAP_DSP_MBCMD_DSPCFG_SYSADRL 0x29 +#define OMAP_DSP_MBCMD_DSPCFG_PROTREV 0x70 +#define OMAP_DSP_MBCMD_DSPCFG_ABORT 0x78 +#define OMAP_DSP_MBCMD_DSPCFG_LAST 0x80 + +#define OMAP_DSP_MBCMD_REGRW_MEMR 0x00 +#define OMAP_DSP_MBCMD_REGRW_MEMW 0x01 +#define OMAP_DSP_MBCMD_REGRW_IOR 0x02 +#define OMAP_DSP_MBCMD_REGRW_IOW 0x03 +#define OMAP_DSP_MBCMD_REGRW_DATA 0x04 + +#define OMAP_DSP_MBCMD_VARID_ICRMASK 0x00 +#define OMAP_DSP_MBCMD_VARID_LOADINFO 0x01 + +#define OMAP_DSP_TTYP_ARCV 0x0001 +#define OMAP_DSP_TTYP_ASND 0x0002 +#define OMAP_DSP_TTYP_BKMD 0x0004 +#define OMAP_DSP_TTYP_BKDM 0x0008 +#define OMAP_DSP_TTYP_PVMD 0x0010 +#define OMAP_DSP_TTYP_PVDM 0x0020 + +#define OMAP_DSP_EID_BADTID 0x10 +#define OMAP_DSP_EID_BADTCN 0x11 +#define OMAP_DSP_EID_BADBID 0x20 +#define OMAP_DSP_EID_BADCNT 0x21 +#define OMAP_DSP_EID_NOTLOCKED 0x22 +#define OMAP_DSP_EID_STVBUF 0x23 +#define OMAP_DSP_EID_BADADR 0x24 +#define OMAP_DSP_EID_BADTCTL 0x30 +#define OMAP_DSP_EID_BADPARAM 0x50 +#define OMAP_DSP_EID_FATAL 0x58 +#define OMAP_DSP_EID_NOMEM 0xc0 +#define OMAP_DSP_EID_NORES 0xc1 +#define OMAP_DSP_EID_IPBFULL 0xc2 +#define OMAP_DSP_EID_TASKNOTRDY 0xe0 +#define OMAP_DSP_EID_TASKBSY 0xe1 +#define OMAP_DSP_EID_TASKERR 0xef +#define OMAP_DSP_EID_BADCFGTYP 0xf0 +#define OMAP_DSP_EID_DEBUG 0xf8 +#define OMAP_DSP_EID_BADSEQ 0xfe +#define OMAP_DSP_EID_BADCMD 0xff + +#define OMAP_DSP_TNM_LEN 16 + +#define OMAP_DSP_TID_FREE 0xff +#define OMAP_DSP_TID_ANON 0xfe + +#define OMAP_DSP_BID_NULL 0xffff +#define OMAP_DSP_BID_PVT 0xfffe + +#endif /* ASM_ARCH_DSP_H */ diff -Nru a/include/asm-arm/arch-omap/dsp_common.h b/include/asm-arm/arch-omap/dsp_common.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/include/asm-arm/arch-omap/dsp_common.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,32 @@ +/* + * linux/include/asm-arm/arch-omap/dsp_common.h + * + * Header for OMAP DSP subsystem control + * + * Copyright (C) 2004 Nokia Corporation + * + * Written by Toshihiro Kobayashi + * + * 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 + * + * 2004/09/22: DSP Gateway version 3.1 + */ + +#ifndef ASM_ARCH_DSP_COMMON_H +#define ASM_ARCH_DSP_COMMON_H + +void omap_dsp_request_idle(void); + +#endif /* ASM_ARCH_DSP_COMMON_H */ diff -Nru a/include/asm-arm/arch-omap/entry-macro.S b/include/asm-arm/arch-omap/entry-macro.S --- a/include/asm-arm/arch-omap/entry-macro.S 2005-03-02 10:51:31 -08:00 +++ b/include/asm-arm/arch-omap/entry-macro.S 2005-03-02 10:51:31 -08:00 @@ -8,6 +8,14 @@ * warranty of any kind, whether express or implied. */ +#if defined(CONFIG_ARCH_OMAP730) && \ + (defined(CONFIG_ARCH_OMAP1510) || defined(CONFIG_ARCH_OMAP16XX)) +#error "FIXME: OMAP730 doesn't support multiple-OMAP" +#elif defined(CONFIG_ARCH_OMAP730) +#undef INT_IH2_IRQ +#define INT_IH2_IRQ INT_730_IH2_IRQ +#endif + .macro disable_fiq .endm diff -Nru a/include/asm-arm/arch-omap/fpga.h b/include/asm-arm/arch-omap/fpga.h --- a/include/asm-arm/arch-omap/fpga.h 2005-03-02 10:51:31 -08:00 +++ b/include/asm-arm/arch-omap/fpga.h 2005-03-02 10:51:31 -08:00 @@ -38,8 +38,7 @@ #define H2P2_DBG_FPGA_SIZE SZ_4K /* SIZE */ #define H2P2_DBG_FPGA_START 0x04000000 /* PA */ -#define H2P2_DBG_FPGA_ETHR_START H2P2_DBG_FPGA_START -#define H2P2_DBG_FPGA_ETHR_BASE H2P2_DBG_FPGA_BASE +#define H2P2_DBG_FPGA_ETHR_START (H2P2_DBG_FPGA_START + 0x300) #define H2P2_DBG_FPGA_FPGA_REV (H2P2_DBG_FPGA_BASE + 0x10) /* FPGA Revision */ #define H2P2_DBG_FPGA_BOARD_REV (H2P2_DBG_FPGA_BASE + 0x12) /* Board Revision */ #define H2P2_DBG_FPGA_GPIO (H2P2_DBG_FPGA_BASE + 0x14) /* GPIO outputs */ @@ -48,12 +47,31 @@ #define H2P2_DBG_FPGA_LAN_STATUS (H2P2_DBG_FPGA_BASE + 0x1A) /* LAN Status line */ #define H2P2_DBG_FPGA_LAN_RESET (H2P2_DBG_FPGA_BASE + 0x1C) /* LAN Reset line */ -/* LEDs definition on debug board (16 LEDs) */ -#define H2P2_DBG_FPGA_LED_CLAIMRELEASE (1 << 15) -#define H2P2_DBG_FPGA_LED_STARTSTOP (1 << 14) -#define H2P2_DBG_FPGA_LED_HALTED (1 << 13) -#define H2P2_DBG_FPGA_LED_IDLE (1 << 12) -#define H2P2_DBG_FPGA_LED_TIMER (1 << 11) +/* NOTE: most boards don't have a static mapping for the FPGA ... */ +struct h2p2_dbg_fpga { + /* offset 0x00 */ + u16 smc91x[8]; + /* offset 0x10 */ + u16 fpga_rev; + u16 board_rev; + u16 gpio_outputs; + u16 leds; + /* offset 0x18 */ + u16 misc_inputs; + u16 lan_status; + u16 lan_reset; + u16 reserved0; + /* offset 0x20 */ + u16 ps2_data; + u16 ps2_ctrl; + /* plus also 4 rs232 ports ... */ +}; + +/* LEDs definition on debug board (16 LEDs, all physically green) */ +#define H2P2_DBG_FPGA_LED_GREEN (1 << 15) +#define H2P2_DBG_FPGA_LED_AMBER (1 << 14) +#define H2P2_DBG_FPGA_LED_RED (1 << 13) +#define H2P2_DBG_FPGA_LED_BLUE (1 << 12) /* cpu0 load-meter LEDs */ #define H2P2_DBG_FPGA_LOAD_METER (1 << 0) // A bit of fun on our board ... #define H2P2_DBG_FPGA_LOAD_METER_SIZE 11 @@ -116,7 +134,6 @@ #define INNOVATOR_FPGA_IMR2 (OMAP1510_FPGA_BASE + 0x210) #define OMAP1510_FPGA_ETHR_START (OMAP1510_FPGA_START + 0x300) -#define OMAP1510_FPGA_ETHR_BASE (OMAP1510_FPGA_BASE + 0x300) /* * Power up Giga UART driver, turn on HID clock. diff -Nru a/include/asm-arm/arch-omap/gpioexpander.h b/include/asm-arm/arch-omap/gpioexpander.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/include/asm-arm/arch-omap/gpioexpander.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,24 @@ +/* + * linux/include/asm-arm/arch-omap/gpioexpander.h + * + * + * Copyright (C) 2004 Texas Instruments, Inc. + * + * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef __ASM_ARCH_OMAP_GPIOEXPANDER_H +#define __ASM_ARCH_OMAP_GPIOEXPANDER_H + +/* Function Prototypes for GPIO Expander functions */ + +int read_gpio_expa(u8 *, int); +int write_gpio_expa(u8 , int); + +#endif /* __ASM_ARCH_OMAP_GPIOEXPANDER_H */ diff -Nru a/include/asm-arm/arch-omap/hardware.h b/include/asm-arm/arch-omap/hardware.h --- a/include/asm-arm/arch-omap/hardware.h 2005-03-02 10:51:31 -08:00 +++ b/include/asm-arm/arch-omap/hardware.h 2005-03-02 10:51:31 -08:00 @@ -94,53 +94,15 @@ #define ULPD_STATUS_REQ (ULPD_REG_BASE + 0x40) #define ULPD_APLL_CTRL (ULPD_REG_BASE + 0x4c) #define ULPD_POWER_CTRL (ULPD_REG_BASE + 0x50) +#define ULPD_SOFT_DISABLE_REQ_REG (ULPD_REG_BASE + 0x68) +#define ULPD_SDW_CLK_DIV_CTRL_SEL (ULPD_REG_BASE + 0x74) #define ULPD_CAM_CLK_CTRL (ULPD_REG_BASE + 0x7c) /* * --------------------------------------------------------------------------- - * Timers + * Watchdog timer * --------------------------------------------------------------------------- */ -#define OMAP_32kHz_TIMER_BASE 0xfffb9000 - -/* 32k Timer Registers */ -#define TIMER32k_CR 0x08 -#define TIMER32k_TVR 0x00 -#define TIMER32k_TCR 0x04 - -/* 32k Timer Control Register definition */ -#define TIMER32k_TSS (1<<0) -#define TIMER32k_TRB (1<<1) -#define TIMER32k_INT (1<<2) -#define TIMER32k_ARL (1<<3) - -/* MPU Timer base addresses */ -#define OMAP_TIMER1_BASE (0xfffec500) -#define OMAP_TIMER2_BASE (0xfffec600) -#define OMAP_TIMER3_BASE (0xfffec700) -#define OMAP_MPUTIMER_BASE OMAP_TIMER1_BASE -#define OMAP_MPUTIMER_OFFSET 0x100 - -/* MPU Timer Registers */ -#define OMAP_TIMER1_CNTL (OMAP_TIMER_BASE1 + 0x0) -#define OMAP_TIMER1_LOAD_TIM (OMAP_TIMER_BASE1 + 0x4) -#define OMAP_TIMER1_READ_TIM (OMAP_TIMER_BASE1 + 0x8) - -#define OMAP_TIMER2_CNTL (OMAP_TIMER_BASE2 + 0x0) -#define OMAP_TIMER2_LOAD_TIM (OMAP_TIMER_BASE2 + 0x4) -#define OMAP_TIMER2_READ_TIM (OMAP_TIMER_BASE2 + 0x8) - -#define OMAP_TIMER3_CNTL (OMAP_TIMER_BASE3 + 0x0) -#define OMAP_TIMER3_LOAD_TIM (OMAP_TIMER_BASE3 + 0x4) -#define OMAP_TIMER3_READ_TIM (OMAP_TIMER_BASE3 + 0x8) - -/* CNTL_TIMER register bits */ -#define MPUTIM_FREE (1<<6) -#define MPUTIM_CLOCK_ENABLE (1<<5) -#define MPUTIM_PTV_MASK (0x7< or + * + * 2003 (c) MontaVista Software, Inc. This file is licensed under the + * terms of the GNU General Public License version 2. This program is + * licensed "as is" without any warranty of any kind, whether express + * or implied. + * + * History: + * + * 20030620: George G. Davis + * Initially based on linux-2.4.19-rmk7-pxa1/include/asm-arm/arch-pxa/ide.h + * 2002 (c) MontaVista Software, Inc. + * + */ + +#include +#include +#include +#include + + +/* + * 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... */ +} diff -Nru a/include/asm-arm/arch-omap/irqs.h b/include/asm-arm/arch-omap/irqs.h --- a/include/asm-arm/arch-omap/irqs.h 2005-03-02 10:51:31 -08:00 +++ b/include/asm-arm/arch-omap/irqs.h 2005-03-02 10:51:31 -08:00 @@ -149,9 +149,16 @@ #define INT_1610_McBSP2RX_OF (31 + IH2_BASE) #define INT_1610_STI (32 + IH2_BASE) #define INT_1610_STI_WAKEUP (33 + IH2_BASE) +#define INT_1610_GPTIMER3 (34 + IH2_BASE) +#define INT_1610_GPTIMER4 (35 + IH2_BASE) +#define INT_1610_GPTIMER5 (36 + IH2_BASE) +#define INT_1610_GPTIMER6 (37 + IH2_BASE) +#define INT_1610_GPTIMER7 (38 + IH2_BASE) +#define INT_1610_GPTIMER8 (39 + IH2_BASE) #define INT_1610_GPIO_BANK2 (40 + IH2_BASE) #define INT_1610_GPIO_BANK3 (41 + IH2_BASE) #define INT_1610_MMC2 (42 + IH2_BASE) +#define INT_1610_CF (43 + IH2_BASE) #define INT_1610_GPIO_BANK4 (48 + IH2_BASE) #define INT_1610_SPI (49 + IH2_BASE) #define INT_1610_DMA_CH6 (53 + IH2_BASE) diff -Nru a/include/asm-arm/arch-omap/mcbsp.h b/include/asm-arm/arch-omap/mcbsp.h --- a/include/asm-arm/arch-omap/mcbsp.h 2005-03-02 10:51:31 -08:00 +++ b/include/asm-arm/arch-omap/mcbsp.h 2005-03-02 10:51:31 -08:00 @@ -250,4 +250,8 @@ /* SPI specific API */ void omap_mcbsp_set_spi_mode(unsigned int id, const struct omap_mcbsp_spi_cfg * spi_cfg); +/* Polled read/write functions */ +int omap_mcbsp_pollread(unsigned int id, u16 * buf); +int omap_mcbsp_pollwrite(unsigned int id, u16 buf); + #endif diff -Nru a/include/asm-arm/arch-omap/memory.h b/include/asm-arm/arch-omap/memory.h --- a/include/asm-arm/arch-omap/memory.h 2005-03-02 10:51:31 -08:00 +++ b/include/asm-arm/arch-omap/memory.h 2005-03-02 10:51:31 -08:00 @@ -25,8 +25,8 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * 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., + * 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. */ diff -Nru a/include/asm-arm/arch-omap/mux.h b/include/asm-arm/arch-omap/mux.h --- a/include/asm-arm/arch-omap/mux.h 2005-03-02 10:51:31 -08:00 +++ b/include/asm-arm/arch-omap/mux.h 2005-03-02 10:51:31 -08:00 @@ -174,6 +174,7 @@ M14_1510_GPIO2, /* OMAP1610 GPIO */ + P18_1610_GPIO3, Y15_1610_GPIO17, /* OMAP-1710 GPIO */ @@ -239,6 +240,7 @@ V5_1610_GPIO24, AA20_1610_GPIO_41, W19_1610_GPIO48, + M7_1610_GPIO62, /* OMAP-1610 uWire */ V19_1610_UWIRE_SCLK, @@ -316,6 +318,12 @@ R10_1610_MCLK_ON, R10_1610_MCLK_OFF, + /* CompactFlash controller */ + P11_1610_CF_CD2, + R11_1610_CF_IOIS16, + V10_1610_CF_IREQ, + W10_1610_CF_RESET, + W11_1610_CF_CD1, } reg_cfg_t; #if defined(__MUX_C__) && defined(CONFIG_OMAP_MUX) @@ -355,7 +363,8 @@ /* USB internal master generic */ MUX_CFG("R18_USB_VBUS", 7, 9, 2, 1, 11, 0, NA, 0, 1) MUX_CFG("R18_1510_USB_GPIO0", 7, 9, 0, 1, 11, 1, NA, 0, 1) -MUX_CFG("W4_USB_PUEN", D, 3, 0, 3, 5, 1, NA, 0, 1) +/* works around erratum: W4_USB_PUEN and W4_USB_PUDIS are switched! */ +MUX_CFG("W4_USB_PUEN", D, 3, 3, 3, 5, 1, NA, 0, 1) MUX_CFG("W4_USB_CLKO", D, 3, 1, 3, 5, 0, NA, 0, 1) MUX_CFG("W4_USB_HIGHZ", D, 3, 4, 3, 5, 0, 3, 0, 1) MUX_CFG("W4_GPIO58", D, 3, 7, 3, 5, 0, 3, 0, 1) @@ -388,6 +397,7 @@ MUX_CFG("M14_1510_GPIO2", 7, 3, 0, 1, 9, 1, 0, 0, 1) /* OMAP1610 GPIO */ +MUX_CFG("P18_1610_GPIO3", 7, 0, 0, 1, 8, 0, NA, 0, 1) MUX_CFG("Y15_1610_GPIO17", A, 0, 7, 2, 6, 0, NA, 0, 1) /* OMAP-1710 GPIO */ @@ -454,6 +464,7 @@ MUX_CFG("V5_1610_GPIO24", B, 15, 7, 2, 21, 0, 2, 1, 1) MUX_CFG("AA20_1610_GPIO_41", 9, 9, 7, 1, 31, 0, 1, 1, 1) MUX_CFG("W19_1610_GPIO48", 8, 15, 7, 1, 23, 1, 1, 0, 1) +MUX_CFG("M7_1610_GPIO62", 10, 0, 0, 4, 24, 0, 4, 0, 1) /* OMAP-1610 uWire */ MUX_CFG("V19_1610_UWIRE_SCLK", 8, 6, 0, 1, 20, 0, 1, 1, 1) @@ -528,6 +539,13 @@ MUX_CFG("V5_1710_MCLK_OFF", B, 15, 6, NA, 0, 0, NA, 0, 0) MUX_CFG("R10_1610_MCLK_ON", B, 18, 0, NA, 22, 0, NA, 1, 0) MUX_CFG("R10_1610_MCLK_OFF", B, 18, 6, 2, 22, 1, 2, 1, 1) + +/* CompactFlash controller, conflicts with MMC1 */ +MUX_CFG("P11_1610_CF_CD2", A, 27, 3, 2, 15, 1, 2, 1, 1) +MUX_CFG("R11_1610_CF_IOIS16", B, 0, 3, 2, 16, 1, 2, 1, 1) +MUX_CFG("V10_1610_CF_IREQ", A, 24, 3, 2, 14, 0, 2, 0, 1) +MUX_CFG("W10_1610_CF_RESET", A, 18, 3, 2, 12, 1, 2, 1, 1) +MUX_CFG("W11_1610_CF_CD1", 10, 15, 3, 3, 8, 1, 3, 1, 1) }; #endif /* __MUX_C__ */ diff -Nru a/include/asm-arm/arch-omap/omap16xx.h b/include/asm-arm/arch-omap/omap16xx.h --- a/include/asm-arm/arch-omap/omap16xx.h 2005-03-02 10:51:31 -08:00 +++ b/include/asm-arm/arch-omap/omap16xx.h 2005-03-02 10:51:31 -08:00 @@ -121,6 +121,13 @@ #define OMAP16XX_SUBLVDS_CONF_VALID (1 << 13) /* + * ---------------------------------------------------------------------------- + * System control registers + * ---------------------------------------------------------------------------- + */ +#define OMAP1610_RESET_CONTROL 0xfffe1140 + +/* * --------------------------------------------------------------------------- * TIPB bus interface * --------------------------------------------------------------------------- diff -Nru a/include/asm-arm/arch-omap/param.h b/include/asm-arm/arch-omap/param.h --- a/include/asm-arm/arch-omap/param.h 2005-03-02 10:51:31 -08:00 +++ b/include/asm-arm/arch-omap/param.h 2005-03-02 10:51:31 -08:00 @@ -1,24 +1,8 @@ /* * linux/include/asm-arm/arch-omap/param.h * - * Initially based on linux/include/asm-arm/arch-integrator/param.h - * Copyright (C) 1999 ARM Limited - * - * BRIEF MODULE DESCRIPTION - * a place holder - * - * 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 */ +#ifdef CONFIG_OMAP_32K_TIMER_HZ +#define HZ CONFIG_OMAP_32K_TIMER_HZ +#endif diff -Nru a/include/asm-arm/arch-omap/pm.h b/include/asm-arm/arch-omap/pm.h --- a/include/asm-arm/arch-omap/pm.h 2005-03-02 10:51:31 -08:00 +++ b/include/asm-arm/arch-omap/pm.h 2005-03-02 10:51:31 -08:00 @@ -61,7 +61,11 @@ #define PER_EN 0x1 #define CPU_SUSPEND_SIZE 200 -#define ULPD_LOW_POWER_EN 0x0001 +#define ULPD_LOW_PWR_EN 0x0001 +#define ULPD_DEEP_SLEEP_TRANSITION_EN 0x0010 +#define ULPD_SETUP_ANALOG_CELL_3_VAL 1 +#define ULPD_SETUP_ANALOG_CELL_3 0xfffe0824 +#define ULPD_POWER_CTRL_REG_VAL 0x1209 #define DSP_IDLE_DELAY 10 #define DSP_IDLE 0x0040 @@ -86,13 +90,14 @@ #define OMAP1510_BIG_SLEEP_REQUEST 0x0cc5 #define OMAP1510_IDLE_LOOP_REQUEST 0x0c00 #define OMAP1510_IDLE_CLOCK_DOMAINS 0x2 -#define OMAP1510_ULPD_LOW_POWER_REQ 0x0001 -#define OMAP1610_DEEP_SLEEP_REQUEST 0x17c7 -#define OMAP1610_BIG_SLEEP_REQUEST TBD +/* Both big sleep and deep sleep use same values. Difference is in ULPD. */ +#define OMAP1610_IDLECT1_SLEEP_VAL 0x13c7 +#define OMAP1610_IDLECT2_SLEEP_VAL 0x09c7 +#define OMAP1610_IDLECT3_VAL 0x3f +#define OMAP1610_IDLECT3_SLEEP_ORMASK 0x2c +#define OMAP1610_IDLECT3 0xfffece24 #define OMAP1610_IDLE_LOOP_REQUEST 0x0400 -#define OMAP1610_IDLE_CLOCK_DOMAINS 0x09c7 -#define OMAP1610_ULPD_LOW_POWER_REQ 0x3 #ifndef OMAP1510_SRAM_IDLE_SUSPEND #define OMAP1510_SRAM_IDLE_SUSPEND 0 diff -Nru a/include/asm-arm/arch-omap/tc.h b/include/asm-arm/arch-omap/tc.h --- a/include/asm-arm/arch-omap/tc.h 2005-03-02 10:51:31 -08:00 +++ b/include/asm-arm/arch-omap/tc.h 2005-03-02 10:51:31 -08:00 @@ -24,20 +24,28 @@ #ifndef __ASM_ARCH_TC_H #define __ASM_ARCH_TC_H -#define OMAP_TC_OCPT1_PRIOR 0xFFFECC00 -#define OMAP_TC_EMIFS_PRIOR 0xFFFECC04 -#define OMAP_TC_EMIFF_PRIOR 0xFFFECC08 -#define OMAP_TC_OCPT2_PRIOR 0xFFFECCD0 - - -/* EMIF Slow Interface Configuration Register */ -#define OMAP_EMIFS_CONFIG_REG __REG32(EMIFS_CONFIG) - -#define OMAP_EMIFS_CONFIG_FR (1 << 4) -#define OMAP_EMIFS_CONFIG_PDE (1 << 3) -#define OMAP_EMIFS_CONFIG_PWD_EN (1 << 2) -#define OMAP_EMIFS_CONFIG_BM (1 << 1) -#define OMAP_EMIFS_CONFIG_WP (1 << 0) +#define TCMIF_BASE 0xfffecc00 +#define OMAP_TC_OCPT1_PRIOR (TCMIF_BASE + 0x00) +#define OMAP_TC_EMIFS_PRIOR (TCMIF_BASE + 0x04) +#define OMAP_TC_EMIFF_PRIOR (TCMIF_BASE + 0x08) +#define EMIFS_CONFIG (TCMIF_BASE + 0x0c) +#define EMIFS_CS0_CONFIG (TCMIF_BASE + 0x10) +#define EMIFS_CS1_CONFIG (TCMIF_BASE + 0x14) +#define EMIFS_CS2_CONFIG (TCMIF_BASE + 0x18) +#define EMIFS_CS3_CONFIG (TCMIF_BASE + 0x1c) +#define EMIFF_SDRAM_CONFIG (TCMIF_BASE + 0x20) +#define EMIFF_MRS (TCMIF_BASE + 0x24) +#define TC_TIMEOUT1 (TCMIF_BASE + 0x28) +#define TC_TIMEOUT2 (TCMIF_BASE + 0x2c) +#define TC_TIMEOUT3 (TCMIF_BASE + 0x30) +#define TC_ENDIANISM (TCMIF_BASE + 0x34) +#define EMIFF_SDRAM_CONFIG_2 (TCMIF_BASE + 0x3c) +#define EMIF_CFG_DYNAMIC_WS (TCMIF_BASE + 0x40) +#define EMIFS_ACS0 (TCMIF_BASE + 0x50) +#define EMIFS_ACS1 (TCMIF_BASE + 0x54) +#define EMIFS_ACS2 (TCMIF_BASE + 0x58) +#define EMIFS_ACS3 (TCMIF_BASE + 0x5c) +#define OMAP_TC_OCPT2_PRIOR (TCMIF_BASE + 0xd0) /* external EMIFS chipselect regions */ #define OMAP_CS1_PHYS 0x04000000 @@ -60,5 +68,38 @@ #define OMAP_CS3_PHYS 0x0c000000 #define OMAP_CS3_SIZE SZ_64M + +#ifndef __ASSEMBLER__ + +/* EMIF Slow Interface Configuration Register */ +#define OMAP_EMIFS_CONFIG_REG __REG32(EMIFS_CONFIG) + +#define OMAP_EMIFS_CONFIG_FR (1 << 4) +#define OMAP_EMIFS_CONFIG_PDE (1 << 3) +#define OMAP_EMIFS_CONFIG_PWD_EN (1 << 2) +#define OMAP_EMIFS_CONFIG_BM (1 << 1) +#define OMAP_EMIFS_CONFIG_WP (1 << 0) + +#define EMIFS_CCS(n) __REG32(EMIFS_CS0_CONFIG + (4 * (n))) +#define EMIFS_ACS(n) __REG32(EMIFS_ACS0 + (4 * (n))) + +/* Almost all documentation for chip and board memory maps assumes + * BM is clear. Most devel boards have a switch to control booting + * from NOR flash (using external chipselect 3) rather than mask ROM, + * which uses BM to interchange the physical CS0 and CS3 addresses. + */ +static inline u32 omap_cs0_phys(void) +{ + return (OMAP_EMIFS_CONFIG_REG & OMAP_EMIFS_CONFIG_BM) + ? OMAP_CS3_PHYS : 0; +} + +static inline u32 omap_cs3_phys(void) +{ + return (OMAP_EMIFS_CONFIG_REG & OMAP_EMIFS_CONFIG_BM) + ? 0 : OMAP_CS3_PHYS; +} + +#endif /* __ASSEMBLER__ */ #endif /* __ASM_ARCH_TC_H */ diff -Nru a/include/asm-arm/arch-omap/tps65010.h b/include/asm-arm/arch-omap/tps65010.h --- a/include/asm-arm/arch-omap/tps65010.h 2005-03-02 10:51:31 -08:00 +++ b/include/asm-arm/arch-omap/tps65010.h 2005-03-02 10:51:31 -08:00 @@ -30,6 +30,65 @@ /* * ---------------------------------------------------------------------------- + * Registers, all 8 bits + * ---------------------------------------------------------------------------- + */ + +#define TPS_CHGSTATUS 0x01 +# define TPS_CHG_USB (1 << 7) +# define TPS_CHG_AC (1 << 6) +# define TPS_CHG_THERM (1 << 5) +# define TPS_CHG_TERM (1 << 4) +# define TPS_CHG_TAPER_TMO (1 << 3) +# define TPS_CHG_CHG_TMO (1 << 2) +# define TPS_CHG_PRECHG_TMO (1 << 1) +# define TPS_CHG_TEMP_ERR (1 << 0) +#define TPS_REGSTATUS 0x02 +# define TPS_REG_ONOFF (1 << 7) +# define TPS_REG_COVER (1 << 6) +# define TPS_REG_UVLO (1 << 5) +# define TPS_REG_PG_LD02 (1 << 3) +# define TPS_REG_PG_LD01 (1 << 2) +# define TPS_REG_PG_MAIN (1 << 1) +# define TPS_REG_PG_CORE (1 << 0) +#define TPS_MASK1 0x03 +#define TPS_MASK2 0x04 +#define TPS_ACKINT1 0x05 +#define TPS_ACKINT2 0x06 +#define TPS_CHGCONFIG 0x07 +# define TPS_CHARGE_POR (1 << 7) +# define TPS65013_AUA (1 << 7) +# define TPS_CHARGE_RESET (1 << 6) +# define TPS_CHARGE_FAST (1 << 5) +# define TPS_CHARGE_CURRENT (3 << 3) +# define TPS_VBUS_500MA (1 << 2) +# define TPS_VBUS_CHARGING (1 << 1) +# define TPS_CHARGE_ENABLE (1 << 0) +#define TPS_LED1_ON 0x08 +#define TPS_LED1_PER 0x09 +#define TPS_LED2_ON 0x0a +#define TPS_LED2_PER 0x0b +#define TPS_VDCDC1 0x0c +# define TPS_ENABLE_LP (1 << 3) +#define TPS_VDCDC2 0x0d +#define TPS_VREGS1 0x0e +# define TPS_LDO2_ENABLE (1 << 7) +# define TPS_LDO2_OFF (1 << 6) +# define TPS_VLDO2_3_0V (3 << 4) +# define TPS_VLDO2_2_75V (2 << 4) +# define TPS_VLDO2_2_5V (1 << 4) +# define TPS_VLDO2_1_8V (0 << 4) +# define TPS_LDO1_ENABLE (1 << 3) +# define TPS_LDO1_OFF (1 << 2) +# define TPS_VLDO1_3_0V (3 << 0) +# define TPS_VLDO1_2_75V (2 << 0) +# define TPS_VLDO1_2_5V (1 << 0) +# define TPS_VLDO1_ADJ (0 << 0) +#define TPS_MASK3 0x0f +#define TPS_DEFGPIO 0x10 + +/* + * ---------------------------------------------------------------------------- * Macros used by exported functions * ---------------------------------------------------------------------------- */ @@ -75,6 +134,17 @@ * mode: ON or OFF */ extern int tps65010_set_low_pwr(unsigned mode); + +/* tps65010_config_vregs1 parameter: + * value to be written to VREGS1 register + * Note: The complete register is written, set all bits you need + */ +extern int tps65010_config_vregs1(unsigned value); + +/* tps65013_set_low_pwr parameter: + * mode: ON or OFF + */ +extern int tps65013_set_low_pwr(unsigned mode); #endif /* __ASM_ARCH_TPS65010_H */ diff -Nru a/include/asm-arm/dma-mapping.h b/include/asm-arm/dma-mapping.h --- a/include/asm-arm/dma-mapping.h 2005-03-02 10:51:31 -08:00 +++ b/include/asm-arm/dma-mapping.h 2005-03-02 10:51:31 -08:00 @@ -5,6 +5,7 @@ #include #include /* need struct page */ +#include #include diff -Nru a/include/asm-arm/hardware/clock.h b/include/asm-arm/hardware/clock.h --- a/include/asm-arm/hardware/clock.h 2005-03-02 10:51:31 -08:00 +++ b/include/asm-arm/hardware/clock.h 2005-03-02 10:51:31 -08:00 @@ -64,6 +64,12 @@ void clk_unuse(struct clk *clk); /** + * clk_get_usecount - get the use count + * @clk: clock source + */ +int clk_get_usecount(struct clk *clk); + +/** * clk_get_rate - obtain the current clock rate (in Hz) for a clock source. * This is only valid once the clock source has been enabled. * @clk: clock source diff -Nru a/include/asm-arm/hardware/tsc2101.h b/include/asm-arm/hardware/tsc2101.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/include/asm-arm/hardware/tsc2101.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,300 @@ +/* + * + * TI TSC2101 Audio CODEC and TS control registers definition + * + * + * Copyright 2003 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * source@mvista.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, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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. + */ + +#ifndef __ASM_HARDWARE_TSC2101_H +#define __ASM_HARDWARE_TSC2101_H + +/* Page 0 Touch Screen Data Registers */ +#define TSC2101_TS_X (0x00) +#define TSC2101_TS_Y (0x01) +#define TSC2101_TS_Z1 (0x02) +#define TSC2101_TS_Z2 (0x03) +#define TSC2101_TS_BAT (0x05) +#define TSC2101_TS_AUX1 (0x07) +#define TSC2101_TS_AUX2 (0x08) +#define TSC2101_TS_TEMP1 (0x09) +#define TSC2101_TS_TEMP2 (0x0A) + +/* Page 1 Touch Screen Control registers */ +#define TSC2101_TS_ADC_CTRL (0x00) +#define TSC2101_TS_STATUS (0x01) +#define TSC2101_TS_BUFFER_CTRL (0x02) +#define TSC2101_TS_REF_CTRL (0x03) +#define TSC2101_TS_RESET_CTRL (0x04) +#define TSC2101_TS_CONFIG_CTRL (0x05) +#define TSC2101_TS_TEMP_MAX_THRESHOLD (0x06) +#define TSC2101_TS_TEMP_MIN_THRESHOLD (0x07) +#define TSC2101_TS_AUX1_MAX_THRESHOLD (0x08) +#define TSC2101_TS_AUX1_MIN_THRESHOLD (0x09) +#define TSC2101_TS_AUX2_MAX_THRESHOLD (0x0A) +#define TSC2101_TS_AUX2_MIN_THRESHOLD (0x0B) +#define TSC2101_TS_MEASURE_CONFIG (0x0C) +#define TSC2101_TS_PROG_DELAY (0x0D) + +/* Page 2 Audio codec Control registers */ +#define TSC2101_AUDIO_CTRL_1 (0x00) +#define TSC2101_HEADSET_GAIN_CTRL (0x01) +#define TSC2101_DAC_GAIN_CTRL (0x02) +#define TSC2101_MIXER_PGA_CTRL (0x03) +#define TSC2101_AUDIO_CTRL_2 (0x04) +#define TSC2101_CODEC_POWER_CTRL (0x05) +#define TSC2101_AUDIO_CTRL_3 (0x06) +#define TSC2101_LCH_BASS_BOOST_N0 (0x07) +#define TSC2101_LCH_BASS_BOOST_N1 (0x08) +#define TSC2101_LCH_BASS_BOOST_N2 (0x09) +#define TSC2101_LCH_BASS_BOOST_N3 (0x0A) +#define TSC2101_LCH_BASS_BOOST_N4 (0x0B) +#define TSC2101_LCH_BASS_BOOST_N5 (0x0C) +#define TSC2101_LCH_BASS_BOOST_D1 (0x0D) +#define TSC2101_LCH_BASS_BOOST_D2 (0x0E) +#define TSC2101_LCH_BASS_BOOST_D4 (0x0F) +#define TSC2101_LCH_BASS_BOOST_D5 (0x10) +#define TSC2101_RCH_BASS_BOOST_N0 (0x11) +#define TSC2101_RCH_BASS_BOOST_N1 (0x12) +#define TSC2101_RCH_BASS_BOOST_N2 (0x13) +#define TSC2101_RCH_BASS_BOOST_N3 (0x14) +#define TSC2101_RCH_BASS_BOOST_N4 (0x15) +#define TSC2101_RCH_BASS_BOOST_N5 (0x16) +#define TSC2101_RCH_BASS_BOOST_D1 (0x17) +#define TSC2101_RCH_BASS_BOOST_D2 (0x18) +#define TSC2101_RCH_BASS_BOOST_D4 (0x19) +#define TSC2101_RCH_BASS_BOOST_D5 (0x1A) +#define TSC2101_PLL_PROG_1 (0x1B) +#define TSC2101_PLL_PROG_2 (0x1C) +#define TSC2101_AUDIO_CTRL_4 (0x1D) +#define TSC2101_HANDSET_GAIN_CTRL (0x1E) +#define TSC2101_BUZZER_GAIN_CTRL (0x1F) +#define TSC2101_AUDIO_CTRL_5 (0x20) +#define TSC2101_AUDIO_CTRL_6 (0x21) +#define TSC2101_AUDIO_CTRL_7 (0x22) +#define TSC2101_GPIO_CTRL (0x23) +#define TSC2101_AGC_CTRL (0x24) +#define TSC2101_POWERDOWN_STS (0x25) +#define TSC2101_MIC_AGC_CONTROL (0x26) +#define TSC2101_CELL_AGC_CONTROL (0x27) + +/* Bit field definitions for TS Control */ +#define TSC2101_DATA_AVAILABLE 0x4000 +#define TSC2101_BUFFERMODE_DISABLE 0x0 +#define TSC2101_REF_POWERUP 0x16 +#define TSC2101_ENABLE_TOUCHDETECT 0x08 +#define TSC2101_PRG_DELAY 0x0900 +#define TSC2101_ADC_CONTROL 0x8874 +#define TSC2101_ADC_POWERDOWN 0x4000 + +/* Bit position */ +#define TSC2101_BIT(ARG) ((0x01)<<(ARG)) + +/* Field masks for Audio Control 1 */ +#define AC1_ADCHPF(ARG) (((ARG) & 0x03) << 14) +#define AC1_WLEN(ARG) (((ARG) & 0x03) << 10) +#define AC1_DATFM(ARG) (((ARG) & 0x03) << 8) +#define AC1_DACFS(ARG) (((ARG) & 0x07) << 3) +#define AC1_ADCFS(ARG) (((ARG) & 0x07)) + +/* Field masks for TSC2101_HEADSET_GAIN_CTRL */ +#define HGC_ADMUT_HED TSC2101_BIT(15) +#define HGC_ADPGA_HED(ARG) (((ARG) & 0x7F) << 8) +#define HGC_AGCTG_HED(ARG) (((ARG) & 0x07) << 5) +#define HGC_AGCTC_HED(ARG) (((ARG) & 0x0F) << 1) +#define HGC_AGCEN_HED (0x01) + +/* Field masks for TSC2101_DAC_GAIN_CTRL */ +#define DGC_DALMU TSC2101_BIT(15) +#define DGC_DALVL(ARG) (((ARG) & 0x7F) << 8) +#define DGC_DARMU TSC2101_BIT(7) +#define DGC_DARVL(ARG) (((ARG) & 0x7F)) + +/* Field masks for TSC2101_MIXER_PGA_CTRL */ +#define MPC_ASTMU TSC2101_BIT(15) +#define MPC_ASTG(ARG) (((ARG) & 0x7F) << 8) +#define MPC_MICSEL(ARG) (((ARG) & 0x07) << 5) +#define MPC_MICADC TSC2101_BIT(4) +#define MPC_CPADC TSC2101_BIT(3) +#define MPC_ASTGF (0x01) + +/* Field formats for TSC2101_AUDIO_CTRL_2 */ +#define AC2_KCLEN TSC2101_BIT(15) +#define AC2_KCLAC(ARG) (((ARG) & 0x07) << 12) +#define AC2_APGASS TSC2101_BIT(11) +#define AC2_KCLFRQ(ARG) (((ARG) & 0x07) << 8) +#define AC2_KCLLN(ARG) (((ARG) & 0x0F) << 4) +#define AC2_DLGAF TSC2101_BIT(3) +#define AC2_DRGAF TSC2101_BIT(2) +#define AC2_DASTC TSC2101_BIT(1) +#define AC2_ADGAF (0x01) + +/* Field masks for TSC2101_CODEC_POWER_CTRL */ +#define CPC_MBIAS_HND TSC2101_BIT(15) +#define CPC_MBIAS_HED TSC2101_BIT(14) +#define CPC_ASTPWD TSC2101_BIT(13) +#define CPC_SP1PWDN TSC2101_BIT(12) +#define CPC_SP2PWDN TSC2101_BIT(11) +#define CPC_DAPWDN TSC2101_BIT(10) +#define CPC_ADPWDN TSC2101_BIT(9) +#define CPC_VGPWDN TSC2101_BIT(8) +#define CPC_COPWDN TSC2101_BIT(7) +#define CPC_LSPWDN TSC2101_BIT(6) +#define CPC_ADPWDF TSC2101_BIT(5) +#define CPC_LDAPWDF TSC2101_BIT(4) +#define CPC_RDAPWDF TSC2101_BIT(3) +#define CPC_ASTPWF TSC2101_BIT(2) +#define CPC_BASSBC TSC2101_BIT(1) +#define CPC_DEEMPF (0x01) + +/* Field masks for TSC2101_AUDIO_CTRL_3 */ +#define AC3_DMSVOL(ARG) (((ARG) & 0x03) << 14) +#define AC3_REFFS TSC2101_BIT(13) +#define AC3_DAXFM TSC2101_BIT(12) +#define AC3_SLVMS TSC2101_BIT(11) +#define AC3_ADCOVF TSC2101_BIT(8) +#define AC3_DALOVF TSC2101_BIT(7) +#define AC3_DAROVF TSC2101_BIT(6) +#define AC3_CLPST TSC2101_BIT(3) +#define AC3_REVID(ARG) (((ARG) & 0x07)) + +/* Field masks for TSC2101_PLL_PROG_1 */ +#define PLL1_PLLSEL TSC2101_BIT(15) +#define PLL1_QVAL(ARG) (((ARG) & 0x0F) << 11) +#define PLL1_PVAL(ARG) (((ARG) & 0x07) << 8) +#define PLL1_I_VAL(ARG) (((ARG) & 0x3F) << 2) + +/* Field masks of TSC2101_PLL_PROG_2 */ +#define PLL2_D_VAL(ARG) (((ARG) & 0x3FFF) << 2) + +/* Field masks for TSC2101_AUDIO_CTRL_4 */ +#define AC4_ADSTPD TSC2101_BIT(15) +#define AC4_DASTPD TSC2101_BIT(14) +#define AC4_ASSTPD TSC2101_BIT(13) +#define AC4_CISTPD TSC2101_BIT(12) +#define AC4_BISTPD TSC2101_BIT(11) +#define AC4_AGCHYS(ARG) (((ARG) & 0x03) << 9) +#define AC4_MB_HED(ARG) (((ARG) & 0x03) << 7) +#define AC4_MB_HND TSC2101_BIT(6) +#define AC4_SCPFL TSC2101_BIT(1) + +/* Field masks settings for TSC2101_HANDSET_GAIN_CTRL */ +#define HNGC_ADMUT_HND TSC2101_BIT(15) +#define HNGC_ADPGA_HND(ARG) (((ARG) & 0x7F) << 8) +#define HNGC_AGCTG_HND(ARG) (((ARG) & 0x07) << 5) +#define HNGC_AGCTC_HND(ARG) (((ARG) & 0x0F) << 1) +#define HNGC_AGCEN_HND (0x01) + +/* Field masks settings for TSC2101_BUZZER_GAIN_CTRL */ +#define BGC_MUT_CP TSC2101_BIT(15) +#define BGC_CPGA(ARG) (((ARG) & 0x7F) << 8) +#define BGC_CPGF TSC2101_BIT(7) +#define BGC_MUT_BU TSC2101_BIT(6) +#define BGC_BPGA(ARG) (((ARG) & 0x0F) << 2) +#define BGC_BUGF TSC2101_BIT(1) + +/* Field masks settings for TSC2101_AUDIO_CTRL_5 */ +#define AC5_DIFFIN TSC2101_BIT(15) +#define AC5_DAC2SPK1(ARG) (((ARG) & 0x03) << 13) +#define AC5_AST2SPK1 TSC2101_BIT(12) +#define AC5_BUZ2SPK1 TSC2101_BIT(11) +#define AC5_KCL2SPK1 TSC2101_BIT(10) +#define AC5_CPI2SPK1 TSC2101_BIT(9) +#define AC5_DAC2SPK2(ARG) (((ARG) & 0x03) << 7) +#define AC5_AST2SPK2 TSC2101_BIT(6) +#define AC5_BUZ2SPK2 TSC2101_BIT(5) +#define AC5_KCL2SPK2 TSC2101_BIT(4) +#define AC5_CPI2SPK2 TSC2101_BIT(3) +#define AC5_MUTSPK1 TSC2101_BIT(2) +#define AC5_MUTSPK2 TSC2101_BIT(1) +#define AC5_HDSCPTC (0x01) + +/* Field masks settings for TSC2101_AUDIO_CTRL_6 */ +#define AC6_SPL2LSK TSC2101_BIT(15) +#define AC6_AST2LSK TSC2101_BIT(14) +#define AC6_BUZ2LSK TSC2101_BIT(13) +#define AC6_KCL2LSK TSC2101_BIT(12) +#define AC6_CPI2LSK TSC2101_BIT(11) +#define AC6_MIC2CPO TSC2101_BIT(10) +#define AC6_SPL2CPO TSC2101_BIT(9) +#define AC6_SPR2CPO TSC2101_BIT(8) +#define AC6_MUTLSPK TSC2101_BIT(7) +#define AC6_MUTSPK2 TSC2101_BIT(6) +#define AC6_LDSCPTC TSC2101_BIT(5) +#define AC6_VGNDSCPTC TSC2101_BIT(4) +#define AC6_CAPINTF TSC2101_BIT(3) + +/* Field masks settings for TSC2101_AUDIO_CTRL_7 */ +#define AC7_DETECT TSC2101_BIT(15) +#define AC7_HESTYPE(ARG) (((ARG) & 0x03) << 13) +#define AC7_HDDETFL TSC2101_BIT(12) +#define AC7_BDETFL TSC2101_BIT(11) +#define AC7_HDDEBNPG(ARG) (((ARG) & 0x03) << 9) +#define AC7_BDEBNPG(ARG) (((ARG) & 0x03) << 6) +#define AC7_DGPIO2 TSC2101_BIT(4) +#define AC7_DGPIO1 TSC2101_BIT(3) +#define AC7_CLKGPIO2 TSC2101_BIT(2) +#define AC7_ADWSF(ARG) (((ARG) & 0x03)) + +/* Field masks settings for TSC2101_GPIO_CTRL */ +#define GC_GPO2EN TSC2101_BIT(15) +#define GC_GPO2SG TSC2101_BIT(14) +#define GC_GPI2EN TSC2101_BIT(13) +#define GC_GPI2SGF TSC2101_BIT(12) +#define GC_GPO1EN TSC2101_BIT(11) +#define GC_GPO1SG TSC2101_BIT(10) +#define GC_GPI1EN TSC2101_BIT(9) +#define GC_GPI1SGF TSC2101_BIT(8) + +/* Field masks for TSC2101_AGC_CTRL */ +#define AC_AGCNF_CELL TSC2101_BIT(14) +#define AC_AGCNL(ARG) (((ARG) & 0x07) << 11) +#define AC_AGCHYS_CELL(ARG) (((ARG) & 0x03) << 9) +#define AC_CLPST_CELL TSC2101_BIT(8) +#define AC_AGCTG_CELL(ARG) (((ARG) & 0x07) << 5) +#define AC_AGCTC_CELL(ARG) (((ARG) & 0x0F) << 1) +#define AC_AGCEN_CELL (0x01) + +/* Field masks for TSC2101_POWERDOWN_STS */ +#define PS_SPK1FL TSC2101_BIT(15) +#define PS_SPK2FL TSC2101_BIT(14) +#define PS_HNDFL TSC2101_BIT(13) +#define PS_VGNDFL TSC2101_BIT(12) +#define PS_LSPKFL TSC2101_BIT(11) +#define PS_CELLFL TSC2101_BIT(10) +#define PS_PSEQ TSC2101_BIT(5) +#define PS_PSTIME TSC2101_BIT(4) + +/* Field masks for Register Mic AGC Control */ +#define MAC_MMPGA(ARG) (((ARG) & 0x7F) << 9) +#define MAC_MDEBNS(ARG) (((ARG) & 0x07) << 6) +#define MAC_MDEBSN(ARG) (((ARG) & 0x07) << 3) + +/* Field masks for Register Cellphone AGC Control */ +#define CAC_CMPGA(ARG) (((ARG) & 0x7F) << 9) +#define CAC_CDEBNS(ARG) (((ARG) & 0x07) << 6) +#define CAC_CDEBSN(ARG) (((ARG) & 0x07) << 3) + +#endif /* __ASM_HARDWARE_TSC2101_H */ diff -Nru a/include/asm-arm/mach/dyn_tick.h b/include/asm-arm/mach/dyn_tick.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/include/asm-arm/mach/dyn_tick.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,57 @@ +/* + * linux/include/asm-arm/mach/dyn_tick.h + * + * Dynamic Tick Timer + * + * Copyright (C) 2004 Nokia Corporation + * Written by Tony Lindgen and + * Tuukka Tikkanen + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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. + */ + +#ifndef __ASM_ARM_MACH_DYN_TICK_H +#define __ASM_ARM_MACH_DYN_TICK_H + +#define DYN_TICK_ENABLED (1 << 0) + +/* + * Interface for system specific dynamic tick timer hardware functions + */ +struct dyn_tick_timer { + int (*enable)(void); /* Enables dynamic tick */ + int (*disable)(void); /* Disables dynamic tick */ + void (*reprogram)(void); /* Reprograms the timer */ + unsigned int state; /* Enabled or disabled */ +}; + +#define DYN_TICK_INT_ENABLED (1 << 0) + +/* + * Interface for calling timer interrupt from other interrupts as well + */ +struct dyn_tick_timer_int { + int skip; /* Timer interrupt to skip */ + int (*handler)(int irq, void *dev_id, struct pt_regs *regs); + int state; /* Enabled or disabled */ +}; + +#endif diff -Nru a/include/asm-arm/mach/time.h b/include/asm-arm/mach/time.h --- a/include/asm-arm/mach/time.h 2005-03-02 10:51:31 -08:00 +++ b/include/asm-arm/mach/time.h 2005-03-02 10:51:31 -08:00 @@ -39,6 +39,13 @@ void (*suspend)(void); void (*resume)(void); unsigned long (*offset)(void); + +#ifdef CONFIG_NO_IDLE_HZ + struct dyn_tick_timer *dyn_tick; + struct dyn_tick_timer_int *dyn_tick_int; + struct dyn_tick_timer_idle *dyn_tick_idle; +#endif + }; extern struct sys_timer *system_timer; diff -Nru a/include/asm-arm/setup.h b/include/asm-arm/setup.h --- a/include/asm-arm/setup.h 2005-03-02 10:51:31 -08:00 +++ b/include/asm-arm/setup.h 2005-03-02 10:51:31 -08:00 @@ -134,6 +134,13 @@ u8 adfsdrives; }; +/* TI OMAP specific information */ +#define ATAG_OMAP 0x414f4d50 + +struct tag_omap { + u8 data[0]; +}; + /* footbridge memory clock, see arch/arm/mach-footbridge/arch.c */ #define ATAG_MEMCLK 0x41000402 @@ -158,6 +165,11 @@ * Acorn specific */ struct tag_acorn acorn; + + /* + * OMAP specific + */ + struct tag_omap omap; /* * DC21285 specific diff -Nru a/include/linux/fb.h b/include/linux/fb.h --- a/include/linux/fb.h 2005-03-02 10:51:31 -08:00 +++ b/include/linux/fb.h 2005-03-02 10:51:31 -08:00 @@ -103,6 +103,7 @@ #define FB_ACCEL_SIS_GLAMOUR_2 40 /* SiS 315, 650, 740 */ #define FB_ACCEL_SIS_XABRE 41 /* SiS 330 ("Xabre") */ #define FB_ACCEL_I830 42 /* Intel 830M/845G/85x/865G */ +#define FB_ACCEL_OMAP1610 42 /* TI OMAP16xx */ #define FB_ACCEL_NEOMAGIC_NM2070 90 /* NeoMagic NM2070 */ #define FB_ACCEL_NEOMAGIC_NM2090 91 /* NeoMagic NM2090 */ diff -Nru a/init/do_mounts.c b/init/do_mounts.c --- a/init/do_mounts.c 2005-03-02 10:51:31 -08:00 +++ b/init/do_mounts.c 2005-03-02 10:51:31 -08:00 @@ -287,6 +287,7 @@ char *fs_names = __getname(); char *p; char b[BDEVNAME_SIZE]; + int i = 0; get_fs_names(fs_names); retry: @@ -301,6 +302,14 @@ case -EINVAL: continue; } + + printk("VFS: No root yet, retrying to mount root on %s (%s)\n", + root_device_name, __bdevname(ROOT_DEV, b)); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(10 * HZ); + if (i++ < 5) + goto retry; + /* * Allow the user to distinguish between failed sys_open * and bad superblock on root device. diff -Nru a/kernel/printk.c b/kernel/printk.c --- a/kernel/printk.c 2005-03-02 10:51:31 -08:00 +++ b/kernel/printk.c 2005-03-02 10:51:31 -08:00 @@ -36,6 +36,10 @@ #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) +#ifdef CONFIG_DEBUG_LL +extern void printascii(char *); +#endif + /* printk's without a loglevel use this.. */ #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */ @@ -540,6 +544,10 @@ /* Emit the output into the temporary buffer */ printed_len = vscnprintf(printk_buf, sizeof(printk_buf), fmt, args); + +#ifdef CONFIG_DEBUG_LL + printascii(printk_buf); +#endif /* * Copy the output into log_buf. If the caller didn't provide diff -Nru a/sound/oss/Kconfig b/sound/oss/Kconfig --- a/sound/oss/Kconfig 2005-03-02 10:51:31 -08:00 +++ b/sound/oss/Kconfig 2005-03-02 10:51:31 -08:00 @@ -4,6 +4,33 @@ # More hacking for modularisation. # # Prompt user for primary drivers. +config SOUND_OMAP + tristate "OMAP Sound Driver" + depends on SOUND_PRIME!=n && SOUND + ---help--- + OMAP Audio driver + +config SOUND_OMAP_TSC2101 + tristate "TSC2101 Stereo Codec" + depends on SOUND_OMAP && ( MACH_OMAP_H2 || MACH_OMAP_H3 ) + select OMAP_TSC2101 + select OMAP_UWIRE if ARCH_OMAP + ---help--- + Tsc2101 Audio Codec Driver for OMAP will be enabled. + Will also Enable the following: + 1. uWire Driver based on Platform + 2. TSC2101 Glue driver + +config SOUND_OMAP_AIC23 + tristate "AIC23 Stereo Codec" + depends on SOUND_OMAP && ( MACH_OMAP_INNOVATOR || MACH_OMAP_OSK ) + select OMAP_DSP if ARCH_OMAP + select SENSORS_TLV320AIC23 if ARCH_OMAP + ---help--- + AIC23 Audio Codec Driver for OMAP will be enabled. + This will also enable OMAP DSP support because McBSP needed for + this is a DSP peripheral. Additionally, AIC23 I2C support is enabled. + config SOUND_BT878 tristate "BT878 audio dma" depends on SOUND_PRIME!=n && SOUND diff -Nru a/sound/oss/Makefile b/sound/oss/Makefile --- a/sound/oss/Makefile 2005-03-02 10:51:31 -08:00 +++ b/sound/oss/Makefile 2005-03-02 10:51:31 -08:00 @@ -8,6 +8,10 @@ obj-$(CONFIG_SOUND_OSS) += sound.o obj-$(CONFIG_SOUND_CS4232) += cs4232.o ad1848.o +obj-$(CONFIG_SOUND_OMAP) += omap-audio-dma-intfc.o omap-audio.o +obj-$(CONFIG_SOUND_OMAP_TSC2101)+= omap-audio-tsc2101.o +obj-$(CONFIG_SOUND_OMAP_AIC23) += omap-audio-aic23.o + # Please leave it as is, cause the link order is significant ! obj-$(CONFIG_SOUND_SH_DAC_AUDIO) += sh_dac_audio.o diff -Nru a/sound/oss/omap-audio-aic23.c b/sound/oss/omap-audio-aic23.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/sound/oss/omap-audio-aic23.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,731 @@ +/* + * linux/sound/oss/omap-audio-aic23.c + * + * Glue audio driver for TI TLV320AIC23 codec + * + * Copyright (c) 2000 Nicolas Pitre + * Copyright (C) 2001, Steve Johnson + * Copyright (C) 2004 Texas Instruments, Inc. + * Copyright (C) 2005 Dirk Behme + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "omap-audio.h" +#include "omap-audio-dma-intfc.h" + +#ifdef CONFIG_PROC_FS +#include +#define PROC_START_FILE "driver/aic23-audio-start" +#define PROC_STOP_FILE "driver/aic23-audio-stop" +#endif + +//#define DEBUG + +#ifdef DEBUG +#define DPRINTK(ARGS...) printk("<%s>: ",__FUNCTION__);printk(ARGS) +#else +#define DPRINTK( x... ) +#endif + +#define CODEC_NAME "AIC23" + +#if CONFIG_MACH_OMAP_OSK +#define PLATFORM_NAME "OMAP OSK" +#elif CONFIG_MACH_OMAP_INNOVATOR +#define PLATFORM_NAME "OMAP INNOVATOR" +#else +#error "Unsupported plattform" +#endif + +/* Define to set the AIC23 as the master w.r.t McBSP */ +#define AIC23_MASTER + +#define CODEC_CLOCK 12000000 + +/* + * AUDIO related MACROS + */ +#define DEFAULT_BITPERSAMPLE 16 +#define AUDIO_RATE_DEFAULT 44100 + +/* Select the McBSP For Audio */ +#define AUDIO_MCBSP OMAP_MCBSP1 + +#define REC_MASK (SOUND_MASK_LINE | SOUND_MASK_MIC) +#define DEV_MASK (REC_MASK | SOUND_MASK_VOLUME) + +#define SET_VOLUME 1 +#define SET_LINE 2 + +#define DEFAULT_OUTPUT_VOLUME 93 +#define DEFAULT_INPUT_VOLUME 0 /* 0 ==> mute line in */ + +#define OUTPUT_VOLUME_MIN LHV_MIN +#define OUTPUT_VOLUME_MAX LHV_MAX +#define OUTPUT_VOLUME_RANGE (OUTPUT_VOLUME_MAX - OUTPUT_VOLUME_MIN) +#define OUTPUT_VOLUME_MASK OUTPUT_VOLUME_MAX + +#define INPUT_VOLUME_MIN LIV_MIN +#define INPUT_VOLUME_MAX LIV_MAX +#define INPUT_VOLUME_RANGE (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN) +#define INPUT_VOLUME_MASK INPUT_VOLUME_MAX + +#define NUMBER_SAMPLE_RATES_SUPPORTED 9 + +static audio_stream_t output_stream = { + .id = "AIC23 out", + .dma_dev = OMAP_DMA_MCBSP1_TX, + .input_or_output = FMODE_WRITE +}; + +static audio_stream_t input_stream = { + .id = "AIC23 in", + .dma_dev = OMAP_DMA_MCBSP1_RX, + .input_or_output = FMODE_READ +}; + +static struct clk *aic23_mclk = 0; + +static int audio_dev_id, mixer_dev_id; + +static struct aic23_local_info { + u8 volume; + u16 volume_reg; + u8 line; + u8 mic; + u16 input_volume_reg; + int mod_cnt; +} aic23_local; + +struct sample_rate_reg_info { + u32 sample_rate; + u8 control; /* SR3, SR2, SR1, SR0 and BOSR */ + u8 divider; /* if 0 CLKIN = MCLK, if 1 CLKIN = MCLK/2 */ +}; + +/* To Store the default sample rate */ +static long audio_samplerate = AUDIO_RATE_DEFAULT; + +/* DAC USB-mode sampling rates (MCLK = 12 MHz) */ +static const struct sample_rate_reg_info +reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = { + {96000, 0x0E, 0}, + {88200, 0x1F, 0}, + {48000, 0x00, 0}, + {44100, 0x11, 0}, + {32000, 0x0C, 0}, + {24000, 0x00, 1}, + {16000, 0x0C, 1}, + { 8000, 0x06, 0}, + { 4000, 0x06, 1}, +}; + +static struct omap_mcbsp_reg_cfg initial_config = { + .spcr2 = FREE | FRST | GRST | XRST | XINTM(3), + .spcr1 = RINTM(3) | RRST, + .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) | + RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(1), + .rcr1 = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16), + .xcr2 = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) | + XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(0) | XFIG, + .xcr1 = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16), + .srgr1 = FWID(DEFAULT_BITPERSAMPLE - 1), + .srgr2 = GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1), +#ifndef AIC23_MASTER + /* configure McBSP to be the I2S master */ + .pcr0 = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP, +#else + /* configure McBSP to be the I2S slave */ + .pcr0 = CLKXP | CLKRP, +#endif /* AIC23_MASTER */ +}; + +static void omap_aic23_initialize(void *dummy); +static void omap_aic23_shutdown(void *dummy); +static int omap_aic23_ioctl(struct inode *inode, struct file *file, + uint cmd, ulong arg); +static int omap_aic23_probe(void); +#ifdef MODULE +static void omap_aic23_remove(void); +#endif +static int omap_aic23_suspend(void); +static int omap_aic23_resume(void); +static inline void aic23_configure(void); +static int mixer_open(struct inode *inode, struct file *file); +static int mixer_release(struct inode *inode, struct file *file); +static int mixer_ioctl(struct inode *inode, struct file *file, uint cmd, + ulong arg); + +#ifdef CONFIG_PROC_FS +static int codec_start(char *buf, char **start, off_t offset, int count, + int *eof, void *data); +static int codec_stop(char *buf, char **start, off_t offset, int count, + int *eof, void *data); +#endif + + +/* File Op structure for mixer */ +static struct file_operations omap_mixer_fops = { + .open = mixer_open, + .release = mixer_release, + .ioctl = mixer_ioctl, + .owner = THIS_MODULE +}; + +/* To store characteristic info regarding the codec for the audio driver */ +static audio_state_t aic23_state = { + .output_stream = &output_stream, + .input_stream = &input_stream, +/* .need_tx_for_rx = 1, //Once the Full Duplex works */ + .need_tx_for_rx = 0, + .hw_init = omap_aic23_initialize, + .hw_shutdown = omap_aic23_shutdown, + .client_ioctl = omap_aic23_ioctl, + .hw_probe = omap_aic23_probe, + .hw_remove = __exit_p(omap_aic23_remove), + .hw_suspend = omap_aic23_suspend, + .hw_resume = omap_aic23_resume, + .sem = __MUTEX_INITIALIZER(aic23_state.sem), +}; + +/* This will be defined in the audio.h */ +static struct file_operations *omap_audio_fops; + +extern int tlv320aic23_write_value(u8 reg, u16 value); + +/* TLV320AIC23 is a write only device */ +static __inline__ void audio_aic23_write(u8 address, u16 data) +{ + tlv320aic23_write_value(address, data); +} + +static int aic23_update(int flag, int val) +{ + u16 volume; + + /* Ignore separate left/right channel for now, + even the codec does support it. */ + val &= 0xff; + + if (val < 0 || val > 100) { + printk(KERN_ERR "Trying a bad volume value(%d)!\n",val); + return -EPERM; + } + + switch (flag) { + case SET_VOLUME: + // Convert 0 -> 100 volume to 0x00 (LHV_MIN) -> 0x7f (LHV_MAX) + // volume range + volume = ((val * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MIN; + + // R/LHV[6:0] 1111111 (+6dB) to 0000000 (-73dB) in 1db steps, + // default 1111001 (0dB) + aic23_local.volume_reg &= ~OUTPUT_VOLUME_MASK; + aic23_local.volume_reg |= volume; + audio_aic23_write(LEFT_CHANNEL_VOLUME_ADDR, aic23_local.volume_reg); + audio_aic23_write(RIGHT_CHANNEL_VOLUME_ADDR, aic23_local.volume_reg); + break; + + case SET_LINE: + // Convert 0 -> 100 volume to 0x0 (LIV_MIN) -> 0x1f (LIV_MAX) + // volume range + volume = ((val * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN; + + // R/LIV[4:0] 11111 (+12dB) to 00000 (-34.5dB) in 1.5dB steps, + // default 10111 (0dB) + aic23_local.input_volume_reg &= ~INPUT_VOLUME_MASK; + aic23_local.input_volume_reg |= volume; + audio_aic23_write(LEFT_LINE_VOLUME_ADDR, aic23_local.input_volume_reg); + audio_aic23_write(RIGHT_LINE_VOLUME_ADDR, aic23_local.input_volume_reg); + break; + } + return 0; +} + +static int mixer_open(struct inode *inode, struct file *file) +{ + /* Any mixer specific initialization */ + + return 0; +} + +static int mixer_release(struct inode *inode, struct file *file) +{ + /* Any mixer specific Un-initialization */ + + return 0; +} + +static int +mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) +{ + int val; + int ret = 0; + int nr = _IOC_NR(cmd); + + /* + * We only accept mixer (type 'M') ioctls. + */ + if (_IOC_TYPE(cmd) != 'M') + return -EINVAL; + + DPRINTK(" 0x%08x\n", cmd); + + if (cmd == SOUND_MIXER_INFO) { + struct mixer_info mi; + + strncpy(mi.id, "AIC23", sizeof(mi.id)); + strncpy(mi.name, "TI AIC23", sizeof(mi.name)); + mi.modify_counter = aic23_local.mod_cnt; + return copy_to_user((void *)arg, &mi, sizeof(mi)); + } + + if (_IOC_DIR(cmd) & _IOC_WRITE) { + ret = get_user(val, (int *)arg); + if (ret) + goto out; + + + switch (nr) { + case SOUND_MIXER_VOLUME: + aic23_local.volume = val; + aic23_local.mod_cnt++; + ret = aic23_update(SET_VOLUME, val); + break; + + case SOUND_MIXER_LINE: + aic23_local.line = val; + aic23_local.mod_cnt++; + ret = aic23_update(SET_LINE, val); + break; + + case SOUND_MIXER_MIC: + aic23_local.mic = val; + aic23_local.mod_cnt++; + ret = aic23_update(SET_LINE, val); + break; + + case SOUND_MIXER_RECSRC: + break; + + default: + ret = -EINVAL; + } + } + + if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) { + ret = 0; + + switch (nr) { + case SOUND_MIXER_VOLUME: + val = aic23_local.volume; + break; + case SOUND_MIXER_LINE: + val = aic23_local.line; + break; + case SOUND_MIXER_MIC: + val = aic23_local.mic; + break; + case SOUND_MIXER_RECSRC: + val = REC_MASK; + break; + case SOUND_MIXER_RECMASK: + val = REC_MASK; + break; + case SOUND_MIXER_DEVMASK: + val = DEV_MASK; + break; + case SOUND_MIXER_CAPS: + val = 0; + break; + case SOUND_MIXER_STEREODEVS: + val = 0; + break; + default: + val = 0; + ret = -EINVAL; + break; + } + + if (ret == 0) + ret = put_user(val, (int *)arg); + } +out: + return ret; + +} + +int omap_set_samplerate(long sample_rate) +{ + u8 count = 0; + u16 data = 0; + /* wait for any frame to complete */ + udelay(125); + + /* Search for the right sample rate */ + while ((reg_info[count].sample_rate != sample_rate) && + (count < NUMBER_SAMPLE_RATES_SUPPORTED)) { + count++; + } + if (count == NUMBER_SAMPLE_RATES_SUPPORTED) { + printk(KERN_ERR "Invalid Sample Rate %d requested\n", + (int)sample_rate); + return -EPERM; + } + + if (machine_is_omap_innovator()) { + /* set the CODEC clock input source to 12.000MHz */ + fpga_write(fpga_read(OMAP1510_FPGA_POWER) & ~0x01, + OMAP1510_FPGA_POWER); + } + + data = (reg_info[count].divider << CLKIN_SHIFT) | + (reg_info[count].control << BOSR_SHIFT) | USB_CLK_ON; + + audio_aic23_write(SAMPLE_RATE_CONTROL_ADDR, data); + + audio_samplerate = sample_rate; + +#ifndef AIC23_MASTER + { + int clkgdv = 0; + /* + Set Sample Rate at McBSP + + Formula : + Codec System Clock = CODEC_CLOCK, or half if clock_divider = 1; + clkgdv = ((Codec System Clock / (SampleRate * BitsPerSample * 2)) - 1); + + FWID = BitsPerSample - 1; + FPER = (BitsPerSample * 2) - 1; + */ + if (reg_info[count].divider) + clkgdv = CODEC_CLOCK / 2; + else + clkgdv = CODEC_CLOCK; + + clkgdv = (clkgdv / (sample_rate * DEFAULT_BITPERSAMPLE * 2)) - 1; + + initial_config.srgr1 = (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv)); + + initial_config.srgr2 = + (CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)); + + omap_mcbsp_config(AUDIO_MCBSP, &initial_config); + } +#endif /* AIC23_MASTER */ + + return 0; +} + +static void omap_aic23_initialize(void *dummy) +{ + DPRINTK("entry\n"); + + /* initialize with default sample rate */ + audio_samplerate = AUDIO_RATE_DEFAULT; + + omap_mcbsp_request(AUDIO_MCBSP); + + /* if configured, then stop mcbsp */ + omap_mcbsp_stop(AUDIO_MCBSP); + + omap_mcbsp_config(AUDIO_MCBSP, &initial_config); + omap_mcbsp_start(AUDIO_MCBSP); + aic23_configure(); + + DPRINTK("exit\n"); +} + +static void omap_aic23_shutdown(void *dummy) +{ + /* + Turn off codec after it is done. + Can't do it immediately, since it may still have + buffered data. + + Wait 20ms (arbitrary value) and then turn it off. + */ + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(2); + + omap_mcbsp_stop(AUDIO_MCBSP); + omap_mcbsp_free(AUDIO_MCBSP); + + audio_aic23_write(RESET_CONTROL_ADDR, 0); + audio_aic23_write(POWER_DOWN_CONTROL_ADDR, 0xff); +} + +static inline void aic23_configure() +{ + /* Reset codec */ + audio_aic23_write(RESET_CONTROL_ADDR, 0); + + /* Initialize the AIC23 internal state */ + + /* Left/Right line input volume control */ + aic23_local.line = DEFAULT_INPUT_VOLUME; + aic23_local.mic = DEFAULT_INPUT_VOLUME; + aic23_update(SET_LINE, DEFAULT_INPUT_VOLUME); + + /* Left/Right headphone channel volume control */ + /* Zero-cross detect on */ + aic23_local.volume_reg = LZC_ON; + aic23_update(SET_VOLUME, aic23_local.volume); + + /* Analog audio path control, DAC selected, delete INSEL_MIC for line in */ + audio_aic23_write(ANALOG_AUDIO_CONTROL_ADDR, DAC_SELECTED | INSEL_MIC); + + /* Digital audio path control, de-emphasis control 44.1kHz */ + audio_aic23_write(DIGITAL_AUDIO_CONTROL_ADDR, DEEMP_44K); + + /* Power control, everything is on */ + audio_aic23_write(POWER_DOWN_CONTROL_ADDR, 0); + + /* Digital audio interface, master/slave mode, I2S, 16 bit */ +#ifdef AIC23_MASTER + audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR, MS_MASTER | IWL_16 | FOR_DSP); +#else + audio_aic23_write(DIGITAL_AUDIO_FORMAT_ADDR, IWL_16 | FOR_DSP); +#endif /* AIC23_MASTER */ + + /* Enable digital interface */ + audio_aic23_write(DIGITAL_INTERFACE_ACT_ADDR, ACT_ON); + + /* clock configuration */ + omap_set_samplerate(audio_samplerate); +} + +static int +omap_aic23_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) +{ + long val; + int ret = 0; + + DPRINTK(" 0x%08x\n", cmd); + + /* + * These are platform dependent ioctls which are not handled by the + * generic omap-audio module. + */ + switch (cmd) { + case SNDCTL_DSP_STEREO: + ret = get_user(val, (int *)arg); + if (ret) + return ret; + /* the AIC23 is stereo only */ + ret = (val == 0) ? -EINVAL : 1; + return put_user(ret, (int *)arg); + + case SNDCTL_DSP_CHANNELS: + case SOUND_PCM_READ_CHANNELS: + /* the AIC23 is stereo only */ + return put_user(2, (long *)arg); + + case SNDCTL_DSP_SPEED: + ret = get_user(val, (long *)arg); + if (ret) + break; + ret = omap_set_samplerate(val); + if (ret) + break; + /* fall through */ + + case SOUND_PCM_READ_RATE: + return put_user(audio_samplerate, (long *)arg); + + case SOUND_PCM_READ_BITS: + case SNDCTL_DSP_SETFMT: + case SNDCTL_DSP_GETFMTS: + /* we can do 16-bit only */ + 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 ret; +} + +static int omap_aic23_probe(void) +{ + /* Get the fops from audio oss driver */ + if (!(omap_audio_fops = audio_get_fops())) { + printk(KERN_ERR "Unable to get the file operations for AIC23 OSS driver\n"); + audio_unregister_codec(&aic23_state); + return -EPERM; + } + + aic23_local.volume = DEFAULT_OUTPUT_VOLUME; + + /* register devices */ + audio_dev_id = register_sound_dsp(omap_audio_fops, -1); + mixer_dev_id = register_sound_mixer(&omap_mixer_fops, -1); + +#ifdef CONFIG_PROC_FS + create_proc_read_entry(PROC_START_FILE, 0 /* default mode */ , + NULL /* parent dir */ , + codec_start, NULL /* client data */ ); + + create_proc_read_entry(PROC_STOP_FILE, 0 /* default mode */ , + NULL /* parent dir */ , + codec_stop, NULL /* client data */ ); +#endif + + /* Announcement Time */ + printk(KERN_INFO PLATFORM_NAME " " CODEC_NAME + " audio support initialized\n"); + return 0; +} + +#ifdef MODULE +static void __exit omap_aic23_remove(void) +{ + /* Un-Register the codec with the audio driver */ + unregister_sound_dsp(audio_dev_id); + unregister_sound_mixer(mixer_dev_id); + +#ifdef CONFIG_PROC_FS + remove_proc_entry(PROC_START_FILE, NULL); + remove_proc_entry(PROC_STOP_FILE, NULL); +#endif +} +#endif /* MODULE */ + +static int omap_aic23_suspend(void) +{ + /* Empty for the moment */ + return 0; +} + +static int omap_aic23_resume(void) +{ + /* Empty for the moment */ + return 0; +} + +static int __init audio_aic23_init(void) +{ + + int err = 0; + + if (machine_is_omap_osk()) { + /* Set MCLK to be clock input for AIC23 */ + aic23_mclk = clk_get(0, "mclk"); + + if(clk_get_rate( aic23_mclk) != CODEC_CLOCK){ + /* MCLK ist not at CODEC_CLOCK */ + if( clk_get_usecount(aic23_mclk) > 0 ){ + /* MCLK is already in use */ + printk(KERN_WARNING "MCLK in use at %d Hz. We change it to %d Hz\n", + (uint)clk_get_rate( aic23_mclk), CODEC_CLOCK); + } + if( clk_set_rate( aic23_mclk, CODEC_CLOCK ) ){ + printk(KERN_ERR "Cannot set MCLK for AIC23 CODEC\n"); + return -ECANCELED; + } + } + + clk_use( aic23_mclk ); + + DPRINTK("MCLK = %d [%d], usecount = %d\n",(uint)clk_get_rate( aic23_mclk ), + CODEC_CLOCK, clk_get_usecount( aic23_mclk)); + } + + if (machine_is_omap_innovator()) { + u8 fpga; + /* + Turn on chip select for CODEC (shared with touchscreen). + Don't turn it back off, in case touch screen needs it. + */ + fpga = fpga_read(OMAP1510_FPGA_TOUCHSCREEN); + fpga |= 0x4; + fpga_write(fpga, OMAP1510_FPGA_TOUCHSCREEN); + } + + /* register the codec with the audio driver */ + if ((err = audio_register_codec(&aic23_state))) { + printk(KERN_ERR + "Failed to register AIC23 driver with Audio OSS Driver\n"); + } + + return err; +} + +static void __exit audio_aic23_exit(void) +{ + (void)audio_unregister_codec(&aic23_state); + return; +} + +#ifdef CONFIG_PROC_FS +static int codec_start(char *buf, char **start, off_t offset, int count, + int *eof, void *data) +{ + void *foo = NULL; + + omap_aic23_initialize(foo); + + printk("AIC23 codec initialization done.\n"); + return 0; +} +static int codec_stop(char *buf, char **start, off_t offset, int count, + int *eof, void *data) +{ + void *foo = NULL; + + omap_aic23_shutdown(foo); + + printk("AIC23 codec shutdown.\n"); + return 0; +} +#endif /* CONFIG_PROC_FS */ + +module_init(audio_aic23_init); +module_exit(audio_aic23_exit); + +MODULE_AUTHOR("Dirk Behme "); +MODULE_DESCRIPTION("Glue audio driver for the TI AIC23 codec."); +MODULE_LICENSE("GPL"); diff -Nru a/sound/oss/omap-audio-dma-intfc.c b/sound/oss/omap-audio-dma-intfc.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/sound/oss/omap-audio-dma-intfc.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,918 @@ +/* + * linux/sound/oss/omap-audio-dma-intfc.c + * + * Common audio DMA handling for the OMAP processors + * + * Copyright (C) 2004 Texas Instruments, Inc. + * + * Copyright (C) 2000, 2001 Nicolas Pitre + * + * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * History: + * + * 2004-06-07 Sriram Kannan - Created new file from omap_audio_dma_intfc.c. This file + * will contain only the DMA interface and buffer handling of OMAP + * audio driver. + * + * 2004-06-22 Sriram Kannan - removed legacy code (auto-init). Self-linking of DMA logical channel. + * + * 2004-08-12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms + * + * 2004-11-01 Nishanth Menon - 16xx platform code base modified to support multi channel chaining. + * + * 2004-12-15 Nishanth Menon - Improved 16xx platform channel logic introduced - tasklets, queue handling updated + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include "omap-audio-dma-intfc.h" + +#include + +#include "omap-audio.h" + +#undef DEBUG +//#define DEBUG +#ifdef DEBUG +#define DPRINTK(ARGS...) printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS) +#define FN_IN printk(KERN_INFO "[%s]: start\n", __FUNCTION__) +#define FN_OUT(n) printk(KERN_INFO "[%s]: end(%u)\n",__FUNCTION__, n) +#else + +#define DPRINTK( x... ) +#define FN_IN +#define FN_OUT(x) +#endif + +#define ERR(ARGS...) printk(KERN_ERR "{%s}-ERROR: ", __FUNCTION__);printk(ARGS); + +#define AUDIO_NAME "omap-audio" +#define AUDIO_NBFRAGS_DEFAULT 8 +#define AUDIO_FRAGSIZE_DEFAULT 8192 + +#define AUDIO_ACTIVE(state) ((state)->rd_ref || (state)->wr_ref) + +#define SPIN_ADDR (dma_addr_t)0 +#define SPIN_SIZE 2048 + +#define NUMBER_OF_CHANNELS_TO_LINK 2 + +/* Channel Queue Handling macros + * tail always points to the current free entry + * Head always points to the current entry being used + * end is either head or tail + */ +#define AUDIO_QUEUE_INIT(s) s->dma_q_head = s->dma_q_tail = s->dma_q_count = 0; +#define AUDIO_QUEUE_FULL(s) (NUMBER_OF_CHANNELS_TO_LINK == s->dma_q_count) +#define AUDIO_QUEUE_EMPTY(s) (0 == s->dma_q_count) +#define __AUDIO_INCREMENT_QUEUE(end) ((end)=((end)+1)%NUMBER_OF_CHANNELS_TO_LINK) +#define AUDIO_INCREMENT_HEAD(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_head); s->dma_q_count--; +#define AUDIO_INCREMENT_TAIL(s) __AUDIO_INCREMENT_QUEUE(s->dma_q_tail); s->dma_q_count++; + +/* DMA buffer fragmentation sizes */ +#define MAX_DMA_SIZE 0x1000000 +#define CUT_DMA_SIZE 0x1000 +/* TODO: To be moved to more appropriate location */ +#define DCSR_ERROR 0x3 +#define DCSR_SYNC_SET (1 << 6) + +#define DCCR_FS (1 << 5) +#define DCCR_PRIO (1 << 6) +#define DCCR_EN (1 << 7) +#define DCCR_AI (1 << 8) +#define DCCR_REPEAT (1 << 9) +/* if 0 the channel works in 3.1 compatible mode*/ +#define DCCR_N31COMP (1 << 10) +#define DCCR_EP (1 << 11) +#define DCCR_SRC_AMODE_BIT 12 +#define DCCR_SRC_AMODE_MASK (0x3<<12) +#define DCCR_DST_AMODE_BIT 14 +#define DCCR_DST_AMODE_MASK (0x3<<14) +#define AMODE_CONST 0x0 +#define AMODE_POST_INC 0x1 +#define AMODE_SINGLE_INDEX 0x2 +#define AMODE_DOUBLE_INDEX 0x3 + +/**************************** DATA STRUCTURES *****************************************/ + +static spinlock_t dma_list_lock = SPIN_LOCK_UNLOCKED; + +struct audio_isr_work_item { + int current_lch; + u16 ch_status; + audio_stream_t *s; +}; + +static char work_item_running = 0; +static struct audio_isr_work_item work1, work2; + + +/*********************************** MODULE SPECIFIC FUNCTIONS PROTOTYPES *************/ + +static void audio_dsr_handler(unsigned long); +DECLARE_TASKLET(audio_isr_work1, audio_dsr_handler, (unsigned long)&work1); +DECLARE_TASKLET(audio_isr_work2, audio_dsr_handler, (unsigned long)&work2); + +static void sound_dma_irq_handler(int lch, u16 ch_status, void *data); +static void audio_dma_callback(int lch, u16 ch_status, void *data); +static int omap_start_sound_dma(audio_stream_t * s, dma_addr_t dma_ptr, + u_int size); +static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr, + u_int dma_size); +static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr, + u_int dma_size); +static int audio_start_dma_chain(audio_stream_t * s); + +/*********************************** GLOBAL FUNCTIONS DEFINTIONS ***********************/ + +/*************************************************************************************** + * + * Buffer creation/destruction + * + **************************************************************************************/ +int audio_setup_buf(audio_stream_t * s) +{ + int frag; + int dmasize = 0; + char *dmabuf = NULL; + dma_addr_t dmaphys = 0; + FN_IN; + if (s->buffers) { + FN_OUT(1); + return -EBUSY; + } + s->buffers = kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL); + if (!s->buffers) + goto err; + memset(s->buffers, 0, sizeof(audio_buf_t) * s->nbfrags); + 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 allocate more smaller buffers. + */ + if (!dmasize) { + dmasize = (s->nbfrags - frag) * s->fragsize; + do { + dmabuf = + dma_alloc_coherent(NULL, dmasize, &dmaphys, + 0); + if (!dmabuf) + dmasize -= s->fragsize; + } + while (!dmabuf && dmasize); + if (!dmabuf) + goto err; + b->master = dmasize; + memzero(dmabuf, dmasize); + } + b->data = dmabuf; + b->dma_addr = dmaphys; + dmabuf += s->fragsize; + dmaphys += s->fragsize; + dmasize -= s->fragsize; + } + s->usr_head = s->dma_head = s->dma_tail = 0; + AUDIO_QUEUE_INIT(s); + s->started = 0; + s->bytecount = 0; + s->fragcount = 0; + s->prevbuf = 0; + sema_init(&s->sem, s->nbfrags); + FN_OUT(0); + return 0; + err: + audio_discard_buf(s); + FN_OUT(1); + return -ENOMEM; +} + +void audio_discard_buf(audio_stream_t * s) +{ + FN_IN; + /* ensure DMA isn't using those buffers */ + audio_reset(s); + if (s->buffers) { + int frag; + for (frag = 0; frag < s->nbfrags; frag++) { + if (!s->buffers[frag].master) + continue; + dma_free_coherent(NULL, + s->buffers[frag].master, + s->buffers[frag].data, + s->buffers[frag].dma_addr); + } + kfree(s->buffers); + s->buffers = NULL; + } + FN_OUT(0); +} + +/*************************************************************************************** + * + * DMA channel requests + * + **************************************************************************************/ +int +omap_request_sound_dma(int device_id, const char *device_name, void *data, + int **channels) +{ + int i, err = 0; + int *chan = NULL; + FN_IN; + if (unlikely((NULL == channels) || (NULL == device_name))) { + BUG(); + return -EPERM; + } + /* Try allocate memory for the num channels */ + *channels = + (int *)kmalloc(sizeof(int) * NUMBER_OF_CHANNELS_TO_LINK, + GFP_KERNEL); + chan = *channels; + if (NULL == chan) { + ERR("No Memory for channel allocs!\n"); + FN_OUT(-ENOMEM); + return -ENOMEM; + } + spin_lock(&dma_list_lock); + for (i = 0; i < NUMBER_OF_CHANNELS_TO_LINK; i++) { + err = + omap_request_dma(device_id, device_name, + sound_dma_irq_handler, data, &chan[i]); + /* Handle Failure condition here */ + if (err < 0) { + int j; + for (j = 0; j < i; j++) { + omap_free_dma(chan[j]); + } + spin_unlock(&dma_list_lock); + kfree(chan); + *channels = NULL; + ERR("Error in requesting channel %d=0x%x\n", i, err); + FN_OUT(err); + return err; + } + } + /* Chain the channels together */ + for (i = 0; i < NUMBER_OF_CHANNELS_TO_LINK; i++) { + int cur_chan = chan[i]; + int nex_chan = + ((NUMBER_OF_CHANNELS_TO_LINK - 1 == + i) ? chan[0] : chan[i + 1]); + omap_dma_link_lch(cur_chan, nex_chan); + } + + spin_unlock(&dma_list_lock); + FN_OUT(0); + return 0; +} + +/*************************************************************************************** + * + * DMA channel requests Freeing + * + **************************************************************************************/ +int omap_free_sound_dma(int **channels) +{ + int i; + int *chan = NULL; + FN_IN; + if (unlikely(NULL == channels)) { + BUG(); + return -EPERM; + } + if (unlikely(NULL == *channels)) { + BUG(); + return -EPERM; + } + chan = (*channels); + for (i = 0; i < NUMBER_OF_CHANNELS_TO_LINK; i++) { + int cur_chan = chan[i]; + int nex_chan = + ((NUMBER_OF_CHANNELS_TO_LINK - 1 == + i) ? chan[0] : chan[i + 1]); + omap_stop_dma(cur_chan); + omap_dma_unlink_lch(cur_chan, nex_chan); + omap_free_dma(cur_chan); + } + kfree(*channels); + *channels = NULL; + FN_OUT(0); + return 0; +} + +/*************************************************************************************** + * + * Process DMA requests - This will end up starting the transfer. Proper fragments of + * Transfers will be initiated. + * + **************************************************************************************/ +int audio_process_dma(audio_stream_t * s) +{ + int ret = 0; + unsigned long flags; + FN_IN; + + /* Dont let the ISR over ride touching the in_use flag */ + local_irq_save(flags); + if (1 == s->in_use) { + local_irq_restore(flags); + ERR("Called again while In Use\n"); + return 0; + } + s->in_use = 1; + local_irq_restore(flags); + + if (s->stopped) + goto spin; + + if (s->dma_spinref > 0 && s->pending_frags) { + s->dma_spinref = 0; + DMA_CLEAR(s); + } + while (s->pending_frags) { + audio_buf_t *b = &s->buffers[s->dma_head]; + u_int dma_size = s->fragsize - b->offset; + if (dma_size > MAX_DMA_SIZE) + dma_size = CUT_DMA_SIZE; + ret = + omap_start_sound_dma(s, b->dma_addr + b->offset, dma_size); + if (ret) { + goto process_out; + } + b->dma_ref++; + b->offset += dma_size; + if (b->offset >= s->fragsize) { + s->pending_frags--; + if (++s->dma_head >= s->nbfrags) + s->dma_head = 0; + } + } + spin: + if (s->spin_idle) { + int spincnt = 0; + ERR("we are spinning\n"); + while (omap_start_sound_dma(s, SPIN_ADDR, SPIN_SIZE) == 0) + spincnt++; + /* + * Note: if there is still a data buffer being + * processed then the ref count is negative. This + * allows for the DMA termination to be accounted in + * the proper order. Of course dma_spinref can't be + * greater than 0 if dma_ref is not 0 since we kill + * the spinning above as soon as there is real data to process. + */ + if (s->buffers && s->buffers[s->dma_tail].dma_ref) + spincnt = -spincnt; + s->dma_spinref += spincnt; + } + + process_out: + s->in_use = 0; + + FN_OUT(ret); + return ret; +} + +/*************************************************************************************** + * + * Prime Rx - Since the recieve buffer has no time limit as to when it would arrive, + * we need to prime it + * + **************************************************************************************/ +void audio_prime_rx(audio_state_t * state) +{ + audio_stream_t *is = state->input_stream; + + FN_IN; + if (state->need_tx_for_rx) { + /* + * With some codecs like the Philips UDA1341 we must ensure + * there is an output stream at any time while recording since + * this is how the UDA1341 gets its clock from the SA1100. + * So while there is no playback data to send, the output DMA + * will spin with all zeroes. We use the cache flush special + * area for that. + */ + state->output_stream->spin_idle = 1; + audio_process_dma(state->output_stream); + } + is->pending_frags = is->nbfrags; + sema_init(&is->sem, 0); + is->active = 1; + audio_process_dma(is); + + FN_OUT(0); + return; +} + +/*************************************************************************************** + * + * set the fragment size + * + **************************************************************************************/ +int audio_set_fragments(audio_stream_t * s, int val) +{ + FN_IN; + if (s->active) + return -EBUSY; + if (s->buffers) + audio_discard_buf(s); + s->nbfrags = (val >> 16) & 0x7FFF; + val &= 0xFFFF; + if (val < 4) + val = 4; + if (val > 15) + val = 15; + s->fragsize = 1 << val; + if (s->nbfrags < 2) + s->nbfrags = 2; + if (s->nbfrags * s->fragsize > 128 * 1024) + s->nbfrags = 128 * 1024 / s->fragsize; + FN_OUT(0); + if (audio_setup_buf(s)) + return -ENOMEM; + return val | (s->nbfrags << 16); + +} + +/*************************************************************************************** + * + * Sync up the buffers before we shutdown, else under-run errors will happen + * + **************************************************************************************/ +int audio_sync(struct file *file) +{ + audio_state_t *state = file->private_data; + audio_stream_t *s = state->output_stream; + audio_buf_t *b; + u_int shiftval = 0; + unsigned long flags; + + DECLARE_WAITQUEUE(wait, current); + + FN_IN; + + if (!(file->f_mode & FMODE_WRITE) || !s->buffers || s->mapped) { + FN_OUT(1); + return 0; + } + + /* + * Send current buffer if it contains data. Be sure to send + * a full sample count. + */ + b = &s->buffers[s->usr_head]; + if (b->offset &= ~3) { + down(&s->sem); + /* + * HACK ALERT ! + * To avoid increased complexity in the rest of the code + * where full fragment sizes are assumed, we cheat a little + * with the start pointer here and don't forget to restore + * it later. + */ + shiftval = s->fragsize - b->offset; + b->offset = shiftval; + b->dma_addr -= shiftval; + b->data -= shiftval; + local_irq_save(flags); + s->bytecount -= shiftval; + if (++s->usr_head >= s->nbfrags) + s->usr_head = 0; + + s->pending_frags++; + audio_process_dma(s); + local_irq_restore(flags); + } + + /* Let's wait for all buffers to complete */ + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&s->wq, &wait); + while ((s->pending_frags || (atomic_read(&s->sem.count) < s->nbfrags)) + && !signal_pending(current)) { + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&s->wq, &wait); + + /* undo the pointer hack above */ + if (shiftval) { + local_irq_save(flags); + b->dma_addr += shiftval; + b->data += shiftval; + /* ensure sane DMA code behavior if not yet processed */ + if (b->offset != 0) + b->offset = s->fragsize; + local_irq_restore(flags); + } + + FN_OUT(0); + return 0; +} + +/*************************************************************************************** + * + * Stop all the DMA channels of the stream + * + **************************************************************************************/ +void audio_stop_dma(audio_stream_t * s) +{ + int *chan = s->lch; + int i; + FN_IN; + if (unlikely(NULL == chan)) { + BUG(); + return; + } + for (i = 0; i < NUMBER_OF_CHANNELS_TO_LINK; i++) { + int cur_chan = chan[i]; + omap_stop_dma(cur_chan); + } + s->started = 0; + FN_OUT(0); + return; +} + +/*************************************************************************************** + * + * Get the dma posn + * + **************************************************************************************/ +u_int audio_get_dma_pos(audio_stream_t * s) +{ + audio_buf_t *b = &s->buffers[s->dma_tail]; + u_int offset; + + FN_IN; + if (b->dma_ref) { + offset = omap_get_dma_src_pos(s->lch[s->dma_q_head]) - b->dma_addr; + if (offset >= s->fragsize) + offset = s->fragsize - 4; + } else if (s->pending_frags) { + offset = b->offset; + } else { + offset = 0; + } + FN_OUT(offset); + return offset; +} + +/*************************************************************************************** + * + * Reset the audio buffers + * + **************************************************************************************/ +void audio_reset(audio_stream_t * s) +{ + FN_IN; + if (s->buffers) { + audio_stop_dma(s); + s->buffers[s->dma_head].offset = 0; + s->buffers[s->usr_head].offset = 0; + s->usr_head = s->dma_head; + s->pending_frags = s->prevbuf = 0; + sema_init(&s->sem, s->nbfrags); + } + s->active = 0; + s->stopped = 0; + s->started = 0; + FN_OUT(0); + return; +} + +/*************************************************************************************** + * + * Clear any pending transfers + * + **************************************************************************************/ +void omap_clear_sound_dma(audio_stream_t * s) +{ + FN_IN; + omap_clear_dma(s->lch[s->dma_q_head]); + FN_OUT(0); + return; +} + +/*********************************** MODULE FUNCTIONS DEFINTIONS ***********************/ + +#ifdef OMAP1610_MCBSP1_BASE +#undef OMAP1610_MCBSP1_BASE +#endif +#define OMAP1610_MCBSP1_BASE 0xE1011000 + +/*************************************************************************************** + * + * DMA related functions + * + **************************************************************************************/ +static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr, + u_int dma_size) +{ + int dt = 0x1; /* data type 16 */ + int cen = 32; /* Stereo */ + int cfn = dma_size / (2 * cen); + FN_IN; + omap_set_dma_dest_params(channel, 0x05, 0x00, + (OMAP1610_MCBSP1_BASE + 0x806)); + omap_set_dma_src_params(channel, 0x00, 0x01, dma_ptr); + omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00); + FN_OUT(0); + return 0; +} + +static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr, + u_int dma_size) +{ + int dt = 0x1; /* data type 16 */ + int cen = 16; /* mono */ + int cfn = dma_size / (2 * cen); + FN_IN; + omap_set_dma_src_params(channel, 0x05, 0x00, + (OMAP1610_MCBSP1_BASE + 0x802)); + omap_set_dma_dest_params(channel, 0x00, 0x01, dma_ptr); + omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00); + FN_OUT(0); + return 0; +} + +static int audio_start_dma_chain(audio_stream_t * s) +{ + int channel = s->lch[s->dma_q_head]; + FN_IN; + if (!s->started) { + omap_start_dma(channel); + s->started = 1; + } + /* else the dma itself will progress forward with out our help */ + FN_OUT(0); + return 0; +} + +/* Start DMA - + * Do the initial set of work to initialize all the channels as required. + * We shall then initate a transfer + */ +static int omap_start_sound_dma(audio_stream_t * s, dma_addr_t dma_ptr, + u_int dma_size) +{ + int ret = -EPERM; + + FN_IN; + if (unlikely(dma_size > MAX_DMA_SIZE)) { + ERR("DmaSoundDma: Start: overflowed %d-%d\n", dma_size, + MAX_DMA_SIZE); + return -EOVERFLOW; + } + + if (AUDIO_QUEUE_FULL(s)) { + ret = -2; + goto sound_out; + } + if (s->input_or_output == FMODE_WRITE) + /*playback */ + { + ret = + audio_set_dma_params_play(s->lch[s->dma_q_tail], dma_ptr, + dma_size); + } else { + ret = + audio_set_dma_params_capture(s->lch[s->dma_q_tail], dma_ptr, + dma_size); + } + if (ret != 0) { + ret = -2; /* indicate queue full */ + goto sound_out; + } + AUDIO_INCREMENT_TAIL(s); + ret = audio_start_dma_chain(s); + if (ret) { + ERR("dma start failed"); + } + sound_out: + FN_OUT(ret); + return ret; + +} + +/*************************************************************************************** + * + * ISR related functions + * + **************************************************************************************/ +/* The work item handler */ +static void audio_dsr_handler(unsigned long inData) +{ + void *data = (void *)inData; + struct audio_isr_work_item *work = data; + audio_stream_t *s = (work->s); + int sound_curr_lch = work->current_lch; + u16 ch_status = work->ch_status; + + FN_IN; + DPRINTK("lch=%d,status=0x%x, data=%p as=%p\n", sound_curr_lch, + ch_status, data, s); + if (AUDIO_QUEUE_EMPTY(s)) { + ERR("Interrupt(%d) for empty queue(h=%d, T=%d)???\n", + sound_curr_lch, s->dma_q_head, s->dma_q_tail); + ERR("nbfrag=%d,pendfrags=%d,USR-H=%d, QH-%d QT-%d\n", + s->nbfrags, s->pending_frags, s->usr_head, s->dma_head, + s->dma_tail); + FN_OUT(-1); + return; + } + + AUDIO_INCREMENT_HEAD(s); /* Empty the queue */ + + /* Try to fill again */ + audio_dma_callback(sound_curr_lch, ch_status, s); + FN_OUT(0); + +} + +/* Macro to trace the IRQ calls - checks for multi-channel irqs */ +//#define IRQ_TRACE +#ifdef IRQ_TRACE +#define MAX_UP 10 +static char xyz[MAX_UP] = { 0 }; +static int h = 0; +#endif + +/* ISRs have to be short and smart.. So we transfer every heavy duty stuff to the + * work item + */ +static void sound_dma_irq_handler(int sound_curr_lch, u16 ch_status, void *data) +{ + int dma_status = ch_status; + audio_stream_t *s = (audio_stream_t *) data; + FN_IN; +#ifdef IRQ_TRACE + xyz[h++] = '0' + sound_curr_lch; + if (h == MAX_UP - 1) { + printk("%s-", xyz); + h = 0; + } +#endif + DPRINTK("lch=%d,status=0x%x, dma_status=%d, data=%p\n", sound_curr_lch, + ch_status, dma_status, data); + + if (dma_status & (DCSR_ERROR)) { + omap_writew(omap_readw(OMAP_DMA_CCR(sound_curr_lch)) & ~DCCR_EN, + OMAP_DMA_CCR(sound_curr_lch)); + ERR("DCSR_ERROR!\n"); + FN_OUT(-1); + return; + } + + /* Start the work item - we ping pong the work items */ + if (!work_item_running) { + work1.current_lch = sound_curr_lch; + work1.ch_status = ch_status; + work1.s = s; + /* schedule tasklet 1 */ + tasklet_schedule(&audio_isr_work1); + work_item_running = 1; + } else { + work2.current_lch = sound_curr_lch; + work2.ch_status = ch_status; + work2.s = s; + /* schedule tasklet 2 */ + tasklet_schedule(&audio_isr_work2); + work_item_running = 0; + } + + FN_OUT(0); + return; +} + +/* The call back that handles buffer stuff */ +static void audio_dma_callback(int lch, u16 ch_status, void *data) +{ + audio_stream_t *s = data; + audio_buf_t *b = &s->buffers[s->dma_tail]; + FN_IN; + + if (s->dma_spinref > 0) { + s->dma_spinref--; + } else if (!s->buffers) { + printk(KERN_CRIT + "omap_audio: received DMA IRQ for non existent buffers!\n"); + return; + } else if (b->dma_ref && --b->dma_ref == 0 && b->offset >= s->fragsize) { + /* This fragment is done */ + b->offset = 0; + s->bytecount += s->fragsize; + s->fragcount++; + s->dma_spinref = -s->dma_spinref; + + if (++s->dma_tail >= s->nbfrags) + s->dma_tail = 0; + + if (!s->mapped) + up(&s->sem); + else + s->pending_frags++; + + wake_up(&s->wq); + } + + /* Detect End of transfer and Clean up + * Pend frags will be 1 . This means that there is one more chunk of data to + * complete transmission. This implies if channel 1 and channel 2 have data, + * the callback is for channel1 and channel 2 is currently being transmitted + * by the DMA. If we wait for Channel 2's completion before stopping the DMA, + * we will be late since the channels are chained, and the channel 1 would + * have already started trasmitting (junk data), hence a spurious call back + * would occur (for channel 1). Hence we forgo the last buffer transmission. + */ + if ((s->pending_frags < s->prevbuf) + && (s->pending_frags <= (NUMBER_OF_CHANNELS_TO_LINK - 1))) { + DPRINTK("%s Stop pend=%d prev=%d\n", __FUNCTION__, + s->pending_frags, s->prevbuf); + omap_stop_dma(s->lch[s->dma_q_head]); + omap_stop_dma(s->lch[s->dma_q_tail]); + + AUDIO_QUEUE_INIT(s); + b->offset = 0; + s->bytecount += s->fragsize; + s->fragcount++; + + if (++s->dma_tail >= s->nbfrags) + s->dma_tail = 0; + if (!s->mapped) { + while (s->nbfrags != atomic_read(&s->sem.count)) + up(&s->sem); + } + s->prevbuf = s->pending_frags = 0; + wake_up(&s->wq); + s->started = 0; + } else { + s->prevbuf = s->pending_frags; + audio_process_dma(s); + } + + FN_OUT(0); + return; +} + +/********************************************************************************* + * + * audio_get_dma_callback(): return the dma interface call back function + * + *********************************************************************************/ +dma_callback_t audio_get_dma_callback(void) +{ + FN_IN; + FN_OUT(0); + return audio_dma_callback; +} + +MODULE_AUTHOR("Texas Instruments"); +MODULE_DESCRIPTION("Common DMA handling for Audio driver on OMAP processors"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(omap_clear_sound_dma); +EXPORT_SYMBOL(omap_request_sound_dma); +EXPORT_SYMBOL(omap_free_sound_dma); + +EXPORT_SYMBOL(audio_get_dma_callback); +EXPORT_SYMBOL(audio_setup_buf); +EXPORT_SYMBOL(audio_process_dma); +EXPORT_SYMBOL(audio_prime_rx); +EXPORT_SYMBOL(audio_set_fragments); +EXPORT_SYMBOL(audio_sync); +EXPORT_SYMBOL(audio_stop_dma); +EXPORT_SYMBOL(audio_get_dma_pos); +EXPORT_SYMBOL(audio_reset); +EXPORT_SYMBOL(audio_discard_buf); diff -Nru a/sound/oss/omap-audio-dma-intfc.h b/sound/oss/omap-audio-dma-intfc.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/sound/oss/omap-audio-dma-intfc.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,63 @@ +/* + * linux/sound/oss/omap-audio-dma-intfc.h + * + * Common audio DMA handling for the OMAP processors + * + * Copyright (C) 2004 Texas Instruments, Inc. + * + * Copyright (C) 2000, 2001 Nicolas Pitre + * + * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * History: + * + * 2004/08/12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms + */ + +#ifndef __OMAP_AUDIO_DMA_INTFC_H +#define __OMAP_AUDIO_DMA_INTFC_H + +/************************** INCLUDES *************************************/ + +/* Requires omap-audio.h */ +#include "omap-audio.h" + +/************************** GLOBAL MACROS *************************************/ + +/* Provide the Macro interfaces common across platforms */ +#define DMA_REQUEST(e,s, cb) {e=omap_request_sound_dma(s->dma_dev, s->id, s, &s->lch);} +#define DMA_FREE(s) omap_free_sound_dma(&s->lch) +#define DMA_CLEAR(s) omap_clear_sound_dma(s) + +/************************** GLOBAL DATA STRUCTURES *********************************/ + +typedef void (*dma_callback_t) (int lch, u16 ch_status, void *data); + +/************************** GLOBAL FUNCTIONS ***************************************/ + +dma_callback_t audio_get_dma_callback(void); +int audio_setup_buf(audio_stream_t * s); +int audio_process_dma(audio_stream_t * s); +void audio_prime_rx(audio_state_t * state); +int audio_set_fragments(audio_stream_t * s, int val); +int audio_sync(struct file *file); +void audio_stop_dma(audio_stream_t * s); +u_int audio_get_dma_pos(audio_stream_t * s); +void audio_reset(audio_stream_t * s); +void audio_discard_buf(audio_stream_t * s); + +/**************** ARCH SPECIFIC FUNCIONS *******************************************/ + +void omap_clear_sound_dma(audio_stream_t * s); + +int omap_request_sound_dma(int device_id, const char *device_name, void *data, + int **channels); +int omap_free_sound_dma(int **channels); + +#endif /* #ifndef __OMAP_AUDIO_DMA_INTFC_H */ diff -Nru a/sound/oss/omap-audio-tsc2101.c b/sound/oss/omap-audio-tsc2101.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/sound/oss/omap-audio-tsc2101.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,1161 @@ +/* + * linux/sound/oss/omap-audio-tsc2101.c + * + * Glue driver for TSC2101 for OMAP processors + * + * Copyright (C) 2004 Texas Instruments, Inc. + * + * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * History: + * ------- + * 2004-08-12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms. + * 2004-09-14 Sriram Kannan - Added /proc support for asynchronous starting/stopping the codec + * (without affecting the normal driver flow). + * 2004-11-04 Nishanth Menon - Support for power management + * 2004-11-07 Nishanth Menon - Support for Common TSC access b/w Touchscreen and audio drivers + */ + +/***************************** INCLUDES ************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "omap-audio.h" +#include "omap-audio-dma-intfc.h" +#include +#if CONFIG_ARCH_OMAP16XX +#include <../drivers/ssi/omap-uwire.h> +#include +#else +#error "Unsupported configuration" +#endif + +#include +#include <../drivers/ssi/omap-tsc2101.h> + +/***************************** MACROS ************************************/ + +#define PROC_SUPPORT + +#ifdef PROC_SUPPORT +#include +#define PROC_START_FILE "driver/tsc2101-audio-start" +#define PROC_STOP_FILE "driver/tsc2101-audio-stop" +#endif + +#define CODEC_NAME "TSC2101" + +#if CONFIG_ARCH_OMAP16XX +#define PLATFORM_NAME "OMAP16XX" +#endif + +#if CONFIG_ARCH_OMAP16XX +#define OMAP_DSP_BASE 0xE0000000 +#endif + +/* Define to set the tsc as the master w.r.t McBSP */ +#define TSC_MASTER + +/* + * AUDIO related MACROS + */ +#define DEFAULT_BITPERSAMPLE 16 +#define AUDIO_RATE_DEFAULT 44100 +#define PAGE2_AUDIO_CODEC_REGISTERS (2) +#define LEAVE_CS 0x80 + +/* Select the McBSP For Audio */ +#if CONFIG_ARCH_OMAP16XX +#define AUDIO_MCBSP OMAP_MCBSP1 +#else +#error "UnSupported Configuration" +#endif + +#define REC_MASK (SOUND_MASK_LINE | SOUND_MASK_MIC) +#define DEV_MASK (REC_MASK | SOUND_MASK_VOLUME) + +#define SET_VOLUME 1 +#define SET_LINE 2 + +#define DEFAULT_VOLUME 93 +#define DEFAULT_INPUT_VOLUME 0 /* 0 ==> mute line in */ + +/* Tsc Audio Specific */ +#define NUMBER_SAMPLE_RATES_SUPPORTED 16 +#define OUTPUT_VOLUME_MIN 0x7F +#define OUTPUT_VOLUME_MAX 0x32 +#define OUTPUT_VOLUME_RANGE (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX) +#define OUTPUT_VOLUME_MASK OUTPUT_VOLUME_MIN +#define DEFAULT_VOLUME_LEVEL OUTPUT_VOLUME_MAX + +/* use input vol of 75 for 0dB gain */ +#define INPUT_VOLUME_MIN 0x0 +#define INPUT_VOLUME_MAX LIV_MAX +#define INPUT_VOLUME_RANGE (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN) +#define INPUT_VOLUME_MASK INPUT_VOLUME_MAX + +/*********** Debug Macros ********/ +/* To Generate a rather shrill tone -test the entire path */ +//#define TONE_GEN +/* To Generate a tone for each keyclick - test the tsc,spi paths*/ +//#define TEST_KEYCLICK +/* To dump the tsc registers for debug */ +//#define TSC_DUMP_REGISTERS + +#ifdef DPRINTK +#undef DPRINTK +#endif +#undef DEBUG + +//#define DEBUG +#ifdef DEBUG +#define DPRINTK(ARGS...) printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS) +#define FN_IN printk(KERN_INFO "[%s]: start\n", __FUNCTION__) +#define FN_OUT(n) printk(KERN_INFO "[%s]: end(%u)\n",__FUNCTION__, n) +#else +#define DPRINTK( x... ) +#define FN_IN +#define FN_OUT(n) +#endif + +/***************************** Data Structures **********************************/ + +static audio_stream_t output_stream = { + .id = "TSC2101 out", + .dma_dev = OMAP_DMA_MCBSP1_TX, + .input_or_output = FMODE_WRITE +}; + +static audio_stream_t input_stream = { + .id = "TSC2101 in", + .dma_dev = OMAP_DMA_MCBSP1_RX, + .input_or_output = FMODE_READ +}; + +static int audio_dev_id, mixer_dev_id; + +static struct tsc_local_info { + u8 volume; + u16 volume_reg; + u8 line; + u8 mic; + u16 input_volume_reg; + int mod_cnt; +} tsc2101_local; + +struct sample_rate_reg_info { + u16 sample_rate; + u8 divisor; + u8 fs_44kHz; /* if 0 48 khz, if 1 44.1 khz fsref */ +}; + +/* To Store the default sample rate */ +static long audio_samplerate = AUDIO_RATE_DEFAULT; + +static const struct sample_rate_reg_info + reg_info[NUMBER_SAMPLE_RATES_SUPPORTED] = { + /* Div 1 */ + {48000, 0, 0}, + {44100, 0, 1}, + /* Div 1.5 */ + {32000, 1, 0}, + {29400, 1, 1}, + /* Div 2 */ + {24000, 2, 0}, + {22050, 2, 1}, + /* Div 3 */ + {16000, 3, 0}, + {14700, 3, 1}, + /* Div 4 */ + {12000, 4, 0}, + {11025, 4, 1}, + /* Div 5 */ + {9600, 5, 0}, + {8820, 5, 1}, + /* Div 5.5 */ + {8727, 6, 0}, + {8018, 6, 1}, + /* Div 6 */ + {8000, 7, 0}, + {7350, 7, 1}, +}; + +static struct omap_mcbsp_reg_cfg initial_config = { + .spcr2 = FREE | FRST | GRST | XRST | XINTM(3), + .spcr1 = RINTM(3) | RRST, + .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) | + RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(1), + .rcr1 = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16), + .xcr2 = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) | + XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(1) | XFIG, + .xcr1 = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16), + .srgr1 = FWID(15), + .srgr2 = GSYNC | CLKSP | FSGM | FPER(31), + + /* platform specific initialization */ +#if CONFIG_MACH_OMAP_H2 + .pcr0 = CLKXM | CLKRM | FSXP | FSRP | CLKXP | CLKRP, +#elif CONFIG_MACH_OMAP_H3 + +#ifndef TSC_MASTER + .pcr0 = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP, +#else + .pcr0 = CLKRM | SCLKME | FSXP | FSRP | CLKXP | CLKRP, +#endif /* tsc Master defs */ + +#endif /* platform specific inits */ +}; + +/***************************** MODULES SPECIFIC FUNCTION PROTOTYPES ********************/ + +static void omap_tsc2101_initialize(void *dummy); + +static void omap_tsc2101_shutdown(void *dummy); + +static int omap_tsc2101_ioctl(struct inode *inode, struct file *file, + uint cmd, ulong arg); + +static int omap_tsc2101_probe(void); + +static void omap_tsc2101_remove(void); + +static int omap_tsc2101_suspend(void); + +static int omap_tsc2101_resume(void); + +static inline void tsc2101_configure(void); + +static int mixer_open(struct inode *inode, struct file *file); + +static int mixer_release(struct inode *inode, struct file *file); + +static int mixer_ioctl(struct inode *inode, struct file *file, uint cmd, + ulong arg); + +#ifdef TEST_KEYCLICK +void tsc2101_testkeyclick(void); +#endif + +#ifdef TONE_GEN +void toneGen(void); +#endif + +#ifdef TSC_DUMP_REGISTERS +static void tsc2101_dumpRegisters(void); +#endif + +#ifdef PROC_SUPPORT +static int codec_start(char *buf, char **start, off_t offset, int count, + int *eof, void *data); + +static int codec_stop(char *buf, char **start, off_t offset, int count, + int *eof, void *data); + +static void tsc2101_start(void); +#endif + +/******************** DATA STRUCTURES USING FUNCTION POINTERS **************************/ + +/* File Op structure for mixer */ +static struct file_operations omap_mixer_fops = { + .open = mixer_open, + .release = mixer_release, + .ioctl = mixer_ioctl, + .owner = THIS_MODULE +}; + +/* To store characteristic info regarding the codec for the audio driver */ +static audio_state_t tsc2101_state = { + .output_stream = &output_stream, + .input_stream = &input_stream, +/* .need_tx_for_rx = 1, //Once the Full Duplex works */ + .need_tx_for_rx = 0, + .hw_init = omap_tsc2101_initialize, + .hw_shutdown = omap_tsc2101_shutdown, + .client_ioctl = omap_tsc2101_ioctl, + .hw_probe = omap_tsc2101_probe, + .hw_remove = omap_tsc2101_remove, + .hw_suspend = omap_tsc2101_suspend, + .hw_resume = omap_tsc2101_resume, + .sem = __MUTEX_INITIALIZER(tsc2101_state.sem), +}; + +/* This will be defined in the Audio.h */ +static struct file_operations *omap_audio_fops; + +/***************************** MODULES SPECIFIC FUNCTIONs *******************************/ + +/********************************************************************************* + * + * Simplified write for tsc Audio + * + *********************************************************************************/ +static __inline__ void audio_tsc2101_write(u8 address, u16 data) +{ + omap_tsc2101_write(PAGE2_AUDIO_CODEC_REGISTERS, address, data); +} + +/********************************************************************************* + * + * Simplified read for tsc Audio + * + *********************************************************************************/ +static __inline__ u16 audio_tsc2101_read(u8 address) +{ + return (omap_tsc2101_read(PAGE2_AUDIO_CODEC_REGISTERS, address)); +} + +/********************************************************************************* + * + * tsc2101_update() + * Volume Adj etc + * + ********************************************************************************/ +static int tsc2101_update(int flag, int val) +{ + u16 volume; + u16 data; + + FN_IN; + switch (flag) { + case SET_VOLUME: + if (val < 0 || val > 100) { + printk(KERN_ERR "Trying a bad volume value(%d)!\n", + val); + return -EPERM; + } + /* Convert 0 -> 100 volume to 0x7F(min) -> y(max) volume range */ + volume = + ((val * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MAX; + /* invert the value for getting the proper range 0 min and 100 max */ + volume = OUTPUT_VOLUME_MIN - volume; + data = audio_tsc2101_read(TSC2101_DAC_GAIN_CTRL); + data &= + ~(DGC_DALVL(OUTPUT_VOLUME_MIN) | + DGC_DARVL(OUTPUT_VOLUME_MIN)); + data |= DGC_DALVL(volume) | DGC_DARVL(volume); + audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, data); + data = audio_tsc2101_read(TSC2101_DAC_GAIN_CTRL); + + break; + + case SET_LINE: + /* Not implemented yet */ + break; + } + FN_OUT(0); + return 0; +} + +/********************************************************************************* + * + * mixer_open() + * + ********************************************************************************/ +static int mixer_open(struct inode *inode, struct file *file) +{ + /* Any mixer specific initialization */ + + /* Initalize the tsc2101 */ + omap_tsc2101_enable(); + + return 0; +} + +/********************************************************************************* + * + * mixer_release() + * + ********************************************************************************/ +static int mixer_release(struct inode *inode, struct file *file) +{ + /* Any mixer specific Un-initialization */ + omap_tsc2101_disable(); + + return 0; +} + +/********************************************************************************* + * + * mixer_ioctl() + * + ********************************************************************************/ +static int +mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) +{ + int val; + int gain; + int ret = 0; + int nr = _IOC_NR(cmd); + + /* + * We only accept mixer (type 'M') ioctls. + */ + FN_IN; + if (_IOC_TYPE(cmd) != 'M') + return -EINVAL; + + DPRINTK(" 0x%08x\n", cmd); + + if (cmd == SOUND_MIXER_INFO) { + struct mixer_info mi; + + strncpy(mi.id, "TSC2101", sizeof(mi.id)); + strncpy(mi.name, "TI TSC2101", sizeof(mi.name)); + mi.modify_counter = tsc2101_local.mod_cnt; + FN_OUT(1); + return copy_to_user((void *)arg, &mi, sizeof(mi)); + } + + if (_IOC_DIR(cmd) & _IOC_WRITE) { + ret = get_user(val, (int *)arg); + if (ret) + goto out; + + /* Ignore separate left/right channel for now, + * even the codec does support it. + */ + gain = val & 255; + + switch (nr) { + case SOUND_MIXER_VOLUME: + tsc2101_local.volume = val; + tsc2101_local.mod_cnt++; + ret = tsc2101_update(SET_VOLUME, gain); + break; + + case SOUND_MIXER_LINE: + tsc2101_local.line = val; + tsc2101_local.mod_cnt++; + ret = tsc2101_update(SET_LINE, gain); + break; + + case SOUND_MIXER_MIC: + tsc2101_local.mic = val; + tsc2101_local.mod_cnt++; + ret = tsc2101_update(SET_LINE, gain); + break; + + case SOUND_MIXER_RECSRC: + break; + + default: + ret = -EINVAL; + } + } + + if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) { + ret = 0; + + switch (nr) { + case SOUND_MIXER_VOLUME: + val = tsc2101_local.volume; + break; + case SOUND_MIXER_LINE: + val = tsc2101_local.line; + break; + case SOUND_MIXER_MIC: + val = tsc2101_local.mic; + break; + case SOUND_MIXER_RECSRC: + val = REC_MASK; + break; + case SOUND_MIXER_RECMASK: + val = REC_MASK; + break; + case SOUND_MIXER_DEVMASK: + val = DEV_MASK; + break; + case SOUND_MIXER_CAPS: + val = 0; + break; + case SOUND_MIXER_STEREODEVS: + val = 0; + break; + default: + val = 0; + ret = -EINVAL; + break; + } + + if (ret == 0) + ret = put_user(val, (int *)arg); + } + out: + FN_OUT(0); + return ret; + +} + +/********************************************************************************* + * + * omap_set_samplerate() + * + ********************************************************************************/ +int omap_set_samplerate(long sample_rate) +{ + u8 count = 0; + u16 data = 0; + int clkgdv = 0; + /* wait for any frame to complete */ + udelay(125); + + /* Search for the right sample rate */ + while ((reg_info[count].sample_rate != sample_rate) && + (count < NUMBER_SAMPLE_RATES_SUPPORTED)) { + count++; + } + if (count == NUMBER_SAMPLE_RATES_SUPPORTED) { + printk(KERN_ERR "Invalid Sample Rate %d requested\n", + (int)sample_rate); + return -EPERM; + } + + /* Set AC1 */ + data = audio_tsc2101_read(TSC2101_AUDIO_CTRL_1); + /*Clear prev settings */ + data &= ~(AC1_DACFS(0x07) | AC1_ADCFS(0x07)); + data |= + AC1_DACFS(reg_info[count].divisor) | AC1_ADCFS(reg_info[count]. + divisor); + audio_tsc2101_write(TSC2101_AUDIO_CTRL_1, data); + + /* Set the AC3 */ + data = audio_tsc2101_read(TSC2101_AUDIO_CTRL_3); + /*Clear prev settings */ + data &= ~(AC3_REFFS | AC3_SLVMS); + data |= (reg_info[count].fs_44kHz) ? AC3_REFFS : 0; +#ifdef TSC_MASTER + data |= AC3_SLVMS; +#endif /* #ifdef TSC_MASTER */ + audio_tsc2101_write(TSC2101_AUDIO_CTRL_3, data); + + /* program the PLLs */ + if (reg_info[count].fs_44kHz) { + /* 44.1 khz - 12 MHz Mclk */ + audio_tsc2101_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(7)); /* PVAL 1; I_VAL 7 */ + audio_tsc2101_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x1490)); /* D_VAL 5264 */ + } else { + /* 48 khz - 12 Mhz Mclk */ + audio_tsc2101_write(TSC2101_PLL_PROG_1, PLL1_PLLSEL | PLL1_PVAL(1) | PLL1_I_VAL(8)); /* PVAL 1; I_VAL 8 */ + audio_tsc2101_write(TSC2101_PLL_PROG_2, PLL2_D_VAL(0x780)); /* D_VAL 1920 */ + } + + audio_samplerate = sample_rate; + + /* Set the sample rate */ +#ifndef TSC_MASTER + clkgdv = + DEFAULT_MCBSP_CLOCK / (sample_rate * + (DEFAULT_BITPERSAMPLE * 2 - 1)); + if (clkgdv) + initial_config.srgr1 = + (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv)); + else + return (1); + + /* Stereo Mode */ + initial_config.srgr2 = + (CLKSM | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1)); +#else + initial_config.srgr1 = + (FWID(DEFAULT_BITPERSAMPLE - 1) | CLKGDV(clkgdv)); + initial_config.srgr2 = + ((GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1))); + +#endif /* end of #ifdef TSC_MASTER */ + omap_mcbsp_config(AUDIO_MCBSP, &initial_config); + + return 0; +} + +/********************************************************************************* + * + * omap_tsc2101_initialize() [hw_init() ] + * + ********************************************************************************/ +static void omap_tsc2101_initialize(void *dummy) +{ + + DPRINTK("omap_tsc2101_initialize entry\n"); + + /* initialize with default sample rate */ + audio_samplerate = AUDIO_RATE_DEFAULT; + + omap_mcbsp_request(AUDIO_MCBSP); + + /* if configured, then stop mcbsp */ + omap_mcbsp_stop(AUDIO_MCBSP); + + omap_tsc2101_enable(); + + omap_mcbsp_config(AUDIO_MCBSP, &initial_config); + omap_mcbsp_start(AUDIO_MCBSP); + tsc2101_configure(); + +#ifdef TEST_KEYCLICK + tsc2101_testkeyclick(); +#endif + +#ifdef TONE_GEN + toneGen(); +#endif + + DPRINTK("omap_tsc2101_initialize exit\n"); +} + +/********************************************************************************* + * + * omap_tsc2101_shutdown() [hw_shutdown() ] + * + ********************************************************************************/ +static void omap_tsc2101_shutdown(void *dummy) +{ + /* + Turn off codec after it is done. + Can't do it immediately, since it may still have + buffered data. + + Wait 20ms (arbitrary value) and then turn it off. + */ + + FN_IN; + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(2); + + omap_mcbsp_stop(AUDIO_MCBSP); + omap_mcbsp_free(AUDIO_MCBSP); + + audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL, + ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC)); + + omap_tsc2101_disable(); + + FN_OUT(0); +} + +/********************************************************************************* + * + * tsc2101_configure + * + ********************************************************************************/ +static inline void tsc2101_configure() +{ + FN_IN; + + audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL, 0x0000); + + /*Headset Input not muted */ + /*AGC for Headset In off */ + audio_tsc2101_write(TSC2101_HEADSET_GAIN_CTRL, HGC_ADPGA_HED(0x7D)); + + /*Mute Analog Sidetone */ + /*Select MIC_INHED input for headset */ + /*Cell Phone In not connected */ + audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL, + MPC_ASTMU | MPC_ASTG(0x40) | MPC_MICADC); + + /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */ + /* 1dB AGC hysteresis */ + /* MICes bias 2V */ + audio_tsc2101_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0)); + + /* Set codec output volume */ + audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, 0x0000); + + /* DAC left and right routed to SPK2 */ + /* SPK1/2 unmuted */ + audio_tsc2101_write(TSC2101_AUDIO_CTRL_5, + AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 | + AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 | + AC5_HDSCPTC); + + /* OUT8P/N muted, CPOUT muted */ + + audio_tsc2101_write(TSC2101_AUDIO_CTRL_6, + AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC | + AC6_VGNDSCPTC); + + /* Headset/Hook switch detect disabled */ + audio_tsc2101_write(TSC2101_AUDIO_CTRL_7, 0x0000); + + /* Initialize the AIC23 internal state */ + /* + The AIC23 uses 9 bits for register control. The + extra bit gets placed in the LSB of the subregister + address, and the address is shifted by one. + the volume control is only for earphone not line out + line input volume can be controlled but not in following code + which pick the default value 0dB + */ + + /* Left line input volume control */ + tsc2101_local.line = DEFAULT_INPUT_VOLUME; + tsc2101_local.mic = DEFAULT_INPUT_VOLUME; + tsc2101_update(SET_LINE, DEFAULT_INPUT_VOLUME); + + /* Left/Right headphone channel volume control */ + /* Zero-cross detect on */ + tsc2101_update(SET_VOLUME, tsc2101_local.volume); + + /* clock configuration */ + omap_set_samplerate(audio_samplerate); + +#ifdef TSC_DUMP_REGISTERS + tsc2101_dumpRegisters(); +#endif + + FN_OUT(0); +} + +#ifdef PROC_SUPPORT +static void tsc2101_start() +{ + FN_IN; + + audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL, 0x0000); + + /*Headset Input not muted */ + /*AGC for Headset In off */ + audio_tsc2101_write(TSC2101_HEADSET_GAIN_CTRL, HGC_ADPGA_HED(0x7D)); + + /*Mute Analog Sidetone */ + /*Select MIC_INHED input for headset */ + /*Cell Phone In not connected */ + audio_tsc2101_write(TSC2101_MIXER_PGA_CTRL, + MPC_ASTMU | MPC_ASTG(0x40) | MPC_MICADC); + + /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */ + /* 1dB AGC hysteresis */ + /* MICes bias 2V */ + audio_tsc2101_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0)); + + /* Set codec output volume */ + audio_tsc2101_write(TSC2101_DAC_GAIN_CTRL, 0x0000); + + /* DAC left and right routed to SPK2 */ + /* SPK1/2 unmuted */ + audio_tsc2101_write(TSC2101_AUDIO_CTRL_5, + AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 | + AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 | + AC5_HDSCPTC); + + /* OUT8P/N muted, CPOUT muted */ + + audio_tsc2101_write(TSC2101_AUDIO_CTRL_6, + AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC | + AC6_VGNDSCPTC); + + /* Headset/Hook switch detect disabled */ + audio_tsc2101_write(TSC2101_AUDIO_CTRL_7, 0x0000); + + /* Initialize the AIC23 internal state */ + /* + The AIC23 uses 9 bits for register control. The + extra bit gets placed in the LSB of the subregister + address, and the address is shifted by one. + the volume control is only for earphone not line out + line input volume can be controlled but not in following code + which pick the default value 0dB + */ + + /* Left line input volume control */ + tsc2101_local.line = DEFAULT_INPUT_VOLUME; + tsc2101_local.mic = DEFAULT_INPUT_VOLUME; + tsc2101_update(SET_LINE, DEFAULT_INPUT_VOLUME); + + /* Left/Right headphone channel volume control */ + /* Zero-cross detect on */ + tsc2101_update(SET_VOLUME, tsc2101_local.volume); + + FN_OUT(0); + +} +#endif + +/****************************************************************************************** + * + * All generic ioctl's are handled by audio_ioctl() [File: omap-audio.c]. This + * routine handles some platform specific ioctl's + * + ******************************************************************************************/ +static int +omap_tsc2101_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) +{ + long val; + int ret = 0; + + DPRINTK(" 0x%08x\n", cmd); + + /* + * These are platform dependent ioctls which are not handled by the + * generic omap-audio module. + */ + switch (cmd) { + case SNDCTL_DSP_STEREO: + ret = get_user(val, (int *)arg); + if (ret) + return ret; + /* the AIC23 is stereo only */ + ret = (val == 0) ? -EINVAL : 1; + FN_OUT(1); + return put_user(ret, (int *)arg); + + case SNDCTL_DSP_CHANNELS: + case SOUND_PCM_READ_CHANNELS: + /* the AIC23 is stereo only */ + FN_OUT(2); + return put_user(2, (long *)arg); + + case SNDCTL_DSP_SPEED: + ret = get_user(val, (long *)arg); + if (ret) + break; + ret = omap_set_samplerate(val); + if (ret) + break; + /* fall through */ + + case SOUND_PCM_READ_RATE: + FN_OUT(3); + return put_user(audio_samplerate, (long *)arg); + + case SOUND_PCM_READ_BITS: + case SNDCTL_DSP_SETFMT: + case SNDCTL_DSP_GETFMTS: + /* we can do 16-bit only */ + FN_OUT(4); + return put_user(AFMT_S16_LE, (long *)arg); + + default: + /* Maybe this is meant for the mixer (As per OSS Docs) */ + FN_OUT(5); + return mixer_ioctl(inode, file, cmd, arg); + } + + FN_OUT(0); + return ret; +} + +/********************************************************************************* + * + * module_probe for TSC2101 + * + ********************************************************************************/ +static int omap_tsc2101_probe(void) +{ + FN_IN; + + /* Get the fops from audio oss driver */ + if (!(omap_audio_fops = audio_get_fops())) { + printk(KERN_ERR "Unable to Get the FOPs of Audio OSS driver\n"); + audio_unregister_codec(&tsc2101_state); + return -EPERM; + } + + tsc2101_local.volume = DEFAULT_VOLUME; + + /* register devices */ + audio_dev_id = register_sound_dsp(omap_audio_fops, -1); + mixer_dev_id = register_sound_mixer(&omap_mixer_fops, -1); + +#ifdef PROC_SUPPORT + create_proc_read_entry(PROC_START_FILE, 0 /* default mode */ , + NULL /* parent dir */ , + codec_start, NULL /* client data */ ); + + create_proc_read_entry(PROC_STOP_FILE, 0 /* default mode */ , + NULL /* parent dir */ , + codec_stop, NULL /* client data */ ); +#endif + + /* Announcement Time */ + printk(KERN_INFO PLATFORM_NAME " " CODEC_NAME + " Audio support initialized\n"); + + FN_OUT(0); + return 0; +} + +/********************************************************************************* + * + * Module Remove for TSC2101 + * + ********************************************************************************/ +static void omap_tsc2101_remove(void) +{ + FN_IN; + /* Un-Register the codec with the audio driver */ + unregister_sound_dsp(audio_dev_id); + unregister_sound_mixer(mixer_dev_id); + +#ifdef PROC_SUPPORT + remove_proc_entry(PROC_START_FILE, NULL); + remove_proc_entry(PROC_STOP_FILE, NULL); +#endif + FN_OUT(0); + +} + +/********************************************************************************* + * + * Module Suspend for TSC2101 + * + ********************************************************************************/ +static int omap_tsc2101_suspend(void) +{ + + FN_OUT(0); + return 0; +} + +/********************************************************************************* + * + * Module Resume for TSC2101 + * + ********************************************************************************/ +static int omap_tsc2101_resume(void) +{ + + FN_OUT(0); + return 0; +} + +/********************************************************************************* + * + * module_init for TSC2101 + * + ********************************************************************************/ +static int __init audio_tsc2101_init(void) +{ + + int err = 0; + FN_IN; + /* register the codec with the audio driver */ + if ((err = audio_register_codec(&tsc2101_state))) { + printk(KERN_ERR + "Failed to register TSC driver with Audio OSS Driver\n"); + } + FN_OUT(err); + return err; +} + +/********************************************************************************* + * + * module_exit for TSC2101 + * + ********************************************************************************/ +static void __exit audio_tsc2101_exit(void) +{ + + FN_IN; + (void)audio_unregister_codec(&tsc2101_state); + FN_OUT(0); + return; +} + +/**************************** DEBUG FUNCTIONS ***********************************/ + +/********************************************************************************* + * TEST_KEYCLICK: + * This is a test to generate various keyclick sound on tsc. + * verifies if the tsc and the spi interfaces are operational. + * + ********************************************************************************/ +#ifdef TEST_KEYCLICK +void tsc2101_testkeyclick(void) +{ + u8 freq = 0; + u16 old_reg_val, reg_val; + u32 uDummyVal = 0; + u32 uTryVal = 0; + + old_reg_val = audio_tsc2101_read(TSC2101_AUDIO_CTRL_2); + + /* Keyclick active, max amplitude and longest key click len(32 period) */ + printk(KERN_INFO " TESTING KEYCLICK\n Listen carefully NOW....\n"); + printk(KERN_INFO " OLD REG VAL=0x%x\n", old_reg_val); + /* try all frequencies */ + for (; freq < 8; freq++) { + /* Keyclick active, max amplitude and longest key click len(32 period) */ + reg_val = old_reg_val | AC2_KCLAC(0x7) | AC2_KCLLN(0xF); + uDummyVal = 0; + uTryVal = 0; + printk(KERN_INFO "\n\nTrying frequency %d reg val= 0x%x\n", + freq, reg_val | AC2_KCLFRQ(freq) | AC2_KCLEN); + audio_tsc2101_write(TSC2101_AUDIO_CTRL_2, + reg_val | AC2_KCLFRQ(freq) | AC2_KCLEN); + printk("DONE. Wait 10 ms ...\n"); + /* wait till the kclk bit is auto cleared! time out also to be considered. */ + while (audio_tsc2101_read(TSC2101_AUDIO_CTRL_2) & AC2_KCLEN) { + udelay(3); + uTryVal++; + if (uTryVal > 2000) { + printk(KERN_ERR + "KEYCLICK TIMED OUT! freq val=%d, POSSIBLE ERROR!\n", + freq); + printk(KERN_INFO + "uTryVal == %d: Read back new reg val= 0x%x\n", + uTryVal, + audio_tsc2101_read + (TSC2101_AUDIO_CTRL_2)); + /* clear */ + audio_tsc2101_write(TSC2101_AUDIO_CTRL_2, 0x00); + break; + } + } + } + /* put the old value back */ + audio_tsc2101_write(TSC2101_AUDIO_CTRL_2, old_reg_val); + printk(KERN_INFO " KEYCLICK TEST COMPLETE\n"); + +} /* End of tsc2101_testkeyclick */ + +#endif /* TEST_KEYCLICK */ + +/********************************************************************************* + * TONEGEN: + * This is a test to generate a rather unpleasant sound.. + * verifies if the mcbsp is active (requires MCBSP_DIRECT_RW to be active on McBSP) + * + ********************************************************************************/ +#ifdef TONE_GEN +/* Generates a shrill tone */ +u16 tone[] = { + 0x0ce4, 0x0ce4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE, + 0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C, + 0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2, + 0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C, + 0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A, + 0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676, + 0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83, + 0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E, + 0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94, + 0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03, + 0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000, + 0x0CE4, 0x0CE4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE, + 0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C, + 0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2, + 0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C, + 0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A, + 0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676, + 0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83, + 0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E, + 0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94, + 0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03, + 0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000, + 0x0CE4, 0x0CE4, 0x1985, 0x1985, 0x25A1, 0x25A1, 0x30FD, 0x30FE, + 0x3B56, 0x3B55, 0x447A, 0x447A, 0x4C3B, 0x4C3C, 0x526D, 0x526C, + 0x56F1, 0x56F1, 0x59B1, 0x59B1, 0x5A9E, 0x5A9D, 0x59B1, 0x59B2, + 0x56F3, 0x56F2, 0x526D, 0x526D, 0x4C3B, 0x4C3B, 0x447C, 0x447C, + 0x3B5A, 0x3B59, 0x30FE, 0x30FE, 0x25A5, 0x25A6, 0x1989, 0x198A, + 0x0CE5, 0x0CE3, 0x0000, 0x0000, 0xF31C, 0xF31C, 0xE677, 0xE676, + 0xDA5B, 0xDA5B, 0xCF03, 0xCF03, 0xC4AA, 0xC4AA, 0xBB83, 0xBB83, + 0xB3C5, 0xB3C5, 0xAD94, 0xAD94, 0xA90D, 0xA90E, 0xA64F, 0xA64E, + 0xA562, 0xA563, 0xA64F, 0xA64F, 0xA910, 0xA90F, 0xAD93, 0xAD94, + 0xB3C4, 0xB3C4, 0xBB87, 0xBB86, 0xC4AB, 0xC4AB, 0xCF03, 0xCF03, + 0xDA5B, 0xDA5A, 0xE67B, 0xE67B, 0xF31B, 0xF3AC, 0x0000, 0x0000 +}; + +void toneGen(void) +{ + int count = 0; + int ret = 0; + printk(KERN_INFO "TONE GEN TEST :"); + + for (count = 0; count < 5000; count++) { + int bytes; + for (bytes = 0; bytes < sizeof(tone) / 2; bytes++) { + ret = omap_mcbsp_pollwrite(AUDIO_MCBSP, tone[bytes]); + if (ret == -1) { + /* retry */ + bytes--; + } else if (ret == -2) { + printk(KERN_INFO "ERROR:bytes=%d\n", bytes); + return; + } + } + } + printk(KERN_INFO "SUCCESS\n"); +} + +#endif /* End of TONE_GEN */ + +/********************************************************************************* + * + * TSC_DUMP_REGISTERS: + * This will dump the entire register set of Page 2 tsc2101. + * Useful for major goof ups + * + ********************************************************************************/ +#ifdef TSC_DUMP_REGISTERS +static void tsc2101_dumpRegisters(void) +{ + int i = 0; + u16 data = 0; + printk("TSC 2101 Register dump for Page 2 \n"); + for (i = 0; i < 0x27; i++) { + data = audio_tsc2101_read(i); + printk(KERN_INFO "Register[%x]=0x%04x\n", i, data); + + } +} +#endif /* End of #ifdef TSC_DUMP_REGISTERS */ + +#ifdef PROC_SUPPORT +static int codec_start(char *buf, char **start, off_t offset, int count, + int *eof, void *data) +{ + omap_tsc2101_enable(); + tsc2101_start(); + printk("Codec initialization done.\n"); + return 0; +} +static int codec_stop(char *buf, char **start, off_t offset, int count, + int *eof, void *data) +{ + + omap_tsc2101_disable(); + audio_tsc2101_write(TSC2101_CODEC_POWER_CTRL, + ~(CPC_SP1PWDN | CPC_SP2PWDN | CPC_BASSBC)); + printk("Codec shutdown.\n"); + return 0; +} +#endif + +/********************************************************************************* + * + * Other misc management, registration etc + * + ********************************************************************************/ +module_init(audio_tsc2101_init); +module_exit(audio_tsc2101_exit); + +MODULE_AUTHOR("Texas Instruments"); +MODULE_DESCRIPTION + ("Glue audio driver for the TI OMAP1610/OMAP1710 TSC2101 codec."); +MODULE_LICENSE("GPL"); diff -Nru a/sound/oss/omap-audio.c b/sound/oss/omap-audio.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/sound/oss/omap-audio.c 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,1166 @@ +/* + * linux/sound/oss/omap-audio.c + * + * Common audio handling for the OMAP processors + * + * Copyright (C) 2004 Texas Instruments, Inc. + * + * Copyright (C) 2000, 2001 Nicolas Pitre + * + * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * History: + * + * 2004/08/12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms + * + * 2004-11-01 Nishanth Menon - modified to support 16xx and 17xx + * platform multi channel chaining. + * + * 2004-11-04 Nishanth Menon - Added support for power management + * + * 2004-12-17 Nishanth Menon - Provided proper module handling support + */ + +/***************************** INCLUDES ************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "omap-audio-dma-intfc.h" +#include "omap-audio.h" + +/***************************** MACROS ************************************/ + +#undef DEBUG +//#define DEBUG +#ifdef DEBUG +#define DPRINTK printk +#define FN_IN printk("[omap_audio.c:[%s] start\n", __FUNCTION__) +#define FN_OUT(n) printk("[omap_audio.c:[%s] end(%d)\n", __FUNCTION__ , n) +#else +#define DPRINTK( x... ) +#define FN_IN +#define FN_OUT(x) +#endif + +#define OMAP_AUDIO_NAME "omap-audio" +#define AUDIO_NBFRAGS_DEFAULT 8 +#define AUDIO_FRAGSIZE_DEFAULT 8192 + +/* HACK ALERT!: These values will bave to be tuned as this is a trade off b/w + * Sampling Rate vs buffer size and delay we are prepared to do before giving up + */ +#define MAX_QUEUE_FULL_RETRIES 1000000 +#define QUEUE_WAIT_TIME 10 + +#define AUDIO_ACTIVE(state) ((state)->rd_ref || (state)->wr_ref) + +#define SPIN_ADDR (dma_addr_t)0 +#define SPIN_SIZE 2048 + +/***************************** MODULES SPECIFIC FUNCTION PROTOTYPES ********************/ + +static int audio_write(struct file *file, const char *buffer, + size_t count, loff_t * ppos); + +static int audio_read(struct file *file, char *buffer, size_t count, + loff_t * ppos); + +static int audio_mmap(struct file *file, struct vm_area_struct *vma); + +static unsigned int audio_poll(struct file *file, + struct poll_table_struct *wait); + +static loff_t audio_llseek(struct file *file, loff_t offset, int origin); + +static int audio_ioctl(struct inode *inode, struct file *file, uint cmd, + ulong arg); + +static int audio_open(struct inode *inode, struct file *file); + +static int audio_release(struct inode *inode, struct file *file); + +static int audio_probe(struct device *dev); + +static int audio_remove(struct device *dev); + +static void audio_shutdown(struct device *dev); + +static int audio_suspend(struct device *dev, u32 state, u32 level); + +static int audio_resume(struct device *dev, u32 level); + +static void audio_free(struct device *dev); + +/***************************** Data Structures **********************************/ + +/* + * The function pointer set to be registered by the codec. + */ +static audio_state_t audio_state = { 0 }; + +/* DMA Call back function */ +static dma_callback_t audio_dma_callback = 0; + +/* File Ops structure */ +static struct file_operations omap_audio_fops = { + .open = audio_open, + .release = audio_release, + .write = audio_write, + .read = audio_read, + .mmap = audio_mmap, + .poll = audio_poll, + .ioctl = audio_ioctl, + .llseek = audio_llseek, + .owner = THIS_MODULE +}; + +/* Driver information */ +static struct device_driver omap_audio_driver = { + .name = OMAP_AUDIO_NAME, + .bus = &platform_bus_type, + .probe = audio_probe, + .remove = audio_remove, + .suspend = audio_suspend, + .resume = audio_resume, + .shutdown = audio_shutdown, +}; + +/* Device Information */ +static struct platform_device omap_audio_device = { + .name = OMAP_AUDIO_NAME, + .dev = { + .driver_data = &audio_state, + .release = audio_free, + }, + .id = 0, +}; + +/***************************** GLOBAL FUNCTIONs **********************************/ + +/* Power Management Functions for Linux Device Model */ +/* DEBUG PUPOSES ONLY! */ +#ifdef CONFIG_PM +//#undef CONFIG_PM +#endif + +#ifdef CONFIG_PM +/********************************************************************************* + * + * audio_ldm_suspend(): Suspend operation + * + *********************************************************************************/ +static int audio_ldm_suspend(void *data) +{ + audio_state_t *state = data; + + FN_IN; + + /* + * Reject the suspend request if we are already actively transmitting data + * Rationale: We dont want to be suspended while in the middle of a call! + */ + if (AUDIO_ACTIVE(state) && state->hw_init) { + printk(KERN_ERR "Audio device Active, Cannot Suspend"); + return -EPERM; +#if 0 + /* NOTE: + * This Piece of code is commented out in hope + * That one day we would need to suspend the device while + * audio operations are in progress and resume the operations + * once the resume is done. + * This is just a sample implementation of how it could be done. + * Currently NOT SUPPORTED + */ + audio_stream_t *is = state->input_stream; + audio_stream_t *os = state->output_stream; + int stopstate; + if (is && is->buffers) { + printk("IS Suspend\n"); + stopstate = is->stopped; + audio_stop_dma(is); + DMA_CLEAR(is); + is->dma_spinref = 0; + is->stopped = stopstate; + } + if (os && os->buffers) { + printk("OS Suspend\n"); + stopstate = os->stopped; + audio_stop_dma(os); + DMA_CLEAR(os); + os->dma_spinref = 0; + os->stopped = stopstate; + } +#endif + } + + FN_OUT(0); + return 0; +} + +/********************************************************************************* + * + * audio_ldm_resume(): Resume Operations + * + *********************************************************************************/ +static int audio_ldm_resume(void *data) +{ + audio_state_t *state = data; + + FN_IN; + if (AUDIO_ACTIVE(state) && state->hw_init) { + /* Should never occur - since we never suspend with active state */ + BUG(); + return -EPERM; +#if 0 + /* NOTE: + * This Piece of code is commented out in hope + * That one day we would need to suspend the device while + * audio operations are in progress and resume the operations + * once the resume is done. + * This is just a sample implementation of how it could be done. + * Currently NOT SUPPORTED + */ + audio_stream_t *is = state->input_stream; + audio_stream_t *os = state->output_stream; + if (os && os->buffers) { + printk("OS Resume\n"); + audio_reset(os); + audio_process_dma(os); + } + if (is && is->buffers) { + printk("IS Resume\n"); + audio_reset(is); + audio_process_dma(is); + } +#endif + } + FN_OUT(0); + return 0; +} +#endif /* End of #ifdef CONFIG_PM */ + +/********************************************************************************* + * + * audio_free(): The Audio driver release function + * This is a dummy function required by the platform driver + * + *********************************************************************************/ +static void audio_free(struct device *dev) +{ + /* Nothing to Release! */ +} + +/********************************************************************************* + * + * audio_probe(): The Audio driver probe function + * WARNING!!!! : It is expected that the codec would have registered with us by now + * + *********************************************************************************/ +static int audio_probe(struct device *dev) +{ + int ret; + FN_IN; + if (!audio_state.hw_probe) { + printk(KERN_ERR "Probe Function Not Registered\n"); + return -ENODEV; + } + ret = audio_state.hw_probe(); + FN_OUT(ret); + return ret; +} + +/********************************************************************************* + * + * audio_remove() Function to handle removal operations + * + *********************************************************************************/ +static int audio_remove(struct device *dev) +{ + FN_IN; + if (audio_state.hw_remove) { + audio_state.hw_remove(); + } + FN_OUT(0); + return 0; +} + +/********************************************************************************* + * + * audio_shutdown(): Function to handle shutdown operations + * + *********************************************************************************/ +static void audio_shutdown(struct device *dev) +{ + FN_IN; + if (audio_state.hw_cleanup) { + audio_state.hw_cleanup(); + } + FN_OUT(0); + return; +} + +/********************************************************************************* + * + * audio_suspend(): Function to handle suspend operations + * + *********************************************************************************/ +static int audio_suspend(struct device *dev, u32 state, u32 level) +{ + int ret = 0; + +#ifdef CONFIG_PM + void *data = dev->driver_data; + FN_IN; + if (level != 3) { + return 0; + } + if (audio_state.hw_suspend) { + ret = audio_ldm_suspend(data); + if (ret == 0) + ret = audio_state.hw_suspend(); + } + if (ret) { + printk(KERN_INFO "Audio Suspend Failed \n"); + } else { + printk(KERN_INFO "Audio Suspend Success \n"); + } +#endif /* CONFIG_PM */ + + FN_OUT(ret); + return ret; +} + +/********************************************************************************* + * + * audio_resume(): Function to handle resume operations + * + *********************************************************************************/ +static int audio_resume(struct device *dev, u32 level) +{ + int ret = 0; + +#ifdef CONFIG_PM + void *data = dev->driver_data; + FN_IN; + if (level != 0) { + return 0; + } + if (audio_state.hw_resume) { + ret = audio_ldm_resume(data); + if (ret == 0) + ret = audio_state.hw_resume(); + } + if (ret) { + printk(KERN_INFO " Audio Resume Failed \n"); + } else { + printk(KERN_INFO " Audio Resume Success \n"); + } +#endif /* CONFIG_PM */ + + FN_OUT(ret); + return ret; +} + +/********************************************************************************* + * + * audio_get_fops(): Return the fops required to get the function pointers of + * OMAP Audio Driver + * + *********************************************************************************/ +struct file_operations *audio_get_fops(void) +{ + FN_IN; + FN_OUT(0); + return &omap_audio_fops; +} + +/********************************************************************************* + * + * audio_register_codec(): Register a Codec fn points using this function + * WARNING!!!!! : Codecs should ensure that they do so! no sanity checks + * during runtime is done due to obvious performance + * penalties. + * + *********************************************************************************/ +int audio_register_codec(audio_state_t * codec_state) +{ + int ret; + FN_IN; + + /* We dont handle multiple codecs now */ + if (audio_state.hw_init) { + printk(KERN_ERR " Codec Already registered\n"); + return -EPERM; + } + + /* Grab the dma Callback */ + audio_dma_callback = audio_get_dma_callback(); + if (!audio_dma_callback) { + printk(KERN_ERR "Unable to get call back function\n"); + return -EPERM; + } + + /* Sanity checks */ + if (!codec_state) { + printk(KERN_ERR "NULL ARGUMENT!\n"); + return -EPERM; + } + + if (!codec_state->hw_probe || !codec_state->hw_init + || !codec_state->hw_shutdown || !codec_state->client_ioctl) { + printk(KERN_ERR + "Required Fn Entry point Missing probe=%p init=%p,down=%p,ioctl=%p!\n", + codec_state->hw_probe, codec_state->hw_init, + codec_state->hw_shutdown, codec_state->client_ioctl); + return -EPERM; + } + + memcpy(&audio_state, codec_state, sizeof(audio_state_t)); + + ret = platform_device_register(&omap_audio_device); + if (ret != 0) { + printk(KERN_ERR "Platform dev_register failed =%d\n", ret); + ret = -ENODEV; + goto register_out; + } + + ret = driver_register(&omap_audio_driver); + if (ret != 0) { + printk(KERN_ERR "Device Register failed =%d\n", ret); + ret = -ENODEV; + platform_device_unregister(&omap_audio_device); + goto register_out; + } + + register_out: + + FN_OUT(ret); + return ret; +} + +/********************************************************************************* + * + * audio_unregister_codec(): Un-Register a Codec using this function + * + *********************************************************************************/ +int audio_unregister_codec(audio_state_t * codec_state) +{ + FN_IN; + + /* We dont handle multiple codecs now */ + if (!audio_state.hw_init) { + printk(KERN_ERR " No Codec registered\n"); + return -EPERM; + } + /* Security check */ + if (audio_state.hw_init != codec_state->hw_init) { + printk(KERN_ERR + " Attempt to unregister codec which was not registered with us\n"); + return -EPERM; + } + + driver_unregister(&omap_audio_driver); + platform_device_unregister(&omap_audio_device); + + memset(&audio_state, 0, sizeof(audio_state_t)); + + FN_OUT(0); + return 0; +} + +/***************************** MODULES SPECIFIC FUNCTION *************************/ + +/********************************************************************************* + * + * audio_write(): Exposed to write() call + * + *********************************************************************************/ +static int +audio_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) +{ + const char *buffer0 = buffer; + audio_state_t *state = file->private_data; + audio_stream_t *s = state->output_stream; + int chunksize, ret = 0; + + DPRINTK("audio_write: count=%d\n", count); + if (*ppos != file->f_pos) { + printk("FPOS not ppos ppos=0x%x fpos =0x%x\n", (u32) * ppos, + (u32) file->f_pos); + return -ESPIPE; + } + if (s->mapped) { + printk("s already mapped\n"); + return -ENXIO; + } + if (!s->buffers && audio_setup_buf(s)) { + printk("NO MEMORY\n"); + return -ENOMEM; + } + + while (count > 0) { + audio_buf_t *b = &s->buffers[s->usr_head]; + + /* Wait for a buffer to become free */ + 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; + DPRINTK("write %d to %d\n", chunksize, s->usr_head); + if (copy_from_user(b->data + b->offset, buffer, chunksize)) { + printk(KERN_ERR "Audio: CopyFrom User failed \n"); + up(&s->sem); + return -EFAULT; + } + + buffer += chunksize; + count -= chunksize; + b->offset += chunksize; + + if (b->offset < s->fragsize) { + up(&s->sem); + break; + } + + /* Update pointers and send current fragment to DMA */ + b->offset = 0; + if (++s->usr_head >= s->nbfrags) + s->usr_head = 0; + /* Add the num of frags pending */ + s->pending_frags++; + s->active = 1; + + audio_process_dma(s); + + } + + if ((buffer - buffer0)) + ret = buffer - buffer0; + DPRINTK("audio_write: return=%d\n", ret); + return ret; +} + +/********************************************************************************* + * + * audio_read(): Exposed as read() function + * + *********************************************************************************/ +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; + unsigned long flags; + + DPRINTK("audio_read: count=%d\n", count); + + if (*ppos != file->f_pos) { + printk("AudioRead - FPOS not ppos ppos=0x%x fpos =0x%x\n", + (u32) * ppos, (u32) file->f_pos); + return -ESPIPE; + } + if (s->mapped) { + printk("AudioRead - s already mapped\n"); + return -ENXIO; + } + + if (!s->active) { + if (!s->buffers && audio_setup_buf(s)) { + printk("AudioRead - No Memory\n"); + return -ENOMEM; + } + audio_prime_rx(state); + } + + while (count > 0) { + audio_buf_t *b = &s->buffers[s->usr_head]; + + /* 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 the current buffer */ + chunksize = s->fragsize - b->offset; + if (chunksize > count) + chunksize = count; + DPRINTK("read %d from %d\n", chunksize, s->usr_head); + if (copy_to_user(buffer, b->data + b->offset, chunksize)) { + up(&s->sem); + return -EFAULT; + } + buffer += chunksize; + count -= chunksize; + b->offset += chunksize; + if (b->offset < s->fragsize) { + up(&s->sem); + break; + } + + /* Update pointers and return current fragment to DMA */ + local_irq_save(flags); + b->offset = 0; + if (++s->usr_head >= s->nbfrags) + s->usr_head = 0; + + s->pending_frags++; + local_irq_restore(flags); + audio_process_dma(s); + + } + + if ((buffer - buffer0)) + ret = buffer - buffer0; + DPRINTK("audio_read: return=%d\n", ret); + return ret; +} + +/********************************************************************************* + * + * audio_mmap(): Exposed as mmap Function + * !!WARNING: Still under development + * + *********************************************************************************/ +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; + + FN_IN; + 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_pfn_range(vma, vma_addr, buf->dma_addr >> PAGE_SHIFT, + buf->master, vma->vm_page_prot); + if (ret) + return ret; + vma_addr += buf->master; + } + s->mapped = 1; + + FN_OUT(0); + return 0; +} + +/********************************************************************************* + * + * audio_poll(): Exposed as poll function + * + *********************************************************************************/ +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; + + DPRINTK("audio_poll(): mode=%s%s\n", + (file->f_mode & FMODE_READ) ? "r" : "", + (file->f_mode & FMODE_WRITE) ? "w" : ""); + + if (file->f_mode & FMODE_READ) { + /* Start audio input if not already active */ + if (!is->active) { + if (!is->buffers && audio_setup_buf(is)) + return -ENOMEM; + audio_prime_rx(state); + } + poll_wait(file, &is->wq, wait); + } + + if (file->f_mode & FMODE_WRITE) { + if (!os->buffers && audio_setup_buf(os)) + return -ENOMEM; + poll_wait(file, &os->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; + + DPRINTK("audio_poll() returned mask of %s%s\n", + (mask & POLLIN) ? "r" : "", (mask & POLLOUT) ? "w" : ""); + + FN_OUT(mask); + return mask; +} + +/********************************************************************************* + * + * audio_llseek(): Exposed as lseek() function. + * + *********************************************************************************/ +static loff_t audio_llseek(struct file *file, loff_t offset, int origin) +{ + FN_IN; + FN_OUT(0); + return -ESPIPE; +} + +/********************************************************************************* + * + * audio_ioctl(): Handles generic ioctls. If there is a request for something this + * fn cannot handle, its then given to client specific ioctl routine, that will take + * up platform specific requests + * + *********************************************************************************/ +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; + + DPRINTK(__FILE__ " audio_ioctl 0x%08x\n", cmd); + + /* dispatch based on command */ + 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; + FN_OUT(1); + return put_user(val, (int *)arg); + + case SNDCTL_DSP_SETFRAGMENT: + if (get_user(val, (long *)arg)) { + FN_OUT(2); + return -EFAULT; + } + if (file->f_mode & FMODE_READ) { + int ret = audio_set_fragments(is, val); + if (ret < 0) { + FN_OUT(3); + return ret; + } + ret = put_user(ret, (int *)arg); + if (ret) { + FN_OUT(4); + return ret; + } + } + if (file->f_mode & FMODE_WRITE) { + int ret = audio_set_fragments(os, val); + if (ret < 0) { + FN_OUT(5); + return ret; + } + ret = put_user(ret, (int *)arg); + if (ret) { + FN_OUT(6); + return ret; + } + } + FN_OUT(7); + return 0; + + case SNDCTL_DSP_SYNC: + FN_OUT(8); + return audio_sync(file); + + case SNDCTL_DSP_SETDUPLEX: + FN_OUT(9); + return 0; + + case SNDCTL_DSP_POST: + FN_OUT(10); + return 0; + + case SNDCTL_DSP_GETTRIGGER: + val = 0; + if (file->f_mode & FMODE_READ && is->active && !is->stopped) + val |= PCM_ENABLE_INPUT; + if (file->f_mode & FMODE_WRITE && os->active && !os->stopped) + val |= PCM_ENABLE_OUTPUT; + FN_OUT(11); + return put_user(val, (int *)arg); + + case SNDCTL_DSP_SETTRIGGER: + if (get_user(val, (int *)arg)) { + FN_OUT(12); + return -EFAULT; + } + if (file->f_mode & FMODE_READ) { + if (val & PCM_ENABLE_INPUT) { + unsigned long flags; + if (!is->active) { + if (!is->buffers && audio_setup_buf(is)) { + FN_OUT(13); + return -ENOMEM; + } + audio_prime_rx(state); + } + local_irq_save(flags); + is->stopped = 0; + local_irq_restore(flags); + audio_process_dma(is); + + } else { + audio_stop_dma(is); + } + } + if (file->f_mode & FMODE_WRITE) { + if (val & PCM_ENABLE_OUTPUT) { + unsigned long flags; + if (!os->buffers && audio_setup_buf(os)) { + FN_OUT(14); + return -ENOMEM; + } + local_irq_save(flags); + if (os->mapped && !os->pending_frags) { + os->pending_frags = os->nbfrags; + sema_init(&os->sem, 0); + os->active = 1; + } + os->stopped = 0; + local_irq_restore(flags); + audio_process_dma(os); + + } else { + audio_stop_dma(os); + } + } + FN_OUT(15); + return 0; + + case SNDCTL_DSP_GETOPTR: + case SNDCTL_DSP_GETIPTR: + { + count_info inf = { 0, }; + audio_stream_t *s = + (cmd == SNDCTL_DSP_GETOPTR) ? os : is; + int bytecount, offset; + unsigned long flags; + + if ((s == is && !(file->f_mode & FMODE_READ)) || + (s == os && !(file->f_mode & FMODE_WRITE))) { + FN_OUT(16); + return -EINVAL; + } + if (s->active) { + local_irq_save(flags); + offset = audio_get_dma_pos(s); + inf.ptr = s->dma_tail * s->fragsize + offset; + bytecount = s->bytecount + offset; + s->bytecount = -offset; + inf.blocks = s->fragcount; + s->fragcount = 0; + local_irq_restore(flags); + if (bytecount < 0) + bytecount = 0; + inf.bytes = bytecount; + } + FN_OUT(17); + return copy_to_user((void *)arg, &inf, sizeof(inf)); + } + + 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))) { + FN_OUT(18); + return -EINVAL; + } + if (!s->buffers && audio_setup_buf(s)) { + FN_OUT(19); + return -ENOMEM; + } + inf.bytes = atomic_read(&s->sem.count) * s->fragsize; + + inf.fragments = inf.bytes / s->fragsize; + inf.fragsize = s->fragsize; + inf.fragstotal = s->nbfrags; + FN_OUT(20); + return copy_to_user((void *)arg, &inf, sizeof(inf)); + } + + case SNDCTL_DSP_NONBLOCK: + file->f_flags |= O_NONBLOCK; + FN_OUT(21); + return 0; + + case SNDCTL_DSP_RESET: + if (file->f_mode & FMODE_READ) { + audio_reset(is); + if (state->need_tx_for_rx) { + unsigned long flags; + local_irq_save(flags); + os->spin_idle = 0; + local_irq_restore(flags); + } + } + if (file->f_mode & FMODE_WRITE) { + audio_reset(os); + } + FN_OUT(22); + return 0; + + default: + /* + * Let the client of this module handle the + * non generic ioctls + */ + FN_OUT(23); + return state->client_ioctl(inode, file, cmd, arg); + } + + FN_OUT(0); + return 0; +} + +/********************************************************************************* + * + * audio_open(): Exposed as open() function + * + *********************************************************************************/ +static int audio_open(struct inode *inode, struct file *file) +{ + audio_state_t *state = (&audio_state); + audio_stream_t *os = state->output_stream; + audio_stream_t *is = state->input_stream; + int err, need_tx_dma; + static unsigned char tsc2101_init_flag = 0; + + FN_IN; + + /* Lock the module */ + if (!try_module_get(THIS_MODULE)) { + printk(KERN_CRIT "Failed to get module\n"); + return -ESTALE; + } + /* Lock the codec module */ + if (!try_module_get(state->owner)) { + printk(KERN_CRIT "Failed to get codec module\n"); + module_put(THIS_MODULE); + return -ESTALE; + } + + 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; + err = -EINVAL; + if ((file->f_mode & FMODE_READ) && state->need_tx_for_rx && !os) + goto out; + + /* request DMA channels */ + need_tx_dma = ((file->f_mode & FMODE_WRITE) || + ((file->f_mode & FMODE_READ) && state->need_tx_for_rx)); + if (state->wr_ref || (state->rd_ref && state->need_tx_for_rx)) + need_tx_dma = 0; + if (need_tx_dma) { + DMA_REQUEST(err, os, audio_dma_callback); + if (err < 0) + goto out; + } + if (file->f_mode & FMODE_READ) { + DMA_REQUEST(err, is, audio_dma_callback); + if (err < 0) { + if (need_tx_dma) + DMA_FREE(os); + goto out; + } + } + + /* now complete initialisation */ + if (!AUDIO_ACTIVE(state)) { + if (state->hw_init && !tsc2101_init_flag) { + state->hw_init(state->data); + tsc2101_init_flag = 0; + + } + + } + + if ((file->f_mode & FMODE_WRITE)) { + state->wr_ref = 1; + audio_reset(os); + os->fragsize = AUDIO_FRAGSIZE_DEFAULT; + os->nbfrags = AUDIO_NBFRAGS_DEFAULT; + os->mapped = 0; + init_waitqueue_head(&os->wq); + } + + if (file->f_mode & FMODE_READ) { + state->rd_ref = 1; + audio_reset(is); + is->fragsize = AUDIO_FRAGSIZE_DEFAULT; + is->nbfrags = AUDIO_NBFRAGS_DEFAULT; + is->mapped = 0; + init_waitqueue_head(&is->wq); + } + + file->private_data = state; + err = 0; + + out: + up(&state->sem); + if (err) { + module_put(state->owner); + module_put(THIS_MODULE); + } + FN_OUT(err); + return err; +} + +/********************************************************************************* + * + * audio_release(): Exposed as release function() + * + *********************************************************************************/ +static int audio_release(struct inode *inode, struct file *file) +{ + audio_state_t *state = file->private_data; + audio_stream_t *os = state->output_stream; + audio_stream_t *is = state->input_stream; + + FN_IN; + + down(&state->sem); + + if (file->f_mode & FMODE_READ) { + audio_discard_buf(is); + DMA_FREE(is); + is->dma_spinref = 0; + if (state->need_tx_for_rx) { + os->spin_idle = 0; + if (!state->wr_ref) { + DMA_FREE(os); + os->dma_spinref = 0; + } + } + state->rd_ref = 0; + } + + if (file->f_mode & FMODE_WRITE) { + audio_sync(file); + audio_discard_buf(os); + if (!state->need_tx_for_rx || !state->rd_ref) { + DMA_FREE(os); + os->dma_spinref = 0; + } + state->wr_ref = 0; + } + + if (!AUDIO_ACTIVE(state)) { + if (state->hw_shutdown) + state->hw_shutdown(state->data); + } + + up(&state->sem); + + module_put(state->owner); + module_put(THIS_MODULE); + + FN_OUT(0); + return 0; +} + +EXPORT_SYMBOL(audio_register_codec); +EXPORT_SYMBOL(audio_unregister_codec); +EXPORT_SYMBOL(audio_get_fops); + +MODULE_AUTHOR("Texas Instruments"); +MODULE_DESCRIPTION("Common audio handling for OMAP processors"); +MODULE_LICENSE("GPL"); diff -Nru a/sound/oss/omap-audio.h b/sound/oss/omap-audio.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/sound/oss/omap-audio.h 2005-03-02 10:51:31 -08:00 @@ -0,0 +1,121 @@ +/* + * linux/sound/oss/omap-audio.h + * + * Common audio handling for the OMAP processors + * + * Copyright (C) 2004 Texas Instruments, Inc. + * + * Copyright (C) 2000, 2001 Nicolas Pitre + * + * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * History + * ------- + * 2004/08/12 Nishanth Menon - Modified to integrate Audio requirements on 1610,1710 platforms + * + * 2004/04/04 Nishanth menon - Added hooks for power management + */ + +#ifndef __OMAP_AUDIO_H +#define __OMAP_AUDIO_H + +/* Requires dma.h */ +#include + +/* + * Buffer Management + */ +typedef struct { + int offset; /* current offset */ + char *data; /* points to actual buffer */ + dma_addr_t dma_addr; /* physical buffer address */ + int dma_ref; /* DMA refcount */ + int master; /* owner for buffer allocation, contain size when true */ +} audio_buf_t; + +/* + * Structure describing the data stream related information + */ +typedef struct { + char *id; /* identification string */ + audio_buf_t *buffers; /* pointer to audio buffer structures */ + u_int usr_head; /* user fragment index */ + u_int dma_head; /* DMA fragment index to go */ + u_int dma_tail; /* DMA fragment index to complete */ + u_int fragsize; /* fragment i.e. buffer size */ + u_int nbfrags; /* nbr of fragments i.e. buffers */ + u_int pending_frags; /* Fragments sent to DMA */ + int dma_dev; /* device identifier for DMA */ + +#ifdef OMAP_DMA_CHAINING_SUPPORT + lch_chain *dma_chain; + dma_regs_t *dma_regs; /* points to our DMA registers */ +#else + u_int prevbuf; /* Prev pending frag size sent to DMA */ + char started; /* to store if the chain was started or not */ + int dma_q_head; /* DMA Channel Q Head */ + int dma_q_tail; /* DMA Channel Q Tail */ + char dma_q_count; /* DMA Channel Q Count */ + char in_use; /* Is this is use? */ + int *lch; /* Chain of channels this stream is linked to */ +#endif + int input_or_output; /* Direction of this data stream */ + int bytecount; /* nbr of processed bytes */ + int fragcount; /* nbr of fragment transitions */ + struct semaphore sem; /* account for fragment usage */ + wait_queue_head_t wq; /* for poll */ + int dma_spinref; /* DMA is spinning */ + int mapped:1; /* mmap()'ed buffers */ + int active:1; /* actually in progress */ + int stopped:1; /* might be active but stopped */ + int spin_idle:1; /* have DMA spin on zeros when idle */ +} audio_stream_t; + +/* + * State structure for one instance + */ +typedef struct { + struct module *owner; /* Codec module ID */ + audio_stream_t *output_stream; + audio_stream_t *input_stream; + int rd_ref:1; /* open reference for recording */ + int wr_ref:1; /* open reference for playback */ + int need_tx_for_rx:1; /* if data must be sent while receiving */ + void *data; + void (*hw_init) (void *); + void (*hw_shutdown) (void *); + int (*client_ioctl) (struct inode *, struct file *, uint, ulong); + int (*hw_probe) (void); + void (*hw_remove) (void); + void (*hw_cleanup) (void); + int (*hw_suspend) (void); + int (*hw_resume) (void); + struct pm_dev *pm_dev; + struct semaphore sem; /* to protect against races in attach() */ +} audio_state_t; + +#ifdef AUDIO_PM +void audio_ldm_suspend(void *data); + +void audio_ldm_resume(void *data); + +#endif + +/* Register a Codec using this function */ +extern int audio_register_codec(audio_state_t * codec_state); +/* Un-Register a Codec using this function */ +extern int audio_unregister_codec(audio_state_t * codec_state); +/* Function to provide fops of omap audio driver */ +extern struct file_operations *audio_get_fops(void); +/* Function to initialize the device info for audio driver */ +extern int audio_dev_init(void); +/* Function to un-initialize the device info for audio driver */ +void audio_dev_uninit(void); + +#endif /* End of #ifndef __OMAP_AUDIO_H */