summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/arm/Samsung-S3C24XX/DMA.txt46
-rw-r--r--Documentation/arm/Samsung-S3C24XX/Overview.txt21
-rw-r--r--arch/arm/Kconfig26
-rw-r--r--arch/arm/Makefile8
-rw-r--r--arch/arm/boot/.gitignore2
-rw-r--r--arch/arm/boot/compressed/.gitignore1
-rw-r--r--arch/arm/common/dmabounce.c87
-rw-r--r--arch/arm/common/gic.c109
-rw-r--r--arch/arm/configs/s3c2410_defconfig142
-rw-r--r--arch/arm/kernel/Makefile1
-rw-r--r--arch/arm/kernel/calls.S1
-rw-r--r--arch/arm/kernel/crunch.c1
-rw-r--r--arch/arm/kernel/ecard.c2
-rw-r--r--arch/arm/kernel/machine_kexec.c78
-rw-r--r--arch/arm/kernel/relocate_kernel.S74
-rw-r--r--arch/arm/kernel/setup.c3
-rw-r--r--arch/arm/kernel/time.c4
-rw-r--r--arch/arm/mach-ep93xx/clock.c6
-rw-r--r--arch/arm/mach-ep93xx/core.c115
-rw-r--r--arch/arm/mach-pxa/generic.c24
-rw-r--r--arch/arm/mach-realview/Kconfig11
-rw-r--r--arch/arm/mach-realview/platsmp.c4
-rw-r--r--arch/arm/mach-realview/realview_eb.c38
-rw-r--r--arch/arm/mach-s3c2400/Kconfig13
-rw-r--r--arch/arm/mach-s3c2400/Makefile15
-rw-r--r--arch/arm/mach-s3c2400/gpio.c (renamed from arch/arm/mach-s3c2410/s3c2400-gpio.c)2
-rw-r--r--arch/arm/mach-s3c2410/Kconfig338
-rw-r--r--arch/arm/mach-s3c2410/Makefile103
-rw-r--r--arch/arm/mach-s3c2410/bast-irq.c2
-rw-r--r--arch/arm/mach-s3c2410/bast.h2
-rw-r--r--arch/arm/mach-s3c2410/clock.c565
-rw-r--r--arch/arm/mach-s3c2410/dma.c1546
-rw-r--r--arch/arm/mach-s3c2410/gpio.c165
-rw-r--r--arch/arm/mach-s3c2410/irq.c775
-rw-r--r--arch/arm/mach-s3c2410/mach-amlm5900.c14
-rw-r--r--arch/arm/mach-s3c2410/mach-bast.c6
-rw-r--r--arch/arm/mach-s3c2410/mach-h1940.c64
-rw-r--r--arch/arm/mach-s3c2410/mach-n30.c9
-rw-r--r--arch/arm/mach-s3c2410/mach-otom.c8
-rw-r--r--arch/arm/mach-s3c2410/mach-qt2410.c448
-rw-r--r--arch/arm/mach-s3c2410/mach-smdk2410.c8
-rw-r--r--arch/arm/mach-s3c2410/mach-vr1000.c6
-rw-r--r--arch/arm/mach-s3c2410/pm.c653
-rw-r--r--arch/arm/mach-s3c2410/s3c2410-clock.c276
-rw-r--r--arch/arm/mach-s3c2410/s3c2410-dma.c161
-rw-r--r--arch/arm/mach-s3c2410/s3c2410-gpio.c71
-rw-r--r--arch/arm/mach-s3c2410/s3c2410-irq.c48
-rw-r--r--arch/arm/mach-s3c2410/s3c2410-pm.c156
-rw-r--r--arch/arm/mach-s3c2410/s3c2410-sleep.S68
-rw-r--r--arch/arm/mach-s3c2410/s3c2410.c10
-rw-r--r--arch/arm/mach-s3c2410/sleep.S151
-rw-r--r--arch/arm/mach-s3c2410/usb-simtec.c2
-rw-r--r--arch/arm/mach-s3c2412/Kconfig58
-rw-r--r--arch/arm/mach-s3c2412/Makefile21
-rw-r--r--arch/arm/mach-s3c2412/clock.c (renamed from arch/arm/mach-s3c2410/s3c2412-clock.c)8
-rw-r--r--arch/arm/mach-s3c2412/dma.c (renamed from arch/arm/mach-s3c2410/s3c2412-dma.c)7
-rw-r--r--arch/arm/mach-s3c2412/irq.c (renamed from arch/arm/mach-s3c2410/s3c2412-irq.c)8
-rw-r--r--arch/arm/mach-s3c2412/mach-smdk2413.c (renamed from arch/arm/mach-s3c2410/mach-smdk2413.c)68
-rw-r--r--arch/arm/mach-s3c2412/mach-vstms.c (renamed from arch/arm/mach-s3c2410/mach-vstms.c)13
-rw-r--r--arch/arm/mach-s3c2412/pm.c (renamed from arch/arm/mach-s3c2410/s3c2412-pm.c)8
-rw-r--r--arch/arm/mach-s3c2412/s3c2412.c (renamed from arch/arm/mach-s3c2410/s3c2412.c)12
-rw-r--r--arch/arm/mach-s3c2440/Kconfig71
-rw-r--r--arch/arm/mach-s3c2440/Makefile23
-rw-r--r--arch/arm/mach-s3c2440/clock.c (renamed from arch/arm/mach-s3c2410/s3c2440-clock.c)6
-rw-r--r--arch/arm/mach-s3c2440/dma.c (renamed from arch/arm/mach-s3c2410/s3c2440-dma.c)51
-rw-r--r--arch/arm/mach-s3c2440/dsc.c (renamed from arch/arm/mach-s3c2410/s3c2440-dsc.c)6
-rw-r--r--arch/arm/mach-s3c2440/irq.c (renamed from arch/arm/mach-s3c2410/s3c2440-irq.c)8
-rw-r--r--arch/arm/mach-s3c2440/mach-anubis.c (renamed from arch/arm/mach-s3c2410/mach-anubis.c)8
-rw-r--r--arch/arm/mach-s3c2440/mach-nexcoder.c (renamed from arch/arm/mach-s3c2410/mach-nexcoder.c)12
-rw-r--r--arch/arm/mach-s3c2440/mach-osiris.c (renamed from arch/arm/mach-s3c2410/mach-osiris.c)8
-rw-r--r--arch/arm/mach-s3c2440/mach-rx3715.c (renamed from arch/arm/mach-s3c2410/mach-rx3715.c)11
-rw-r--r--arch/arm/mach-s3c2440/mach-smdk2440.c (renamed from arch/arm/mach-s3c2410/mach-smdk2440.c)17
-rw-r--r--arch/arm/mach-s3c2440/s3c2440.c (renamed from arch/arm/mach-s3c2410/s3c2440.c)8
-rw-r--r--arch/arm/mach-s3c2442/Kconfig27
-rw-r--r--arch/arm/mach-s3c2442/Makefile16
-rw-r--r--arch/arm/mach-s3c2442/clock.c (renamed from arch/arm/mach-s3c2410/s3c2442-clock.c)6
-rw-r--r--arch/arm/mach-s3c2442/s3c2442.c (renamed from arch/arm/mach-s3c2410/s3c2442.c)6
-rw-r--r--arch/arm/mach-s3c2443/Kconfig29
-rw-r--r--arch/arm/mach-s3c2443/Makefile20
-rw-r--r--arch/arm/mach-s3c2443/clock.c1007
-rw-r--r--arch/arm/mach-s3c2443/dma.c180
-rw-r--r--arch/arm/mach-s3c2443/irq.c290
-rw-r--r--arch/arm/mach-s3c2443/mach-smdk2443.c137
-rw-r--r--arch/arm/mach-s3c2443/s3c2443.c97
-rw-r--r--arch/arm/mm/Kconfig7
-rw-r--r--arch/arm/mm/Makefile2
-rw-r--r--arch/arm/mm/cache-l2x0.c104
-rw-r--r--arch/arm/mm/consistent.c17
-rw-r--r--arch/arm/mm/context.c12
-rw-r--r--arch/arm/mm/fault-armv.c2
-rw-r--r--arch/arm/mm/mmu.c3
-rw-r--r--arch/arm/mm/proc-v6.S22
-rw-r--r--arch/arm/mm/proc-xsc3.S151
-rw-r--r--arch/arm/mm/tlb-v6.S4
-rw-r--r--arch/arm/plat-s3c24xx/Kconfig99
-rw-r--r--arch/arm/plat-s3c24xx/Makefile30
-rw-r--r--arch/arm/plat-s3c24xx/clock.c449
-rw-r--r--arch/arm/plat-s3c24xx/common-smdk.c (renamed from arch/arm/mach-s3c2410/common-smdk.c)8
-rw-r--r--arch/arm/plat-s3c24xx/cpu.c (renamed from arch/arm/mach-s3c2410/cpu.c)29
-rw-r--r--arch/arm/plat-s3c24xx/devs.c (renamed from arch/arm/mach-s3c2410/devs.c)21
-rw-r--r--arch/arm/plat-s3c24xx/dma.c1499
-rw-r--r--arch/arm/plat-s3c24xx/gpio.c188
-rw-r--r--arch/arm/plat-s3c24xx/irq.c801
-rw-r--r--arch/arm/plat-s3c24xx/pm-simtec.c (renamed from arch/arm/mach-s3c2410/pm-simtec.c)4
-rw-r--r--arch/arm/plat-s3c24xx/pm.c659
-rw-r--r--arch/arm/plat-s3c24xx/s3c244x-irq.c (renamed from arch/arm/mach-s3c2410/s3c244x-irq.c)8
-rw-r--r--arch/arm/plat-s3c24xx/s3c244x.c (renamed from arch/arm/mach-s3c2410/s3c244x.c)16
-rw-r--r--arch/arm/plat-s3c24xx/s3c244x.h (renamed from arch/arm/mach-s3c2410/s3c244x.h)2
-rw-r--r--arch/arm/plat-s3c24xx/sleep.S157
-rw-r--r--arch/arm/plat-s3c24xx/time.c (renamed from arch/arm/mach-s3c2410/time.c)6
-rw-r--r--drivers/i2c/busses/i2c-pxa.c241
-rw-r--r--drivers/serial/Kconfig3
-rw-r--r--drivers/serial/imx.c14
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.c16
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.h15
-rw-r--r--include/asm-arm/.gitignore2
-rw-r--r--include/asm-arm/arch-ep93xx/ep93xx-regs.h5
-rw-r--r--include/asm-arm/arch-ep93xx/irqs.h8
-rw-r--r--include/asm-arm/arch-ep93xx/platform.h1
-rw-r--r--include/asm-arm/arch-imx/entry-macro.S18
-rw-r--r--include/asm-arm/arch-ixp4xx/udc.h22
-rw-r--r--include/asm-arm/arch-pxa/pxa-regs.h24
-rw-r--r--include/asm-arm/arch-pxa/udc.h30
-rw-r--r--include/asm-arm/arch-realview/hardware.h2
-rw-r--r--include/asm-arm/arch-realview/irqs.h5
-rw-r--r--include/asm-arm/arch-realview/platform.h18
-rw-r--r--include/asm-arm/arch-realview/scu.h8
-rw-r--r--include/asm-arm/arch-s3c2410/dma.h36
-rw-r--r--include/asm-arm/arch-s3c2410/irqs.h74
-rw-r--r--include/asm-arm/arch-s3c2410/regs-adc.h2
-rw-r--r--include/asm-arm/arch-s3c2410/regs-gpio.h32
-rw-r--r--include/asm-arm/arch-s3c2410/regs-s3c2443-clock.h194
-rw-r--r--include/asm-arm/arch-s3c2410/regs-serial.h13
-rw-r--r--include/asm-arm/arch-s3c2410/reset.h22
-rw-r--r--include/asm-arm/arch-s3c2410/system.h15
-rw-r--r--include/asm-arm/arch-s3c2410/udc.h36
-rw-r--r--include/asm-arm/cacheflush.h49
-rw-r--r--include/asm-arm/device.h10
-rw-r--r--include/asm-arm/dma-mapping.h18
-rw-r--r--include/asm-arm/domain.h1
-rw-r--r--include/asm-arm/hardware/arm_scu.h2
-rw-r--r--include/asm-arm/hardware/cache-l2x0.h56
-rw-r--r--include/asm-arm/hardware/gic.h5
-rw-r--r--include/asm-arm/hardware/sa1111.h93
-rw-r--r--include/asm-arm/kexec.h30
-rw-r--r--include/asm-arm/pgtable.h54
-rw-r--r--include/asm-arm/plat-s3c24xx/clock.h (renamed from arch/arm/mach-s3c2410/clock.h)2
-rw-r--r--include/asm-arm/plat-s3c24xx/common-smdk.h (renamed from arch/arm/mach-s3c2410/common-smdk.h)2
-rw-r--r--include/asm-arm/plat-s3c24xx/cpu.h (renamed from arch/arm/mach-s3c2410/cpu.h)3
-rw-r--r--include/asm-arm/plat-s3c24xx/devs.h (renamed from arch/arm/mach-s3c2410/devs.h)2
-rw-r--r--include/asm-arm/plat-s3c24xx/dma.h (renamed from arch/arm/mach-s3c2410/dma.h)34
-rw-r--r--include/asm-arm/plat-s3c24xx/irq.h (renamed from arch/arm/mach-s3c2410/irq.h)2
-rw-r--r--include/asm-arm/plat-s3c24xx/pm.h (renamed from arch/arm/mach-s3c2410/pm.h)2
-rw-r--r--include/asm-arm/plat-s3c24xx/s3c2400.h (renamed from arch/arm/mach-s3c2410/s3c2400.h)2
-rw-r--r--include/asm-arm/plat-s3c24xx/s3c2410.h (renamed from arch/arm/mach-s3c2410/s3c2410.h)2
-rw-r--r--include/asm-arm/plat-s3c24xx/s3c2412.h (renamed from arch/arm/mach-s3c2410/s3c2412.h)2
-rw-r--r--include/asm-arm/plat-s3c24xx/s3c2440.h (renamed from arch/arm/mach-s3c2410/s3c2440.h)2
-rw-r--r--include/asm-arm/plat-s3c24xx/s3c2442.h (renamed from arch/arm/mach-s3c2410/s3c2442.h)2
-rw-r--r--include/asm-arm/plat-s3c24xx/s3c2443.h32
-rw-r--r--include/asm-arm/system.h62
-rw-r--r--include/asm-arm/tlbflush.h50
-rw-r--r--include/asm-arm/unistd.h1
-rw-r--r--include/linux/kexec.h1
163 files changed, 9162 insertions, 5251 deletions
diff --git a/Documentation/arm/Samsung-S3C24XX/DMA.txt b/Documentation/arm/Samsung-S3C24XX/DMA.txt
new file mode 100644
index 00000000000..37f4edcc5d8
--- /dev/null
+++ b/Documentation/arm/Samsung-S3C24XX/DMA.txt
@@ -0,0 +1,46 @@
+ S3C2410 DMA
+ ===========
+
+Introduction
+------------
+
+ The kernel provides an interface to manage DMA transfers
+ using the DMA channels in the cpu, so that the central
+ duty of managing channel mappings, and programming the
+ channel generators is in one place.
+
+
+DMA Channel Ordering
+--------------------
+
+ Many of the range do not have connections for the DMA
+ channels to all sources, which means that some devices
+ have a restricted number of channels that can be used.
+
+ To allow flexibilty for each cpu type and board, the
+ dma code can be given an dma ordering structure which
+ allows the order of channel search to be specified, as
+ well as allowing the prohibition of certain claims.
+
+ struct s3c24xx_dma_order has a list of channels, and
+ each channel within has a slot for a list of dma
+ channel numbers. The slots are searched in order, for
+ the presence of a dma channel number with DMA_CH_VALID
+ orred in.
+
+ If the order has the flag DMA_CH_NEVER set, then after
+ checking the channel list, the system will return no
+ found channel, thus denying the request.
+
+ A board support file can call s3c24xx_dma_order_set()
+ to register an complete ordering set. The routine will
+ copy the data, so the original can be discared with
+ __initdata.
+
+
+Authour
+-------
+
+Ben Dooks,
+Copyright (c) 2007 Ben Dooks, Simtec Electronics
+Licensed under the GPL v2
diff --git a/Documentation/arm/Samsung-S3C24XX/Overview.txt b/Documentation/arm/Samsung-S3C24XX/Overview.txt
index 28d014714ab..c31b76fa66c 100644
--- a/Documentation/arm/Samsung-S3C24XX/Overview.txt
+++ b/Documentation/arm/Samsung-S3C24XX/Overview.txt
@@ -8,13 +8,10 @@ Introduction
The Samsung S3C24XX range of ARM9 System-on-Chip CPUs are supported
by the 's3c2410' architecture of ARM Linux. Currently the S3C2410,
- S3C2440 and S3C2442 devices are supported.
+ S3C2412, S3C2413, S3C2440 and S3C2442 devices are supported.
Support for the S3C2400 series is in progress.
- Support for the S3C2412 and S3C2413 CPUs is being merged.
-
-
Configuration
-------------
@@ -26,6 +23,22 @@ Configuration
please check the machine specific documentation.
+Layout
+------
+
+ The core support files are located in the platform code contained in
+ arch/arm/plat-s3c24xx with headers in include/asm-arm/plat-s3c24xx.
+ This directory should be kept to items shared between the platform
+ code (arch/arm/plat-s3c24xx) and the arch/arm/mach-s3c24* code.
+
+ Each cpu has a directory with the support files for it, and the
+ machines that carry the device. For example S3C2410 is contained
+ in arch/arm/mach-s3c2410 and S3C2440 in arch/arm/mach-s3c2440
+
+ Register, kernel and platform data definitions are held in the
+ include/asm-arm/arch-s3c2410 directory.
+
+
Machines
--------
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 9c7565c8f37..195650935c7 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -280,6 +280,7 @@ config ARCH_PXA
bool "PXA2xx-based"
depends on MMU
select ARCH_MTD_XIP
+ select GENERIC_TIME
help
Support for Intel's PXA2XX processor line.
@@ -303,7 +304,7 @@ config ARCH_SA1100
Support for StrongARM 11x0 based boards.
config ARCH_S3C2410
- bool "Samsung S3C2410, S3C2412, S3C2413, S3C2440, S3C2442"
+ bool "Samsung S3C2410, S3C2412, S3C2413, S3C2440, S3C2442, S3C2443"
help
Samsung S3C2410X CPU based systems, such as the Simtec Electronics
BAST (<http://www.simtec.co.uk/products/EB110ITX/>), the IPAQ 1940 or
@@ -363,7 +364,16 @@ source "arch/arm/mach-omap1/Kconfig"
source "arch/arm/mach-omap2/Kconfig"
+source "arch/arm/plat-s3c24xx/Kconfig"
+
+if ARCH_S3C2410
+source "arch/arm/mach-s3c2400/Kconfig"
source "arch/arm/mach-s3c2410/Kconfig"
+source "arch/arm/mach-s3c2412/Kconfig"
+source "arch/arm/mach-s3c2440/Kconfig"
+source "arch/arm/mach-s3c2442/Kconfig"
+source "arch/arm/mach-s3c2443/Kconfig"
+endif
source "arch/arm/mach-lh7a40x/Kconfig"
@@ -738,6 +748,20 @@ config XIP_PHYS_ADDR
be linked for and stored to. This address is dependent on your
own flash usage.
+config KEXEC
+ bool "Kexec system call (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ help
+ kexec is a system call that implements the ability to shutdown your
+ current kernel, and to start another kernel. It is like a reboot
+ but it is indepedent of the system firmware. And like a reboot
+ you can start any kernel with it, not just Linux.
+
+ It is an ongoing process to be certain the hardware in a machine
+ is properly shutdown, so do not be surprised if this code does not
+ initially work for you. It may help to enable device hotplugging
+ support.
+
endmenu
if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP || ARCH_IMX )
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 0205547fa45..2cd871c82c9 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -149,7 +149,7 @@ MACHINE := arch/arm/mach-$(machine-y)/
else
MACHINE :=
endif
-
+
export TEXT_OFFSET GZFLAGS MMUEXT
# Do we have FASTFPE?
@@ -161,6 +161,11 @@ endif
# If we have a machine-specific directory, then include it in the build.
core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
core-y += $(MACHINE)
+core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2400/
+core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2412/
+core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2440/
+core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2442/
+core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2443/
core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/
core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ)
core-$(CONFIG_VFP) += arch/arm/vfp/
@@ -168,6 +173,7 @@ core-$(CONFIG_VFP) += arch/arm/vfp/
# If we have a common platform directory, then include it in the build.
core-$(CONFIG_PLAT_IOP) += arch/arm/plat-iop/
core-$(CONFIG_ARCH_OMAP) += arch/arm/plat-omap/
+core-$(CONFIG_PLAT_S3C24XX) += arch/arm/plat-s3c24xx/
drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/
drivers-$(CONFIG_ARCH_CLPS7500) += drivers/acorn/char/
diff --git a/arch/arm/boot/.gitignore b/arch/arm/boot/.gitignore
new file mode 100644
index 00000000000..171a0853caf
--- /dev/null
+++ b/arch/arm/boot/.gitignore
@@ -0,0 +1,2 @@
+Image
+zImage
diff --git a/arch/arm/boot/compressed/.gitignore b/arch/arm/boot/compressed/.gitignore
new file mode 100644
index 00000000000..aefee20cbf9
--- /dev/null
+++ b/arch/arm/boot/compressed/.gitignore
@@ -0,0 +1 @@
+piggy.gz
diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c
index 2e635b814c1..6fbe7722aa4 100644
--- a/arch/arm/common/dmabounce.c
+++ b/arch/arm/common/dmabounce.c
@@ -32,7 +32,6 @@
#include <asm/cacheflush.h>
-#undef DEBUG
#undef STATS
#ifdef STATS
@@ -66,14 +65,13 @@ struct dmabounce_pool {
};
struct dmabounce_device_info {
- struct list_head node;
-
struct device *dev;
struct list_head safe_buffers;
#ifdef STATS
unsigned long total_allocs;
unsigned long map_op_count;
unsigned long bounce_count;
+ int attr_res;
#endif
struct dmabounce_pool small;
struct dmabounce_pool large;
@@ -81,33 +79,23 @@ struct dmabounce_device_info {
rwlock_t lock;
};
-static LIST_HEAD(dmabounce_devs);
-
#ifdef STATS
-static void print_alloc_stats(struct dmabounce_device_info *device_info)
+static ssize_t dmabounce_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- printk(KERN_INFO
- "%s: dmabounce: sbp: %lu, lbp: %lu, other: %lu, total: %lu\n",
- device_info->dev->bus_id,
- device_info->small.allocs, device_info->large.allocs,
+ struct dmabounce_device_info *device_info = dev->archdata.dmabounce;
+ return sprintf(buf, "%lu %lu %lu %lu %lu %lu\n",
+ device_info->small.allocs,
+ device_info->large.allocs,
device_info->total_allocs - device_info->small.allocs -
device_info->large.allocs,
- device_info->total_allocs);
+ device_info->total_allocs,
+ device_info->map_op_count,
+ device_info->bounce_count);
}
-#endif
-
-/* find the given device in the dmabounce device list */
-static inline struct dmabounce_device_info *
-find_dmabounce_dev(struct device *dev)
-{
- struct dmabounce_device_info *d;
- list_for_each_entry(d, &dmabounce_devs, node)
- if (d->dev == dev)
- return d;
-
- return NULL;
-}
+static DEVICE_ATTR(dmabounce_stats, 0400, dmabounce_show, NULL);
+#endif
/* allocate a 'safe' buffer and keep track of it */
@@ -162,8 +150,6 @@ alloc_safe_buffer(struct dmabounce_device_info *device_info, void *ptr,
if (pool)
pool->allocs++;
device_info->total_allocs++;
- if (device_info->total_allocs % 1000 == 0)
- print_alloc_stats(device_info);
#endif
write_lock_irqsave(&device_info->lock, flags);
@@ -218,20 +204,11 @@ free_safe_buffer(struct dmabounce_device_info *device_info, struct safe_buffer *
/* ************************************************** */
-#ifdef STATS
-static void print_map_stats(struct dmabounce_device_info *device_info)
-{
- dev_info(device_info->dev,
- "dmabounce: map_op_count=%lu, bounce_count=%lu\n",
- device_info->map_op_count, device_info->bounce_count);
-}
-#endif
-
static inline dma_addr_t
map_single(struct device *dev, void *ptr, size_t size,
enum dma_data_direction dir)
{
- struct dmabounce_device_info *device_info = find_dmabounce_dev(dev);
+ struct dmabounce_device_info *device_info = dev->archdata.dmabounce;
dma_addr_t dma_addr;
int needs_bounce = 0;
@@ -281,10 +258,14 @@ map_single(struct device *dev, void *ptr, size_t size,
ptr = buf->safe;
dma_addr = buf->safe_dma_addr;
+ } else {
+ /*
+ * We don't need to sync the DMA buffer since
+ * it was allocated via the coherent allocators.
+ */
+ consistent_sync(ptr, size, dir);
}
- consistent_sync(ptr, size, dir);
-
return dma_addr;
}
@@ -292,7 +273,7 @@ static inline void
unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
enum dma_data_direction dir)
{
- struct dmabounce_device_info *device_info = find_dmabounce_dev(dev);
+ struct dmabounce_device_info *device_info = dev->archdata.dmabounce;
struct safe_buffer *buf = NULL;
/*
@@ -317,12 +298,12 @@ unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
DO_STATS ( device_info->bounce_count++ );
if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL) {
- unsigned long ptr;
+ void *ptr = buf->ptr;
dev_dbg(dev,
"%s: copy back safe %p to unsafe %p size %d\n",
- __func__, buf->safe, buf->ptr, size);
- memcpy(buf->ptr, buf->safe, size);
+ __func__, buf->safe, ptr, size);
+ memcpy(ptr, buf->safe, size);
/*
* DMA buffers must have the same cache properties
@@ -332,8 +313,8 @@ unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
* bidirectional case because we know the cache
* lines will be coherent with the data written.
*/
- ptr = (unsigned long)buf->ptr;
dmac_clean_range(ptr, ptr + size);
+ outer_clean_range(__pa(ptr), __pa(ptr) + size);
}
free_safe_buffer(device_info, buf);
}
@@ -343,7 +324,7 @@ static inline void
sync_single(struct device *dev, dma_addr_t dma_addr, size_t size,
enum dma_data_direction dir)
{
- struct dmabounce_device_info *device_info = find_dmabounce_dev(dev);
+ struct dmabounce_device_info *device_info = dev->archdata.dmabounce;
struct safe_buffer *buf = NULL;
if (device_info)
@@ -397,7 +378,10 @@ sync_single(struct device *dev, dma_addr_t dma_addr, size_t size,
default:
BUG();
}
- consistent_sync(buf->safe, size, dir);
+ /*
+ * No need to sync the safe buffer - it was allocated
+ * via the coherent allocators.
+ */
} else {
consistent_sync(dma_to_virt(dev, dma_addr), size, dir);
}
@@ -604,9 +588,10 @@ dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size,
device_info->total_allocs = 0;
device_info->map_op_count = 0;
device_info->bounce_count = 0;
+ device_info->attr_res = device_create_file(dev, &dev_attr_dmabounce_stats);
#endif
- list_add(&device_info->node, &dmabounce_devs);
+ dev->archdata.dmabounce = device_info;
printk(KERN_INFO "dmabounce: registered device %s on %s bus\n",
dev->bus_id, dev->bus->name);
@@ -623,7 +608,9 @@ dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size,
void
dmabounce_unregister_dev(struct device *dev)
{
- struct dmabounce_device_info *device_info = find_dmabounce_dev(dev);
+ struct dmabounce_device_info *device_info = dev->archdata.dmabounce;
+
+ dev->archdata.dmabounce = NULL;
if (!device_info) {
printk(KERN_WARNING
@@ -645,12 +632,10 @@ dmabounce_unregister_dev(struct device *dev)
dma_pool_destroy(device_info->large.pool);
#ifdef STATS
- print_alloc_stats(device_info);
- print_map_stats(device_info);
+ if (device_info->attr_res == 0)
+ device_remove_file(dev, &dev_attr_dmabounce_stats);
#endif
- list_del(&device_info->node);
-
kfree(device_info);
printk(KERN_INFO "dmabounce: device %s on %s bus unregistered\n",
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 09b9d1b6844..4deece5fbdf 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -14,7 +14,9 @@
*
* o There is one CPU Interface per CPU, which sends interrupts sent
* by the Distributor, and interrupts generated locally, to the
- * associated CPU.
+ * associated CPU. The base address of the CPU interface is usually
+ * aliased so that the same address points to different chips depending
+ * on the CPU it is accessed from.
*
* Note that IRQs 0-31 are special - they are local to each CPU.
* As such, the enable set/clear, pending set/clear and active bit
@@ -31,10 +33,38 @@
#include <asm/mach/irq.h>
#include <asm/hardware/gic.h>
-static void __iomem *gic_dist_base;
-static void __iomem *gic_cpu_base;
static DEFINE_SPINLOCK(irq_controller_lock);
+struct gic_chip_data {
+ unsigned int irq_offset;
+ void __iomem *dist_base;
+ void __iomem *cpu_base;
+};
+
+#ifndef MAX_GIC_NR
+#define MAX_GIC_NR 1
+#endif
+
+static struct gic_chip_data gic_data[MAX_GIC_NR];
+
+static inline void __iomem *gic_dist_base(unsigned int irq)
+{
+ struct gic_chip_data *gic_data = get_irq_chip_data(irq);
+ return gic_data->dist_base;
+}
+
+static inline void __iomem *gic_cpu_base(unsigned int irq)
+{
+ struct gic_chip_data *gic_data = get_irq_chip_data(irq);
+ return gic_data->cpu_base;
+}
+
+static inline unsigned int gic_irq(unsigned int irq)
+{
+ struct gic_chip_data *gic_data = get_irq_chip_data(irq);
+ return irq - gic_data->irq_offset;
+}
+
/*
* Routines to acknowledge, disable and enable interrupts
*
@@ -55,8 +85,8 @@ static void gic_ack_irq(unsigned int irq)
u32 mask = 1 << (irq % 32);
spin_lock(&irq_controller_lock);
- writel(mask, gic_dist_base + GIC_DIST_ENABLE_CLEAR + (irq / 32) * 4);
- writel(irq, gic_cpu_base + GIC_CPU_EOI);
+ writel(mask, gic_dist_base(irq) + GIC_DIST_ENABLE_CLEAR + (gic_irq(irq) / 32) * 4);
+ writel(gic_irq(irq), gic_cpu_base(irq) + GIC_CPU_EOI);
spin_unlock(&irq_controller_lock);
}
@@ -65,7 +95,7 @@ static void gic_mask_irq(unsigned int irq)
u32 mask = 1 << (irq % 32);
spin_lock(&irq_controller_lock);
- writel(mask, gic_dist_base + GIC_DIST_ENABLE_CLEAR + (irq / 32) * 4);
+ writel(mask, gic_dist_base(irq) + GIC_DIST_ENABLE_CLEAR + (gic_irq(irq) / 32) * 4);
spin_unlock(&irq_controller_lock);
}
@@ -74,14 +104,14 @@ static void gic_unmask_irq(unsigned int irq)
u32 mask = 1 << (irq % 32);
spin_lock(&irq_controller_lock);
- writel(mask, gic_dist_base + GIC_DIST_ENABLE_SET + (irq / 32) * 4);
+ writel(mask, gic_dist_base(irq) + GIC_DIST_ENABLE_SET + (gic_irq(irq) / 32) * 4);
spin_unlock(&irq_controller_lock);
}
#ifdef CONFIG_SMP
static void gic_set_cpu(unsigned int irq, cpumask_t mask_val)
{
- void __iomem *reg = gic_dist_base + GIC_DIST_TARGET + (irq & ~3);
+ void __iomem *reg = gic_dist_base(irq) + GIC_DIST_TARGET + (gic_irq(irq) & ~3);
unsigned int shift = (irq % 4) * 8;
unsigned int cpu = first_cpu(mask_val);
u32 val;
@@ -95,6 +125,37 @@ static void gic_set_cpu(unsigned int irq, cpumask_t mask_val)
}
#endif
+static void fastcall gic_handle_cascade_irq(unsigned int irq,
+ struct irq_desc *desc)
+{
+ struct gic_chip_data *chip_data = get_irq_data(irq);
+ struct irq_chip *chip = get_irq_chip(irq);
+ unsigned int cascade_irq;
+ unsigned long status;
+
+ /* primary controller ack'ing */
+ chip->ack(irq);
+
+ spin_lock(&irq_controller_lock);
+ status = readl(chip_data->cpu_base + GIC_CPU_INTACK);
+ spin_unlock(&irq_controller_lock);
+
+ cascade_irq = (status & 0x3ff);
+ if (cascade_irq > 1020)
+ goto out;
+ if (cascade_irq < 32 || cascade_irq >= NR_IRQS) {
+ do_bad_IRQ(cascade_irq, desc);
+ goto out;
+ }
+
+ cascade_irq += chip_data->irq_offset;
+ generic_handle_irq(cascade_irq);
+
+ out:
+ /* primary controller unmasking */
+ chip->unmask(irq);
+}
+
static struct irq_chip gic_chip = {
.name = "GIC",
.ack = gic_ack_irq,
@@ -105,15 +166,29 @@ static struct irq_chip gic_chip = {
#endif
};
-void __init gic_dist_init(void __iomem *base)
+void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
+{
+ if (gic_nr >= MAX_GIC_NR)
+ BUG();
+ if (set_irq_data(irq, &gic_data[gic_nr]) != 0)
+ BUG();
+ set_irq_chained_handler(irq, gic_handle_cascade_irq);
+}
+
+void __init gic_dist_init(unsigned int gic_nr, void __iomem *base,
+ unsigned int irq_start)
{
unsigned int max_irq, i;
u32 cpumask = 1 << smp_processor_id();
+ if (gic_nr >= MAX_GIC_NR)
+ BUG();
+
cpumask |= cpumask << 8;
cpumask |= cpumask << 16;
- gic_dist_base = base;
+ gic_data[gic_nr].dist_base = base;
+ gic_data[gic_nr].irq_offset = (irq_start - 1) & ~31;
writel(0, base + GIC_DIST_CTRL);
@@ -158,8 +233,9 @@ void __init gic_dist_init(void __iomem *base)
/*
* Setup the Linux IRQ subsystem.
*/
- for (i = 29; i < max_irq; i++) {
+ for (i = irq_start; i < gic_data[gic_nr].irq_offset + max_irq; i++) {
set_irq_chip(i, &gic_chip);
+ set_irq_chip_data(i, &gic_data[gic_nr]);
set_irq_handler(i, handle_level_irq);
set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
}
@@ -167,9 +243,13 @@ void __init gic_dist_init(void __iomem *base)
writel(1, base + GIC_DIST_CTRL);
}
-void __cpuinit gic_cpu_init(void __iomem *base)
+void __cpuinit gic_cpu_init(unsigned int gic_nr, void __iomem *base)
{
- gic_cpu_base = base;
+ if (gic_nr >= MAX_GIC_NR)
+ BUG();
+
+ gic_data[gic_nr].cpu_base = base;
+
writel(0xf0, base + GIC_CPU_PRIMASK);
writel(1, base + GIC_CPU_CTRL);
}
@@ -179,6 +259,7 @@ void gic_raise_softirq(cpumask_t cpumask, unsigned int irq)
{
unsigned long map = *cpus_addr(cpumask);
- writel(map << 16 | irq, gic_dist_base + GIC_DIST_SOFTINT);
+ /* this always happens on GIC0 */
+ writel(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT);
}
#endif
diff --git a/arch/arm/configs/s3c2410_defconfig b/arch/arm/configs/s3c2410_defconfig
index 3b31a33d008..df19e363203 100644
--- a/arch/arm/configs/s3c2410_defconfig
+++ b/arch/arm/configs/s3c2410_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.19-rc4
-# Fri Nov 3 17:41:31 2006
+# Linux kernel version: 2.6.20
+# Thu Feb 15 11:26:24 2007
#
CONFIG_ARM=y
# CONFIG_GENERIC_TIME is not set
@@ -11,6 +11,8 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_VECTORS_BASE=0xffff0000
@@ -37,13 +39,14 @@ CONFIG_SYSVIPC=y
# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SYSCTL=y
# CONFIG_EMBEDDED is not set
CONFIG_UID16=y
-# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -76,7 +79,9 @@ CONFIG_KMOD=y
# Block layer
#
CONFIG_BLOCK=y
+# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
#
# IO Schedulers
@@ -110,6 +115,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
# CONFIG_ARCH_IMX is not set
# CONFIG_ARCH_IOP32X is not set
# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IOP13XX is not set
# CONFIG_ARCH_IXP4XX is not set
# CONFIG_ARCH_IXP2000 is not set
# CONFIG_ARCH_IXP23XX is not set
@@ -122,54 +128,73 @@ CONFIG_ARCH_S3C2410=y
# CONFIG_ARCH_SHARK is not set
# CONFIG_ARCH_LH7A40X is not set
# CONFIG_ARCH_OMAP is not set
+CONFIG_PLAT_S3C24XX=y
+CONFIG_CPU_S3C244X=y
+CONFIG_PM_SIMTEC=y
+# CONFIG_S3C2410_BOOT_WATCHDOG is not set
+# CONFIG_S3C2410_BOOT_ERROR_RESET is not set
+# CONFIG_S3C2410_PM_DEBUG is not set
+# CONFIG_S3C2410_PM_CHECK is not set
+CONFIG_S3C2410_LOWLEVEL_UART_PORT=0
+CONFIG_S3C2410_DMA=y
+# CONFIG_S3C2410_DMA_DEBUG is not set
+CONFIG_MACH_SMDK=y
#
-# S3C24XX Implementations
+# S3C2400 Machines
#
-# CONFIG_MACH_AML_M5900 is not set
-CONFIG_MACH_ANUBIS=y
-CONFIG_MACH_OSIRIS=y
-CONFIG_ARCH_BAST=y
-CONFIG_BAST_PC104_IRQ=y
+CONFIG_CPU_S3C2410=y
+CONFIG_CPU_S3C2410_DMA=y
+CONFIG_S3C2410_PM=y
+CONFIG_S3C2410_GPIO=y
+CONFIG_S3C2410_CLOCK=y
+
+#
+# S3C2410 Machines
+#
+CONFIG_ARCH_SMDK2410=y
CONFIG_ARCH_H1940=y
+CONFIG_PM_H1940=y
CONFIG_MACH_N30=y
-CONFIG_MACH_SMDK=y
-CONFIG_ARCH_SMDK2410=y
-CONFIG_ARCH_S3C2440=y
-CONFIG_SMDK2440_CPU2440=y
-CONFIG_SMDK2440_CPU2442=y
-CONFIG_MACH_S3C2413=y
-CONFIG_MACH_SMDK2413=y
-CONFIG_MACH_VR1000=y
-CONFIG_MACH_RX3715=y
+CONFIG_ARCH_BAST=y
CONFIG_MACH_OTOM=y
-CONFIG_MACH_NEXCODER_2440=y
-CONFIG_MACH_VSTMS=y
-CONFIG_S3C2410_CLOCK=y
-CONFIG_S3C2410_PM=y
-CONFIG_CPU_S3C2410_DMA=y
-CONFIG_CPU_S3C2410=y
-CONFIG_S3C2412_PM=y
+CONFIG_MACH_AML_M5900=y
+CONFIG_BAST_PC104_IRQ=y
+CONFIG_MACH_VR1000=y
CONFIG_CPU_S3C2412=y
-CONFIG_CPU_S3C244X=y
+CONFIG_S3C2412_DMA=y
+CONFIG_S3C2412_PM=y
+
+#
+# S3C2412 Machines
+#
+CONFIG_MACH_SMDK2413=y
+CONFIG_MACH_S3C2413=y
+CONFIG_MACH_VSTMS=y
CONFIG_CPU_S3C2440=y
+CONFIG_S3C2440_DMA=y
+
+#
+# S3C2440 Machines
+#
+CONFIG_MACH_ANUBIS=y
+CONFIG_MACH_OSIRIS=y
+CONFIG_MACH_RX3715=y
+CONFIG_ARCH_S3C2440=y
+CONFIG_MACH_NEXCODER_2440=y
+CONFIG_SMDK2440_CPU2440=y
CONFIG_CPU_S3C2442=y
#
-# S3C2410 Boot
+# S3C2442 Machines
#
-# CONFIG_S3C2410_BOOT_WATCHDOG is not set
-# CONFIG_S3C2410_BOOT_ERROR_RESET is not set
+CONFIG_SMDK2440_CPU2442=y
+CONFIG_CPU_S3C2443=y
#
-# S3C2410 Setup
+# S3C2443 Machines
#
-CONFIG_S3C2410_DMA=y
-# CONFIG_S3C2410_DMA_DEBUG is not set
-# CONFIG_S3C2410_PM_DEBUG is not set
-# CONFIG_S3C2410_PM_CHECK is not set
-CONFIG_PM_SIMTEC=y
-CONFIG_S3C2410_LOWLEVEL_UART_PORT=0
+CONFIG_MACH_SMDK2443=y
#
# Processor Type
@@ -196,6 +221,7 @@ CONFIG_CPU_CP15_MMU=y
# CONFIG_CPU_DCACHE_DISABLE is not set
# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+# CONFIG_OUTER_CACHE is not set
#
# Bus support
@@ -303,6 +329,7 @@ CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
@@ -385,6 +412,7 @@ CONFIG_MTD_CMDLINE_PARTS=y
# User Modules And Translation Layers
#
CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
@@ -531,6 +559,11 @@ CONFIG_BLK_DEV_IDE_BAST=y
# CONFIG_SCSI_NETLINK is not set
#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
# Multi-device support (RAID and LVM)
#
# CONFIG_MD is not set
@@ -682,7 +715,7 @@ CONFIG_SERIAL_NONSTANDARD=y
# CONFIG_DIGIEPCA is not set
# CONFIG_MOXA_INTELLIO is not set
# CONFIG_MOXA_SMARTIO is not set
-# CONFIG_ISI is not set
+# CONFIG_MOXA_SMARTIO_NEW is not set
# CONFIG_SYNCLINKMP is not set
# CONFIG_N_HDLC is not set
# CONFIG_RISCOM8 is not set
@@ -700,13 +733,14 @@ CONFIG_SERIAL_8250_NR_UARTS=8
CONFIG_SERIAL_8250_RUNTIME_UARTS=4
CONFIG_SERIAL_8250_EXTENDED=y
CONFIG_SERIAL_8250_MANY_PORTS=y
-CONFIG_SERIAL_8250_SHARE_IRQ=y
-# CONFIG_SERIAL_8250_DETECT_IRQ is not set
-# CONFIG_SERIAL_8250_RSA is not set
# CONFIG_SERIAL_8250_FOURPORT is not set
# CONFIG_SERIAL_8250_ACCENT is not set
# CONFIG_SERIAL_8250_BOCA is not set
+# CONFIG_SERIAL_8250_EXAR_ST16C554 is not set
# CONFIG_SERIAL_8250_HUB6 is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_RSA is not set
#
# Non-8250 serial port support
@@ -755,10 +789,6 @@ CONFIG_HW_RANDOM=y
# CONFIG_NVRAM is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
-
-#
-# Ftape, the floppy tape device driver
-#
# CONFIG_RAW_DRIVER is not set
#
@@ -863,6 +893,7 @@ CONFIG_SENSORS_LM85=m
# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
# CONFIG_SENSORS_SMSC47M192 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
@@ -870,6 +901,7 @@ CONFIG_SENSORS_LM85=m
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83791D is not set
# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
# CONFIG_SENSORS_W83627EHF is not set
@@ -952,6 +984,11 @@ CONFIG_FONT_8x16=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -1028,6 +1065,7 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
# CONFIG_USB_KAWETH is not set
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
# CONFIG_USB_USBNET is not set
CONFIG_USB_MON=y
@@ -1179,9 +1217,6 @@ CONFIG_RAMFS=y
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
-CONFIG_JFFS_FS=y
-CONFIG_JFFS_FS_VERBOSE=0
-# CONFIG_JFFS_PROC_FS is not set
CONFIG_JFFS2_FS=y
CONFIG_JFFS2_FS_DEBUG=0
CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -1191,7 +1226,7 @@ CONFIG_JFFS2_FS_WRITEBUFFER=y
CONFIG_JFFS2_ZLIB=y
CONFIG_JFFS2_RTIME=y
# CONFIG_JFFS2_RUBIN is not set
-# CONFIG_CRAMFS is not set
+CONFIG_CRAMFS=y
# CONFIG_VXFS_FS is not set
# CONFIG_HPFS_FS is not set
# CONFIG_QNX4FS_FS is not set
@@ -1285,6 +1320,11 @@ CONFIG_NLS_DEFAULT="iso8859-1"
# CONFIG_NLS_UTF8 is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Profiling support
#
# CONFIG_PROFILING is not set
@@ -1296,6 +1336,8 @@ CONFIG_NLS_DEFAULT="iso8859-1"
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=16
CONFIG_DETECT_SOFTLOCKUP=y
@@ -1311,12 +1353,10 @@ CONFIG_DEBUG_MUTEXES=y
# CONFIG_DEBUG_KOBJECT is not set
CONFIG_DEBUG_BUGVERBOSE=y
CONFIG_DEBUG_INFO=y
-# CONFIG_DEBUG_FS is not set
# CONFIG_DEBUG_VM is not set
# CONFIG_DEBUG_LIST is not set
CONFIG_FRAME_POINTER=y
CONFIG_FORCED_INLINING=y
-# CONFIG_HEADERS_CHECK is not set
# CONFIG_RCU_TORTURE_TEST is not set
CONFIG_DEBUG_USER=y
# CONFIG_DEBUG_ERRORS is not set
@@ -1339,6 +1379,7 @@ CONFIG_DEBUG_S3C2410_UART=0
#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
@@ -1346,3 +1387,4 @@ CONFIG_CRC32=y
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index ab06a86e85d..d5002889773 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_ARTHUR) += arthur.o
obj-$(CONFIG_ISA_DMA) += dma-isa.o
obj-$(CONFIG_PCI) += bios32.o isa.o
obj-$(CONFIG_SMP) += smp.o
+obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o
obj-$(CONFIG_CRUNCH) += crunch.o crunch-bits.o
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index f7598cbc7ec..ae89cdd82b1 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -356,6 +356,7 @@
CALL(sys_move_pages)
/* 345 */ CALL(sys_getcpu)
CALL(sys_ni_syscall) /* eventually epoll_pwait */
+ CALL(sys_kexec_load)
#ifndef syscalls_counted
.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
#define syscalls_counted
diff --git a/arch/arm/kernel/crunch.c b/arch/arm/kernel/crunch.c
index cec83783206..627d79414c9 100644
--- a/arch/arm/kernel/crunch.c
+++ b/arch/arm/kernel/crunch.c
@@ -75,6 +75,7 @@ static struct notifier_block crunch_notifier_block = {
static int __init crunch_init(void)
{
thread_register_notifier(&crunch_notifier_block);
+ elf_hwcap |= HWCAP_CRUNCH;
return 0;
}
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c
index 71257e3d513..f1c0fb97417 100644
--- a/arch/arm/kernel/ecard.c
+++ b/arch/arm/kernel/ecard.c
@@ -1009,7 +1009,7 @@ ecard_probe(int slot, card_type_t type)
ec->fiqmask = 4;
}
- for (i = 0; i < sizeof(blacklist) / sizeof(*blacklist); i++)
+ for (i = 0; i < ARRAY_SIZE(blacklist); i++)
if (blacklist[i].manufacturer == ec->cid.manufacturer &&
blacklist[i].product == ec->cid.product) {
ec->card_desc = blacklist[i].type;
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
new file mode 100644
index 00000000000..863c66454f2
--- /dev/null
+++ b/arch/arm/kernel/machine_kexec.c
@@ -0,0 +1,78 @@
+/*
+ * machine_kexec.c - handle transition of Linux booting another kernel
+ */
+
+#include <linux/mm.h>
+#include <linux/kexec.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/mmu_context.h>
+#include <asm/io.h>
+#include <asm/cacheflush.h>
+#include <asm/mach-types.h>
+
+const extern unsigned char relocate_new_kernel[];
+const extern unsigned int relocate_new_kernel_size;
+
+extern void setup_mm_for_reboot(char mode);
+
+extern unsigned long kexec_start_address;
+extern unsigned long kexec_indirection_page;
+extern unsigned long kexec_mach_type;
+
+/*
+ * Provide a dummy crash_notes definition while crash dump arrives to arm.
+ * This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
+ */
+
+int machine_kexec_prepare(struct kimage *image)
+{
+ return 0;
+}
+
+void machine_kexec_cleanup(struct kimage *image)
+{
+}
+
+void machine_shutdown(void)
+{
+}
+
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+}
+
+void machine_kexec(struct kimage *image)
+{
+ unsigned long page_list;
+ unsigned long reboot_code_buffer_phys;
+ void *reboot_code_buffer;
+
+
+ page_list = image->head & PAGE_MASK;
+
+ /* we need both effective and real address here */
+ reboot_code_buffer_phys =
+ page_to_pfn(image->control_code_page) << PAGE_SHIFT;
+ reboot_code_buffer = page_address(image->control_code_page);
+
+ /* Prepare parameters for reboot_code_buffer*/
+ kexec_start_address = image->start;
+ kexec_indirection_page = page_list;
+ kexec_mach_type = machine_arch_type;
+
+ /* copy our kernel relocation code to the control code page */
+ memcpy(reboot_code_buffer,
+ relocate_new_kernel, relocate_new_kernel_size);
+
+
+ flush_icache_range((unsigned long) reboot_code_buffer,
+ (unsigned long) reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE);
+ printk(KERN_INFO "Bye!\n");
+
+ cpu_proc_fin();
+ setup_mm_for_reboot(0); /* mode is not used, so just pass 0*/
+ cpu_reset(reboot_code_buffer_phys);
+}
diff --git a/arch/arm/kernel/relocate_kernel.S b/arch/arm/kernel/relocate_kernel.S
new file mode 100644
index 00000000000..7baadae7cb2
--- /dev/null
+++ b/arch/arm/kernel/relocate_kernel.S
@@ -0,0 +1,74 @@
+/*
+ * relocate_kernel.S - put the kernel image in place to boot
+ */
+
+#include <asm/kexec.h>
+
+ .globl relocate_new_kernel
+relocate_new_kernel:
+
+ ldr r0,kexec_indirection_page
+ ldr r1,kexec_start_address
+
+
+0: /* top, read another word for the indirection page */
+ ldr r3, [r0],#4
+
+ /* Is it a destination page. Put destination address to r4 */
+ tst r3,#1,0
+ beq 1f
+ bic r4,r3,#1
+ b 0b
+1:
+ /* Is it an indirection page */
+ tst r3,#2,0
+ beq 1f
+ bic r0,r3,#2
+ b 0b
+1:
+
+ /* are we done ? */
+ tst r3,#4,0
+ beq 1f
+ b 2f
+
+1:
+ /* is it source ? */
+ tst r3,#8,0
+ beq 0b
+ bic r3,r3,#8
+ mov r6,#1024
+9:
+ ldr r5,[r3],#4
+ str r5,[r4],#4
+ subs r6,r6,#1
+ bne 9b
+ b 0b
+
+2:
+ /* Jump to relocated kernel */
+ mov lr,r1
+ mov r0,#0
+ ldr r1,kexec_mach_type
+ mov r2,#0
+ mov pc,lr
+
+ .globl kexec_start_address
+kexec_start_address:
+ .long 0x0
+
+ .globl kexec_indirection_page
+kexec_indirection_page:
+ .long 0x0
+
+ .globl kexec_mach_type
+kexec_mach_type:
+ .long 0x0
+
+relocate_new_kernel_end:
+
+ .globl relocate_new_kernel_size
+relocate_new_kernel_size:
+ .long relocate_new_kernel_end - relocate_new_kernel
+
+
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index bbab134cd82..243aea45805 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -88,6 +88,9 @@ struct cpu_user_fns cpu_user;
#ifdef MULTI_CACHE
struct cpu_cache_fns cpu_cache;
#endif
+#ifdef CONFIG_OUTER_CACHE
+struct outer_cache_fns outer_cache;
+#endif
struct stack {
u32 irq[3];
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index 3c8cdcfe8d4..3825acd6687 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -40,12 +40,14 @@
*/
struct sys_timer *system_timer;
+#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
/* this needs a better home */
DEFINE_SPINLOCK(rtc_lock);
-#ifdef CONFIG_SA1100_RTC_MODULE
+#ifdef CONFIG_RTC_DRV_CMOS_MODULE
EXPORT_SYMBOL(rtc_lock);
#endif
+#endif /* pc-style 'CMOS' RTC support */
/* change this if you have some constant time drift */
#define USECS_PER_JIFFY (1000000/HZ)
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index 08ad782c164..f174d1a3b11 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/module.h>
#include <linux/string.h>
#include <asm/div64.h>
#include <asm/hardware.h>
@@ -124,7 +125,7 @@ static unsigned long calc_pll_rate(u32 config_word)
return (unsigned long)rate;
}
-void ep93xx_clock_init(void)
+static int __init ep93xx_clock_init(void)
{
u32 value;
@@ -153,4 +154,7 @@ void ep93xx_clock_init(void)
printk(KERN_INFO "ep93xx: FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n",
clk_f.rate / 1000000, clk_h.rate / 1000000,
clk_p.rate / 1000000);
+
+ return 0;
}
+arch_initcall(ep93xx_clock_init);
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 6b26346191c..829aed696d9 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -152,22 +152,30 @@ struct sys_timer ep93xx_timer = {
/*************************************************************************
* GPIO handling for EP93xx
*************************************************************************/
-static unsigned char gpio_int_enable[2];
-static unsigned char gpio_int_type1[2];
-static unsigned char gpio_int_type2[2];
+static unsigned char gpio_int_unmasked[3];
+static unsigned char gpio_int_enabled[3];
+static unsigned char gpio_int_type1[3];
+static unsigned char gpio_int_type2[3];
-static void update_gpio_ab_int_params(int port)
+static void update_gpio_int_params(int abf)
{
- if (port == 0) {
+ if (abf == 0) {
__raw_writeb(0, EP93XX_GPIO_A_INT_ENABLE);
__raw_writeb(gpio_int_type2[0], EP93XX_GPIO_A_INT_TYPE2);
__raw_writeb(gpio_int_type1[0], EP93XX_GPIO_A_INT_TYPE1);
- __raw_writeb(gpio_int_enable[0], EP93XX_GPIO_A_INT_ENABLE);
- } else if (port == 1) {
+ __raw_writeb(gpio_int_unmasked[0] & gpio_int_enabled[0], EP93XX_GPIO_A_INT_ENABLE);
+ } else if (abf == 1) {
__raw_writeb(0, EP93XX_GPIO_B_INT_ENABLE);
__raw_writeb(gpio_int_type2[1], EP93XX_GPIO_B_INT_TYPE2);
__raw_writeb(gpio_int_type1[1], EP93XX_GPIO_B_INT_TYPE1);
- __raw_writeb(gpio_int_enable[1], EP93XX_GPIO_B_INT_ENABLE);
+ __raw_writeb(gpio_int_unmasked[1] & gpio_int_enabled[1], EP93XX_GPIO_B_INT_ENABLE);
+ } else if (abf == 2) {
+ __raw_writeb(0, EP93XX_GPIO_F_INT_ENABLE);
+ __raw_writeb(gpio_int_type2[2], EP93XX_GPIO_F_INT_TYPE2);
+ __raw_writeb(gpio_int_type1[2], EP93XX_GPIO_F_INT_TYPE1);
+ __raw_writeb(gpio_int_unmasked[2] & gpio_int_enabled[2], EP93XX_GPIO_F_INT_ENABLE);
+ } else {
+ BUG();
}
}
@@ -192,8 +200,13 @@ void gpio_line_config(int line, int direction)
local_irq_save(flags);
if (direction == GPIO_OUT) {
if (line >= 0 && line < 16) {
- gpio_int_enable[line >> 3] &= ~(1 << (line & 7));
- update_gpio_ab_int_params(line >> 3);
+ /* Port A/B. */
+ gpio_int_unmasked[line >> 3] &= ~(1 << (line & 7));
+ update_gpio_int_params(line >> 3);
+ } else if (line >= 40 && line < 48) {
+ /* Port F. */
+ gpio_int_unmasked[2] &= ~(1 << (line & 7));
+ update_gpio_int_params(2);
}
v = __raw_readb(data_direction_register);
@@ -244,8 +257,7 @@ EXPORT_SYMBOL(gpio_line_set);
/*************************************************************************
* EP93xx IRQ handling
*************************************************************************/
-static void ep93xx_gpio_ab_irq_handler(unsigned int irq,
- struct irq_desc *desc)
+static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc)
{
unsigned char status;
int i;
@@ -267,37 +279,46 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq,
}
}
-static void ep93xx_gpio_ab_irq_mask_ack(unsigned int irq)
+static void ep93xx_gpio_f_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ int gpio_irq = IRQ_EP93XX_GPIO(16) + (((irq + 1) & 7) ^ 4);
+
+ desc_handle_irq(gpio_irq, irq_desc + gpio_irq);
+}
+
+static void ep93xx_gpio_irq_mask_ack(unsigned int irq)
{
int line = irq - IRQ_EP93XX_GPIO(0);
int port = line >> 3;
- gpio_int_enable[port] &= ~(1 << (line & 7));
- update_gpio_ab_int_params(port);
+ gpio_int_unmasked[port] &= ~(1 << (line & 7));
+ update_gpio_int_params(port);
- if (line >> 3) {
- __raw_writel(1 << (line & 7), EP93XX_GPIO_B_INT_ACK);
- } else {
+ if (port == 0) {
__raw_writel(1 << (line & 7), EP93XX_GPIO_A_INT_ACK);
+ } else if (port == 1) {
+ __raw_writel(1 << (line & 7), EP93XX_GPIO_B_INT_ACK);
+ } else if (port == 2) {
+ __raw_writel(1 << (line & 7), EP93XX_GPIO_F_INT_ACK);
}
}
-static void ep93xx_gpio_ab_irq_mask(unsigned int irq)
+static void ep93xx_gpio_irq_mask(unsigned int irq)
{
int line = irq - IRQ_EP93XX_GPIO(0);
int port = line >> 3;
- gpio_int_enable[port] &= ~(1 << (line & 7));
- update_gpio_ab_int_params(port);
+ gpio_int_unmasked[port] &= ~(1 << (line & 7));
+ update_gpio_int_params(port);
}
-static void ep93xx_gpio_ab_irq_unmask(unsigned int irq)
+static void ep93xx_gpio_irq_unmask(unsigned int irq)
{
int line = irq - IRQ_EP93XX_GPIO(0);
int port = line >> 3;
- gpio_int_enable[port] |= 1 << (line & 7);
- update_gpio_ab_int_params(port);
+ gpio_int_unmasked[port] |= 1 << (line & 7);
+ update_gpio_int_params(port);
}
@@ -306,40 +327,51 @@ static void ep93xx_gpio_ab_irq_unmask(unsigned int irq)
* edge (1) triggered, while gpio_int_type2 controls whether it
* triggers on low/falling (0) or high/rising (1).
*/
-static int ep93xx_gpio_ab_irq_type(unsigned int irq, unsigned int type)
+static int ep93xx_gpio_irq_type(unsigned int irq, unsigned int type)
{
int port;
int line;
line = irq - IRQ_EP93XX_GPIO(0);
- gpio_line_config(line, GPIO_IN);
+ if (line >= 0 && line < 16) {
+ gpio_line_config(line, GPIO_IN);
+ } else {
+ gpio_line_config(EP93XX_GPIO_LINE_F(line), GPIO_IN);
+ }
port = line >> 3;
line &= 7;
if (type & IRQT_RISING) {
+ gpio_int_enabled[port] |= 1 << line;
gpio_int_type1[port] |= 1 << line;
gpio_int_type2[port] |= 1 << line;
} else if (type & IRQT_FALLING) {
+ gpio_int_enabled[port] |= 1 << line;
gpio_int_type1[port] |= 1 << line;
gpio_int_type2[port] &= ~(1 << line);
} else if (type & IRQT_HIGH) {
+ gpio_int_enabled[port] |= 1 << line;
gpio_int_type1[port] &= ~(1 << line);
gpio_int_type2[port] |= 1 << line;
} else if (type & IRQT_LOW) {
+ gpio_int_enabled[port] |= 1 << line;
gpio_int_type1[port] &= ~(1 << line);
gpio_int_type2[port] &= ~(1 << line);
+ } else {
+ gpio_int_enabled[port] &= ~(1 << line);
}
- update_gpio_ab_int_params(port);
+ update_gpio_int_params(port);
return 0;
}
-static struct irq_chip ep93xx_gpio_ab_irq_chip = {
- .ack = ep93xx_gpio_ab_irq_mask_ack,
- .mask = ep93xx_gpio_ab_irq_mask,
- .unmask = ep93xx_gpio_ab_irq_unmask,
- .set_type = ep93xx_gpio_ab_irq_type,
+static struct irq_chip ep93xx_gpio_irq_chip = {
+ .name = "GPIO",
+ .ack = ep93xx_gpio_irq_mask_ack,
+ .mask = ep93xx_gpio_irq_mask,
+ .unmask = ep93xx_gpio_irq_unmask,
+ .set_type = ep93xx_gpio_irq_type,
};
@@ -350,12 +382,21 @@ void __init ep93xx_init_irq(void)
vic_init((void *)EP93XX_VIC1_BASE, 0, EP93XX_VIC1_VALID_IRQ_MASK);
vic_init((void *)EP93XX_VIC2_BASE, 32, EP93XX_VIC2_VALID_IRQ_MASK);
- for (irq = IRQ_EP93XX_GPIO(0) ; irq <= IRQ_EP93XX_GPIO(15); irq++) {
- set_irq_chip(irq, &ep93xx_gpio_ab_irq_chip);
+ for (irq = IRQ_EP93XX_GPIO(0); irq <= IRQ_EP93XX_GPIO(23); irq++) {
+ set_irq_chip(irq, &ep93xx_gpio_irq_chip);
set_irq_handler(irq, handle_level_irq);
set_irq_flags(irq, IRQF_VALID);
}
+
set_irq_chained_handler(IRQ_EP93XX_GPIO_AB, ep93xx_gpio_ab_irq_handler);
+ set_irq_chained_handler(IRQ_EP93XX_GPIO0MUX, ep93xx_gpio_f_irq_handler);
+ set_irq_chained_handler(IRQ_EP93XX_GPIO1MUX, ep93xx_gpio_f_irq_handler);
+ set_irq_chained_handler(IRQ_EP93XX_GPIO2MUX, ep93xx_gpio_f_irq_handler);
+ set_irq_chained_handler(IRQ_EP93XX_GPIO3MUX, ep93xx_gpio_f_irq_handler);
+ set_irq_chained_handler(IRQ_EP93XX_GPIO4MUX, ep93xx_gpio_f_irq_handler);
+ set_irq_chained_handler(IRQ_EP93XX_GPIO5MUX, ep93xx_gpio_f_irq_handler);
+ set_irq_chained_handler(IRQ_EP93XX_GPIO6MUX, ep93xx_gpio_f_irq_handler);
+ set_irq_chained_handler(IRQ_EP93XX_GPIO7MUX, ep93xx_gpio_f_irq_handler);
}
@@ -461,8 +502,6 @@ void __init ep93xx_init_devices(void)
{
unsigned int v;
- ep93xx_clock_init();
-
/*
* Disallow access to MaverickCrunch initially.
*/
@@ -477,8 +516,4 @@ void __init ep93xx_init_devices(void)
platform_device_register(&ep93xx_rtc_device);
platform_device_register(&ep93xx_ohci_device);
-
-#ifdef CONFIG_CRUNCH
- elf_hwcap |= HWCAP_CRUNCH;
-#endif
}
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
index 9de1278d234..390524c4710 100644
--- a/arch/arm/mach-pxa/generic.c
+++ b/arch/arm/mach-pxa/generic.c
@@ -338,6 +338,27 @@ static struct platform_device i2c_device = {
.num_resources = ARRAY_SIZE(i2c_resources),
};
+#ifdef CONFIG_PXA27x
+static struct resource i2c_power_resources[] = {
+ {
+ .start = 0x40f00180,
+ .end = 0x40f001a3,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = IRQ_PWRI2C,
+ .end = IRQ_PWRI2C,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device i2c_power_device = {
+ .name = "pxa2xx-i2c",
+ .id = 1,
+ .resource = i2c_power_resources,
+ .num_resources = ARRAY_SIZE(i2c_resources),
+};
+#endif
+
void __init pxa_set_i2c_info(struct i2c_pxa_platform_data *info)
{
i2c_device.dev.platform_data = info;
@@ -392,6 +413,9 @@ static struct platform_device *devices[] __initdata = {
&stuart_device,
&pxaficp_device,
&i2c_device,
+#ifdef CONFIG_PXA27x
+ &i2c_power_device,
+#endif
&i2s_device,
&pxartc_device,
};
diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig
index 17f5f4439fe..35156ca39df 100644
--- a/arch/arm/mach-realview/Kconfig
+++ b/arch/arm/mach-realview/Kconfig
@@ -10,10 +10,21 @@ config MACH_REALVIEW_EB
config REALVIEW_MPCORE
bool "Support MPcore tile"
depends on MACH_REALVIEW_EB
+ select CACHE_L2X0
help
Enable support for the MPCore tile on the Realview platform.
Since there are device address and interrupt differences, a
kernel built with this option enabled is not compatible with
other tiles.
+config REALVIEW_MPCORE_REVB
+ bool "Support MPcore RevB tile"
+ depends on REALVIEW_MPCORE
+ default n
+ help
+ Enable support for the MPCore RevB tile on the Realview platform.
+ Since there are device address differences, a
+ kernel built with this option enabled is not compatible with
+ other tiles.
+
endmenu
diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c
index b8484e15dac..fce3596f995 100644
--- a/arch/arm/mach-realview/platsmp.c
+++ b/arch/arm/mach-realview/platsmp.c
@@ -52,13 +52,14 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
* core (e.g. timer irq), then they will not have been enabled
* for us: do so
*/
- gic_cpu_init(__io_address(REALVIEW_GIC_CPU_BASE));
+ gic_cpu_init(0, __io_address(REALVIEW_GIC_CPU_BASE));
/*
* let the primary processor know we're out of the
* pen, then head off into the C entry point
*/
pen_release = -1;
+ smp_wmb();
/*
* Synchronise with the boot thread.
@@ -102,6 +103,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
timeout = jiffies + (1 * HZ);
while (time_before(jiffies, timeout)) {
+ smp_rmb();
if (pen_release == -1)
break;
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index 9741b4d3c9c..3dba666151d 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -31,6 +31,7 @@
#include <asm/mach-types.h>
#include <asm/hardware/gic.h>
#include <asm/hardware/icst307.h>
+#include <asm/hardware/cache-l2x0.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -57,7 +58,26 @@ static struct map_desc realview_eb_io_desc[] __initdata = {
.pfn = __phys_to_pfn(REALVIEW_GIC_DIST_BASE),
.length = SZ_4K,
.type = MT_DEVICE,
+ },
+#ifdef CONFIG_REALVIEW_MPCORE
+ {
+ .virtual = IO_ADDRESS(REALVIEW_GIC1_CPU_BASE),
+ .pfn = __phys_to_pfn(REALVIEW_GIC1_CPU_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = IO_ADDRESS(REALVIEW_GIC1_DIST_BASE),
+ .pfn = __phys_to_pfn(REALVIEW_GIC1_DIST_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE,
}, {
+ .virtual = IO_ADDRESS(REALVIEW_MPCORE_L220_BASE),
+ .pfn = __phys_to_pfn(REALVIEW_MPCORE_L220_BASE),
+ .length = SZ_8K,
+ .type = MT_DEVICE,
+ },
+#endif
+ {
.virtual = IO_ADDRESS(REALVIEW_SCTL_BASE),
.pfn = __phys_to_pfn(REALVIEW_SCTL_BASE),
.length = SZ_4K,
@@ -138,19 +158,29 @@ static void __init gic_init_irq(void)
#ifdef CONFIG_REALVIEW_MPCORE
unsigned int pldctrl;
writel(0x0000a05f, __io_address(REALVIEW_SYS_LOCK));
- pldctrl = readl(__io_address(REALVIEW_SYS_BASE) + 0xd8);
+ pldctrl = readl(__io_address(REALVIEW_SYS_BASE) + REALVIEW_MPCORE_SYS_PLD_CTRL1);
pldctrl |= 0x00800000; /* New irq mode */
- writel(pldctrl, __io_address(REALVIEW_SYS_BASE) + 0xd8);
+ writel(pldctrl, __io_address(REALVIEW_SYS_BASE) + REALVIEW_MPCORE_SYS_PLD_CTRL1);
writel(0x00000000, __io_address(REALVIEW_SYS_LOCK));
#endif
- gic_dist_init(__io_address(REALVIEW_GIC_DIST_BASE));
- gic_cpu_init(__io_address(REALVIEW_GIC_CPU_BASE));
+ gic_dist_init(0, __io_address(REALVIEW_GIC_DIST_BASE), 29);
+ gic_cpu_init(0, __io_address(REALVIEW_GIC_CPU_BASE));
+#ifdef CONFIG_REALVIEW_MPCORE
+ gic_dist_init(1, __io_address(REALVIEW_GIC1_DIST_BASE), 64);
+ gic_cpu_init(1, __io_address(REALVIEW_GIC1_CPU_BASE));
+ gic_cascade_irq(1, IRQ_EB_IRQ1);
+#endif
}
static void __init realview_eb_init(void)
{
int i;
+#ifdef CONFIG_REALVIEW_MPCORE
+ /* 1MB (128KB/way), 8-way associativity, evmon/parity/share enabled
+ * Bits: .... ...0 0111 1001 0000 .... .... .... */
+ l2x0_init(__io_address(REALVIEW_MPCORE_L220_BASE), 0x00790000, 0xfe000fff);
+#endif
clk_register(&realview_clcd_clk);
platform_device_register(&realview_flash_device);
diff --git a/arch/arm/mach-s3c2400/Kconfig b/arch/arm/mach-s3c2400/Kconfig
new file mode 100644
index 00000000000..deab0722836
--- /dev/null
+++ b/arch/arm/mach-s3c2400/Kconfig
@@ -0,0 +1,13 @@
+# arch/arm/mach-s3c2400/Kconfig
+#
+# Copyright 2007 Simtec Electronics
+#
+# Licensed under GPLv2
+
+
+
+menu "S3C2400 Machines"
+
+
+endmenu
+
diff --git a/arch/arm/mach-s3c2400/Makefile b/arch/arm/mach-s3c2400/Makefile
new file mode 100644
index 00000000000..7e23f4e1376
--- /dev/null
+++ b/arch/arm/mach-s3c2400/Makefile
@@ -0,0 +1,15 @@
+# arch/arm/mach-s3c2400/Makefile
+#
+# Copyright 2007 Simtec Electronics
+#
+# Licensed under GPLv2
+
+obj-y :=
+obj-m :=
+obj-n :=
+obj- :=
+
+obj-$(CONFIG_CPU_S3C2400) += gpio.o
+
+# Machine support
+
diff --git a/arch/arm/mach-s3c2410/s3c2400-gpio.c b/arch/arm/mach-s3c2400/gpio.c
index 1576d01d5f8..758e160410e 100644
--- a/arch/arm/mach-s3c2410/s3c2400-gpio.c
+++ b/arch/arm/mach-s3c2400/gpio.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/s3c2400-gpio.c
+/* linux/arch/arm/mach-s3c2400/gpio.c
*
* Copyright (c) 2006 Lucas Correia Villa Real <lucasvr@gobolinux.org>
*
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
index eb4ec411312..d4b013b283c 100644
--- a/arch/arm/mach-s3c2410/Kconfig
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -1,54 +1,51 @@
-if ARCH_S3C2410
+# arch/arm/mach-s3c2410/Kconfig
+#
+# Copyright 2007 Simtec Electronics
+#
+# Licensed under GPLv2
-menu "S3C24XX Implementations"
+config CPU_S3C2410
+ bool
+ depends on ARCH_S3C2410
+ select S3C2410_CLOCK
+ select S3C2410_GPIO
+ select S3C2410_PM if PM
+ help
+ Support for S3C2410 and S3C2410A family from the S3C24XX line
+ of Samsung Mobile CPUs.
-config MACH_AML_M5900
- bool "AML M5900 Series"
- select CPU_S3C2410
- select PM_SIMTEC if PM
+config CPU_S3C2410_DMA
+ bool
+ depends on S3C2410_DMA && (CPU_S3C2410 || CPU_S3C2442)
+ default y if CPU_S3C2410 || CPU_S3C2442
help
- Say Y here if you are using the American Microsystems M5900 Series
- <http://www.amltd.com>
+ DMA device selection for S3C2410 and compatible CPUs
-config MACH_ANUBIS
- bool "Simtec Electronics ANUBIS"
- select CPU_S3C2440
- select PM_SIMTEC if PM
+config S3C2410_PM
+ bool
help
- Say Y here if you are using the Simtec Electronics ANUBIS
- development system
+ Power Management code common to S3C2410 and better
-config MACH_OSIRIS
- bool "Simtec IM2440D20 (OSIRIS) module"
- select CPU_S3C2440
- select PM_SIMTEC if PM
+config S3C2410_GPIO
+ bool
help
- Say Y here if you are using the Simtec IM2440D20 module, also
- known as the Osiris.
+ GPIO code for S3C2410 and similar processors
-config ARCH_BAST
- bool "Simtec Electronics BAST (EB2410ITX)"
- select CPU_S3C2410
- select PM_SIMTEC if PM
- select ISA
+config S3C2410_CLOCK
+ bool
help
- Say Y here if you are using the Simtec Electronics EB2410ITX
- development board (also known as BAST)
+ Clock code for the S3C2410, and similar processors
- Product page: <http://www.simtec.co.uk/products/EB2410ITX/>.
-config BAST_PC104_IRQ
- bool "BAST PC104 IRQ support"
- depends on ARCH_BAST
- default y
- help
- Say Y here to enable the PC104 IRQ routing on the
- Simtec BAST (EB2410ITX)
+menu "S3C2410 Machines"
-config PM_H1940
- bool
+config ARCH_SMDK2410
+ bool "SMDK2410/A9M2410"
+ select CPU_S3C2410
+ select MACH_SMDK
help
- Internal node for H1940 and related PM
+ Say Y here if you are using the SMDK2410 or the derived module A9M2410
+ <http://www.fsforth.de>
config ARCH_H1940
bool "IPAQ H1940"
@@ -57,7 +54,10 @@ config ARCH_H1940
help
Say Y here if you are using the HP IPAQ H1940
- <http://www.handhelds.org/projects/h1940.html>.
+config PM_H1940
+ bool
+ help
+ Internal node for H1940 and related PM
config MACH_N30
bool "Acer N30"
@@ -65,53 +65,36 @@ config MACH_N30
help
Say Y here if you are using the Acer N30
- <http://zoo.weinigel.se/n30>.
-
-config MACH_SMDK
- bool
- help
- Common machine code for SMDK2410 and SMDK2440
-
-config ARCH_SMDK2410
- bool "SMDK2410/A9M2410"
+config ARCH_BAST
+ bool "Simtec Electronics BAST (EB2410ITX)"
select CPU_S3C2410
- select MACH_SMDK
+ select PM_SIMTEC if PM
+ select ISA
help
- Say Y here if you are using the SMDK2410 or the derived module A9M2410
- <http://www.fsforth.de>
+ Say Y here if you are using the Simtec Electronics EB2410ITX
+ development board (also known as BAST)
-config ARCH_S3C2440
- bool "SMDK2440"
- select CPU_S3C2440
- select MACH_SMDK
+config MACH_OTOM
+ bool "NexVision OTOM Board"
+ select CPU_S3C2410
help
- Say Y here if you are using the SMDK2440.
-
-config SMDK2440_CPU2440
- bool "SMDK2440 with S3C2440 CPU module"
- depends on ARCH_S3C2440
- default y if ARCH_S3C2440
- select CPU_S3C2440
-
-config SMDK2440_CPU2442
- bool "SMDM2440 with S3C2442 CPU module"
- depends on ARCH_S3C2440
- select CPU_S3C2442
+ Say Y here if you are using the Nex Vision OTOM board
-config MACH_S3C2413
- bool
+config MACH_AML_M5900
+ bool "AML M5900 Series"
+ select CPU_S3C2410
+ select PM_SIMTEC if PM
help
- Internal node for S3C2413 version of SMDK2413, so that
- machine_is_s3c2413() will work when MACH_SMDK2413 is
- selected
+ Say Y here if you are using the American Microsystems M5900 Series
+ <http://www.amltd.com>
-config MACH_SMDK2413
- bool "SMDK2413"
- select CPU_S3C2412
- select MACH_S3C2413
- select MACH_SMDK
+config BAST_PC104_IRQ
+ bool "BAST PC104 IRQ support"
+ depends on ARCH_BAST
+ default y
help
- Say Y here if you are using an SMDK2413
+ Say Y here to enable the PC104 IRQ routing on the
+ Simtec BAST (EB2410ITX)
config MACH_VR1000
bool "Thorcom VR1000"
@@ -120,202 +103,11 @@ config MACH_VR1000
help
Say Y here if you are using the Thorcom VR1000 board.
- This linux port is currently being maintained by Simtec, on behalf
- of Thorcom. Any queries, please contact Thorcom first.
-
-config MACH_RX3715
- bool "HP iPAQ rx3715"
- select CPU_S3C2440
- select PM_H1940 if PM
- help
- Say Y here if you are using the HP iPAQ rx3715.
-
- See <http://www.handhelds.org/projects/rx3715.html> for more
- information on this project
-
-config MACH_OTOM
- bool "NexVision OTOM Board"
- select CPU_S3C2410
- help
- Say Y here if you are using the Nex Vision OTOM board
-
-config MACH_NEXCODER_2440
- bool "NexVision NEXCODER 2440 Light Board"
- select CPU_S3C2440
- help
- Say Y here if you are using the Nex Vision NEXCODER 2440 Light Board
-
-config MACH_VSTMS
- bool "VMSTMS"
- select CPU_S3C2412
+config MACH_QT2410
+ bool "QT2410"
+ select CPU_S3C2410
help
- Say Y here if you are using an VSTMS board
+ Say Y here if you are using the Armzone QT2410
endmenu
-config S3C2410_CLOCK
- bool
- help
- Clock code for the S3C2410, and similar processors
-
-config S3C2410_PM
- bool
- help
- Power Management code common to S3C2410 and better
-
-config CPU_S3C2410_DMA
- bool
- depends on S3C2410_DMA && (CPU_S3C2410 || CPU_S3C2442)
- default y if CPU_S3C2410 || CPU_S3C2442
- help
- DMA device selection for S3C2410 and compatible CPUs
-
-config CPU_S3C2410
- bool
- depends on ARCH_S3C2410
- select S3C2410_CLOCK
- select S3C2410_PM if PM
- help
- Support for S3C2410 and S3C2410A family from the S3C24XX line
- of Samsung Mobile CPUs.
-
-# internal node to signify if we are only dealing with an S3C2412
-
-config CPU_S3C2412_ONLY
- bool
- depends on ARCH_S3C2410 && !CPU_S3C2400 && !CPU_S3C2410 && \
- !CPU_S3C2440 && !CPU_S3C2442 && CPU_S3C2412
- default y if CPU_S3C2412
-
-config S3C2412_PM
- bool
- help
- Internal config node to apply S3C2412 power management
-
-config CPU_S3C2412
- bool
- depends on ARCH_S3C2410
- select S3C2412_PM if PM
- help
- Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line
-
-config CPU_S3C244X
- bool
- depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442)
- help
- Support for S3C2440 and S3C2442 Samsung Mobile CPU based systems.
-
-config CPU_S3C2440
- bool
- depends on ARCH_S3C2410
- select S3C2410_CLOCK
- select S3C2410_PM if PM
- select CPU_S3C244X
- help
- Support for S3C2440 Samsung Mobile CPU based systems.
-
-config CPU_S3C2442
- bool
- depends on ARCH_S3C2420
- select S3C2410_CLOCK
- select S3C2410_PM if PM
- select CPU_S3C244X
- help
- Support for S3C2442 Samsung Mobile CPU based systems.
-
-comment "S3C2410 Boot"
-
-config S3C2410_BOOT_WATCHDOG
- bool "S3C2410 Initialisation watchdog"
- depends on ARCH_S3C2410 && S3C2410_WATCHDOG
- help
- Say y to enable the watchdog during the kernel decompression
- stage. If the kernel fails to uncompress, then the watchdog
- will trigger a reset and the system should restart.
-
- Although this uses the same hardware unit as the kernel watchdog
- driver, it is not a replacement for it. If you use this option,
- you will have to use the watchdg driver to either stop the timeout
- or restart it. If you do not, then your kernel will reboot after
- startup.
-
- The driver uses a fixed timeout value, so the exact time till the
- system resets depends on the value of PCLK. The timeout on an
- 200MHz s3c2410 should be about 30 seconds.
-
-config S3C2410_BOOT_ERROR_RESET
- bool "S3C2410 Reboot on decompression error"
- depends on ARCH_S3C2410
- help
- Say y here to use the watchdog to reset the system if the
- kernel decompressor detects an error during decompression.
-
-
-comment "S3C2410 Setup"
-
-config S3C2410_DMA
- bool "S3C2410 DMA support"
- depends on ARCH_S3C2410
- help
- S3C2410 DMA support. This is needed for drivers like sound which
- use the S3C2410's DMA system to move data to and from the
- peripheral blocks.
-
-config S3C2410_DMA_DEBUG
- bool "S3C2410 DMA support debug"
- depends on ARCH_S3C2410 && S3C2410_DMA
- help
- Enable debugging output for the DMA code. This option sends info
- to the kernel log, at priority KERN_DEBUG.
-
- Note, it is easy to create and fill the log buffer in a small
- amount of time, as well as using an significant percentage of
- the CPU time doing so.
-
-
-config S3C2410_PM_DEBUG
- bool "S3C2410 PM Suspend debug"
- depends on ARCH_S3C2410 && PM
- help
- Say Y here if you want verbose debugging from the PM Suspend and
- Resume code. See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
- for more information.
-
-config S3C2410_PM_CHECK
- bool "S3C2410 PM Suspend Memory CRC"
- depends on ARCH_S3C2410 && PM && CRC32
- help
- Enable the PM code's memory area checksum over sleep. This option
- will generate CRCs of all blocks of memory, and store them before
- going to sleep. The blocks are then checked on resume for any
- errors.
-
-config S3C2410_PM_CHECK_CHUNKSIZE
- int "S3C2410 PM Suspend CRC Chunksize (KiB)"
- depends on ARCH_S3C2410 && PM && S3C2410_PM_CHECK
- default 64
- help
- Set the chunksize in Kilobytes of the CRC for checking memory
- corruption over suspend and resume. A smaller value will mean that
- the CRC data block will take more memory, but wil identify any
- faults with better precision.
-
-config PM_SIMTEC
- bool
- help
- Common power management code for systems that are
- compatible with the Simtec style of power management
-
-config S3C2410_LOWLEVEL_UART_PORT
- int "S3C2410 UART to use for low-level messages"
- default 0
- help
- Choice of which UART port to use for the low-level messages,
- such as the `Uncompressing...` at start time. The value of
- this configuration should be between zero and two. The port
- must have been initialised by the boot-loader before use.
-
- Note, this does not affect the port used by the debug messages,
- which is a separate configuration.
-
-endif
diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
index 27663e28cc8..9a3d3d24c08 100644
--- a/arch/arm/mach-s3c2410/Makefile
+++ b/arch/arm/mach-s3c2410/Makefile
@@ -1,92 +1,31 @@
-
+# arch/arm/mach-s3c2410/Makefile
#
-# Makefile for the linux kernel.
+# Copyright 2007 Simtec Electronics
#
+# Licensed under GPLv2
-# Object file lists.
-
-obj-y := cpu.o irq.o time.o gpio.o clock.o devs.o
-obj-m :=
-obj-n :=
-obj- :=
-obj-dma-y :=
-obj-dma-n :=
-
-# DMA
-obj-$(CONFIG_S3C2410_DMA) += dma.o
-
-# S3C2400 support files
-obj-$(CONFIG_CPU_S3C2400) += s3c2400-gpio.o
-
-# S3C2410 support files
+obj-y :=
+obj-m :=
+obj-n :=
+obj- :=
obj-$(CONFIG_CPU_S3C2410) += s3c2410.o
-obj-$(CONFIG_CPU_S3C2410) += s3c2410-gpio.o
-obj-$(CONFIG_CPU_S3C2410) += s3c2410-irq.o
-
-obj-$(CONFIG_S3C2410_PM) += s3c2410-pm.o s3c2410-sleep.o
-obj-$(CONFIG_CPU_S3C2410_DMA) += s3c2410-dma.o
-
-# Power Management support
-
-obj-$(CONFIG_PM) += pm.o sleep.o
-obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o
-obj-$(CONFIG_PM_H1940) += pm-h1940.o
-
-# S3C2412 support
-obj-$(CONFIG_CPU_S3C2412) += s3c2412.o
-obj-$(CONFIG_CPU_S3C2412) += s3c2412-irq.o
-obj-$(CONFIG_CPU_S3C2412) += s3c2412-clock.o
-obj-dma-$(CONFIG_CPU_S3C2412) += s3c2412-dma.o
-
-obj-$(CONFIG_S3C2412_PM) += s3c2412-pm.o
-
-#
-# S3C244X support
-
-obj-$(CONFIG_CPU_S3C244X) += s3c244x.o
-obj-$(CONFIG_CPU_S3C244X) += s3c244x-irq.o
-
-# Clock control
-
-obj-$(CONFIG_S3C2410_CLOCK) += s3c2410-clock.o
-
-# S3C2440 support
-
-obj-$(CONFIG_CPU_S3C2440) += s3c2440.o s3c2440-dsc.o
-obj-$(CONFIG_CPU_S3C2440) += s3c2440-irq.o
-obj-$(CONFIG_CPU_S3C2440) += s3c2440-clock.o
-obj-$(CONFIG_CPU_S3C2440) += s3c2410-gpio.o
-obj-dma-$(CONFIG_CPU_S3C2440) += s3c2440-dma.o
+obj-$(CONFIG_CPU_S3C2410) += irq.o
+obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o
+obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o
+obj-$(CONFIG_S3C2410_PM) += pm.o sleep.o
+obj-$(CONFIG_S3C2410_GPIO) += gpio.o
+obj-$(CONFIG_S3C2410_CLOCK) += clock.o
-# S3C2442 support
+# Machine support
-obj-$(CONFIG_CPU_S3C2442) += s3c2442.o
-obj-$(CONFIG_CPU_S3C2442) += s3c2442-clock.o
-
-# bast extras
-
-obj-$(CONFIG_BAST_PC104_IRQ) += bast-irq.o
-
-# merge in dma objects
-
-obj-y += $(obj-dma-y)
-
-# machine specific support
-
-obj-$(CONFIG_MACH_AML_M5900) += mach-amlm5900.o
-obj-$(CONFIG_MACH_ANUBIS) += mach-anubis.o
-obj-$(CONFIG_MACH_OSIRIS) += mach-osiris.o
-obj-$(CONFIG_ARCH_BAST) += mach-bast.o usb-simtec.o
+obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o
obj-$(CONFIG_ARCH_H1940) += mach-h1940.o
+obj-$(CONFIG_PM_H1940) += pm-h1940.o
obj-$(CONFIG_MACH_N30) += mach-n30.o
-obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o
-obj-$(CONFIG_MACH_SMDK2413) += mach-smdk2413.o
-obj-$(CONFIG_ARCH_S3C2440) += mach-smdk2440.o
-obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o
-obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o
+obj-$(CONFIG_ARCH_BAST) += mach-bast.o usb-simtec.o
obj-$(CONFIG_MACH_OTOM) += mach-otom.o
-obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o
-obj-$(CONFIG_MACH_VSTMS) += mach-vstms.o
-
-obj-$(CONFIG_MACH_SMDK) += common-smdk.o \ No newline at end of file
+obj-$(CONFIG_MACH_AML_M5900) += mach-amlm5900.o
+obj-$(CONFIG_BAST_PC104_IRQ) += bast-irq.o
+obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o
+obj-$(CONFIG_MACH_QT2410) += mach-qt2410.o
diff --git a/arch/arm/mach-s3c2410/bast-irq.c b/arch/arm/mach-s3c2410/bast-irq.c
index 379efe70778..daeba427d78 100644
--- a/arch/arm/mach-s3c2410/bast-irq.c
+++ b/arch/arm/mach-s3c2410/bast-irq.c
@@ -39,7 +39,7 @@
#include <asm/arch/bast-map.h>
#include <asm/arch/bast-irq.h>
-#include "irq.h"
+#include <asm/plat-s3c24xx/irq.h>
#if 0
#include <asm/debug-ll.h>
diff --git a/arch/arm/mach-s3c2410/bast.h b/arch/arm/mach-s3c2410/bast.h
index e5d03311752..e98543742eb 100644
--- a/arch/arm/mach-s3c2410/bast.h
+++ b/arch/arm/mach-s3c2410/bast.h
@@ -1,2 +1,2 @@
-
+/* linux/arch/arm/mach-s3c2410/bast.h
extern void bast_init_irq(void);
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c
index e13fb677889..5b4831c4c1d 100644
--- a/arch/arm/mach-s3c2410/clock.c
+++ b/arch/arm/mach-s3c2410/clock.c
@@ -1,15 +1,9 @@
/* linux/arch/arm/mach-s3c2410/clock.c
*
- * Copyright (c) 2004-2005 Simtec Electronics
+ * Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
- * S3C24XX Core clock control support
- *
- * Based on, and code from linux/arch/arm/mach-versatile/clock.c
- **
- ** Copyright (C) 2004 ARM Limited.
- ** Written by Deep Blue Solutions Limited.
- *
+ * S3C2410,S3C2440,S3C2442 Clock control 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
@@ -32,418 +26,251 @@
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/err.h>
-#include <linux/platform_device.h>
#include <linux/sysdev.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
#include <linux/clk.h>
#include <linux/mutex.h>
#include <linux/delay.h>
+#include <linux/serial_core.h>
+
+#include <asm/mach/map.h>
#include <asm/hardware.h>
-#include <asm/irq.h>
#include <asm/io.h>
+#include <asm/arch/regs-serial.h>
#include <asm/arch/regs-clock.h>
#include <asm/arch/regs-gpio.h>
-#include "clock.h"
-#include "cpu.h"
-
-/* clock information */
+#include <asm/plat-s3c24xx/s3c2410.h>
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/cpu.h>
-static LIST_HEAD(clocks);
-
-DEFINE_MUTEX(clocks_mutex);
-
-/* enable and disable calls for use with the clk struct */
-
-static int clk_null_enable(struct clk *clk, int enable)
+int s3c2410_clkcon_enable(struct clk *clk, int enable)
{
- return 0;
-}
-
-/* Clock API calls */
+ unsigned int clocks = clk->ctrlbit;
+ unsigned long clkcon;
-struct clk *clk_get(struct device *dev, const char *id)
-{
- struct clk *p;
- struct clk *clk = ERR_PTR(-ENOENT);
- int idno;
+ clkcon = __raw_readl(S3C2410_CLKCON);
- if (dev == NULL || dev->bus != &platform_bus_type)
- idno = -1;
+ if (enable)
+ clkcon |= clocks;
else
- idno = to_platform_device(dev)->id;
-
- mutex_lock(&clocks_mutex);
-
- list_for_each_entry(p, &clocks, list) {
- if (p->id == idno &&
- strcmp(id, p->name) == 0 &&
- try_module_get(p->owner)) {
- clk = p;
- break;
- }
- }
-
- /* check for the case where a device was supplied, but the
- * clock that was being searched for is not device specific */
-
- if (IS_ERR(clk)) {
- list_for_each_entry(p, &clocks, list) {
- if (p->id == -1 && strcmp(id, p->name) == 0 &&
- try_module_get(p->owner)) {
- clk = p;
- break;
- }
- }
- }
+ clkcon &= ~clocks;
- mutex_unlock(&clocks_mutex);
- return clk;
-}
+ /* ensure none of the special function bits set */
+ clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER);
-void clk_put(struct clk *clk)
-{
- module_put(clk->owner);
-}
+ __raw_writel(clkcon, S3C2410_CLKCON);
-int clk_enable(struct clk *clk)
-{
- if (IS_ERR(clk) || clk == NULL)
- return -EINVAL;
-
- clk_enable(clk->parent);
-
- mutex_lock(&clocks_mutex);
-
- if ((clk->usage++) == 0)
- (clk->enable)(clk, 1);
-
- mutex_unlock(&clocks_mutex);
return 0;
}
-void clk_disable(struct clk *clk)
-{
- if (IS_ERR(clk) || clk == NULL)
- return;
-
- mutex_lock(&clocks_mutex);
-
- if ((--clk->usage) == 0)
- (clk->enable)(clk, 0);
-
- mutex_unlock(&clocks_mutex);
- clk_disable(clk->parent);
-}
-
-
-unsigned long clk_get_rate(struct clk *clk)
-{
- if (IS_ERR(clk))
- return 0;
-
- if (clk->rate != 0)
- return clk->rate;
-
- if (clk->get_rate != NULL)
- return (clk->get_rate)(clk);
-
- if (clk->parent != NULL)
- return clk_get_rate(clk->parent);
-
- return clk->rate;
-}
-
-long clk_round_rate(struct clk *clk, unsigned long rate)
-{
- if (!IS_ERR(clk) && clk->round_rate)
- return (clk->round_rate)(clk, rate);
-
- return rate;
-}
-
-int clk_set_rate(struct clk *clk, unsigned long rate)
-{
- int ret;
-
- if (IS_ERR(clk))
- return -EINVAL;
-
- mutex_lock(&clocks_mutex);
- ret = (clk->set_rate)(clk, rate);
- mutex_unlock(&clocks_mutex);
-
- return ret;
-}
-
-struct clk *clk_get_parent(struct clk *clk)
+static int s3c2410_upll_enable(struct clk *clk, int enable)
{
- return clk->parent;
-}
-
-int clk_set_parent(struct clk *clk, struct clk *parent)
-{
- int ret = 0;
-
- if (IS_ERR(clk))
- return -EINVAL;
-
- mutex_lock(&clocks_mutex);
-
- if (clk->set_parent)
- ret = (clk->set_parent)(clk, parent);
-
- mutex_unlock(&clocks_mutex);
-
- return ret;
-}
-
-EXPORT_SYMBOL(clk_get);
-EXPORT_SYMBOL(clk_put);
-EXPORT_SYMBOL(clk_enable);
-EXPORT_SYMBOL(clk_disable);
-EXPORT_SYMBOL(clk_get_rate);
-EXPORT_SYMBOL(clk_round_rate);
-EXPORT_SYMBOL(clk_set_rate);
-EXPORT_SYMBOL(clk_get_parent);
-EXPORT_SYMBOL(clk_set_parent);
-
-/* base clocks */
-
-struct clk clk_xtal = {
- .name = "xtal",
- .id = -1,
- .rate = 0,
- .parent = NULL,
- .ctrlbit = 0,
-};
-
-struct clk clk_mpll = {
- .name = "mpll",
- .id = -1,
-};
-
-struct clk clk_upll = {
- .name = "upll",
- .id = -1,
- .parent = NULL,
- .ctrlbit = 0,
-};
-
-struct clk clk_f = {
- .name = "fclk",
- .id = -1,
- .rate = 0,
- .parent = &clk_mpll,
- .ctrlbit = 0,
-};
-
-struct clk clk_h = {
- .name = "hclk",
- .id = -1,
- .rate = 0,
- .parent = NULL,
- .ctrlbit = 0,
-};
-
-struct clk clk_p = {
- .name = "pclk",
- .id = -1,
- .rate = 0,
- .parent = NULL,
- .ctrlbit = 0,
-};
-
-struct clk clk_usb_bus = {
- .name = "usb-bus",
- .id = -1,
- .rate = 0,
- .parent = &clk_upll,
-};
-
-/* clocks that could be registered by external code */
-
-static int s3c24xx_dclk_enable(struct clk *clk, int enable)
-{
- unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON);
+ unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
+ unsigned long orig = clkslow;
if (enable)
- dclkcon |= clk->ctrlbit;
+ clkslow &= ~S3C2410_CLKSLOW_UCLK_OFF;
else
- dclkcon &= ~clk->ctrlbit;
+ clkslow |= S3C2410_CLKSLOW_UCLK_OFF;
- __raw_writel(dclkcon, S3C24XX_DCLKCON);
+ __raw_writel(clkslow, S3C2410_CLKSLOW);
- return 0;
-}
+ /* if we started the UPLL, then allow to settle */
-static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
-{
- unsigned long dclkcon;
- unsigned int uclk;
-
- if (parent == &clk_upll)
- uclk = 1;
- else if (parent == &clk_p)
- uclk = 0;
- else
- return -EINVAL;
-
- clk->parent = parent;
-
- dclkcon = __raw_readl(S3C24XX_DCLKCON);
-
- if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) {
- if (uclk)
- dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK;
- else
- dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK;
- } else {
- if (uclk)
- dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK;
- else
- dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK;
- }
-
- __raw_writel(dclkcon, S3C24XX_DCLKCON);
+ if (enable && (orig & S3C2410_CLKSLOW_UCLK_OFF))
+ udelay(200);
return 0;
}
-
-static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent)
-{
- unsigned long mask;
- unsigned long source;
-
- /* calculate the MISCCR setting for the clock */
-
- if (parent == &clk_xtal)
- source = S3C2410_MISCCR_CLK0_MPLL;
- else if (parent == &clk_upll)
- source = S3C2410_MISCCR_CLK0_UPLL;
- else if (parent == &clk_f)
- source = S3C2410_MISCCR_CLK0_FCLK;
- else if (parent == &clk_h)
- source = S3C2410_MISCCR_CLK0_HCLK;
- else if (parent == &clk_p)
- source = S3C2410_MISCCR_CLK0_PCLK;
- else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0)
- source = S3C2410_MISCCR_CLK0_DCLK0;
- else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1)
- source = S3C2410_MISCCR_CLK0_DCLK0;
- else
- return -EINVAL;
-
- clk->parent = parent;
-
- if (clk == &s3c24xx_dclk0)
- mask = S3C2410_MISCCR_CLK0_MASK;
- else {
- source <<= 4;
- mask = S3C2410_MISCCR_CLK1_MASK;
+/* standard clock definitions */
+
+static struct clk init_clocks_disable[] = {
+ {
+ .name = "nand",
+ .id = -1,
+ .parent = &clk_h,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_NAND,
+ }, {
+ .name = "sdi",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_SDI,
+ }, {
+ .name = "adc",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_ADC,
+ }, {
+ .name = "i2c",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_IIC,
+ }, {
+ .name = "iis",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_IIS,
+ }, {
+ .name = "spi",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_SPI,
}
-
- s3c2410_modify_misccr(mask, source);
- return 0;
-}
-
-/* external clock definitions */
-
-struct clk s3c24xx_dclk0 = {
- .name = "dclk0",
- .id = -1,
- .ctrlbit = S3C2410_DCLKCON_DCLK0EN,
- .enable = s3c24xx_dclk_enable,
- .set_parent = s3c24xx_dclk_setparent,
-};
-
-struct clk s3c24xx_dclk1 = {
- .name = "dclk1",
- .id = -1,
- .ctrlbit = S3C2410_DCLKCON_DCLK0EN,
- .enable = s3c24xx_dclk_enable,
- .set_parent = s3c24xx_dclk_setparent,
};
-struct clk s3c24xx_clkout0 = {
- .name = "clkout0",
- .id = -1,
- .set_parent = s3c24xx_clkout_setparent,
+static struct clk init_clocks[] = {
+ {
+ .name = "lcd",
+ .id = -1,
+ .parent = &clk_h,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_LCDC,
+ }, {
+ .name = "gpio",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_GPIO,
+ }, {
+ .name = "usb-host",
+ .id = -1,
+ .parent = &clk_h,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_USBH,
+ }, {
+ .name = "usb-device",
+ .id = -1,
+ .parent = &clk_h,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_USBD,
+ }, {
+ .name = "timers",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_PWMT,
+ }, {
+ .name = "uart",
+ .id = 0,
+ .parent = &clk_p,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_UART0,
+ }, {
+ .name = "uart",
+ .id = 1,
+ .parent = &clk_p,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_UART1,
+ }, {
+ .name = "uart",
+ .id = 2,
+ .parent = &clk_p,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_UART2,
+ }, {
+ .name = "rtc",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2410_clkcon_enable,
+ .ctrlbit = S3C2410_CLKCON_RTC,
+ }, {
+ .name = "watchdog",
+ .id = -1,
+ .parent = &clk_p,
+ .ctrlbit = 0,
+ }, {
+ .name = "usb-bus-host",
+ .id = -1,
+ .parent = &clk_usb_bus,
+ }, {
+ .name = "usb-bus-gadget",
+ .id = -1,
+ .parent = &clk_usb_bus,
+ },
};
-struct clk s3c24xx_clkout1 = {
- .name = "clkout1",
- .id = -1,
- .set_parent = s3c24xx_clkout_setparent,
-};
-
-struct clk s3c24xx_uclk = {
- .name = "uclk",
- .id = -1,
-};
-
-/* initialise the clock system */
-
-int s3c24xx_register_clock(struct clk *clk)
-{
- clk->owner = THIS_MODULE;
-
- if (clk->enable == NULL)
- clk->enable = clk_null_enable;
-
- /* add to the list of available clocks */
-
- mutex_lock(&clocks_mutex);
- list_add(&clk->list, &clocks);
- mutex_unlock(&clocks_mutex);
-
- return 0;
-}
-
-/* initalise all the clocks */
+/* s3c2410_baseclk_add()
+ *
+ * Add all the clocks used by the s3c2410 or compatible CPUs
+ * such as the S3C2440 and S3C2442.
+ *
+ * We cannot use a system device as we are needed before any
+ * of the init-calls that initialise the devices are actually
+ * done.
+*/
-int __init s3c24xx_setup_clocks(unsigned long xtal,
- unsigned long fclk,
- unsigned long hclk,
- unsigned long pclk)
+int __init s3c2410_baseclk_add(void)
{
- printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n");
+ unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
+ unsigned long clkcon = __raw_readl(S3C2410_CLKCON);
+ struct clk *clkp;
+ struct clk *xtal;
+ int ret;
+ int ptr;
- /* initialise the main system clocks */
+ clk_upll.enable = s3c2410_upll_enable;
- clk_xtal.rate = xtal;
- clk_upll.rate = s3c2410_get_pll(__raw_readl(S3C2410_UPLLCON), xtal);
+ if (s3c24xx_register_clock(&clk_usb_bus) < 0)
+ printk(KERN_ERR "failed to register usb bus clock\n");
- clk_mpll.rate = fclk;
- clk_h.rate = hclk;
- clk_p.rate = pclk;
- clk_f.rate = fclk;
+ /* register clocks from clock array */
- /* assume uart clocks are correctly setup */
+ clkp = init_clocks;
+ for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
+ /* ensure that we note the clock state */
- /* register our clocks */
+ clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0;
- if (s3c24xx_register_clock(&clk_xtal) < 0)
- printk(KERN_ERR "failed to register master xtal\n");
+ ret = s3c24xx_register_clock(clkp);
+ if (ret < 0) {
+ printk(KERN_ERR "Failed to register clock %s (%d)\n",
+ clkp->name, ret);
+ }
+ }
- if (s3c24xx_register_clock(&clk_mpll) < 0)
- printk(KERN_ERR "failed to register mpll clock\n");
+ /* We must be careful disabling the clocks we are not intending to
+ * be using at boot time, as subsytems such as the LCD which do
+ * their own DMA requests to the bus can cause the system to lockup
+ * if they where in the middle of requesting bus access.
+ *
+ * Disabling the LCD clock if the LCD is active is very dangerous,
+ * and therefore the bootloader should be careful to not enable
+ * the LCD clock if it is not needed.
+ */
+
+ /* install (and disable) the clocks we do not need immediately */
+
+ clkp = init_clocks_disable;
+ for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
+
+ ret = s3c24xx_register_clock(clkp);
+ if (ret < 0) {
+ printk(KERN_ERR "Failed to register clock %s (%d)\n",
+ clkp->name, ret);
+ }
- if (s3c24xx_register_clock(&clk_upll) < 0)
- printk(KERN_ERR "failed to register upll clock\n");
+ s3c2410_clkcon_enable(clkp, 0);
+ }
- if (s3c24xx_register_clock(&clk_f) < 0)
- printk(KERN_ERR "failed to register cpu fclk\n");
+ /* show the clock-slow value */
- if (s3c24xx_register_clock(&clk_h) < 0)
- printk(KERN_ERR "failed to register cpu hclk\n");
+ xtal = clk_get(NULL, "xtal");
- if (s3c24xx_register_clock(&clk_p) < 0)
- printk(KERN_ERR "failed to register cpu pclk\n");
+ printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n",
+ print_mhz(clk_get_rate(xtal) /
+ ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))),
+ (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast",
+ (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on",
+ (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on");
return 0;
}
diff --git a/arch/arm/mach-s3c2410/dma.c b/arch/arm/mach-s3c2410/dma.c
index fa860e716b4..67d1ad36397 100644
--- a/arch/arm/mach-s3c2410/dma.c
+++ b/arch/arm/mach-s3c2410/dma.c
@@ -1,9 +1,9 @@
/* linux/arch/arm/mach-s3c2410/dma.c
*
- * Copyright (c) 2003-2005,2006 Simtec Electronics
+ * Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
- * S3C2410 DMA core
+ * S3C2410 DMA selection
*
* http://armlinux.simtec.co.uk/
*
@@ -12,1430 +12,170 @@
* published by the Free Software Foundation.
*/
-
-#ifdef CONFIG_S3C2410_DMA_DEBUG
-#define DEBUG
-#endif
-
-#include <linux/module.h>
+#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
#include <linux/sysdev.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
+#include <linux/serial_core.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/hardware.h>
-#include <asm/io.h>
#include <asm/dma.h>
-
-#include <asm/mach/dma.h>
-#include <asm/arch/map.h>
-
-#include "dma.h"
-
-/* io map for dma */
-static void __iomem *dma_base;
-static struct kmem_cache *dma_kmem;
-
-struct s3c24xx_dma_selection dma_sel;
-
-/* dma channel state information */
-struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
-
-/* debugging functions */
-
-#define BUF_MAGIC (0xcafebabe)
-
-#define dmawarn(fmt...) printk(KERN_DEBUG fmt)
-
-#define dma_regaddr(chan, reg) ((chan)->regs + (reg))
-
-#if 1
-#define dma_wrreg(chan, reg, val) writel((val), (chan)->regs + (reg))
-#else
-static inline void
-dma_wrreg(struct s3c2410_dma_chan *chan, int reg, unsigned long val)
-{
- pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg);
- writel(val, dma_regaddr(chan, reg));
-}
-#endif
-
-#define dma_rdreg(chan, reg) readl((chan)->regs + (reg))
-
-/* captured register state for debug */
-
-struct s3c2410_dma_regstate {
- unsigned long dcsrc;
- unsigned long disrc;
- unsigned long dstat;
- unsigned long dcon;
- unsigned long dmsktrig;
+#include <asm/arch/dma.h>
+
+#include <asm/plat-s3c24xx/cpu.h>
+#include <asm/plat-s3c24xx/dma.h>
+
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-ac97.h>
+#include <asm/arch/regs-mem.h>
+#include <asm/arch/regs-lcd.h>
+#include <asm/arch/regs-sdi.h>
+#include <asm/arch/regs-iis.h>
+#include <asm/arch/regs-spi.h>
+
+static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = {
+ [DMACH_XD0] = {
+ .name = "xdreq0",
+ .channels[0] = S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID,
+ },
+ [DMACH_XD1] = {
+ .name = "xdreq1",
+ .channels[1] = S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID,
+ },
+ [DMACH_SDI] = {
+ .name = "sdi",
+ .channels[0] = S3C2410_DCON_CH0_SDI | DMA_CH_VALID,
+ .channels[2] = S3C2410_DCON_CH2_SDI | DMA_CH_VALID,
+ .channels[3] = S3C2410_DCON_CH3_SDI | DMA_CH_VALID,
+ .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
+ .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
+ },
+ [DMACH_SPI0] = {
+ .name = "spi0",
+ .channels[1] = S3C2410_DCON_CH1_SPI | DMA_CH_VALID,
+ .hw_addr.to = S3C2410_PA_SPI + S3C2410_SPTDAT,
+ .hw_addr.from = S3C2410_PA_SPI + S3C2410_SPRDAT,
+ },
+ [DMACH_SPI1] = {
+ .name = "spi1",
+ .channels[3] = S3C2410_DCON_CH3_SPI | DMA_CH_VALID,
+ .hw_addr.to = S3C2410_PA_SPI + 0x20 + S3C2410_SPTDAT,
+ .hw_addr.from = S3C2410_PA_SPI + 0x20 + S3C2410_SPRDAT,
+ },
+ [DMACH_UART0] = {
+ .name = "uart0",
+ .channels[0] = S3C2410_DCON_CH0_UART0 | DMA_CH_VALID,
+ .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH,
+ .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH,
+ },
+ [DMACH_UART1] = {
+ .name = "uart1",
+ .channels[1] = S3C2410_DCON_CH1_UART1 | DMA_CH_VALID,
+ .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH,
+ .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH,
+ },
+ [DMACH_UART2] = {
+ .name = "uart2",
+ .channels[3] = S3C2410_DCON_CH3_UART2 | DMA_CH_VALID,
+ .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH,
+ .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH,
+ },
+ [DMACH_TIMER] = {
+ .name = "timer",
+ .channels[0] = S3C2410_DCON_CH0_TIMER | DMA_CH_VALID,
+ .channels[2] = S3C2410_DCON_CH2_TIMER | DMA_CH_VALID,
+ .channels[3] = S3C2410_DCON_CH3_TIMER | DMA_CH_VALID,
+ },
+ [DMACH_I2S_IN] = {
+ .name = "i2s-sdi",
+ .channels[1] = S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID,
+ .channels[2] = S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID,
+ .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
+ },
+ [DMACH_I2S_OUT] = {
+ .name = "i2s-sdo",
+ .channels[2] = S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID,
+ .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
+ },
+ [DMACH_USB_EP1] = {
+ .name = "usb-ep1",
+ .channels[0] = S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID,
+ },
+ [DMACH_USB_EP2] = {
+ .name = "usb-ep2",
+ .channels[1] = S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID,
+ },
+ [DMACH_USB_EP3] = {
+ .name = "usb-ep3",
+ .channels[2] = S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID,
+ },
+ [DMACH_USB_EP4] = {
+ .name = "usb-ep4",
+ .channels[3] =S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID,
+ },
};
-#ifdef CONFIG_S3C2410_DMA_DEBUG
-
-/* dmadbg_showregs
- *
- * simple debug routine to print the current state of the dma registers
-*/
-
-static void
-dmadbg_capture(struct s3c2410_dma_chan *chan, struct s3c2410_dma_regstate *regs)
-{
- regs->dcsrc = dma_rdreg(chan, S3C2410_DMA_DCSRC);
- regs->disrc = dma_rdreg(chan, S3C2410_DMA_DISRC);
- regs->dstat = dma_rdreg(chan, S3C2410_DMA_DSTAT);
- regs->dcon = dma_rdreg(chan, S3C2410_DMA_DCON);
- regs->dmsktrig = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
-}
-
-static void
-dmadbg_dumpregs(const char *fname, int line, struct s3c2410_dma_chan *chan,
- struct s3c2410_dma_regstate *regs)
-{
- printk(KERN_DEBUG "dma%d: %s:%d: DCSRC=%08lx, DISRC=%08lx, DSTAT=%08lx DMT=%02lx, DCON=%08lx\n",
- chan->number, fname, line,
- regs->dcsrc, regs->disrc, regs->dstat, regs->dmsktrig,
- regs->dcon);
-}
-
-static void
-dmadbg_showchan(const char *fname, int line, struct s3c2410_dma_chan *chan)
-{
- struct s3c2410_dma_regstate state;
-
- dmadbg_capture(chan, &state);
-
- printk(KERN_DEBUG "dma%d: %s:%d: ls=%d, cur=%p, %p %p\n",
- chan->number, fname, line, chan->load_state,
- chan->curr, chan->next, chan->end);
-
- dmadbg_dumpregs(fname, line, chan, &state);
-}
-
-static void
-dmadbg_showregs(const char *fname, int line, struct s3c2410_dma_chan *chan)
-{
- struct s3c2410_dma_regstate state;
-
- dmadbg_capture(chan, &state);
- dmadbg_dumpregs(fname, line, chan, &state);
-}
-
-#define dbg_showregs(chan) dmadbg_showregs(__FUNCTION__, __LINE__, (chan))
-#define dbg_showchan(chan) dmadbg_showchan(__FUNCTION__, __LINE__, (chan))
-#else
-#define dbg_showregs(chan) do { } while(0)
-#define dbg_showchan(chan) do { } while(0)
-#endif /* CONFIG_S3C2410_DMA_DEBUG */
-
-static struct s3c2410_dma_chan *dma_chan_map[DMACH_MAX];
-
-/* lookup_dma_channel
- *
- * change the dma channel number given into a real dma channel id
-*/
-
-static struct s3c2410_dma_chan *lookup_dma_channel(unsigned int channel)
-{
- if (channel & DMACH_LOW_LEVEL)
- return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL];
- else
- return dma_chan_map[channel];
-}
-
-/* s3c2410_dma_stats_timeout
- *
- * Update DMA stats from timeout info
-*/
-
-static void
-s3c2410_dma_stats_timeout(struct s3c2410_dma_stats *stats, int val)
+static void s3c2410_dma_select(struct s3c2410_dma_chan *chan,
+ struct s3c24xx_dma_map *map)
{
- if (stats == NULL)
- return;
-
- if (val > stats->timeout_longest)
- stats->timeout_longest = val;
- if (val < stats->timeout_shortest)
- stats->timeout_shortest = val;
-
- stats->timeout_avg += val;
+ chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID;
}
-/* s3c2410_dma_waitforload
- *
- * wait for the DMA engine to load a buffer, and update the state accordingly
-*/
-
-static int
-s3c2410_dma_waitforload(struct s3c2410_dma_chan *chan, int line)
-{
- int timeout = chan->load_timeout;
- int took;
-
- if (chan->load_state != S3C2410_DMALOAD_1LOADED) {
- printk(KERN_ERR "dma%d: s3c2410_dma_waitforload() called in loadstate %d from line %d\n", chan->number, chan->load_state, line);
- return 0;
- }
-
- if (chan->stats != NULL)
- chan->stats->loads++;
-
- while (--timeout > 0) {
- if ((dma_rdreg(chan, S3C2410_DMA_DSTAT) << (32-20)) != 0) {
- took = chan->load_timeout - timeout;
-
- s3c2410_dma_stats_timeout(chan->stats, took);
-
- switch (chan->load_state) {
- case S3C2410_DMALOAD_1LOADED:
- chan->load_state = S3C2410_DMALOAD_1RUNNING;
- break;
-
- default:
- printk(KERN_ERR "dma%d: unknown load_state in s3c2410_dma_waitforload() %d\n", chan->number, chan->load_state);
- }
-
- return 1;
- }
- }
-
- if (chan->stats != NULL) {
- chan->stats->timeout_failed++;
- }
-
- return 0;
-}
-
-
-
-/* s3c2410_dma_loadbuffer
- *
- * load a buffer, and update the channel state
-*/
-
-static inline int
-s3c2410_dma_loadbuffer(struct s3c2410_dma_chan *chan,
- struct s3c2410_dma_buf *buf)
-{
- unsigned long reload;
-
- pr_debug("s3c2410_chan_loadbuffer: loading buff %p (0x%08lx,0x%06x)\n",
- buf, (unsigned long)buf->data, buf->size);
-
- if (buf == NULL) {
- dmawarn("buffer is NULL\n");
- return -EINVAL;
- }
-
- /* check the state of the channel before we do anything */
-
- if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
- dmawarn("load_state is S3C2410_DMALOAD_1LOADED\n");
- }
-
- if (chan->load_state == S3C2410_DMALOAD_1LOADED_1RUNNING) {
- dmawarn("state is S3C2410_DMALOAD_1LOADED_1RUNNING\n");
- }
-
- /* it would seem sensible if we are the last buffer to not bother
- * with the auto-reload bit, so that the DMA engine will not try
- * and load another transfer after this one has finished...
- */
- if (chan->load_state == S3C2410_DMALOAD_NONE) {
- pr_debug("load_state is none, checking for noreload (next=%p)\n",
- buf->next);
- reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0;
- } else {
- //pr_debug("load_state is %d => autoreload\n", chan->load_state);
- reload = S3C2410_DCON_AUTORELOAD;
- }
-
- if ((buf->data & 0xf0000000) != 0x30000000) {
- dmawarn("dmaload: buffer is %p\n", (void *)buf->data);
- }
-
- writel(buf->data, chan->addr_reg);
-
- dma_wrreg(chan, S3C2410_DMA_DCON,
- chan->dcon | reload | (buf->size/chan->xfer_unit));
-
- chan->next = buf->next;
-
- /* update the state of the channel */
-
- switch (chan->load_state) {
- case S3C2410_DMALOAD_NONE:
- chan->load_state = S3C2410_DMALOAD_1LOADED;
- break;
-
- case S3C2410_DMALOAD_1RUNNING:
- chan->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING;
- break;
-
- default:
- dmawarn("dmaload: unknown state %d in loadbuffer\n",
- chan->load_state);
- break;
- }
-
- return 0;
-}
-
-/* s3c2410_dma_call_op
- *
- * small routine to call the op routine with the given op if it has been
- * registered
-*/
-
-static void
-s3c2410_dma_call_op(struct s3c2410_dma_chan *chan, enum s3c2410_chan_op op)
-{
- if (chan->op_fn != NULL) {
- (chan->op_fn)(chan, op);
- }
-}
-
-/* s3c2410_dma_buffdone
- *
- * small wrapper to check if callback routine needs to be called, and
- * if so, call it
-*/
-
-static inline void
-s3c2410_dma_buffdone(struct s3c2410_dma_chan *chan, struct s3c2410_dma_buf *buf,
- enum s3c2410_dma_buffresult result)
-{
-#if 0
- pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n",
- chan->callback_fn, buf, buf->id, buf->size, result);
-#endif
-
- if (chan->callback_fn != NULL) {
- (chan->callback_fn)(chan, buf->id, buf->size, result);
- }
-}
-
-/* s3c2410_dma_start
- *
- * start a dma channel going
-*/
-
-static int s3c2410_dma_start(struct s3c2410_dma_chan *chan)
-{
- unsigned long tmp;
- unsigned long flags;
-
- pr_debug("s3c2410_start_dma: channel=%d\n", chan->number);
-
- local_irq_save(flags);
-
- if (chan->state == S3C2410_DMA_RUNNING) {
- pr_debug("s3c2410_start_dma: already running (%d)\n", chan->state);
- local_irq_restore(flags);
- return 0;
- }
-
- chan->state = S3C2410_DMA_RUNNING;
-
- /* check wether there is anything to load, and if not, see
- * if we can find anything to load
- */
-
- if (chan->load_state == S3C2410_DMALOAD_NONE) {
- if (chan->next == NULL) {
- printk(KERN_ERR "dma%d: channel has nothing loaded\n",
- chan->number);
- chan->state = S3C2410_DMA_IDLE;
- local_irq_restore(flags);
- return -EINVAL;
- }
-
- s3c2410_dma_loadbuffer(chan, chan->next);
- }
-
- dbg_showchan(chan);
-
- /* enable the channel */
-
- if (!chan->irq_enabled) {
- enable_irq(chan->irq);
- chan->irq_enabled = 1;
- }
-
- /* start the channel going */
-
- tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
- tmp &= ~S3C2410_DMASKTRIG_STOP;
- tmp |= S3C2410_DMASKTRIG_ON;
- dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
-
- pr_debug("dma%d: %08lx to DMASKTRIG\n", chan->number, tmp);
-
-#if 0
- /* the dma buffer loads should take care of clearing the AUTO
- * reloading feature */
- tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
- tmp &= ~S3C2410_DCON_NORELOAD;
- dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
-#endif
-
- s3c2410_dma_call_op(chan, S3C2410_DMAOP_START);
-
- dbg_showchan(chan);
-
- /* if we've only loaded one buffer onto the channel, then chec
- * to see if we have another, and if so, try and load it so when
- * the first buffer is finished, the new one will be loaded onto
- * the channel */
-
- if (chan->next != NULL) {
- if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
-
- if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
- pr_debug("%s: buff not yet loaded, no more todo\n",
- __FUNCTION__);
- } else {
- chan->load_state = S3C2410_DMALOAD_1RUNNING;
- s3c2410_dma_loadbuffer(chan, chan->next);
- }
-
- } else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) {
- s3c2410_dma_loadbuffer(chan, chan->next);
- }
- }
-
-
- local_irq_restore(flags);
-
- return 0;
-}
-
-/* s3c2410_dma_canload
- *
- * work out if we can queue another buffer into the DMA engine
-*/
-
-static int
-s3c2410_dma_canload(struct s3c2410_dma_chan *chan)
-{
- if (chan->load_state == S3C2410_DMALOAD_NONE ||
- chan->load_state == S3C2410_DMALOAD_1RUNNING)
- return 1;
-
- return 0;
-}
-
-/* s3c2410_dma_enqueue
- *
- * queue an given buffer for dma transfer.
- *
- * id the device driver's id information for this buffer
- * data the physical address of the buffer data
- * size the size of the buffer in bytes
- *
- * If the channel is not running, then the flag S3C2410_DMAF_AUTOSTART
- * is checked, and if set, the channel is started. If this flag isn't set,
- * then an error will be returned.
- *
- * It is possible to queue more than one DMA buffer onto a channel at
- * once, and the code will deal with the re-loading of the next buffer
- * when necessary.
-*/
-
-int s3c2410_dma_enqueue(unsigned int channel, void *id,
- dma_addr_t data, int size)
-{
- struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
- struct s3c2410_dma_buf *buf;
- unsigned long flags;
-
- if (chan == NULL)
- return -EINVAL;
-
- pr_debug("%s: id=%p, data=%08x, size=%d\n",
- __FUNCTION__, id, (unsigned int)data, size);
-
- buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC);
- if (buf == NULL) {
- pr_debug("%s: out of memory (%ld alloc)\n",
- __FUNCTION__, (long)sizeof(*buf));
- return -ENOMEM;
- }
-
- //pr_debug("%s: new buffer %p\n", __FUNCTION__, buf);
- //dbg_showchan(chan);
-
- buf->next = NULL;
- buf->data = buf->ptr = data;
- buf->size = size;
- buf->id = id;
- buf->magic = BUF_MAGIC;
-
- local_irq_save(flags);
-
- if (chan->curr == NULL) {
- /* we've got nothing loaded... */
- pr_debug("%s: buffer %p queued onto empty channel\n",
- __FUNCTION__, buf);
-
- chan->curr = buf;
- chan->end = buf;
- chan->next = NULL;
- } else {
- pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n",
- chan->number, __FUNCTION__, buf);
-
- if (chan->end == NULL)
- pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n",
- chan->number, __FUNCTION__, chan);
-
- chan->end->next = buf;
- chan->end = buf;
- }
-
- /* if necessary, update the next buffer field */
- if (chan->next == NULL)
- chan->next = buf;
-
- /* check to see if we can load a buffer */
- if (chan->state == S3C2410_DMA_RUNNING) {
- if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) {
- if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
- printk(KERN_ERR "dma%d: loadbuffer:"
- "timeout loading buffer\n",
- chan->number);
- dbg_showchan(chan);
- local_irq_restore(flags);
- return -EINVAL;
- }
- }
-
- while (s3c2410_dma_canload(chan) && chan->next != NULL) {
- s3c2410_dma_loadbuffer(chan, chan->next);
- }
- } else if (chan->state == S3C2410_DMA_IDLE) {
- if (chan->flags & S3C2410_DMAF_AUTOSTART) {
- s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_START);
- }
- }
-
- local_irq_restore(flags);
- return 0;
-}
-
-EXPORT_SYMBOL(s3c2410_dma_enqueue);
-
-static inline void
-s3c2410_dma_freebuf(struct s3c2410_dma_buf *buf)
-{
- int magicok = (buf->magic == BUF_MAGIC);
-
- buf->magic = -1;
-
- if (magicok) {
- kmem_cache_free(dma_kmem, buf);
- } else {
- printk("s3c2410_dma_freebuf: buff %p with bad magic\n", buf);
- }
-}
-
-/* s3c2410_dma_lastxfer
- *
- * called when the system is out of buffers, to ensure that the channel
- * is prepared for shutdown.
-*/
-
-static inline void
-s3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan)
-{
-#if 0
- pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n",
- chan->number, chan->load_state);
-#endif
-
- switch (chan->load_state) {
- case S3C2410_DMALOAD_NONE:
- break;
-
- case S3C2410_DMALOAD_1LOADED:
- if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
- /* flag error? */
- printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
- chan->number, __FUNCTION__);
- return;
- }
- break;
-
- case S3C2410_DMALOAD_1LOADED_1RUNNING:
- /* I belive in this case we do not have anything to do
- * until the next buffer comes along, and we turn off the
- * reload */
- return;
-
- default:
- pr_debug("dma%d: lastxfer: unhandled load_state %d with no next\n",
- chan->number, chan->load_state);
- return;
-
- }
-
- /* hopefully this'll shut the damned thing up after the transfer... */
- dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD);
-}
-
-
-#define dmadbg2(x...)
-
-static irqreturn_t
-s3c2410_dma_irq(int irq, void *devpw)
-{
- struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw;
- struct s3c2410_dma_buf *buf;
-
- buf = chan->curr;
-
- dbg_showchan(chan);
-
- /* modify the channel state */
-
- switch (chan->load_state) {
- case S3C2410_DMALOAD_1RUNNING:
- /* TODO - if we are running only one buffer, we probably
- * want to reload here, and then worry about the buffer
- * callback */
-
- chan->load_state = S3C2410_DMALOAD_NONE;
- break;
-
- case S3C2410_DMALOAD_1LOADED:
- /* iirc, we should go back to NONE loaded here, we
- * had a buffer, and it was never verified as being
- * loaded.
- */
-
- chan->load_state = S3C2410_DMALOAD_NONE;
- break;
-
- case S3C2410_DMALOAD_1LOADED_1RUNNING:
- /* we'll worry about checking to see if another buffer is
- * ready after we've called back the owner. This should
- * ensure we do not wait around too long for the DMA
- * engine to start the next transfer
- */
-
- chan->load_state = S3C2410_DMALOAD_1LOADED;
- break;
-
- case S3C2410_DMALOAD_NONE:
- printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n",
- chan->number);
- break;
-
- default:
- printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n",
- chan->number, chan->load_state);
- break;
- }
-
- if (buf != NULL) {
- /* update the chain to make sure that if we load any more
- * buffers when we call the callback function, things should
- * work properly */
-
- chan->curr = buf->next;
- buf->next = NULL;
-
- if (buf->magic != BUF_MAGIC) {
- printk(KERN_ERR "dma%d: %s: buf %p incorrect magic\n",
- chan->number, __FUNCTION__, buf);
- return IRQ_HANDLED;
- }
-
- s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK);
-
- /* free resouces */
- s3c2410_dma_freebuf(buf);
- } else {
- }
-
- /* only reload if the channel is still running... our buffer done
- * routine may have altered the state by requesting the dma channel
- * to stop or shutdown... */
-
- /* todo: check that when the channel is shut-down from inside this
- * function, we cope with unsetting reload, etc */
-
- if (chan->next != NULL && chan->state != S3C2410_DMA_IDLE) {
- unsigned long flags;
-
- switch (chan->load_state) {
- case S3C2410_DMALOAD_1RUNNING:
- /* don't need to do anything for this state */
- break;
-
- case S3C2410_DMALOAD_NONE:
- /* can load buffer immediately */
- break;
-
- case S3C2410_DMALOAD_1LOADED:
- if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
- /* flag error? */
- printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
- chan->number, __FUNCTION__);
- return IRQ_HANDLED;
- }
-
- break;
-
- case S3C2410_DMALOAD_1LOADED_1RUNNING:
- goto no_load;
-
- default:
- printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n",
- chan->number, chan->load_state);
- return IRQ_HANDLED;
- }
-
- local_irq_save(flags);
- s3c2410_dma_loadbuffer(chan, chan->next);
- local_irq_restore(flags);
- } else {
- s3c2410_dma_lastxfer(chan);
-
- /* see if we can stop this channel.. */
- if (chan->load_state == S3C2410_DMALOAD_NONE) {
- pr_debug("dma%d: end of transfer, stopping channel (%ld)\n",
- chan->number, jiffies);
- s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL,
- S3C2410_DMAOP_STOP);
- }
- }
-
- no_load:
- return IRQ_HANDLED;
-}
-
-static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel);
-
-/* s3c2410_request_dma
- *
- * get control of an dma channel
-*/
-
-int s3c2410_dma_request(unsigned int channel,
- struct s3c2410_dma_client *client,
- void *dev)
-{
- struct s3c2410_dma_chan *chan;
- unsigned long flags;
- int err;
-
- pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n",
- channel, client->name, dev);
-
- local_irq_save(flags);
-
- chan = s3c2410_dma_map_channel(channel);
- if (chan == NULL) {
- local_irq_restore(flags);
- return -EBUSY;
- }
-
- dbg_showchan(chan);
-
- chan->client = client;
- chan->in_use = 1;
-
- if (!chan->irq_claimed) {
- pr_debug("dma%d: %s : requesting irq %d\n",
- channel, __FUNCTION__, chan->irq);
-
- chan->irq_claimed = 1;
- local_irq_restore(flags);
-
- err = request_irq(chan->irq, s3c2410_dma_irq, IRQF_DISABLED,
- client->name, (void *)chan);
-
- local_irq_save(flags);
-
- if (err) {
- chan->in_use = 0;
- chan->irq_claimed = 0;
- local_irq_restore(flags);
-
- printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n",
- client->name, chan->irq, chan->number);
- return err;
- }
-
- chan->irq_enabled = 1;
- }
-
- local_irq_restore(flags);
-
- /* need to setup */
-
- pr_debug("%s: channel initialised, %p\n", __FUNCTION__, chan);
-
- return 0;
-}
-
-EXPORT_SYMBOL(s3c2410_dma_request);
+static struct s3c24xx_dma_selection __initdata s3c2410_dma_sel = {
+ .select = s3c2410_dma_select,
+ .dcon_mask = 7 << 24,
+ .map = s3c2410_dma_mappings,
+ .map_size = ARRAY_SIZE(s3c2410_dma_mappings),
+};
-/* s3c2410_dma_free
- *
- * release the given channel back to the system, will stop and flush
- * any outstanding transfers, and ensure the channel is ready for the
- * next claimant.
- *
- * Note, although a warning is currently printed if the freeing client
- * info is not the same as the registrant's client info, the free is still
- * allowed to go through.
-*/
+static struct s3c24xx_dma_order __initdata s3c2410_dma_order = {
+ .channels = {
+ [DMACH_SDI] = {
+ .list = {
+ [0] = 3 | DMA_CH_VALID,
+ [1] = 2 | DMA_CH_VALID,
+ [2] = 0 | DMA_CH_VALID,
+ },
+ },
+ [DMACH_I2S_IN] = {
+ .list = {
+ [0] = 1 | DMA_CH_VALID,
+ [1] = 2 | DMA_CH_VALID,
+ },
+ },
+ },
+};
-int s3c2410_dma_free(dmach_t channel, struct s3c2410_dma_client *client)
+static int s3c2410_dma_add(struct sys_device *sysdev)
{
- struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
- unsigned long flags;
-
- if (chan == NULL)
- return -EINVAL;
-
- local_irq_save(flags);
-
- if (chan->client != client) {
- printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n",
- channel, chan->client, client);
- }
-
- /* sort out stopping and freeing the channel */
-
- if (chan->state != S3C2410_DMA_IDLE) {
- pr_debug("%s: need to stop dma channel %p\n",
- __FUNCTION__, chan);
-
- /* possibly flush the channel */
- s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STOP);
- }
-
- chan->client = NULL;
- chan->in_use = 0;
-
- if (chan->irq_claimed)
- free_irq(chan->irq, (void *)chan);
-
- chan->irq_claimed = 0;
-
- if (!(channel & DMACH_LOW_LEVEL))
- dma_chan_map[channel] = NULL;
-
- local_irq_restore(flags);
-
- return 0;
+ s3c2410_dma_init();
+ s3c24xx_dma_order_set(&s3c2410_dma_order);
+ return s3c24xx_dma_init_map(&s3c2410_dma_sel);
}
-EXPORT_SYMBOL(s3c2410_dma_free);
-
-static int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan)
-{
- unsigned long flags;
- unsigned long tmp;
-
- pr_debug("%s:\n", __FUNCTION__);
-
- dbg_showchan(chan);
-
- local_irq_save(flags);
-
- s3c2410_dma_call_op(chan, S3C2410_DMAOP_STOP);
-
- tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
- tmp |= S3C2410_DMASKTRIG_STOP;
- //tmp &= ~S3C2410_DMASKTRIG_ON;
- dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
-
-#if 0
- /* should also clear interrupts, according to WinCE BSP */
- tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
- tmp |= S3C2410_DCON_NORELOAD;
- dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
-#endif
-
- /* should stop do this, or should we wait for flush? */
- chan->state = S3C2410_DMA_IDLE;
- chan->load_state = S3C2410_DMALOAD_NONE;
-
- local_irq_restore(flags);
-
- return 0;
-}
+#if defined(CONFIG_CPU_S3C2410)
+static struct sysdev_driver s3c2410_dma_driver = {
+ .add = s3c2410_dma_add,
+};
-void s3c2410_dma_waitforstop(struct s3c2410_dma_chan *chan)
+static int __init s3c2410_dma_drvinit(void)
{
- unsigned long tmp;
- unsigned int timeout = 0x10000;
-
- while (timeout-- > 0) {
- tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
-
- if (!(tmp & S3C2410_DMASKTRIG_ON))
- return;
- }
-
- pr_debug("dma%d: failed to stop?\n", chan->number);
+ return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_dma_driver);
}
-
-/* s3c2410_dma_flush
- *
- * stop the channel, and remove all current and pending transfers
-*/
-
-static int s3c2410_dma_flush(struct s3c2410_dma_chan *chan)
-{
- struct s3c2410_dma_buf *buf, *next;
- unsigned long flags;
-
- pr_debug("%s: chan %p (%d)\n", __FUNCTION__, chan, chan->number);
-
- dbg_showchan(chan);
-
- local_irq_save(flags);
-
- if (chan->state != S3C2410_DMA_IDLE) {
- pr_debug("%s: stopping channel...\n", __FUNCTION__ );
- s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP);
- }
-
- buf = chan->curr;
- if (buf == NULL)
- buf = chan->next;
-
- chan->curr = chan->next = chan->end = NULL;
-
- if (buf != NULL) {
- for ( ; buf != NULL; buf = next) {
- next = buf->next;
-
- pr_debug("%s: free buffer %p, next %p\n",
- __FUNCTION__, buf, buf->next);
-
- s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT);
- s3c2410_dma_freebuf(buf);
- }
- }
-
- dbg_showregs(chan);
-
- s3c2410_dma_waitforstop(chan);
-
-#if 0
- /* should also clear interrupts, according to WinCE BSP */
- {
- unsigned long tmp;
-
- tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
- tmp |= S3C2410_DCON_NORELOAD;
- dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
- }
+arch_initcall(s3c2410_dma_drvinit);
#endif
- dbg_showregs(chan);
-
- local_irq_restore(flags);
-
- return 0;
-}
-
-int
-s3c2410_dma_started(struct s3c2410_dma_chan *chan)
-{
- unsigned long flags;
-
- local_irq_save(flags);
-
- dbg_showchan(chan);
-
- /* if we've only loaded one buffer onto the channel, then chec
- * to see if we have another, and if so, try and load it so when
- * the first buffer is finished, the new one will be loaded onto
- * the channel */
-
- if (chan->next != NULL) {
- if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
-
- if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
- pr_debug("%s: buff not yet loaded, no more todo\n",
- __FUNCTION__);
- } else {
- chan->load_state = S3C2410_DMALOAD_1RUNNING;
- s3c2410_dma_loadbuffer(chan, chan->next);
- }
-
- } else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) {
- s3c2410_dma_loadbuffer(chan, chan->next);
- }
- }
-
-
- local_irq_restore(flags);
-
- return 0;
-
-}
-
-int
-s3c2410_dma_ctrl(dmach_t channel, enum s3c2410_chan_op op)
-{
- struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
-
- if (chan == NULL)
- return -EINVAL;
-
- switch (op) {
- case S3C2410_DMAOP_START:
- return s3c2410_dma_start(chan);
-
- case S3C2410_DMAOP_STOP:
- return s3c2410_dma_dostop(chan);
-
- case S3C2410_DMAOP_PAUSE:
- case S3C2410_DMAOP_RESUME:
- return -ENOENT;
-
- case S3C2410_DMAOP_FLUSH:
- return s3c2410_dma_flush(chan);
-
- case S3C2410_DMAOP_STARTED:
- return s3c2410_dma_started(chan);
-
- case S3C2410_DMAOP_TIMEOUT:
- return 0;
-
- }
-
- return -ENOENT; /* unknown, don't bother */
-}
-
-EXPORT_SYMBOL(s3c2410_dma_ctrl);
-
-/* DMA configuration for each channel
- *
- * DISRCC -> source of the DMA (AHB,APB)
- * DISRC -> source address of the DMA
- * DIDSTC -> destination of the DMA (AHB,APD)
- * DIDST -> destination address of the DMA
-*/
-
-/* s3c2410_dma_config
- *
- * xfersize: size of unit in bytes (1,2,4)
- * dcon: base value of the DCONx register
-*/
-
-int s3c2410_dma_config(dmach_t channel,
- int xferunit,
- int dcon)
-{
- struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
-
- pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n",
- __FUNCTION__, channel, xferunit, dcon);
-
- if (chan == NULL)
- return -EINVAL;
-
- pr_debug("%s: Initial dcon is %08x\n", __FUNCTION__, dcon);
-
- dcon |= chan->dcon & dma_sel.dcon_mask;
-
- pr_debug("%s: New dcon is %08x\n", __FUNCTION__, dcon);
-
- switch (xferunit) {
- case 1:
- dcon |= S3C2410_DCON_BYTE;
- break;
-
- case 2:
- dcon |= S3C2410_DCON_HALFWORD;
- break;
-
- case 4:
- dcon |= S3C2410_DCON_WORD;
- break;
-
- default:
- pr_debug("%s: bad transfer size %d\n", __FUNCTION__, xferunit);
- return -EINVAL;
- }
-
- dcon |= S3C2410_DCON_HWTRIG;
- dcon |= S3C2410_DCON_INTREQ;
-
- pr_debug("%s: dcon now %08x\n", __FUNCTION__, dcon);
-
- chan->dcon = dcon;
- chan->xfer_unit = xferunit;
-
- return 0;
-}
-
-EXPORT_SYMBOL(s3c2410_dma_config);
-
-int s3c2410_dma_setflags(dmach_t channel, unsigned int flags)
-{
- struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
-
- if (chan == NULL)
- return -EINVAL;
-
- pr_debug("%s: chan=%p, flags=%08x\n", __FUNCTION__, chan, flags);
-
- chan->flags = flags;
-
- return 0;
-}
-
-EXPORT_SYMBOL(s3c2410_dma_setflags);
-
-
-/* do we need to protect the settings of the fields from
- * irq?
-*/
-
-int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn)
-{
- struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
-
- if (chan == NULL)
- return -EINVAL;
-
- pr_debug("%s: chan=%p, op rtn=%p\n", __FUNCTION__, chan, rtn);
-
- chan->op_fn = rtn;
-
- return 0;
-}
-
-EXPORT_SYMBOL(s3c2410_dma_set_opfn);
-
-int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn)
-{
- struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
-
- if (chan == NULL)
- return -EINVAL;
-
- pr_debug("%s: chan=%p, callback rtn=%p\n", __FUNCTION__, chan, rtn);
-
- chan->callback_fn = rtn;
-
- return 0;
-}
-
-EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);
-
-/* s3c2410_dma_devconfig
- *
- * configure the dma source/destination hardware type and address
- *
- * source: S3C2410_DMASRC_HW: source is hardware
- * S3C2410_DMASRC_MEM: source is memory
- *
- * hwcfg: the value for xxxSTCn register,
- * bit 0: 0=increment pointer, 1=leave pointer
- * bit 1: 0=soucre is AHB, 1=soucre is APB
- *
- * devaddr: physical address of the source
-*/
-
-int s3c2410_dma_devconfig(int channel,
- enum s3c2410_dmasrc source,
- int hwcfg,
- unsigned long devaddr)
-{
- struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
-
- if (chan == NULL)
- return -EINVAL;
-
- pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n",
- __FUNCTION__, (int)source, hwcfg, devaddr);
-
- chan->source = source;
- chan->dev_addr = devaddr;
-
- switch (source) {
- case S3C2410_DMASRC_HW:
- /* source is hardware */
- pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n",
- __FUNCTION__, devaddr, hwcfg);
- dma_wrreg(chan, S3C2410_DMA_DISRCC, hwcfg & 3);
- dma_wrreg(chan, S3C2410_DMA_DISRC, devaddr);
- dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0));
-
- chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST);
- return 0;
-
- case S3C2410_DMASRC_MEM:
- /* source is memory */
- pr_debug( "%s: mem source, devaddr=%08lx, hwcfg=%d\n",
- __FUNCTION__, devaddr, hwcfg);
- dma_wrreg(chan, S3C2410_DMA_DISRCC, (0<<1) | (0<<0));
- dma_wrreg(chan, S3C2410_DMA_DIDST, devaddr);
- dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3);
-
- chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC);
- return 0;
- }
-
- printk(KERN_ERR "dma%d: invalid source type (%d)\n", channel, source);
- return -EINVAL;
-}
-
-EXPORT_SYMBOL(s3c2410_dma_devconfig);
-
-/* s3c2410_dma_getposition
- *
- * returns the current transfer points for the dma source and destination
-*/
-
-int s3c2410_dma_getposition(dmach_t channel, dma_addr_t *src, dma_addr_t *dst)
-{
- struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
-
- if (chan == NULL)
- return -EINVAL;
-
- if (src != NULL)
- *src = dma_rdreg(chan, S3C2410_DMA_DCSRC);
-
- if (dst != NULL)
- *dst = dma_rdreg(chan, S3C2410_DMA_DCDST);
-
- return 0;
-}
-
-EXPORT_SYMBOL(s3c2410_dma_getposition);
-
-
-/* system device class */
-
-#ifdef CONFIG_PM
-
-static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state)
-{
- struct s3c2410_dma_chan *cp = container_of(dev, struct s3c2410_dma_chan, dev);
-
- printk(KERN_DEBUG "suspending dma channel %d\n", cp->number);
-
- if (dma_rdreg(cp, S3C2410_DMA_DMASKTRIG) & S3C2410_DMASKTRIG_ON) {
- /* the dma channel is still working, which is probably
- * a bad thing to do over suspend/resume. We stop the
- * channel and assume that the client is either going to
- * retry after resume, or that it is broken.
- */
-
- printk(KERN_INFO "dma: stopping channel %d due to suspend\n",
- cp->number);
-
- s3c2410_dma_dostop(cp);
- }
-
- return 0;
-}
-
-static int s3c2410_dma_resume(struct sys_device *dev)
-{
- return 0;
-}
-
-#else
-#define s3c2410_dma_suspend NULL
-#define s3c2410_dma_resume NULL
-#endif /* CONFIG_PM */
-
-struct sysdev_class dma_sysclass = {
- set_kset_name("s3c24xx-dma"),
- .suspend = s3c2410_dma_suspend,
- .resume = s3c2410_dma_resume,
+#if defined(CONFIG_CPU_S3C2442)
+/* S3C2442 DMA contains the same selection table as the S3C2410 */
+static struct sysdev_driver s3c2442_dma_driver = {
+ .add = s3c2410_dma_add,
};
-/* kmem cache implementation */
-
-static void s3c2410_dma_cache_ctor(void *p, struct kmem_cache *c, unsigned long f)
-{
- memset(p, 0, sizeof(struct s3c2410_dma_buf));
-}
-
-/* initialisation code */
-
-static int __init s3c2410_init_dma(void)
-{
- struct s3c2410_dma_chan *cp;
- int channel;
- int ret;
-
- printk("S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics\n");
-
- dma_base = ioremap(S3C24XX_PA_DMA, 0x200);
- if (dma_base == NULL) {
- printk(KERN_ERR "dma failed to remap register block\n");
- return -ENOMEM;
- }
-
- printk("Registering sysclass\n");
-
- ret = sysdev_class_register(&dma_sysclass);
- if (ret != 0) {
- printk(KERN_ERR "dma sysclass registration failed\n");
- goto err;
- }
-
- dma_kmem = kmem_cache_create("dma_desc", sizeof(struct s3c2410_dma_buf), 0,
- SLAB_HWCACHE_ALIGN,
- s3c2410_dma_cache_ctor, NULL);
-
- if (dma_kmem == NULL) {
- printk(KERN_ERR "dma failed to make kmem cache\n");
- ret = -ENOMEM;
- goto err;
- }
-
- for (channel = 0; channel < S3C2410_DMA_CHANNELS; channel++) {
- cp = &s3c2410_chans[channel];
-
- memset(cp, 0, sizeof(struct s3c2410_dma_chan));
-
- /* dma channel irqs are in order.. */
- cp->number = channel;
- cp->irq = channel + IRQ_DMA0;
- cp->regs = dma_base + (channel*0x40);
-
- /* point current stats somewhere */
- cp->stats = &cp->stats_store;
- cp->stats_store.timeout_shortest = LONG_MAX;
-
- /* basic channel configuration */
-
- cp->load_timeout = 1<<18;
-
- /* register system device */
-
- cp->dev.cls = &dma_sysclass;
- cp->dev.id = channel;
- ret = sysdev_register(&cp->dev);
-
- printk("DMA channel %d at %p, irq %d\n",
- cp->number, cp->regs, cp->irq);
- }
-
- return 0;
-
- err:
- kmem_cache_destroy(dma_kmem);
- iounmap(dma_base);
- dma_base = NULL;
- return ret;
-}
-
-core_initcall(s3c2410_init_dma);
-
-static inline int is_channel_valid(unsigned int channel)
+static int __init s3c2442_dma_drvinit(void)
{
- return (channel & DMA_CH_VALID);
+ return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_dma_driver);
}
-/* s3c2410_dma_map_channel()
- *
- * turn the virtual channel number into a real, and un-used hardware
- * channel.
- *
- * currently this code uses first-free channel from the specified harware
- * map, not taking into account anything that the board setup code may
- * have to say about the likely peripheral set to be in use.
-*/
-
-struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
-{
- struct s3c24xx_dma_map *ch_map;
- struct s3c2410_dma_chan *dmach;
- int ch;
-
- if (dma_sel.map == NULL || channel > dma_sel.map_size)
- return NULL;
-
- ch_map = dma_sel.map + channel;
-
- for (ch = 0; ch < S3C2410_DMA_CHANNELS; ch++) {
- if (!is_channel_valid(ch_map->channels[ch]))
- continue;
-
- if (s3c2410_chans[ch].in_use == 0) {
- printk("mapped channel %d to %d\n", channel, ch);
- break;
- }
- }
-
- if (ch >= S3C2410_DMA_CHANNELS)
- return NULL;
-
- /* update our channel mapping */
-
- dmach = &s3c2410_chans[ch];
- dma_chan_map[channel] = dmach;
-
- /* select the channel */
-
- (dma_sel.select)(dmach, ch_map);
-
- return dmach;
-}
-
-static void s3c24xx_dma_show_ch(struct s3c24xx_dma_map *map, int ch)
-{
- /* show the channel configuration */
-
- printk("%2d: %20s, channels %c%c%c%c\n", ch, map->name,
- (is_channel_valid(map->channels[0]) ? '0' : '-'),
- (is_channel_valid(map->channels[1]) ? '1' : '-'),
- (is_channel_valid(map->channels[2]) ? '2' : '-'),
- (is_channel_valid(map->channels[3]) ? '3' : '-'));
-}
-
-static int s3c24xx_dma_check_entry(struct s3c24xx_dma_map *map, int ch)
-{
- if (1)
- s3c24xx_dma_show_ch(map, ch);
-
- return 0;
-}
-
-int __init s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel)
-{
- struct s3c24xx_dma_map *nmap;
- size_t map_sz = sizeof(*nmap) * sel->map_size;
- int ptr;
-
- nmap = kmalloc(map_sz, GFP_KERNEL);
- if (nmap == NULL)
- return -ENOMEM;
-
- memcpy(nmap, sel->map, map_sz);
- memcpy(&dma_sel, sel, sizeof(*sel));
-
- dma_sel.map = nmap;
-
- for (ptr = 0; ptr < sel->map_size; ptr++)
- s3c24xx_dma_check_entry(nmap+ptr, ptr);
+arch_initcall(s3c2442_dma_drvinit);
+#endif
- return 0;
-}
diff --git a/arch/arm/mach-s3c2410/gpio.c b/arch/arm/mach-s3c2410/gpio.c
index f6fb215bb48..01e795d1146 100644
--- a/arch/arm/mach-s3c2410/gpio.c
+++ b/arch/arm/mach-s3c2410/gpio.c
@@ -1,9 +1,9 @@
/* linux/arch/arm/mach-s3c2410/gpio.c
*
- * Copyright (c) 2004-2005 Simtec Electronics
+ * Copyright (c) 2004-2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
- * S3C24XX GPIO support
+ * S3C2410 GPIO 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
@@ -18,8 +18,7 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
+ */
#include <linux/kernel.h>
#include <linux/init.h>
@@ -33,156 +32,40 @@
#include <asm/arch/regs-gpio.h>
-void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
-{
- void __iomem *base = S3C24XX_GPIO_BASE(pin);
- unsigned long mask;
- unsigned long con;
- unsigned long flags;
-
- if (pin < S3C2410_GPIO_BANKB) {
- mask = 1 << S3C2410_GPIO_OFFSET(pin);
- } else {
- mask = 3 << S3C2410_GPIO_OFFSET(pin)*2;
- }
-
- switch (function) {
- case S3C2410_GPIO_LEAVE:
- mask = 0;
- function = 0;
- break;
-
- case S3C2410_GPIO_INPUT:
- case S3C2410_GPIO_OUTPUT:
- case S3C2410_GPIO_SFN2:
- case S3C2410_GPIO_SFN3:
- if (pin < S3C2410_GPIO_BANKB) {
- function -= 1;
- function &= 1;
- function <<= S3C2410_GPIO_OFFSET(pin);
- } else {
- function &= 3;
- function <<= S3C2410_GPIO_OFFSET(pin)*2;
- }
- }
-
- /* modify the specified register wwith IRQs off */
-
- local_irq_save(flags);
-
- con = __raw_readl(base + 0x00);
- con &= ~mask;
- con |= function;
-
- __raw_writel(con, base + 0x00);
-
- local_irq_restore(flags);
-}
-
-EXPORT_SYMBOL(s3c2410_gpio_cfgpin);
-
-unsigned int s3c2410_gpio_getcfg(unsigned int pin)
-{
- void __iomem *base = S3C24XX_GPIO_BASE(pin);
- unsigned long val = __raw_readl(base);
-
- if (pin < S3C2410_GPIO_BANKB) {
- val >>= S3C2410_GPIO_OFFSET(pin);
- val &= 1;
- val += 1;
- } else {
- val >>= S3C2410_GPIO_OFFSET(pin)*2;
- val &= 3;
- }
-
- return val | S3C2410_GPIO_INPUT;
-}
-
-EXPORT_SYMBOL(s3c2410_gpio_getcfg);
-
-void s3c2410_gpio_pullup(unsigned int pin, unsigned int to)
+int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
+ unsigned int config)
{
- void __iomem *base = S3C24XX_GPIO_BASE(pin);
- unsigned long offs = S3C2410_GPIO_OFFSET(pin);
+ void __iomem *reg = S3C24XX_EINFLT0;
unsigned long flags;
- unsigned long up;
-
- if (pin < S3C2410_GPIO_BANKB)
- return;
-
- local_irq_save(flags);
-
- up = __raw_readl(base + 0x08);
- up &= ~(1L << offs);
- up |= to << offs;
- __raw_writel(up, base + 0x08);
+ unsigned long val;
- local_irq_restore(flags);
-}
+ if (pin < S3C2410_GPG8 || pin > S3C2410_GPG15)
+ return -1;
-EXPORT_SYMBOL(s3c2410_gpio_pullup);
+ config &= 0xff;
-void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
-{
- void __iomem *base = S3C24XX_GPIO_BASE(pin);
- unsigned long offs = S3C2410_GPIO_OFFSET(pin);
- unsigned long flags;
- unsigned long dat;
+ pin -= S3C2410_GPG8;
+ reg += pin & ~3;
local_irq_save(flags);
- dat = __raw_readl(base + 0x04);
- dat &= ~(1 << offs);
- dat |= to << offs;
- __raw_writel(dat, base + 0x04);
-
- local_irq_restore(flags);
-}
-
-EXPORT_SYMBOL(s3c2410_gpio_setpin);
-
-unsigned int s3c2410_gpio_getpin(unsigned int pin)
-{
- void __iomem *base = S3C24XX_GPIO_BASE(pin);
- unsigned long offs = S3C2410_GPIO_OFFSET(pin);
+ /* update filter width and clock source */
- return __raw_readl(base + 0x04) & (1<< offs);
-}
+ val = __raw_readl(reg);
+ val &= ~(0xff << ((pin & 3) * 8));
+ val |= config << ((pin & 3) * 8);
+ __raw_writel(val, reg);
-EXPORT_SYMBOL(s3c2410_gpio_getpin);
+ /* update filter enable */
-unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change)
-{
- unsigned long flags;
- unsigned long misccr;
+ val = __raw_readl(S3C24XX_EXTINT2);
+ val &= ~(1 << ((pin * 4) + 3));
+ val |= on << ((pin * 4) + 3);
+ __raw_writel(val, S3C24XX_EXTINT2);
- local_irq_save(flags);
- misccr = __raw_readl(S3C24XX_MISCCR);
- misccr &= ~clear;
- misccr ^= change;
- __raw_writel(misccr, S3C24XX_MISCCR);
local_irq_restore(flags);
- return misccr;
-}
-
-EXPORT_SYMBOL(s3c2410_modify_misccr);
-
-int s3c2410_gpio_getirq(unsigned int pin)
-{
- if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15)
- return -1; /* not valid interrupts */
-
- if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7)
- return -1; /* not valid pin */
-
- if (pin < S3C2410_GPF4)
- return (pin - S3C2410_GPF0) + IRQ_EINT0;
-
- if (pin < S3C2410_GPG0)
- return (pin - S3C2410_GPF4) + IRQ_EINT4;
-
- return (pin - S3C2410_GPG0) + IRQ_EINT8;
+ return 0;
}
-EXPORT_SYMBOL(s3c2410_gpio_getirq);
+EXPORT_SYMBOL(s3c2410_gpio_irqfilter);
diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c
index 3c0ed7871c5..53cbdaa43ac 100644
--- a/arch/arm/mach-s3c2410/irq.c
+++ b/arch/arm/mach-s3c2410/irq.c
@@ -1,6 +1,6 @@
/* linux/arch/arm/mach-s3c2410/irq.c
*
- * Copyright (c) 2003,2004 Simtec Electronics
+ * Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* This program is free software; you can redistribute it and/or modify
@@ -17,37 +17,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * Changelog:
- *
- * 22-Jul-2004 Ben Dooks <ben@simtec.co.uk>
- * Fixed compile warnings
- *
- * 22-Jul-2004 Roc Wu <cooloney@yahoo.com.cn>
- * Fixed s3c_extirq_type
- *
- * 21-Jul-2004 Arnaud Patard (Rtp) <arnaud.patard@rtp-net.org>
- * Addition of ADC/TC demux
- *
- * 04-Oct-2004 Klaus Fetscher <k.fetscher@fetron.de>
- * Fix for set_irq_type() on low EINT numbers
- *
- * 05-Oct-2004 Ben Dooks <ben@simtec.co.uk>
- * Tidy up KF's patch and sort out new release
- *
- * 05-Oct-2004 Ben Dooks <ben@simtec.co.uk>
- * Add support for power management controls
- *
- * 04-Nov-2004 Ben Dooks
- * Fix standard IRQ wake for EINT0..4 and RTC
- *
- * 22-Feb-2005 Ben Dooks
- * Fixed edge-triggering on ADC IRQ
- *
- * 28-Jun-2005 Ben Dooks
- * Mark IRQ_LCD valid
- *
- * 25-Jul-2005 Ben Dooks
- * Split the S3C2440 IRQ code to seperate file
*/
#include <linux/init.h>
@@ -57,745 +26,23 @@
#include <linux/ptrace.h>
#include <linux/sysdev.h>
-#include <asm/hardware.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-
-#include <asm/mach/irq.h>
-
-#include <asm/arch/regs-irq.h>
-#include <asm/arch/regs-gpio.h>
-
-#include "cpu.h"
-#include "pm.h"
-#include "irq.h"
-
-/* wakeup irq control */
-
-#ifdef CONFIG_PM
-
-/* state for IRQs over sleep */
-
-/* default is to allow for EINT0..EINT15, and IRQ_RTC as wakeup sources
- *
- * set bit to 1 in allow bitfield to enable the wakeup settings on it
-*/
-
-unsigned long s3c_irqwake_intallow = 1L << (IRQ_RTC - IRQ_EINT0) | 0xfL;
-unsigned long s3c_irqwake_intmask = 0xffffffffL;
-unsigned long s3c_irqwake_eintallow = 0x0000fff0L;
-unsigned long s3c_irqwake_eintmask = 0xffffffffL;
-
-int
-s3c_irq_wake(unsigned int irqno, unsigned int state)
-{
- unsigned long irqbit = 1 << (irqno - IRQ_EINT0);
-
- if (!(s3c_irqwake_intallow & irqbit))
- return -ENOENT;
-
- printk(KERN_INFO "wake %s for irq %d\n",
- state ? "enabled" : "disabled", irqno);
-
- if (!state)
- s3c_irqwake_intmask |= irqbit;
- else
- s3c_irqwake_intmask &= ~irqbit;
-
- return 0;
-}
-
-static int
-s3c_irqext_wake(unsigned int irqno, unsigned int state)
-{
- unsigned long bit = 1L << (irqno - EXTINT_OFF);
-
- if (!(s3c_irqwake_eintallow & bit))
- return -ENOENT;
-
- printk(KERN_INFO "wake %s for irq %d\n",
- state ? "enabled" : "disabled", irqno);
-
- if (!state)
- s3c_irqwake_eintmask |= bit;
- else
- s3c_irqwake_eintmask &= ~bit;
-
- return 0;
-}
-
-#else
-#define s3c_irqext_wake NULL
-#define s3c_irq_wake NULL
-#endif
-
-
-static void
-s3c_irq_mask(unsigned int irqno)
-{
- unsigned long mask;
-
- irqno -= IRQ_EINT0;
-
- mask = __raw_readl(S3C2410_INTMSK);
- mask |= 1UL << irqno;
- __raw_writel(mask, S3C2410_INTMSK);
-}
-
-static inline void
-s3c_irq_ack(unsigned int irqno)
-{
- unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
-
- __raw_writel(bitval, S3C2410_SRCPND);
- __raw_writel(bitval, S3C2410_INTPND);
-}
-
-static inline void
-s3c_irq_maskack(unsigned int irqno)
-{
- unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
- unsigned long mask;
-
- mask = __raw_readl(S3C2410_INTMSK);
- __raw_writel(mask|bitval, S3C2410_INTMSK);
-
- __raw_writel(bitval, S3C2410_SRCPND);
- __raw_writel(bitval, S3C2410_INTPND);
-}
-
-
-static void
-s3c_irq_unmask(unsigned int irqno)
-{
- unsigned long mask;
-
- if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23)
- irqdbf2("s3c_irq_unmask %d\n", irqno);
-
- irqno -= IRQ_EINT0;
-
- mask = __raw_readl(S3C2410_INTMSK);
- mask &= ~(1UL << irqno);
- __raw_writel(mask, S3C2410_INTMSK);
-}
-
-struct irq_chip s3c_irq_level_chip = {
- .name = "s3c-level",
- .ack = s3c_irq_maskack,
- .mask = s3c_irq_mask,
- .unmask = s3c_irq_unmask,
- .set_wake = s3c_irq_wake
-};
-
-static struct irq_chip s3c_irq_chip = {
- .name = "s3c",
- .ack = s3c_irq_ack,
- .mask = s3c_irq_mask,
- .unmask = s3c_irq_unmask,
- .set_wake = s3c_irq_wake
-};
-
-static void
-s3c_irqext_mask(unsigned int irqno)
-{
- unsigned long mask;
-
- irqno -= EXTINT_OFF;
-
- mask = __raw_readl(S3C24XX_EINTMASK);
- mask |= ( 1UL << irqno);
- __raw_writel(mask, S3C24XX_EINTMASK);
-}
-
-static void
-s3c_irqext_ack(unsigned int irqno)
-{
- unsigned long req;
- unsigned long bit;
- unsigned long mask;
+#include <asm/plat-s3c24xx/cpu.h>
+#include <asm/plat-s3c24xx/pm.h>
- bit = 1UL << (irqno - EXTINT_OFF);
-
- mask = __raw_readl(S3C24XX_EINTMASK);
-
- __raw_writel(bit, S3C24XX_EINTPEND);
-
- req = __raw_readl(S3C24XX_EINTPEND);
- req &= ~mask;
-
- /* not sure if we should be acking the parent irq... */
-
- if (irqno <= IRQ_EINT7 ) {
- if ((req & 0xf0) == 0)
- s3c_irq_ack(IRQ_EINT4t7);
- } else {
- if ((req >> 8) == 0)
- s3c_irq_ack(IRQ_EINT8t23);
- }
-}
-
-static void
-s3c_irqext_unmask(unsigned int irqno)
+static int s3c2410_irq_add(struct sys_device *sysdev)
{
- unsigned long mask;
-
- irqno -= EXTINT_OFF;
-
- mask = __raw_readl(S3C24XX_EINTMASK);
- mask &= ~( 1UL << irqno);
- __raw_writel(mask, S3C24XX_EINTMASK);
-}
-
-int
-s3c_irqext_type(unsigned int irq, unsigned int type)
-{
- void __iomem *extint_reg;
- void __iomem *gpcon_reg;
- unsigned long gpcon_offset, extint_offset;
- unsigned long newvalue = 0, value;
-
- if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3))
- {
- gpcon_reg = S3C2410_GPFCON;
- extint_reg = S3C24XX_EXTINT0;
- gpcon_offset = (irq - IRQ_EINT0) * 2;
- extint_offset = (irq - IRQ_EINT0) * 4;
- }
- else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7))
- {
- gpcon_reg = S3C2410_GPFCON;
- extint_reg = S3C24XX_EXTINT0;
- gpcon_offset = (irq - (EXTINT_OFF)) * 2;
- extint_offset = (irq - (EXTINT_OFF)) * 4;
- }
- else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15))
- {
- gpcon_reg = S3C2410_GPGCON;
- extint_reg = S3C24XX_EXTINT1;
- gpcon_offset = (irq - IRQ_EINT8) * 2;
- extint_offset = (irq - IRQ_EINT8) * 4;
- }
- else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23))
- {
- gpcon_reg = S3C2410_GPGCON;
- extint_reg = S3C24XX_EXTINT2;
- gpcon_offset = (irq - IRQ_EINT8) * 2;
- extint_offset = (irq - IRQ_EINT16) * 4;
- } else
- return -1;
-
- /* Set the GPIO to external interrupt mode */
- value = __raw_readl(gpcon_reg);
- value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset);
- __raw_writel(value, gpcon_reg);
-
- /* Set the external interrupt to pointed trigger type */
- switch (type)
- {
- case IRQT_NOEDGE:
- printk(KERN_WARNING "No edge setting!\n");
- break;
-
- case IRQT_RISING:
- newvalue = S3C2410_EXTINT_RISEEDGE;
- break;
-
- case IRQT_FALLING:
- newvalue = S3C2410_EXTINT_FALLEDGE;
- break;
-
- case IRQT_BOTHEDGE:
- newvalue = S3C2410_EXTINT_BOTHEDGE;
- break;
-
- case IRQT_LOW:
- newvalue = S3C2410_EXTINT_LOWLEV;
- break;
-
- case IRQT_HIGH:
- newvalue = S3C2410_EXTINT_HILEV;
- break;
-
- default:
- printk(KERN_ERR "No such irq type %d", type);
- return -1;
- }
-
- value = __raw_readl(extint_reg);
- value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset);
- __raw_writel(value, extint_reg);
-
return 0;
}
-static struct irq_chip s3c_irqext_chip = {
- .name = "s3c-ext",
- .mask = s3c_irqext_mask,
- .unmask = s3c_irqext_unmask,
- .ack = s3c_irqext_ack,
- .set_type = s3c_irqext_type,
- .set_wake = s3c_irqext_wake
-};
-
-static struct irq_chip s3c_irq_eint0t4 = {
- .name = "s3c-ext0",
- .ack = s3c_irq_ack,
- .mask = s3c_irq_mask,
- .unmask = s3c_irq_unmask,
- .set_wake = s3c_irq_wake,
- .set_type = s3c_irqext_type,
-};
-
-/* mask values for the parent registers for each of the interrupt types */
-
-#define INTMSK_UART0 (1UL << (IRQ_UART0 - IRQ_EINT0))
-#define INTMSK_UART1 (1UL << (IRQ_UART1 - IRQ_EINT0))
-#define INTMSK_UART2 (1UL << (IRQ_UART2 - IRQ_EINT0))
-#define INTMSK_ADCPARENT (1UL << (IRQ_ADCPARENT - IRQ_EINT0))
-
-
-/* UART0 */
-
-static void
-s3c_irq_uart0_mask(unsigned int irqno)
-{
- s3c_irqsub_mask(irqno, INTMSK_UART0, 7);
-}
-
-static void
-s3c_irq_uart0_unmask(unsigned int irqno)
-{
- s3c_irqsub_unmask(irqno, INTMSK_UART0);
-}
-
-static void
-s3c_irq_uart0_ack(unsigned int irqno)
-{
- s3c_irqsub_maskack(irqno, INTMSK_UART0, 7);
-}
-
-static struct irq_chip s3c_irq_uart0 = {
- .name = "s3c-uart0",
- .mask = s3c_irq_uart0_mask,
- .unmask = s3c_irq_uart0_unmask,
- .ack = s3c_irq_uart0_ack,
-};
-
-/* UART1 */
-
-static void
-s3c_irq_uart1_mask(unsigned int irqno)
-{
- s3c_irqsub_mask(irqno, INTMSK_UART1, 7 << 3);
-}
-
-static void
-s3c_irq_uart1_unmask(unsigned int irqno)
-{
- s3c_irqsub_unmask(irqno, INTMSK_UART1);
-}
-
-static void
-s3c_irq_uart1_ack(unsigned int irqno)
-{
- s3c_irqsub_maskack(irqno, INTMSK_UART1, 7 << 3);
-}
-
-static struct irq_chip s3c_irq_uart1 = {
- .name = "s3c-uart1",
- .mask = s3c_irq_uart1_mask,
- .unmask = s3c_irq_uart1_unmask,
- .ack = s3c_irq_uart1_ack,
-};
-
-/* UART2 */
-
-static void
-s3c_irq_uart2_mask(unsigned int irqno)
-{
- s3c_irqsub_mask(irqno, INTMSK_UART2, 7 << 6);
-}
-
-static void
-s3c_irq_uart2_unmask(unsigned int irqno)
-{
- s3c_irqsub_unmask(irqno, INTMSK_UART2);
-}
-
-static void
-s3c_irq_uart2_ack(unsigned int irqno)
-{
- s3c_irqsub_maskack(irqno, INTMSK_UART2, 7 << 6);
-}
-
-static struct irq_chip s3c_irq_uart2 = {
- .name = "s3c-uart2",
- .mask = s3c_irq_uart2_mask,
- .unmask = s3c_irq_uart2_unmask,
- .ack = s3c_irq_uart2_ack,
-};
-
-/* ADC and Touchscreen */
-
-static void
-s3c_irq_adc_mask(unsigned int irqno)
-{
- s3c_irqsub_mask(irqno, INTMSK_ADCPARENT, 3 << 9);
-}
-
-static void
-s3c_irq_adc_unmask(unsigned int irqno)
-{
- s3c_irqsub_unmask(irqno, INTMSK_ADCPARENT);
-}
-
-static void
-s3c_irq_adc_ack(unsigned int irqno)
-{
- s3c_irqsub_ack(irqno, INTMSK_ADCPARENT, 3 << 9);
-}
-
-static struct irq_chip s3c_irq_adc = {
- .name = "s3c-adc",
- .mask = s3c_irq_adc_mask,
- .unmask = s3c_irq_adc_unmask,
- .ack = s3c_irq_adc_ack,
-};
-
-/* irq demux for adc */
-static void s3c_irq_demux_adc(unsigned int irq,
- struct irq_desc *desc)
-{
- unsigned int subsrc, submsk;
- unsigned int offset = 9;
- struct irq_desc *mydesc;
-
- /* read the current pending interrupts, and the mask
- * for what it is available */
-
- subsrc = __raw_readl(S3C2410_SUBSRCPND);
- submsk = __raw_readl(S3C2410_INTSUBMSK);
-
- subsrc &= ~submsk;
- subsrc >>= offset;
- subsrc &= 3;
-
- if (subsrc != 0) {
- if (subsrc & 1) {
- mydesc = irq_desc + IRQ_TC;
- desc_handle_irq(IRQ_TC, mydesc);
- }
- if (subsrc & 2) {
- mydesc = irq_desc + IRQ_ADC;
- desc_handle_irq(IRQ_ADC, mydesc);
- }
- }
-}
-
-static void s3c_irq_demux_uart(unsigned int start)
-{
- unsigned int subsrc, submsk;
- unsigned int offset = start - IRQ_S3CUART_RX0;
- struct irq_desc *desc;
-
- /* read the current pending interrupts, and the mask
- * for what it is available */
-
- subsrc = __raw_readl(S3C2410_SUBSRCPND);
- submsk = __raw_readl(S3C2410_INTSUBMSK);
-
- irqdbf2("s3c_irq_demux_uart: start=%d (%d), subsrc=0x%08x,0x%08x\n",
- start, offset, subsrc, submsk);
-
- subsrc &= ~submsk;
- subsrc >>= offset;
- subsrc &= 7;
-
- if (subsrc != 0) {
- desc = irq_desc + start;
-
- if (subsrc & 1)
- desc_handle_irq(start, desc);
-
- desc++;
-
- if (subsrc & 2)
- desc_handle_irq(start+1, desc);
-
- desc++;
-
- if (subsrc & 4)
- desc_handle_irq(start+2, desc);
- }
-}
-
-/* uart demux entry points */
-
-static void
-s3c_irq_demux_uart0(unsigned int irq,
- struct irq_desc *desc)
-{
- irq = irq;
- s3c_irq_demux_uart(IRQ_S3CUART_RX0);
-}
-
-static void
-s3c_irq_demux_uart1(unsigned int irq,
- struct irq_desc *desc)
-{
- irq = irq;
- s3c_irq_demux_uart(IRQ_S3CUART_RX1);
-}
-
-static void
-s3c_irq_demux_uart2(unsigned int irq,
- struct irq_desc *desc)
-{
- irq = irq;
- s3c_irq_demux_uart(IRQ_S3CUART_RX2);
-}
-
-static void
-s3c_irq_demux_extint8(unsigned int irq,
- struct irq_desc *desc)
-{
- unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
- unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
-
- eintpnd &= ~eintmsk;
- eintpnd &= ~0xff; /* ignore lower irqs */
-
- /* we may as well handle all the pending IRQs here */
-
- while (eintpnd) {
- irq = __ffs(eintpnd);
- eintpnd &= ~(1<<irq);
-
- irq += (IRQ_EINT4 - 4);
- desc_handle_irq(irq, irq_desc + irq);
- }
-
-}
-
-static void
-s3c_irq_demux_extint4t7(unsigned int irq,
- struct irq_desc *desc)
-{
- unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
- unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
-
- eintpnd &= ~eintmsk;
- eintpnd &= 0xff; /* only lower irqs */
-
- /* we may as well handle all the pending IRQs here */
-
- while (eintpnd) {
- irq = __ffs(eintpnd);
- eintpnd &= ~(1<<irq);
-
- irq += (IRQ_EINT4 - 4);
-
- desc_handle_irq(irq, irq_desc + irq);
- }
-}
-
-#ifdef CONFIG_PM
-
-static struct sleep_save irq_save[] = {
- SAVE_ITEM(S3C2410_INTMSK),
- SAVE_ITEM(S3C2410_INTSUBMSK),
+static struct sysdev_driver s3c2410_irq_driver = {
+ .add = s3c2410_irq_add,
+ .suspend = s3c24xx_irq_suspend,
+ .resume = s3c24xx_irq_resume,
};
-/* the extint values move between the s3c2410/s3c2440 and the s3c2412
- * so we use an array to hold them, and to calculate the address of
- * the register at run-time
-*/
-
-static unsigned long save_extint[3];
-static unsigned long save_eintflt[4];
-static unsigned long save_eintmask;
-
-int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state)
+static int s3c2410_irq_init(void)
{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(save_extint); i++)
- save_extint[i] = __raw_readl(S3C24XX_EXTINT0 + (i*4));
-
- for (i = 0; i < ARRAY_SIZE(save_eintflt); i++)
- save_eintflt[i] = __raw_readl(S3C24XX_EINFLT0 + (i*4));
-
- s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save));
- save_eintmask = __raw_readl(S3C24XX_EINTMASK);
-
- return 0;
+ return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_irq_driver);
}
-int s3c24xx_irq_resume(struct sys_device *dev)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(save_extint); i++)
- __raw_writel(save_extint[i], S3C24XX_EXTINT0 + (i*4));
-
- for (i = 0; i < ARRAY_SIZE(save_eintflt); i++)
- __raw_writel(save_eintflt[i], S3C24XX_EINFLT0 + (i*4));
-
- s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
- __raw_writel(save_eintmask, S3C24XX_EINTMASK);
-
- return 0;
-}
-
-#else
-#define s3c24xx_irq_suspend NULL
-#define s3c24xx_irq_resume NULL
-#endif
-
-/* s3c24xx_init_irq
- *
- * Initialise S3C2410 IRQ system
-*/
-
-void __init s3c24xx_init_irq(void)
-{
- unsigned long pend;
- unsigned long last;
- int irqno;
- int i;
-
- irqdbf("s3c2410_init_irq: clearing interrupt status flags\n");
-
- /* first, clear all interrupts pending... */
-
- last = 0;
- for (i = 0; i < 4; i++) {
- pend = __raw_readl(S3C24XX_EINTPEND);
-
- if (pend == 0 || pend == last)
- break;
-
- __raw_writel(pend, S3C24XX_EINTPEND);
- printk("irq: clearing pending ext status %08x\n", (int)pend);
- last = pend;
- }
-
- last = 0;
- for (i = 0; i < 4; i++) {
- pend = __raw_readl(S3C2410_INTPND);
-
- if (pend == 0 || pend == last)
- break;
-
- __raw_writel(pend, S3C2410_SRCPND);
- __raw_writel(pend, S3C2410_INTPND);
- printk("irq: clearing pending status %08x\n", (int)pend);
- last = pend;
- }
-
- last = 0;
- for (i = 0; i < 4; i++) {
- pend = __raw_readl(S3C2410_SUBSRCPND);
-
- if (pend == 0 || pend == last)
- break;
-
- printk("irq: clearing subpending status %08x\n", (int)pend);
- __raw_writel(pend, S3C2410_SUBSRCPND);
- last = pend;
- }
-
- /* register the main interrupts */
-
- irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n");
-
- for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) {
- /* set all the s3c2410 internal irqs */
-
- switch (irqno) {
- /* deal with the special IRQs (cascaded) */
-
- case IRQ_EINT4t7:
- case IRQ_EINT8t23:
- case IRQ_UART0:
- case IRQ_UART1:
- case IRQ_UART2:
- case IRQ_ADCPARENT:
- set_irq_chip(irqno, &s3c_irq_level_chip);
- set_irq_handler(irqno, handle_level_irq);
- break;
-
- case IRQ_RESERVED6:
- case IRQ_RESERVED24:
- /* no IRQ here */
- break;
-
- default:
- //irqdbf("registering irq %d (s3c irq)\n", irqno);
- set_irq_chip(irqno, &s3c_irq_chip);
- set_irq_handler(irqno, handle_edge_irq);
- set_irq_flags(irqno, IRQF_VALID);
- }
- }
-
- /* setup the cascade irq handlers */
-
- set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7);
- set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8);
-
- set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
- set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);
- set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2);
- set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc);
-
- /* external interrupts */
-
- for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
- irqdbf("registering irq %d (ext int)\n", irqno);
- set_irq_chip(irqno, &s3c_irq_eint0t4);
- set_irq_handler(irqno, handle_edge_irq);
- set_irq_flags(irqno, IRQF_VALID);
- }
-
- for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {
- irqdbf("registering irq %d (extended s3c irq)\n", irqno);
- set_irq_chip(irqno, &s3c_irqext_chip);
- set_irq_handler(irqno, handle_edge_irq);
- set_irq_flags(irqno, IRQF_VALID);
- }
-
- /* register the uart interrupts */
-
- irqdbf("s3c2410: registering external interrupts\n");
-
- for (irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) {
- irqdbf("registering irq %d (s3c uart0 irq)\n", irqno);
- set_irq_chip(irqno, &s3c_irq_uart0);
- set_irq_handler(irqno, handle_level_irq);
- set_irq_flags(irqno, IRQF_VALID);
- }
-
- for (irqno = IRQ_S3CUART_RX1; irqno <= IRQ_S3CUART_ERR1; irqno++) {
- irqdbf("registering irq %d (s3c uart1 irq)\n", irqno);
- set_irq_chip(irqno, &s3c_irq_uart1);
- set_irq_handler(irqno, handle_level_irq);
- set_irq_flags(irqno, IRQF_VALID);
- }
-
- for (irqno = IRQ_S3CUART_RX2; irqno <= IRQ_S3CUART_ERR2; irqno++) {
- irqdbf("registering irq %d (s3c uart2 irq)\n", irqno);
- set_irq_chip(irqno, &s3c_irq_uart2);
- set_irq_handler(irqno, handle_level_irq);
- set_irq_flags(irqno, IRQF_VALID);
- }
-
- for (irqno = IRQ_TC; irqno <= IRQ_ADC; irqno++) {
- irqdbf("registering irq %d (s3c adc irq)\n", irqno);
- set_irq_chip(irqno, &s3c_irq_adc);
- set_irq_handler(irqno, handle_edge_irq);
- set_irq_flags(irqno, IRQF_VALID);
- }
-
- irqdbf("s3c2410: registered interrupt handlers\n");
-}
+arch_initcall(s3c2410_irq_init);
diff --git a/arch/arm/mach-s3c2410/mach-amlm5900.c b/arch/arm/mach-s3c2410/mach-amlm5900.c
index 817e2c68441..72f2cc4fcd0 100644
--- a/arch/arm/mach-s3c2410/mach-amlm5900.c
+++ b/arch/arm/mach-s3c2410/mach-amlm5900.c
@@ -1,4 +1,4 @@
-/***********************************************************************
+/* linux/arch/arm/mach-s3c2410/mach-amlm5900.c
*
* linux/arch/arm/mach-s3c2410/mach-amlm5900.c
*
@@ -35,7 +35,7 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/proc_fs.h>
-
+#include <linux/serial_core.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -52,8 +52,8 @@
#include <asm/arch/regs-lcd.h>
#include <asm/arch/regs-gpio.h>
-#include "devs.h"
-#include "cpu.h"
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/cpu.h>
#ifdef CONFIG_MTD_PARTITIONS
@@ -113,12 +113,6 @@ static struct platform_device amlm5900_device_nor = {
#endif
static struct map_desc amlm5900_iodesc[] __initdata = {
- {
- .virtual = (u32)S3C24XX_VA_SPI,
- .pfn = __phys_to_pfn(S3C2410_PA_SPI),
- .length = SZ_1M,
- .type = MT_DEVICE
- }
};
#define UCON S3C2410_UCON_DEFAULT
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c
index b8b76757ec5..7b81296427e 100644
--- a/arch/arm/mach-s3c2410/mach-bast.c
+++ b/arch/arm/mach-s3c2410/mach-bast.c
@@ -50,9 +50,9 @@
#include <linux/serial_8250.h>
-#include "clock.h"
-#include "devs.h"
-#include "cpu.h"
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/cpu.h>
#include "usb-simtec.h"
#define COPYRIGHT ", (c) 2004-2005 Simtec Electronics"
diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c
index 15b625eae49..01c60d0923c 100644
--- a/arch/arm/mach-s3c2410/mach-h1940.c
+++ b/arch/arm/mach-s3c2410/mach-h1940.c
@@ -25,23 +25,24 @@
#include <asm/mach/irq.h>
#include <asm/hardware.h>
-#include <asm/hardware/iomd.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
-
#include <asm/arch/regs-serial.h>
#include <asm/arch/regs-lcd.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-clock.h>
#include <asm/arch/h1940.h>
#include <asm/arch/h1940-latch.h>
#include <asm/arch/fb.h>
+#include <asm/arch/udc.h>
-#include "clock.h"
-#include "devs.h"
-#include "cpu.h"
-#include "pm.h"
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/cpu.h>
+#include <asm/plat-s3c24xx/pm.h>
static struct map_desc h1940_iodesc[] __initdata = {
[0] = {
@@ -102,6 +103,32 @@ void h1940_latch_control(unsigned int clear, unsigned int set)
EXPORT_SYMBOL_GPL(h1940_latch_control);
+static void h1940_udc_pullup(enum s3c2410_udc_cmd_e cmd)
+{
+ printk(KERN_DEBUG "udc: pullup(%d)\n",cmd);
+
+ switch (cmd)
+ {
+ case S3C2410_UDC_P_ENABLE :
+ h1940_latch_control(0, H1940_LATCH_USB_DP);
+ break;
+ case S3C2410_UDC_P_DISABLE :
+ h1940_latch_control(H1940_LATCH_USB_DP, 0);
+ break;
+ case S3C2410_UDC_P_RESET :
+ break;
+ default:
+ break;
+ }
+}
+
+static struct s3c2410_udc_mach_info h1940_udc_cfg __initdata = {
+ .udc_command = h1940_udc_pullup,
+ .vbus_pin = S3C2410_GPG5,
+ .vbus_pin_inverted = 1,
+};
+
+
/**
* Set lcd on or off
@@ -146,12 +173,19 @@ static struct s3c2410fb_mach_info h1940_lcdcfg __initdata = {
.bpp= {16,16,16},
};
+static struct platform_device s3c_device_leds = {
+ .name = "h1940-leds",
+ .id = -1,
+};
+
static struct platform_device *h1940_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c,
&s3c_device_iis,
+ &s3c_device_usbgadget,
+ &s3c_device_leds,
};
static struct s3c24xx_board h1940_board __initdata = {
@@ -179,7 +213,23 @@ static void __init h1940_init_irq(void)
static void __init h1940_init(void)
{
+ u32 tmp;
+
s3c24xx_fb_set_platdata(&h1940_lcdcfg);
+ s3c24xx_udc_set_platdata(&h1940_udc_cfg);
+
+ /* Turn off suspend on both USB ports, and switch the
+ * selectable USB port to USB device mode. */
+
+ s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
+ S3C2410_MISCCR_USBSUSPND0 |
+ S3C2410_MISCCR_USBSUSPND1, 0x0);
+
+ tmp = (
+ 0x78 << S3C2410_PLLCON_MDIVSHIFT)
+ | (0x02 << S3C2410_PLLCON_PDIVSHIFT)
+ | (0x03 << S3C2410_PLLCON_SDIVSHIFT);
+ writel(tmp, S3C2410_UPLLCON);
}
MACHINE_START(H1940, "IPAQ-H1940")
@@ -189,6 +239,6 @@ MACHINE_START(H1940, "IPAQ-H1940")
.boot_params = S3C2410_SDRAM_PA + 0x100,
.map_io = h1940_map_io,
.init_irq = h1940_init_irq,
- .init_machine = h1940_init,
+ .init_machine = h1940_init,
.timer = &s3c24xx_timer,
MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c2410/mach-n30.c
index 0411e9adb54..261aa4cc077 100644
--- a/arch/arm/mach-s3c2410/mach-n30.c
+++ b/arch/arm/mach-s3c2410/mach-n30.c
@@ -29,7 +29,6 @@
#include <asm/mach/irq.h>
#include <asm/hardware.h>
-#include <asm/hardware/iomd.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
@@ -38,10 +37,10 @@
#include <asm/arch/regs-gpio.h>
#include <asm/arch/iic.h>
-#include "s3c2410.h"
-#include "clock.h"
-#include "devs.h"
-#include "cpu.h"
+#include <asm/plat-s3c24xx/s3c2410.h>
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/cpu.h>
static struct map_desc n30_iodesc[] __initdata = {
/* nothing here yet */
diff --git a/arch/arm/mach-s3c2410/mach-otom.c b/arch/arm/mach-s3c2410/mach-otom.c
index 2c738b375e4..c78ab75b44f 100644
--- a/arch/arm/mach-s3c2410/mach-otom.c
+++ b/arch/arm/mach-s3c2410/mach-otom.c
@@ -32,10 +32,10 @@
#include <asm/arch/regs-serial.h>
#include <asm/arch/regs-gpio.h>
-#include "s3c2410.h"
-#include "clock.h"
-#include "devs.h"
-#include "cpu.h"
+#include <asm/plat-s3c24xx/s3c2410.h>
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/cpu.h>
static struct map_desc otom11_iodesc[] __initdata = {
/* Device area */
diff --git a/arch/arm/mach-s3c2410/mach-qt2410.c b/arch/arm/mach-s3c2410/mach-qt2410.c
new file mode 100644
index 00000000000..c6a41593de2
--- /dev/null
+++ b/arch/arm/mach-s3c2410/mach-qt2410.c
@@ -0,0 +1,448 @@
+/* linux/arch/arm/mach-s3c2410/mach-qt2410.c
+ *
+ * Copyright (C) 2006 by OpenMoko, Inc.
+ * Author: Harald Welte <laforge@openmoko.org>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/mmc/protocol.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/leds-gpio.h>
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/fb.h>
+#include <asm/arch/nand.h>
+#include <asm/arch/udc.h>
+#include <asm/arch/spi.h>
+#include <asm/arch/spi-gpio.h>
+
+#include <asm/plat-s3c24xx/common-smdk.h>
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/cpu.h>
+#include <asm/plat-s3c24xx/pm.h>
+
+static struct map_desc qt2410_iodesc[] __initdata = {
+ { 0xe0000000, __phys_to_pfn(S3C2410_CS3+0x01000000), SZ_1M, MT_DEVICE }
+};
+
+#define UCON S3C2410_UCON_DEFAULT
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg smdk2410_uartcfgs[] = {
+ [0] = {
+ .hwport = 0,
+ .flags = 0,
+ .ucon = UCON,
+ .ulcon = ULCON,
+ .ufcon = UFCON,
+ },
+ [1] = {
+ .hwport = 1,
+ .flags = 0,
+ .ucon = UCON,
+ .ulcon = ULCON,
+ .ufcon = UFCON,
+ },
+ [2] = {
+ .hwport = 2,
+ .flags = 0,
+ .ucon = UCON,
+ .ulcon = ULCON,
+ .ufcon = UFCON,
+ }
+};
+
+/* LCD driver info */
+
+/* Configuration for 640x480 SHARP LQ080V3DG01 */
+static struct s3c2410fb_mach_info qt2410_biglcd_cfg __initdata = {
+ .regs = {
+
+ .lcdcon1 = S3C2410_LCDCON1_TFT16BPP |
+ S3C2410_LCDCON1_TFT |
+ S3C2410_LCDCON1_CLKVAL(0x01), /* HCLK/4 */
+
+ .lcdcon2 = S3C2410_LCDCON2_VBPD(18) | /* 19 */
+ S3C2410_LCDCON2_LINEVAL(479) |
+ S3C2410_LCDCON2_VFPD(10) | /* 11 */
+ S3C2410_LCDCON2_VSPW(14), /* 15 */
+
+ .lcdcon3 = S3C2410_LCDCON3_HBPD(43) | /* 44 */
+ S3C2410_LCDCON3_HOZVAL(639) | /* 640 */
+ S3C2410_LCDCON3_HFPD(115), /* 116 */
+
+ .lcdcon4 = S3C2410_LCDCON4_MVAL(0) |
+ S3C2410_LCDCON4_HSPW(95), /* 96 */
+
+ .lcdcon5 = S3C2410_LCDCON5_FRM565 |
+ S3C2410_LCDCON5_INVVLINE |
+ S3C2410_LCDCON5_INVVFRAME |
+ S3C2410_LCDCON5_PWREN |
+ S3C2410_LCDCON5_HWSWP,
+ },
+
+ .lpcsel = ((0xCE6) & ~7) | 1<<4,
+
+ .width = 640,
+ .height = 480,
+
+ .xres = {
+ .min = 640,
+ .max = 640,
+ .defval = 640,
+ },
+
+ .yres = {
+ .min = 480,
+ .max = 480,
+ .defval = 480,
+ },
+
+ .bpp = {
+ .min = 16,
+ .max = 16,
+ .defval = 16,
+ },
+};
+
+/* Configuration for 480x640 toppoly TD028TTEC1 */
+static struct s3c2410fb_mach_info qt2410_prodlcd_cfg __initdata = {
+ .regs = {
+
+ .lcdcon1 = S3C2410_LCDCON1_TFT16BPP |
+ S3C2410_LCDCON1_TFT |
+ S3C2410_LCDCON1_CLKVAL(0x01), /* HCLK/4 */
+
+ .lcdcon2 = S3C2410_LCDCON2_VBPD(1) | /* 2 */
+ S3C2410_LCDCON2_LINEVAL(639) |/* 640 */
+ S3C2410_LCDCON2_VFPD(3) | /* 4 */
+ S3C2410_LCDCON2_VSPW(1), /* 2 */
+
+ .lcdcon3 = S3C2410_LCDCON3_HBPD(7) | /* 8 */
+ S3C2410_LCDCON3_HOZVAL(479) | /* 479 */
+ S3C2410_LCDCON3_HFPD(23), /* 24 */
+
+ .lcdcon4 = S3C2410_LCDCON4_MVAL(0) |
+ S3C2410_LCDCON4_HSPW(7), /* 8 */
+
+ .lcdcon5 = S3C2410_LCDCON5_FRM565 |
+ S3C2410_LCDCON5_INVVLINE |
+ S3C2410_LCDCON5_INVVFRAME |
+ S3C2410_LCDCON5_PWREN |
+ S3C2410_LCDCON5_HWSWP,
+ },
+
+ .lpcsel = ((0xCE6) & ~7) | 1<<4,
+
+ .width = 480,
+ .height = 640,
+
+ .xres = {
+ .min = 480,
+ .max = 480,
+ .defval = 480,
+ },
+
+ .yres = {
+ .min = 640,
+ .max = 640,
+ .defval = 640,
+ },
+
+ .bpp = {
+ .min = 16,
+ .max = 16,
+ .defval = 16,
+ },
+};
+
+/* Config for 240x320 LCD */
+static struct s3c2410fb_mach_info qt2410_lcd_cfg __initdata = {
+ .regs = {
+
+ .lcdcon1 = S3C2410_LCDCON1_TFT16BPP |
+ S3C2410_LCDCON1_TFT |
+ S3C2410_LCDCON1_CLKVAL(0x04),
+
+ .lcdcon2 = S3C2410_LCDCON2_VBPD(1) |
+ S3C2410_LCDCON2_LINEVAL(319) |
+ S3C2410_LCDCON2_VFPD(6) |
+ S3C2410_LCDCON2_VSPW(3),
+
+ .lcdcon3 = S3C2410_LCDCON3_HBPD(12) |
+ S3C2410_LCDCON3_HOZVAL(239) |
+ S3C2410_LCDCON3_HFPD(7),
+
+ .lcdcon4 = S3C2410_LCDCON4_MVAL(0) |
+ S3C2410_LCDCON4_HSPW(3),
+
+ .lcdcon5 = S3C2410_LCDCON5_FRM565 |
+ S3C2410_LCDCON5_INVVLINE |
+ S3C2410_LCDCON5_INVVFRAME |
+ S3C2410_LCDCON5_PWREN |
+ S3C2410_LCDCON5_HWSWP,
+ },
+
+ .lpcsel = ((0xCE6) & ~7) | 1<<4,
+
+ .width = 240,
+ .height = 320,
+
+ .xres = {
+ .min = 240,
+ .max = 240,
+ .defval = 240,
+ },
+
+ .yres = {
+ .min = 320,
+ .max = 320,
+ .defval = 320,
+ },
+
+ .bpp = {
+ .min = 16,
+ .max = 16,
+ .defval = 16,
+ },
+};
+
+/* CS8900 */
+
+static struct resource qt2410_cs89x0_resources[] = {
+ [0] = {
+ .start = 0x19000000,
+ .end = 0x19000000 + 16,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_EINT9,
+ .end = IRQ_EINT9,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device qt2410_cs89x0 = {
+ .name = "cirrus-cs89x0",
+ .num_resources = ARRAY_SIZE(qt2410_cs89x0_resources),
+ .resource = qt2410_cs89x0_resources,
+};
+
+/* LED */
+
+static struct s3c24xx_led_platdata qt2410_pdata_led = {
+ .gpio = S3C2410_GPB0,
+ .flags = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
+ .name = "led",
+ .def_trigger = "timer",
+};
+
+static struct platform_device qt2410_led = {
+ .name = "s3c24xx_led",
+ .id = 0,
+ .dev = {
+ .platform_data = &qt2410_pdata_led,
+ },
+};
+
+/* SPI */
+
+static void spi_gpio_cs(struct s3c2410_spigpio_info *spi, int cs)
+{
+ switch (cs) {
+ case BITBANG_CS_ACTIVE:
+ s3c2410_gpio_setpin(S3C2410_GPB5, 0);
+ break;
+ case BITBANG_CS_INACTIVE:
+ s3c2410_gpio_setpin(S3C2410_GPB5, 1);
+ break;
+ }
+}
+
+static struct s3c2410_spigpio_info spi_gpio_cfg = {
+ .pin_clk = S3C2410_GPG7,
+ .pin_mosi = S3C2410_GPG6,
+ .pin_miso = S3C2410_GPG5,
+ .chip_select = &spi_gpio_cs,
+};
+
+
+static struct platform_device qt2410_spi = {
+ .name = "s3c24xx-spi-gpio",
+ .id = 1,
+ .dev = {
+ .platform_data = &spi_gpio_cfg,
+ },
+};
+
+/* Board devices */
+
+static struct platform_device *qt2410_devices[] __initdata = {
+ &s3c_device_usb,
+ &s3c_device_lcd,
+ &s3c_device_wdt,
+ &s3c_device_i2c,
+ &s3c_device_iis,
+ &s3c_device_sdi,
+ &s3c_device_usbgadget,
+ &qt2410_spi,
+ &qt2410_cs89x0,
+ &qt2410_led,
+};
+
+static struct s3c24xx_board qt2410_board __initdata = {
+ .devices = qt2410_devices,
+ .devices_count = ARRAY_SIZE(qt2410_devices)
+};
+
+static struct mtd_partition qt2410_nand_part[] = {
+ [0] = {
+ .name = "U-Boot",
+ .size = 0x30000,
+ .offset = 0,
+ },
+ [1] = {
+ .name = "U-Boot environment",
+ .offset = 0x30000,
+ .size = 0x4000,
+ },
+ [2] = {
+ .name = "kernel",
+ .offset = 0x34000,
+ .size = SZ_2M,
+ },
+ [3] = {
+ .name = "initrd",
+ .offset = 0x234000,
+ .size = SZ_4M,
+ },
+ [4] = {
+ .name = "jffs2",
+ .offset = 0x634000,
+ .size = 0x39cc000,
+ },
+};
+
+static struct s3c2410_nand_set qt2410_nand_sets[] = {
+ [0] = {
+ .name = "NAND",
+ .nr_chips = 1,
+ .nr_partitions = ARRAY_SIZE(qt2410_nand_part),
+ .partitions = qt2410_nand_part,
+ },
+};
+
+/* choose a set of timings which should suit most 512Mbit
+ * chips and beyond.
+ */
+
+static struct s3c2410_platform_nand qt2410_nand_info = {
+ .tacls = 20,
+ .twrph0 = 60,
+ .twrph1 = 20,
+ .nr_sets = ARRAY_SIZE(qt2410_nand_sets),
+ .sets = qt2410_nand_sets,
+};
+
+/* UDC */
+
+static struct s3c2410_udc_mach_info qt2410_udc_cfg = {
+};
+
+static char tft_type = 's';
+
+static int __init qt2410_tft_setup(char *str)
+{
+ tft_type = str[0];
+ return 1;
+}
+
+__setup("tft=", qt2410_tft_setup);
+
+static void __init qt2410_map_io(void)
+{
+ s3c24xx_init_io(qt2410_iodesc, ARRAY_SIZE(qt2410_iodesc));
+ s3c24xx_init_clocks(12*1000*1000);
+ s3c24xx_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs));
+ s3c24xx_set_board(&qt2410_board);
+}
+
+static void __init qt2410_machine_init(void)
+{
+ s3c_device_nand.dev.platform_data = &qt2410_nand_info;
+
+ switch (tft_type) {
+ case 'p': /* production */
+ s3c24xx_fb_set_platdata(&qt2410_prodlcd_cfg);
+ break;
+ case 'b': /* big */
+ s3c24xx_fb_set_platdata(&qt2410_biglcd_cfg);
+ break;
+ case 's': /* small */
+ default:
+ s3c24xx_fb_set_platdata(&qt2410_lcd_cfg);
+ break;
+ }
+
+ s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPIO_OUTPUT);
+ s3c2410_gpio_setpin(S3C2410_GPB0, 1);
+
+ s3c24xx_udc_set_platdata(&qt2410_udc_cfg);
+
+ s3c2410_gpio_cfgpin(S3C2410_GPB5, S3C2410_GPIO_OUTPUT);
+
+ s3c2410_pm_init();
+}
+
+MACHINE_START(QT2410, "QT2410")
+ .phys_io = S3C2410_PA_UART,
+ .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
+ .boot_params = S3C2410_SDRAM_PA + 0x100,
+ .map_io = qt2410_map_io,
+ .init_irq = s3c24xx_init_irq,
+ .init_machine = qt2410_machine_init,
+ .timer = &s3c24xx_timer,
+MACHINE_END
+
+
diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c
index 01c0c986d82..57b8a80f33d 100644
--- a/arch/arm/mach-s3c2410/mach-smdk2410.c
+++ b/arch/arm/mach-s3c2410/mach-smdk2410.c
@@ -1,4 +1,4 @@
-/***********************************************************************
+/* linux/arch/arm/mach-s3c2410/mach-smdk2410.c
*
* linux/arch/arm/mach-s3c2410/mach-smdk2410.c
*
@@ -49,10 +49,10 @@
#include <asm/arch/regs-serial.h>
-#include "devs.h"
-#include "cpu.h"
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/cpu.h>
-#include "common-smdk.h"
+#include <asm/plat-s3c24xx/common-smdk.h>
static struct map_desc smdk2410_iodesc[] __initdata = {
/* nothing here yet */
diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c
index a382fc09511..c947c75bcbf 100644
--- a/arch/arm/mach-s3c2410/mach-vr1000.c
+++ b/arch/arm/mach-s3c2410/mach-vr1000.c
@@ -43,9 +43,9 @@
#include <asm/arch/regs-gpio.h>
#include <asm/arch/leds-gpio.h>
-#include "clock.h"
-#include "devs.h"
-#include "cpu.h"
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/cpu.h>
#include "usb-simtec.h"
/* macros for virtual address mods for the io space entries */
diff --git a/arch/arm/mach-s3c2410/pm.c b/arch/arm/mach-s3c2410/pm.c
index ebf294dd31d..3b3a7db4e0d 100644
--- a/arch/arm/mach-s3c2410/pm.c
+++ b/arch/arm/mach-s3c2410/pm.c
@@ -1,11 +1,9 @@
/* linux/arch/arm/mach-s3c2410/pm.c
*
- * Copyright (c) 2004,2006 Simtec Electronics
+ * Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
- * S3C24XX Power Manager (Suspend-To-RAM) support
- *
- * See Documentation/arm/Samsung-S3C24XX/Suspend.txt for more information
+ * S3C2410 (and compatible) Power Manager (Suspend-To-RAM) 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
@@ -20,640 +18,139 @@
* 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
- *
- * Parts based on arch/arm/mach-pxa/pm.c
- *
- * Thanks to Dimitry Andric for debugging
*/
#include <linux/init.h>
#include <linux/suspend.h>
#include <linux/errno.h>
#include <linux/time.h>
-#include <linux/interrupt.h>
-#include <linux/crc32.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/serial_core.h>
+#include <linux/sysdev.h>
-#include <asm/cacheflush.h>
#include <asm/hardware.h>
#include <asm/io.h>
-#include <asm/arch/regs-serial.h>
-#include <asm/arch/regs-clock.h>
-#include <asm/arch/regs-gpio.h>
-#include <asm/arch/regs-mem.h>
-#include <asm/arch/regs-irq.h>
-
-#include <asm/mach/time.h>
-
-#include "pm.h"
-
-/* for external use */
-
-unsigned long s3c_pm_flags;
-
-#define PFX "s3c24xx-pm: "
-
-static struct sleep_save core_save[] = {
- SAVE_ITEM(S3C2410_LOCKTIME),
- SAVE_ITEM(S3C2410_CLKCON),
-
- /* we restore the timings here, with the proviso that the board
- * brings the system up in an slower, or equal frequency setting
- * to the original system.
- *
- * if we cannot guarantee this, then things are going to go very
- * wrong here, as we modify the refresh and both pll settings.
- */
-
- SAVE_ITEM(S3C2410_BWSCON),
- SAVE_ITEM(S3C2410_BANKCON0),
- SAVE_ITEM(S3C2410_BANKCON1),
- SAVE_ITEM(S3C2410_BANKCON2),
- SAVE_ITEM(S3C2410_BANKCON3),
- SAVE_ITEM(S3C2410_BANKCON4),
- SAVE_ITEM(S3C2410_BANKCON5),
-
- SAVE_ITEM(S3C2410_CLKDIVN),
- SAVE_ITEM(S3C2410_MPLLCON),
- SAVE_ITEM(S3C2410_UPLLCON),
- SAVE_ITEM(S3C2410_CLKSLOW),
- SAVE_ITEM(S3C2410_REFRESH),
-};
-
-static struct sleep_save gpio_save[] = {
- SAVE_ITEM(S3C2410_GPACON),
- SAVE_ITEM(S3C2410_GPADAT),
-
- SAVE_ITEM(S3C2410_GPBCON),
- SAVE_ITEM(S3C2410_GPBDAT),
- SAVE_ITEM(S3C2410_GPBUP),
-
- SAVE_ITEM(S3C2410_GPCCON),
- SAVE_ITEM(S3C2410_GPCDAT),
- SAVE_ITEM(S3C2410_GPCUP),
-
- SAVE_ITEM(S3C2410_GPDCON),
- SAVE_ITEM(S3C2410_GPDDAT),
- SAVE_ITEM(S3C2410_GPDUP),
-
- SAVE_ITEM(S3C2410_GPECON),
- SAVE_ITEM(S3C2410_GPEDAT),
- SAVE_ITEM(S3C2410_GPEUP),
-
- SAVE_ITEM(S3C2410_GPFCON),
- SAVE_ITEM(S3C2410_GPFDAT),
- SAVE_ITEM(S3C2410_GPFUP),
+#include <asm/mach-types.h>
- SAVE_ITEM(S3C2410_GPGCON),
- SAVE_ITEM(S3C2410_GPGDAT),
- SAVE_ITEM(S3C2410_GPGUP),
-
- SAVE_ITEM(S3C2410_GPHCON),
- SAVE_ITEM(S3C2410_GPHDAT),
- SAVE_ITEM(S3C2410_GPHUP),
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/h1940.h>
- SAVE_ITEM(S3C2410_DCLKCON),
-};
+#include <asm/plat-s3c24xx/cpu.h>
+#include <asm/plat-s3c24xx/pm.h>
#ifdef CONFIG_S3C2410_PM_DEBUG
-
-#define SAVE_UART(va) \
- SAVE_ITEM((va) + S3C2410_ULCON), \
- SAVE_ITEM((va) + S3C2410_UCON), \
- SAVE_ITEM((va) + S3C2410_UFCON), \
- SAVE_ITEM((va) + S3C2410_UMCON), \
- SAVE_ITEM((va) + S3C2410_UBRDIV)
-
-static struct sleep_save uart_save[] = {
- SAVE_UART(S3C24XX_VA_UART0),
- SAVE_UART(S3C24XX_VA_UART1),
-#ifndef CONFIG_CPU_S3C2400
- SAVE_UART(S3C24XX_VA_UART2),
-#endif
-};
-
-/* debug
- *
- * we send the debug to printascii() to allow it to be seen if the
- * system never wakes up from the sleep
-*/
-
-extern void printascii(const char *);
-
-void pm_dbg(const char *fmt, ...)
-{
- va_list va;
- char buff[256];
-
- va_start(va, fmt);
- vsprintf(buff, fmt, va);
- va_end(va);
-
- printascii(buff);
-}
-
-static void s3c2410_pm_debug_init(void)
-{
- unsigned long tmp = __raw_readl(S3C2410_CLKCON);
-
- /* re-start uart clocks */
- tmp |= S3C2410_CLKCON_UART0;
- tmp |= S3C2410_CLKCON_UART1;
- tmp |= S3C2410_CLKCON_UART2;
-
- __raw_writel(tmp, S3C2410_CLKCON);
- udelay(10);
-}
-
+extern void pm_dbg(const char *fmt, ...);
#define DBG(fmt...) pm_dbg(fmt)
#else
#define DBG(fmt...) printk(KERN_DEBUG fmt)
-
-#define s3c2410_pm_debug_init() do { } while(0)
-
-static struct sleep_save uart_save[] = {};
#endif
-#if defined(CONFIG_S3C2410_PM_CHECK) && CONFIG_S3C2410_PM_CHECK_CHUNKSIZE != 0
-
-/* suspend checking code...
- *
- * this next area does a set of crc checks over all the installed
- * memory, so the system can verify if the resume was ok.
- *
- * CONFIG_S3C2410_PM_CHECK_CHUNKSIZE defines the block-size for the CRC,
- * increasing it will mean that the area corrupted will be less easy to spot,
- * and reducing the size will cause the CRC save area to grow
-*/
-
-#define CHECK_CHUNKSIZE (CONFIG_S3C2410_PM_CHECK_CHUNKSIZE * 1024)
-
-static u32 crc_size; /* size needed for the crc block */
-static u32 *crcs; /* allocated over suspend/resume */
-
-typedef u32 *(run_fn_t)(struct resource *ptr, u32 *arg);
-
-/* s3c2410_pm_run_res
- *
- * go thorugh the given resource list, and look for system ram
-*/
-
-static void s3c2410_pm_run_res(struct resource *ptr, run_fn_t fn, u32 *arg)
-{
- while (ptr != NULL) {
- if (ptr->child != NULL)
- s3c2410_pm_run_res(ptr->child, fn, arg);
-
- if ((ptr->flags & IORESOURCE_MEM) &&
- strcmp(ptr->name, "System RAM") == 0) {
- DBG("Found system RAM at %08lx..%08lx\n",
- ptr->start, ptr->end);
- arg = (fn)(ptr, arg);
- }
-
- ptr = ptr->sibling;
- }
-}
-
-static void s3c2410_pm_run_sysram(run_fn_t fn, u32 *arg)
-{
- s3c2410_pm_run_res(&iomem_resource, fn, arg);
-}
-
-static u32 *s3c2410_pm_countram(struct resource *res, u32 *val)
-{
- u32 size = (u32)(res->end - res->start)+1;
-
- size += CHECK_CHUNKSIZE-1;
- size /= CHECK_CHUNKSIZE;
-
- DBG("Area %08lx..%08lx, %d blocks\n", res->start, res->end, size);
-
- *val += size * sizeof(u32);
- return val;
-}
-
-/* s3c2410_pm_prepare_check
- *
- * prepare the necessary information for creating the CRCs. This
- * must be done before the final save, as it will require memory
- * allocating, and thus touching bits of the kernel we do not
- * know about.
-*/
-
-static void s3c2410_pm_check_prepare(void)
+static void s3c2410_pm_prepare(void)
{
- crc_size = 0;
+ /* ensure at least GSTATUS3 has the resume address */
- s3c2410_pm_run_sysram(s3c2410_pm_countram, &crc_size);
+ __raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C2410_GSTATUS3);
- DBG("s3c2410_pm_prepare_check: %u checks needed\n", crc_size);
+ DBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3));
+ DBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4));
- crcs = kmalloc(crc_size+4, GFP_KERNEL);
- if (crcs == NULL)
- printk(KERN_ERR "Cannot allocated CRC save area\n");
-}
+ if (machine_is_h1940()) {
+ void *base = phys_to_virt(H1940_SUSPEND_CHECK);
+ unsigned long ptr;
+ unsigned long calc = 0;
-static u32 *s3c2410_pm_makecheck(struct resource *res, u32 *val)
-{
- unsigned long addr, left;
+ /* generate check for the bootloader to check on resume */
- for (addr = res->start; addr < res->end;
- addr += CHECK_CHUNKSIZE) {
- left = res->end - addr;
+ for (ptr = 0; ptr < 0x40000; ptr += 0x400)
+ calc += __raw_readl(base+ptr);
- if (left > CHECK_CHUNKSIZE)
- left = CHECK_CHUNKSIZE;
-
- *val = crc32_le(~0, phys_to_virt(addr), left);
- val++;
+ __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM));
}
- return val;
-}
-
-/* s3c2410_pm_check_store
- *
- * compute the CRC values for the memory blocks before the final
- * sleep.
-*/
-
-static void s3c2410_pm_check_store(void)
-{
- if (crcs != NULL)
- s3c2410_pm_run_sysram(s3c2410_pm_makecheck, crcs);
-}
-
-/* in_region
- *
- * return TRUE if the area defined by ptr..ptr+size contatins the
- * what..what+whatsz
-*/
-
-static inline int in_region(void *ptr, int size, void *what, size_t whatsz)
-{
- if ((what+whatsz) < ptr)
- return 0;
-
- if (what > (ptr+size))
- return 0;
-
- return 1;
-}
-
-static u32 *s3c2410_pm_runcheck(struct resource *res, u32 *val)
-{
- void *save_at = phys_to_virt(s3c2410_sleep_save_phys);
- unsigned long addr;
- unsigned long left;
- void *ptr;
- u32 calc;
-
- for (addr = res->start; addr < res->end;
- addr += CHECK_CHUNKSIZE) {
- left = res->end - addr;
+ /* the RX3715 uses similar code and the same H1940 and the
+ * same offsets for resume and checksum pointers */
- if (left > CHECK_CHUNKSIZE)
- left = CHECK_CHUNKSIZE;
+ if (machine_is_rx3715()) {
+ void *base = phys_to_virt(H1940_SUSPEND_CHECK);
+ unsigned long ptr;
+ unsigned long calc = 0;
- ptr = phys_to_virt(addr);
+ /* generate check for the bootloader to check on resume */
- if (in_region(ptr, left, crcs, crc_size)) {
- DBG("skipping %08lx, has crc block in\n", addr);
- goto skip_check;
- }
+ for (ptr = 0; ptr < 0x40000; ptr += 0x4)
+ calc += __raw_readl(base+ptr);
- if (in_region(ptr, left, save_at, 32*4 )) {
- DBG("skipping %08lx, has save block in\n", addr);
- goto skip_check;
- }
-
- /* calculate and check the checksum */
-
- calc = crc32_le(~0, ptr, left);
- if (calc != *val) {
- printk(KERN_ERR PFX "Restore CRC error at "
- "%08lx (%08x vs %08x)\n", addr, calc, *val);
-
- DBG("Restore CRC error at %08lx (%08x vs %08x)\n",
- addr, calc, *val);
- }
-
- skip_check:
- val++;
+ __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM));
}
- return val;
-}
+ if ( machine_is_aml_m5900() )
+ s3c2410_gpio_setpin(S3C2410_GPF2, 1);
-/* s3c2410_pm_check_restore
- *
- * check the CRCs after the restore event and free the memory used
- * to hold them
-*/
-
-static void s3c2410_pm_check_restore(void)
-{
- if (crcs != NULL) {
- s3c2410_pm_run_sysram(s3c2410_pm_runcheck, crcs);
- kfree(crcs);
- crcs = NULL;
- }
}
-#else
-
-#define s3c2410_pm_check_prepare() do { } while(0)
-#define s3c2410_pm_check_restore() do { } while(0)
-#define s3c2410_pm_check_store() do { } while(0)
-#endif
-
-/* helper functions to save and restore register state */
-
-void s3c2410_pm_do_save(struct sleep_save *ptr, int count)
+static int s3c2410_pm_resume(struct sys_device *dev)
{
- for (; count > 0; count--, ptr++) {
- ptr->val = __raw_readl(ptr->reg);
- DBG("saved %p value %08lx\n", ptr->reg, ptr->val);
- }
-}
+ unsigned long tmp;
-/* s3c2410_pm_do_restore
- *
- * restore the system from the given list of saved registers
- *
- * Note, we do not use DBG() in here, as the system may not have
- * restore the UARTs state yet
-*/
+ /* unset the return-from-sleep flag, to ensure reset */
-void s3c2410_pm_do_restore(struct sleep_save *ptr, int count)
-{
- for (; count > 0; count--, ptr++) {
- printk(KERN_DEBUG "restore %p (restore %08lx, was %08x)\n",
- ptr->reg, ptr->val, __raw_readl(ptr->reg));
-
- __raw_writel(ptr->val, ptr->reg);
- }
-}
+ tmp = __raw_readl(S3C2410_GSTATUS2);
+ tmp &= S3C2410_GSTATUS2_OFFRESET;
+ __raw_writel(tmp, S3C2410_GSTATUS2);
-/* s3c2410_pm_do_restore_core
- *
- * similar to s3c2410_pm_do_restore_core
- *
- * WARNING: Do not put any debug in here that may effect memory or use
- * peripherals, as things may be changing!
-*/
+ if ( machine_is_aml_m5900() )
+ s3c2410_gpio_setpin(S3C2410_GPF2, 0);
-static void s3c2410_pm_do_restore_core(struct sleep_save *ptr, int count)
-{
- for (; count > 0; count--, ptr++) {
- __raw_writel(ptr->val, ptr->reg);
- }
+ return 0;
}
-/* s3c2410_pm_show_resume_irqs
- *
- * print any IRQs asserted at resume time (ie, we woke from)
-*/
-
-static void s3c2410_pm_show_resume_irqs(int start, unsigned long which,
- unsigned long mask)
+static int s3c2410_pm_add(struct sys_device *dev)
{
- int i;
+ pm_cpu_prep = s3c2410_pm_prepare;
+ pm_cpu_sleep = s3c2410_cpu_suspend;
- which &= ~mask;
-
- for (i = 0; i <= 31; i++) {
- if ((which) & (1L<<i)) {
- DBG("IRQ %d asserted at resume\n", start+i);
- }
- }
+ return 0;
}
-/* s3c2410_pm_check_resume_pin
- *
- * check to see if the pin is configured correctly for sleep mode, and
- * make any necessary adjustments if it is not
-*/
-
-static void s3c2410_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs)
-{
- unsigned long irqstate;
- unsigned long pinstate;
- int irq = s3c2410_gpio_getirq(pin);
-
- if (irqoffs < 4)
- irqstate = s3c_irqwake_intmask & (1L<<irqoffs);
- else
- irqstate = s3c_irqwake_eintmask & (1L<<irqoffs);
-
- pinstate = s3c2410_gpio_getcfg(pin);
-
- if (!irqstate) {
- if (pinstate == S3C2410_GPIO_IRQ)
- DBG("Leaving IRQ %d (pin %d) enabled\n", irq, pin);
- } else {
- if (pinstate == S3C2410_GPIO_IRQ) {
- DBG("Disabling IRQ %d (pin %d)\n", irq, pin);
- s3c2410_gpio_cfgpin(pin, S3C2410_GPIO_INPUT);
- }
- }
-}
+#if defined(CONFIG_CPU_S3C2410)
+static struct sysdev_driver s3c2410_pm_driver = {
+ .add = s3c2410_pm_add,
+ .resume = s3c2410_pm_resume,
+};
-/* s3c2410_pm_configure_extint
- *
- * configure all external interrupt pins
-*/
+/* register ourselves */
-static void s3c2410_pm_configure_extint(void)
+static int __init s3c2410_pm_drvinit(void)
{
- int pin;
-
- /* for each of the external interrupts (EINT0..EINT15) we
- * need to check wether it is an external interrupt source,
- * and then configure it as an input if it is not
- */
-
- for (pin = S3C2410_GPF0; pin <= S3C2410_GPF7; pin++) {
- s3c2410_pm_check_resume_pin(pin, pin - S3C2410_GPF0);
- }
-
- for (pin = S3C2410_GPG0; pin <= S3C2410_GPG7; pin++) {
- s3c2410_pm_check_resume_pin(pin, (pin - S3C2410_GPG0)+8);
- }
+ return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_pm_driver);
}
-void (*pm_cpu_prep)(void);
-void (*pm_cpu_sleep)(void);
-
-#define any_allowed(mask, allow) (((mask) & (allow)) != (allow))
-
-/* s3c2410_pm_enter
- *
- * central control for sleep/resume process
-*/
-
-static int s3c2410_pm_enter(suspend_state_t state)
-{
- unsigned long regs_save[16];
-
- /* ensure the debug is initialised (if enabled) */
-
- s3c2410_pm_debug_init();
-
- DBG("s3c2410_pm_enter(%d)\n", state);
-
- if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) {
- printk(KERN_ERR PFX "error: no cpu sleep functions set\n");
- return -EINVAL;
- }
-
- if (state != PM_SUSPEND_MEM) {
- printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n");
- return -EINVAL;
- }
-
- /* check if we have anything to wake-up with... bad things seem
- * to happen if you suspend with no wakeup (system will often
- * require a full power-cycle)
- */
-
- if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) &&
- !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) {
- printk(KERN_ERR PFX "No sources enabled for wake-up!\n");
- printk(KERN_ERR PFX "Aborting sleep\n");
- return -EINVAL;
- }
-
- /* prepare check area if configured */
-
- s3c2410_pm_check_prepare();
-
- /* store the physical address of the register recovery block */
-
- s3c2410_sleep_save_phys = virt_to_phys(regs_save);
-
- DBG("s3c2410_sleep_save_phys=0x%08lx\n", s3c2410_sleep_save_phys);
-
- /* save all necessary core registers not covered by the drivers */
-
- s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save));
- s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save));
- s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save));
-
- /* set the irq configuration for wake */
-
- s3c2410_pm_configure_extint();
-
- DBG("sleep: irq wakeup masks: %08lx,%08lx\n",
- s3c_irqwake_intmask, s3c_irqwake_eintmask);
-
- __raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK);
- __raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK);
-
- /* ack any outstanding external interrupts before we go to sleep */
-
- __raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND);
- __raw_writel(__raw_readl(S3C2410_INTPND), S3C2410_INTPND);
- __raw_writel(__raw_readl(S3C2410_SRCPND), S3C2410_SRCPND);
-
- /* call cpu specific preperation */
-
- pm_cpu_prep();
-
- /* flush cache back to ram */
-
- flush_cache_all();
-
- s3c2410_pm_check_store();
-
- /* send the cpu to sleep... */
-
- __raw_writel(0x00, S3C2410_CLKCON); /* turn off clocks over sleep */
-
- /* s3c2410_cpu_save will also act as our return point from when
- * we resume as it saves its own register state, so use the return
- * code to differentiate return from save and return from sleep */
-
- if (s3c2410_cpu_save(regs_save) == 0) {
- flush_cache_all();
- pm_cpu_sleep();
- }
-
- /* restore the cpu state */
-
- cpu_init();
-
- /* restore the system state */
-
- s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save));
- s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save));
- s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save));
-
- s3c2410_pm_debug_init();
-
- /* check what irq (if any) restored the system */
-
- DBG("post sleep: IRQs 0x%08x, 0x%08x\n",
- __raw_readl(S3C2410_SRCPND),
- __raw_readl(S3C2410_EINTPEND));
-
- s3c2410_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND),
- s3c_irqwake_intmask);
-
- s3c2410_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND),
- s3c_irqwake_eintmask);
-
- DBG("post sleep, preparing to return\n");
-
- s3c2410_pm_check_restore();
-
- /* ok, let's return from sleep */
+arch_initcall(s3c2410_pm_drvinit);
+#endif
- DBG("S3C2410 PM Resume (post-restore)\n");
- return 0;
-}
+#if defined(CONFIG_CPU_S3C2440)
+static struct sysdev_driver s3c2440_pm_driver = {
+ .add = s3c2410_pm_add,
+ .resume = s3c2410_pm_resume,
+};
-/*
- * Called after processes are frozen, but before we shut down devices.
- */
-static int s3c2410_pm_prepare(suspend_state_t state)
+static int __init s3c2440_pm_drvinit(void)
{
- return 0;
+ return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_pm_driver);
}
-/*
- * Called after devices are re-setup, but before processes are thawed.
- */
-static int s3c2410_pm_finish(suspend_state_t state)
-{
- return 0;
-}
+arch_initcall(s3c2440_pm_drvinit);
+#endif
-/*
- * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
- */
-static struct pm_ops s3c2410_pm_ops = {
- .pm_disk_mode = PM_DISK_FIRMWARE,
- .prepare = s3c2410_pm_prepare,
- .enter = s3c2410_pm_enter,
- .finish = s3c2410_pm_finish,
+#if defined(CONFIG_CPU_S3C2442)
+static struct sysdev_driver s3c2442_pm_driver = {
+ .add = s3c2410_pm_add,
+ .resume = s3c2410_pm_resume,
};
-/* s3c2410_pm_init
- *
- * Attach the power management functions. This should be called
- * from the board specific initialisation if the board supports
- * it.
-*/
-
-int __init s3c2410_pm_init(void)
+static int __init s3c2442_pm_drvinit(void)
{
- printk("S3C2410 Power Management, (c) 2004 Simtec Electronics\n");
-
- pm_set_ops(&s3c2410_pm_ops);
- return 0;
+ return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_pm_driver);
}
+
+arch_initcall(s3c2442_pm_drvinit);
+#endif
diff --git a/arch/arm/mach-s3c2410/s3c2410-clock.c b/arch/arm/mach-s3c2410/s3c2410-clock.c
deleted file mode 100644
index 992cc6af230..00000000000
--- a/arch/arm/mach-s3c2410/s3c2410-clock.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/s3c2410-clock.c
- *
- * Copyright (c) 2006 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410,S3C2440,S3C2442 Clock control 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 <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/sysdev.h>
-#include <linux/clk.h>
-#include <linux/mutex.h>
-#include <linux/delay.h>
-#include <linux/serial_core.h>
-
-#include <asm/mach/map.h>
-
-#include <asm/hardware.h>
-#include <asm/io.h>
-
-#include <asm/arch/regs-serial.h>
-#include <asm/arch/regs-clock.h>
-#include <asm/arch/regs-gpio.h>
-
-#include "s3c2410.h"
-#include "clock.h"
-#include "cpu.h"
-
-int s3c2410_clkcon_enable(struct clk *clk, int enable)
-{
- unsigned int clocks = clk->ctrlbit;
- unsigned long clkcon;
-
- clkcon = __raw_readl(S3C2410_CLKCON);
-
- if (enable)
- clkcon |= clocks;
- else
- clkcon &= ~clocks;
-
- /* ensure none of the special function bits set */
- clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER);
-
- __raw_writel(clkcon, S3C2410_CLKCON);
-
- return 0;
-}
-
-static int s3c2410_upll_enable(struct clk *clk, int enable)
-{
- unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
- unsigned long orig = clkslow;
-
- if (enable)
- clkslow &= ~S3C2410_CLKSLOW_UCLK_OFF;
- else
- clkslow |= S3C2410_CLKSLOW_UCLK_OFF;
-
- __raw_writel(clkslow, S3C2410_CLKSLOW);
-
- /* if we started the UPLL, then allow to settle */
-
- if (enable && (orig & S3C2410_CLKSLOW_UCLK_OFF))
- udelay(200);
-
- return 0;
-}
-
-/* standard clock definitions */
-
-static struct clk init_clocks_disable[] = {
- {
- .name = "nand",
- .id = -1,
- .parent = &clk_h,
- .enable = s3c2410_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_NAND,
- }, {
- .name = "sdi",
- .id = -1,
- .parent = &clk_p,
- .enable = s3c2410_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_SDI,
- }, {
- .name = "adc",
- .id = -1,
- .parent = &clk_p,
- .enable = s3c2410_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_ADC,
- }, {
- .name = "i2c",
- .id = -1,
- .parent = &clk_p,
- .enable = s3c2410_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_IIC,
- }, {
- .name = "iis",
- .id = -1,
- .parent = &clk_p,
- .enable = s3c2410_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_IIS,
- }, {
- .name = "spi",
- .id = -1,
- .parent = &clk_p,
- .enable = s3c2410_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_SPI,
- }
-};
-
-static struct clk init_clocks[] = {
- {
- .name = "lcd",
- .id = -1,
- .parent = &clk_h,
- .enable = s3c2410_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_LCDC,
- }, {
- .name = "gpio",
- .id = -1,
- .parent = &clk_p,
- .enable = s3c2410_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_GPIO,
- }, {
- .name = "usb-host",
- .id = -1,
- .parent = &clk_h,
- .enable = s3c2410_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_USBH,
- }, {
- .name = "usb-device",
- .id = -1,
- .parent = &clk_h,
- .enable = s3c2410_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_USBD,
- }, {
- .name = "timers",
- .id = -1,
- .parent = &clk_p,
- .enable = s3c2410_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_PWMT,
- }, {
- .name = "uart",
- .id = 0,
- .parent = &clk_p,
- .enable = s3c2410_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_UART0,
- }, {
- .name = "uart",
- .id = 1,
- .parent = &clk_p,
- .enable = s3c2410_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_UART1,
- }, {
- .name = "uart",
- .id = 2,
- .parent = &clk_p,
- .enable = s3c2410_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_UART2,
- }, {
- .name = "rtc",
- .id = -1,
- .parent = &clk_p,
- .enable = s3c2410_clkcon_enable,
- .ctrlbit = S3C2410_CLKCON_RTC,
- }, {
- .name = "watchdog",
- .id = -1,
- .parent = &clk_p,
- .ctrlbit = 0,
- }, {
- .name = "usb-bus-host",
- .id = -1,
- .parent = &clk_usb_bus,
- }, {
- .name = "usb-bus-gadget",
- .id = -1,
- .parent = &clk_usb_bus,
- },
-};
-
-/* s3c2410_baseclk_add()
- *
- * Add all the clocks used by the s3c2410 or compatible CPUs
- * such as the S3C2440 and S3C2442.
- *
- * We cannot use a system device as we are needed before any
- * of the init-calls that initialise the devices are actually
- * done.
-*/
-
-int __init s3c2410_baseclk_add(void)
-{
- unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
- unsigned long clkcon = __raw_readl(S3C2410_CLKCON);
- struct clk *clkp;
- struct clk *xtal;
- int ret;
- int ptr;
-
- clk_upll.enable = s3c2410_upll_enable;
-
- if (s3c24xx_register_clock(&clk_usb_bus) < 0)
- printk(KERN_ERR "failed to register usb bus clock\n");
-
- /* register clocks from clock array */
-
- clkp = init_clocks;
- for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
- /* ensure that we note the clock state */
-
- clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0;
-
- ret = s3c24xx_register_clock(clkp);
- if (ret < 0) {
- printk(KERN_ERR "Failed to register clock %s (%d)\n",
- clkp->name, ret);
- }
- }
-
- /* We must be careful disabling the clocks we are not intending to
- * be using at boot time, as subsytems such as the LCD which do
- * their own DMA requests to the bus can cause the system to lockup
- * if they where in the middle of requesting bus access.
- *
- * Disabling the LCD clock if the LCD is active is very dangerous,
- * and therefore the bootloader should be careful to not enable
- * the LCD clock if it is not needed.
- */
-
- /* install (and disable) the clocks we do not need immediately */
-
- clkp = init_clocks_disable;
- for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
-
- ret = s3c24xx_register_clock(clkp);
- if (ret < 0) {
- printk(KERN_ERR "Failed to register clock %s (%d)\n",
- clkp->name, ret);
- }
-
- s3c2410_clkcon_enable(clkp, 0);
- }
-
- /* show the clock-slow value */
-
- xtal = clk_get(NULL, "xtal");
-
- printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n",
- print_mhz(clk_get_rate(xtal) /
- ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))),
- (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast",
- (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on",
- (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on");
-
- return 0;
-}
diff --git a/arch/arm/mach-s3c2410/s3c2410-dma.c b/arch/arm/mach-s3c2410/s3c2410-dma.c
deleted file mode 100644
index e67ba3911f1..00000000000
--- a/arch/arm/mach-s3c2410/s3c2410-dma.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/s3c2410-dma.c
- *
- * Copyright (c) 2006 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410 DMA selection
- *
- * http://armlinux.simtec.co.uk/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sysdev.h>
-#include <linux/serial_core.h>
-
-#include <asm/dma.h>
-#include <asm/arch/dma.h>
-#include "dma.h"
-
-#include "cpu.h"
-
-#include <asm/arch/regs-serial.h>
-#include <asm/arch/regs-gpio.h>
-#include <asm/arch/regs-ac97.h>
-#include <asm/arch/regs-mem.h>
-#include <asm/arch/regs-lcd.h>
-#include <asm/arch/regs-sdi.h>
-#include <asm/arch/regs-iis.h>
-#include <asm/arch/regs-spi.h>
-
-static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = {
- [DMACH_XD0] = {
- .name = "xdreq0",
- .channels[0] = S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID,
- },
- [DMACH_XD1] = {
- .name = "xdreq1",
- .channels[1] = S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID,
- },
- [DMACH_SDI] = {
- .name = "sdi",
- .channels[0] = S3C2410_DCON_CH0_SDI | DMA_CH_VALID,
- .channels[2] = S3C2410_DCON_CH2_SDI | DMA_CH_VALID,
- .channels[3] = S3C2410_DCON_CH3_SDI | DMA_CH_VALID,
- .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
- .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
- },
- [DMACH_SPI0] = {
- .name = "spi0",
- .channels[1] = S3C2410_DCON_CH1_SPI | DMA_CH_VALID,
- .hw_addr.to = S3C2410_PA_SPI + S3C2410_SPTDAT,
- .hw_addr.from = S3C2410_PA_SPI + S3C2410_SPRDAT,
- },
- [DMACH_SPI1] = {
- .name = "spi1",
- .channels[3] = S3C2410_DCON_CH3_SPI | DMA_CH_VALID,
- .hw_addr.to = S3C2410_PA_SPI + 0x20 + S3C2410_SPTDAT,
- .hw_addr.from = S3C2410_PA_SPI + 0x20 + S3C2410_SPRDAT,
- },
- [DMACH_UART0] = {
- .name = "uart0",
- .channels[0] = S3C2410_DCON_CH0_UART0 | DMA_CH_VALID,
- .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH,
- .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH,
- },
- [DMACH_UART1] = {
- .name = "uart1",
- .channels[1] = S3C2410_DCON_CH1_UART1 | DMA_CH_VALID,
- .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH,
- .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH,
- },
- [DMACH_UART2] = {
- .name = "uart2",
- .channels[3] = S3C2410_DCON_CH3_UART2 | DMA_CH_VALID,
- .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH,
- .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH,
- },
- [DMACH_TIMER] = {
- .name = "timer",
- .channels[0] = S3C2410_DCON_CH0_TIMER | DMA_CH_VALID,
- .channels[2] = S3C2410_DCON_CH2_TIMER | DMA_CH_VALID,
- .channels[3] = S3C2410_DCON_CH3_TIMER | DMA_CH_VALID,
- },
- [DMACH_I2S_IN] = {
- .name = "i2s-sdi",
- .channels[1] = S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID,
- .channels[2] = S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID,
- .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
- },
- [DMACH_I2S_OUT] = {
- .name = "i2s-sdo",
- .channels[2] = S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID,
- .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
- },
- [DMACH_USB_EP1] = {
- .name = "usb-ep1",
- .channels[0] = S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID,
- },
- [DMACH_USB_EP2] = {
- .name = "usb-ep2",
- .channels[1] = S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID,
- },
- [DMACH_USB_EP3] = {
- .name = "usb-ep3",
- .channels[2] = S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID,
- },
- [DMACH_USB_EP4] = {
- .name = "usb-ep4",
- .channels[3] =S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID,
- },
-};
-
-static void s3c2410_dma_select(struct s3c2410_dma_chan *chan,
- struct s3c24xx_dma_map *map)
-{
- chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID;
-}
-
-static struct s3c24xx_dma_selection __initdata s3c2410_dma_sel = {
- .select = s3c2410_dma_select,
- .dcon_mask = 7 << 24,
- .map = s3c2410_dma_mappings,
- .map_size = ARRAY_SIZE(s3c2410_dma_mappings),
-};
-
-static int s3c2410_dma_add(struct sys_device *sysdev)
-{
- return s3c24xx_dma_init_map(&s3c2410_dma_sel);
-}
-
-#if defined(CONFIG_CPU_S3C2410)
-static struct sysdev_driver s3c2410_dma_driver = {
- .add = s3c2410_dma_add,
-};
-
-static int __init s3c2410_dma_init(void)
-{
- return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_dma_driver);
-}
-
-arch_initcall(s3c2410_dma_init);
-#endif
-
-#if defined(CONFIG_CPU_S3C2442)
-/* S3C2442 DMA contains the same selection table as the S3C2410 */
-static struct sysdev_driver s3c2442_dma_driver = {
- .add = s3c2410_dma_add,
-};
-
-static int __init s3c2442_dma_init(void)
-{
- return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_dma_driver);
-}
-
-arch_initcall(s3c2442_dma_init);
-#endif
-
diff --git a/arch/arm/mach-s3c2410/s3c2410-gpio.c b/arch/arm/mach-s3c2410/s3c2410-gpio.c
deleted file mode 100644
index ec3a276cc3c..00000000000
--- a/arch/arm/mach-s3c2410/s3c2410-gpio.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/s3c2410-gpio.c
- *
- * Copyright (c) 2004-2006 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410 GPIO 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 <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-
-#include <asm/hardware.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-
-#include <asm/arch/regs-gpio.h>
-
-int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
- unsigned int config)
-{
- void __iomem *reg = S3C24XX_EINFLT0;
- unsigned long flags;
- unsigned long val;
-
- if (pin < S3C2410_GPG8 || pin > S3C2410_GPG15)
- return -1;
-
- config &= 0xff;
-
- pin -= S3C2410_GPG8;
- reg += pin & ~3;
-
- local_irq_save(flags);
-
- /* update filter width and clock source */
-
- val = __raw_readl(reg);
- val &= ~(0xff << ((pin & 3) * 8));
- val |= config << ((pin & 3) * 8);
- __raw_writel(val, reg);
-
- /* update filter enable */
-
- val = __raw_readl(S3C24XX_EXTINT2);
- val &= ~(1 << ((pin * 4) + 3));
- val |= on << ((pin * 4) + 3);
- __raw_writel(val, S3C24XX_EXTINT2);
-
- local_irq_restore(flags);
-
- return 0;
-}
-
-EXPORT_SYMBOL(s3c2410_gpio_irqfilter);
diff --git a/arch/arm/mach-s3c2410/s3c2410-irq.c b/arch/arm/mach-s3c2410/s3c2410-irq.c
deleted file mode 100644
index c796c9c76e7..00000000000
--- a/arch/arm/mach-s3c2410/s3c2410-irq.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/s3c2410-irq.c
- *
- * Copyright (c) 2006 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
-*/
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/ptrace.h>
-#include <linux/sysdev.h>
-
-#include "cpu.h"
-#include "pm.h"
-
-static int s3c2410_irq_add(struct sys_device *sysdev)
-{
- return 0;
-}
-
-static struct sysdev_driver s3c2410_irq_driver = {
- .add = s3c2410_irq_add,
- .suspend = s3c24xx_irq_suspend,
- .resume = s3c24xx_irq_resume,
-};
-
-static int s3c2410_irq_init(void)
-{
- return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_irq_driver);
-}
-
-arch_initcall(s3c2410_irq_init);
diff --git a/arch/arm/mach-s3c2410/s3c2410-pm.c b/arch/arm/mach-s3c2410/s3c2410-pm.c
deleted file mode 100644
index 8bb6e5e21f5..00000000000
--- a/arch/arm/mach-s3c2410/s3c2410-pm.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/s3c2410-pm.c
- *
- * Copyright (c) 2006 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410 (and compatible) Power Manager (Suspend-To-RAM) 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 <linux/init.h>
-#include <linux/suspend.h>
-#include <linux/errno.h>
-#include <linux/time.h>
-#include <linux/sysdev.h>
-
-#include <asm/hardware.h>
-#include <asm/io.h>
-
-#include <asm/mach-types.h>
-
-#include <asm/arch/regs-gpio.h>
-#include <asm/arch/h1940.h>
-
-#include "cpu.h"
-#include "pm.h"
-
-#ifdef CONFIG_S3C2410_PM_DEBUG
-extern void pm_dbg(const char *fmt, ...);
-#define DBG(fmt...) pm_dbg(fmt)
-#else
-#define DBG(fmt...) printk(KERN_DEBUG fmt)
-#endif
-
-static void s3c2410_pm_prepare(void)
-{
- /* ensure at least GSTATUS3 has the resume address */
-
- __raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C2410_GSTATUS3);
-
- DBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3));
- DBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4));
-
- if (machine_is_h1940()) {
- void *base = phys_to_virt(H1940_SUSPEND_CHECK);
- unsigned long ptr;
- unsigned long calc = 0;
-
- /* generate check for the bootloader to check on resume */
-
- for (ptr = 0; ptr < 0x40000; ptr += 0x400)
- calc += __raw_readl(base+ptr);
-
- __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM));
- }
-
- /* the RX3715 uses similar code and the same H1940 and the
- * same offsets for resume and checksum pointers */
-
- if (machine_is_rx3715()) {
- void *base = phys_to_virt(H1940_SUSPEND_CHECK);
- unsigned long ptr;
- unsigned long calc = 0;
-
- /* generate check for the bootloader to check on resume */
-
- for (ptr = 0; ptr < 0x40000; ptr += 0x4)
- calc += __raw_readl(base+ptr);
-
- __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM));
- }
-
- if ( machine_is_aml_m5900() )
- s3c2410_gpio_setpin(S3C2410_GPF2, 1);
-
-}
-
-static int s3c2410_pm_resume(struct sys_device *dev)
-{
- unsigned long tmp;
-
- /* unset the return-from-sleep flag, to ensure reset */
-
- tmp = __raw_readl(S3C2410_GSTATUS2);
- tmp &= S3C2410_GSTATUS2_OFFRESET;
- __raw_writel(tmp, S3C2410_GSTATUS2);
-
- if ( machine_is_aml_m5900() )
- s3c2410_gpio_setpin(S3C2410_GPF2, 0);
-
- return 0;
-}
-
-static int s3c2410_pm_add(struct sys_device *dev)
-{
- pm_cpu_prep = s3c2410_pm_prepare;
- pm_cpu_sleep = s3c2410_cpu_suspend;
-
- return 0;
-}
-
-#if defined(CONFIG_CPU_S3C2410)
-static struct sysdev_driver s3c2410_pm_driver = {
- .add = s3c2410_pm_add,
- .resume = s3c2410_pm_resume,
-};
-
-/* register ourselves */
-
-static int __init s3c2410_pm_drvinit(void)
-{
- return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_pm_driver);
-}
-
-arch_initcall(s3c2410_pm_drvinit);
-#endif
-
-#if defined(CONFIG_CPU_S3C2440)
-static struct sysdev_driver s3c2440_pm_driver = {
- .add = s3c2410_pm_add,
- .resume = s3c2410_pm_resume,
-};
-
-static int __init s3c2440_pm_drvinit(void)
-{
- return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_pm_driver);
-}
-
-arch_initcall(s3c2440_pm_drvinit);
-#endif
-
-#if defined(CONFIG_CPU_S3C2442)
-static struct sysdev_driver s3c2442_pm_driver = {
- .add = s3c2410_pm_add,
- .resume = s3c2410_pm_resume,
-};
-
-static int __init s3c2442_pm_drvinit(void)
-{
- return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_pm_driver);
-}
-
-arch_initcall(s3c2442_pm_drvinit);
-#endif
diff --git a/arch/arm/mach-s3c2410/s3c2410-sleep.S b/arch/arm/mach-s3c2410/s3c2410-sleep.S
deleted file mode 100644
index 9179a102458..00000000000
--- a/arch/arm/mach-s3c2410/s3c2410-sleep.S
+++ /dev/null
@@ -1,68 +0,0 @@
-/* linux/arch/arm/mach-s3c2410/s3c2410-sleep.S
- *
- * Copyright (c) 2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
- *
- * S3C2410 Power Manager (Suspend-To-RAM) support
- *
- * Based on PXA/SA1100 sleep code by:
- * Nicolas Pitre, (c) 2002 Monta Vista Software Inc
- * Cliff Brake, (c) 2001
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-#include <asm/hardware.h>
-#include <asm/arch/map.h>
-
-#include <asm/arch/regs-gpio.h>
-#include <asm/arch/regs-clock.h>
-#include <asm/arch/regs-mem.h>
-#include <asm/arch/regs-serial.h>
-
- /* s3c2410_cpu_suspend
- *
- * put the cpu into sleep mode
- */
-
-ENTRY(s3c2410_cpu_suspend)
- @@ prepare cpu to sleep
-
- ldr r4, =S3C2410_REFRESH
- ldr r5, =S3C24XX_MISCCR
- ldr r6, =S3C2410_CLKCON
- ldr r7, [ r4 ] @ get REFRESH (and ensure in TLB)
- ldr r8, [ r5 ] @ get MISCCR (and ensure in TLB)
- ldr r9, [ r6 ] @ get CLKCON (and ensure in TLB)
-
- orr r7, r7, #S3C2410_REFRESH_SELF @ SDRAM sleep command
- orr r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals
- orr r9, r9, #S3C2410_CLKCON_POWER @ power down command
-
- teq pc, #0 @ first as a trial-run to load cache
- bl s3c2410_do_sleep
- teq r0, r0 @ now do it for real
- b s3c2410_do_sleep @
-
- @@ align next bit of code to cache line
- .align 8
-s3c2410_do_sleep:
- streq r7, [ r4 ] @ SDRAM sleep command
- streq r8, [ r5 ] @ SDRAM power-down config
- streq r9, [ r6 ] @ CPU sleep
-1: beq 1b
- mov pc, r14
diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c
index 4cdc0d70c19..1a86a980375 100644
--- a/arch/arm/mach-s3c2410/s3c2410.c
+++ b/arch/arm/mach-s3c2410/s3c2410.c
@@ -31,10 +31,10 @@
#include <asm/arch/regs-clock.h>
#include <asm/arch/regs-serial.h>
-#include "s3c2410.h"
-#include "cpu.h"
-#include "devs.h"
-#include "clock.h"
+#include <asm/plat-s3c24xx/s3c2410.h>
+#include <asm/plat-s3c24xx/cpu.h>
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/clock.h>
/* Initial IO mappings */
@@ -110,7 +110,7 @@ static struct sys_device s3c2410_sysdev = {
/* need to register class before we actually register the device, and
* we also need to ensure that it has been initialised before any of the
- * drivers even try to use it (even if not on an s3c2440 based system)
+ * drivers even try to use it (even if not on an s3c2410 based system)
* as a driver which may support both 2410 and 2440 may try and use it.
*/
diff --git a/arch/arm/mach-s3c2410/sleep.S b/arch/arm/mach-s3c2410/sleep.S
index 2018c2e1dcc..637aaba6539 100644
--- a/arch/arm/mach-s3c2410/sleep.S
+++ b/arch/arm/mach-s3c2410/sleep.S
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/sleep.S
+/* linux/arch/arm/mach-s3c2410/s3c2410-sleep.S
*
* Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@@ -34,126 +34,35 @@
#include <asm/arch/regs-mem.h>
#include <asm/arch/regs-serial.h>
-/* CONFIG_DEBUG_RESUME is dangerous if your bootloader does not
- * reset the UART configuration, only enable if you really need this!
-*/
-//#define CONFIG_DEBUG_RESUME
-
- .text
-
- /* s3c2410_cpu_save
- *
- * save enough of the CPU state to allow us to re-start
- * pm.c code. as we store items like the sp/lr, we will
- * end up returning from this function when the cpu resumes
- * so the return value is set to mark this.
- *
- * This arangement means we avoid having to flush the cache
- * from this code.
- *
- * entry:
- * r0 = pointer to save block
- *
- * exit:
- * r0 = 0 => we stored everything
- * 1 => resumed from sleep
- */
-
-ENTRY(s3c2410_cpu_save)
- stmfd sp!, { r4 - r12, lr }
-
- @@ store co-processor registers
-
- mrc p15, 0, r4, c15, c1, 0 @ CP access register
- mrc p15, 0, r5, c13, c0, 0 @ PID
- mrc p15, 0, r6, c3, c0, 0 @ Domain ID
- mrc p15, 0, r7, c2, c0, 0 @ translation table base address
- mrc p15, 0, r8, c1, c0, 0 @ control register
-
- stmia r0, { r4 - r13 }
-
- mov r0, #0
- ldmfd sp, { r4 - r12, pc }
-
- @@ return to the caller, after having the MMU
- @@ turned on, this restores the last bits from the
- @@ stack
-resume_with_mmu:
- mov r0, #1
- ldmfd sp!, { r4 - r12, pc }
-
- .ltorg
-
- @@ the next bits sit in the .data segment, even though they
- @@ happen to be code... the s3c2410_sleep_save_phys needs to be
- @@ accessed by the resume code before it can restore the MMU.
- @@ This means that the variable has to be close enough for the
- @@ code to read it... since the .text segment needs to be RO,
- @@ the data segment can be the only place to put this code.
-
- .data
-
- .global s3c2410_sleep_save_phys
-s3c2410_sleep_save_phys:
- .word 0
-
- /* s3c2410_cpu_resume
+ /* s3c2410_cpu_suspend
*
- * resume code entry for bootloader to call
- *
- * we must put this code here in the data segment as we have no
- * other way of restoring the stack pointer after sleep, and we
- * must not write to the code segment (code is read-only)
+ * put the cpu into sleep mode
*/
-ENTRY(s3c2410_cpu_resume)
- mov r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE
- msr cpsr_c, r0
-
- @@ load UART to allow us to print the two characters for
- @@ resume debug
-
- mov r2, #S3C24XX_PA_UART & 0xff000000
- orr r2, r2, #S3C24XX_PA_UART & 0xff000
-
-#if 0
- /* SMDK2440 LED set */
- mov r14, #S3C24XX_PA_GPIO
- ldr r12, [ r14, #0x54 ]
- bic r12, r12, #3<<4
- orr r12, r12, #1<<7
- str r12, [ r14, #0x54 ]
-#endif
-
-#ifdef CONFIG_DEBUG_RESUME
- mov r3, #'L'
- strb r3, [ r2, #S3C2410_UTXH ]
-1001:
- ldrb r14, [ r3, #S3C2410_UTRSTAT ]
- tst r14, #S3C2410_UTRSTAT_TXE
- beq 1001b
-#endif /* CONFIG_DEBUG_RESUME */
-
- mov r1, #0
- mcr p15, 0, r1, c8, c7, 0 @@ invalidate I & D TLBs
- mcr p15, 0, r1, c7, c7, 0 @@ invalidate I & D caches
-
- ldr r0, s3c2410_sleep_save_phys @ address of restore block
- ldmia r0, { r4 - r13 }
-
- mcr p15, 0, r4, c15, c1, 0 @ CP access register
- mcr p15, 0, r5, c13, c0, 0 @ PID
- mcr p15, 0, r6, c3, c0, 0 @ Domain ID
- mcr p15, 0, r7, c2, c0, 0 @ translation table base
-
-#ifdef CONFIG_DEBUG_RESUME
- mov r3, #'R'
- strb r3, [ r2, #S3C2410_UTXH ]
-#endif
-
- ldr r2, =resume_with_mmu
- mcr p15, 0, r8, c1, c0, 0 @ turn on MMU, etc
- nop @ second-to-last before mmu
- mov pc, r2 @ go back to virtual address
-
- .ltorg
+ENTRY(s3c2410_cpu_suspend)
+ @@ prepare cpu to sleep
+
+ ldr r4, =S3C2410_REFRESH
+ ldr r5, =S3C24XX_MISCCR
+ ldr r6, =S3C2410_CLKCON
+ ldr r7, [ r4 ] @ get REFRESH (and ensure in TLB)
+ ldr r8, [ r5 ] @ get MISCCR (and ensure in TLB)
+ ldr r9, [ r6 ] @ get CLKCON (and ensure in TLB)
+
+ orr r7, r7, #S3C2410_REFRESH_SELF @ SDRAM sleep command
+ orr r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals
+ orr r9, r9, #S3C2410_CLKCON_POWER @ power down command
+
+ teq pc, #0 @ first as a trial-run to load cache
+ bl s3c2410_do_sleep
+ teq r0, r0 @ now do it for real
+ b s3c2410_do_sleep @
+
+ @@ align next bit of code to cache line
+ .align 5
+s3c2410_do_sleep:
+ streq r7, [ r4 ] @ SDRAM sleep command
+ streq r8, [ r5 ] @ SDRAM power-down config
+ streq r9, [ r6 ] @ CPU sleep
+1: beq 1b
+ mov pc, r14
diff --git a/arch/arm/mach-s3c2410/usb-simtec.c b/arch/arm/mach-s3c2410/usb-simtec.c
index 22b0e1cdd4b..bcd562ac1d3 100644
--- a/arch/arm/mach-s3c2410/usb-simtec.c
+++ b/arch/arm/mach-s3c2410/usb-simtec.c
@@ -35,7 +35,7 @@
#include <asm/io.h>
#include <asm/irq.h>
-#include "devs.h"
+#include <asm/plat-s3c24xx/devs.h>
#include "usb-simtec.h"
/* control power and monitor over-current events on various Simtec
diff --git a/arch/arm/mach-s3c2412/Kconfig b/arch/arm/mach-s3c2412/Kconfig
new file mode 100644
index 00000000000..befc5fdbb61
--- /dev/null
+++ b/arch/arm/mach-s3c2412/Kconfig
@@ -0,0 +1,58 @@
+# arch/arm/mach-s3c2412/Kconfig
+#
+# Copyright 2007 Simtec Electronics
+#
+# Licensed under GPLv2
+
+config CPU_S3C2412
+ bool
+ depends on ARCH_S3C2410
+ select S3C2412_PM if PM
+ select S3C2412_DMA if S3C2410_DMA
+ help
+ Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line
+
+config CPU_S3C2412_ONLY
+ bool
+ depends on ARCH_S3C2410 && !CPU_S3C2400 && !CPU_S3C2410 && \
+ !CPU_S3C2440 && !CPU_S3C2442 && !CPU_S3C2443 && CPU_S3C2412
+ default y if CPU_S3C2412
+
+config S3C2412_DMA
+ bool
+ depends on CPU_S3C2412
+ help
+ Internal config node for S3C2412 DMA support
+
+config S3C2412_PM
+ bool
+ help
+ Internal config node to apply S3C2412 power management
+
+
+menu "S3C2412 Machines"
+
+config MACH_SMDK2413
+ bool "SMDK2413"
+ select CPU_S3C2412
+ select MACH_S3C2413
+ select MACH_SMDK
+ help
+ Say Y here if you are using an SMDK2413
+
+config MACH_S3C2413
+ bool
+ help
+ Internal node for S3C2413 version of SMDK2413, so that
+ machine_is_s3c2413() will work when MACH_SMDK2413 is
+ selected
+
+config MACH_VSTMS
+ bool "VMSTMS"
+ select CPU_S3C2412
+ help
+ Say Y here if you are using an VSTMS board
+
+
+endmenu
+
diff --git a/arch/arm/mach-s3c2412/Makefile b/arch/arm/mach-s3c2412/Makefile
new file mode 100644
index 00000000000..f8e011691b3
--- /dev/null
+++ b/arch/arm/mach-s3c2412/Makefile
@@ -0,0 +1,21 @@
+# arch/arm/mach-s3c2412/Makefile
+#
+# Copyright 2007 Simtec Electronics
+#
+# Licensed under GPLv2
+
+obj-y :=
+obj-m :=
+obj-n :=
+obj- :=
+
+obj-$(CONFIG_CPU_S3C2412) += s3c2412.o
+obj-$(CONFIG_CPU_S3C2412) += irq.o
+obj-$(CONFIG_CPU_S3C2412) += clock.o
+obj-$(CONFIG_S3C2412_DMA) += dma.o
+obj-$(CONFIG_S3C2412_PM) += pm.o
+
+# Machine support
+
+obj-$(CONFIG_MACH_SMDK2413) += mach-smdk2413.o
+obj-$(CONFIG_MACH_VSTMS) += mach-vstms.o
diff --git a/arch/arm/mach-s3c2410/s3c2412-clock.c b/arch/arm/mach-s3c2412/clock.c
index 8f94ad83901..6a8e4448770 100644
--- a/arch/arm/mach-s3c2410/s3c2412-clock.c
+++ b/arch/arm/mach-s3c2412/clock.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/s3c2412-clock.c
+/* linux/arch/arm/mach-s3c2412/clock.c
*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@@ -41,9 +41,9 @@
#include <asm/arch/regs-clock.h>
#include <asm/arch/regs-gpio.h>
-#include "s3c2412.h"
-#include "clock.h"
-#include "cpu.h"
+#include <asm/plat-s3c24xx/s3c2412.h>
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/cpu.h>
/* We currently have to assume that the system is running
* from the XTPll input, and that all ***REFCLKs are being
diff --git a/arch/arm/mach-s3c2410/s3c2412-dma.c b/arch/arm/mach-s3c2412/dma.c
index 138f726ac6b..d0f4695c09d 100644
--- a/arch/arm/mach-s3c2410/s3c2412-dma.c
+++ b/arch/arm/mach-s3c2412/dma.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/s3c2412-dma.c
+/* linux/arch/arm/mach-s3c2412/dma.c
*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@@ -21,8 +21,8 @@
#include <asm/arch/dma.h>
#include <asm/io.h>
-#include "dma.h"
-#include "cpu.h"
+#include <asm/plat-s3c24xx/dma.h>
+#include <asm/plat-s3c24xx/cpu.h>
#include <asm/arch/regs-serial.h>
#include <asm/arch/regs-gpio.h>
@@ -146,6 +146,7 @@ static struct s3c24xx_dma_selection __initdata s3c2412_dma_sel = {
static int s3c2412_dma_add(struct sys_device *sysdev)
{
+ s3c2410_dma_init();
return s3c24xx_dma_init_map(&s3c2412_dma_sel);
}
diff --git a/arch/arm/mach-s3c2410/s3c2412-irq.c b/arch/arm/mach-s3c2412/irq.c
index ffcc30b23a8..e89dbdcb1b7 100644
--- a/arch/arm/mach-s3c2410/s3c2412-irq.c
+++ b/arch/arm/mach-s3c2412/irq.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2412/s3c2412-irq.c
+/* linux/arch/arm/mach-s3c2412/irq.c
*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@@ -35,9 +35,9 @@
#include <asm/arch/regs-irq.h>
#include <asm/arch/regs-gpio.h>
-#include "cpu.h"
-#include "irq.h"
-#include "pm.h"
+#include <asm/plat-s3c24xx/cpu.h>
+#include <asm/plat-s3c24xx/irq.h>
+#include <asm/plat-s3c24xx/pm.h>
/* the s3c2412 changes the behaviour of IRQ_EINT0 through IRQ_EINT3 by
* having them turn up in both the INT* and the EINT* registers. Whilst
diff --git a/arch/arm/mach-s3c2410/mach-smdk2413.c b/arch/arm/mach-s3c2412/mach-smdk2413.c
index 4f89abd7a6d..b5befce6c8d 100644
--- a/arch/arm/mach-s3c2410/mach-smdk2413.c
+++ b/arch/arm/mach-s3c2412/mach-smdk2413.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/mach-smdk2413.c
+/* linux/arch/arm/mach-s3c2412/mach-smdk2413.c
*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@@ -37,15 +37,16 @@
#include <asm/arch/regs-lcd.h>
#include <asm/arch/idle.h>
+#include <asm/arch/udc.h>
#include <asm/arch/fb.h>
-#include "s3c2410.h"
-#include "s3c2412.h"
-#include "clock.h"
-#include "devs.h"
-#include "cpu.h"
+#include <asm/plat-s3c24xx/s3c2410.h>
+#include <asm/plat-s3c24xx/s3c2412.h>
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/cpu.h>
-#include "common-smdk.h"
+#include <asm/plat-s3c24xx/common-smdk.h>
static struct map_desc smdk2413_iodesc[] __initdata = {
};
@@ -75,12 +76,38 @@ static struct s3c2410_uartcfg smdk2413_uartcfgs[] __initdata = {
}
};
+static void smdk2413_udc_pullup(enum s3c2410_udc_cmd_e cmd)
+{
+ printk(KERN_DEBUG "udc: pullup(%d)\n",cmd);
+
+ switch (cmd)
+ {
+ case S3C2410_UDC_P_ENABLE :
+ s3c2410_gpio_setpin(S3C2410_GPF2, 1);
+ break;
+ case S3C2410_UDC_P_DISABLE :
+ s3c2410_gpio_setpin(S3C2410_GPF2, 0);
+ break;
+ case S3C2410_UDC_P_RESET :
+ break;
+ default:
+ break;
+ }
+}
+
+
+static struct s3c2410_udc_mach_info smdk2413_udc_cfg __initdata = {
+ .udc_command = smdk2413_udc_pullup,
+};
+
+
static struct platform_device *smdk2413_devices[] __initdata = {
&s3c_device_usb,
//&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c,
&s3c_device_iis,
+ &s3c_device_usbgadget,
};
static struct s3c24xx_board smdk2413_board __initdata = {
@@ -109,7 +136,19 @@ static void __init smdk2413_map_io(void)
}
static void __init smdk2413_machine_init(void)
-{
+{ /* Turn off suspend on both USB ports, and switch the
+ * selectable USB port to USB device mode. */
+
+ s3c2410_gpio_setpin(S3C2410_GPF2, 0);
+ s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPIO_OUTPUT);
+
+ s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
+ S3C2410_MISCCR_USBSUSPND0 |
+ S3C2410_MISCCR_USBSUSPND1, 0x0);
+
+
+ s3c24xx_udc_set_platdata(&smdk2413_udc_cfg);
+
smdk_machine_init();
}
@@ -126,6 +165,19 @@ MACHINE_START(S3C2413, "S3C2413")
.timer = &s3c24xx_timer,
MACHINE_END
+MACHINE_START(SMDK2412, "SMDK2412")
+ /* Maintainer: Ben Dooks <ben@fluff.org> */
+ .phys_io = S3C2410_PA_UART,
+ .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
+ .boot_params = S3C2410_SDRAM_PA + 0x100,
+
+ .fixup = smdk2413_fixup,
+ .init_irq = s3c24xx_init_irq,
+ .map_io = smdk2413_map_io,
+ .init_machine = smdk2413_machine_init,
+ .timer = &s3c24xx_timer,
+MACHINE_END
+
MACHINE_START(SMDK2413, "SMDK2413")
/* Maintainer: Ben Dooks <ben@fluff.org> */
.phys_io = S3C2410_PA_UART,
diff --git a/arch/arm/mach-s3c2410/mach-vstms.c b/arch/arm/mach-s3c2412/mach-vstms.c
index 0360e1055bc..4231b549d79 100644
--- a/arch/arm/mach-s3c2410/mach-vstms.c
+++ b/arch/arm/mach-s3c2412/mach-vstms.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/mach-vstms.c
+/* linux/arch/arm/mach-s3c2412/mach-vstms.c
*
* (C) 2006 Thomas Gleixner <tglx@linutronix.de>
*
@@ -28,7 +28,6 @@
#include <asm/mach/irq.h>
#include <asm/hardware.h>
-#include <asm/hardware/iomd.h>
#include <asm/setup.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -43,11 +42,11 @@
#include <asm/arch/nand.h>
-#include "s3c2410.h"
-#include "s3c2412.h"
-#include "clock.h"
-#include "devs.h"
-#include "cpu.h"
+#include <asm/plat-s3c24xx/s3c2410.h>
+#include <asm/plat-s3c24xx/s3c2412.h>
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/cpu.h>
static struct map_desc vstms_iodesc[] __initdata = {
diff --git a/arch/arm/mach-s3c2410/s3c2412-pm.c b/arch/arm/mach-s3c2412/pm.c
index 19b63322d25..8988dac388a 100644
--- a/arch/arm/mach-s3c2410/s3c2412-pm.c
+++ b/arch/arm/mach-s3c2412/pm.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/s3c2412-pm.c
+/* linux/arch/arm/mach-s3c2412/pm.c
*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@@ -28,10 +28,10 @@
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-dsc.h>
-#include "cpu.h"
-#include "pm.h"
+#include <asm/plat-s3c24xx/cpu.h>
+#include <asm/plat-s3c24xx/pm.h>
-#include "s3c2412.h"
+#include <asm/plat-s3c24xx/s3c2412.h>
static void s3c2412_cpu_suspend(void)
{
diff --git a/arch/arm/mach-s3c2410/s3c2412.c b/arch/arm/mach-s3c2412/s3c2412.c
index 2f651a811ec..aafe0bc593f 100644
--- a/arch/arm/mach-s3c2410/s3c2412.c
+++ b/arch/arm/mach-s3c2412/s3c2412.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/s3c2412.c
+/* linux/arch/arm/mach-s3c2412/s3c2412.c
*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@@ -38,11 +38,11 @@
#include <asm/arch/regs-gpioj.h>
#include <asm/arch/regs-dsc.h>
-#include "s3c2412.h"
-#include "cpu.h"
-#include "devs.h"
-#include "clock.h"
-#include "pm.h"
+#include <asm/plat-s3c24xx/s3c2412.h>
+#include <asm/plat-s3c24xx/cpu.h>
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/pm.h>
#ifndef CONFIG_CPU_S3C2412_ONLY
void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO;
diff --git a/arch/arm/mach-s3c2440/Kconfig b/arch/arm/mach-s3c2440/Kconfig
new file mode 100644
index 00000000000..e3bfda098c0
--- /dev/null
+++ b/arch/arm/mach-s3c2440/Kconfig
@@ -0,0 +1,71 @@
+# arch/arm/mach-s3c2440/Kconfig
+#
+# Copyright 2007 Simtec Electronics
+#
+# Licensed under GPLv2
+
+config CPU_S3C2440
+ bool
+ depends on ARCH_S3C2410
+ select S3C2410_CLOCK
+ select S3C2410_PM if PM
+ select S3C2410_GPIO
+ select S3C2440_DMA if S3C2410_DMA
+ select CPU_S3C244X
+ help
+ Support for S3C2440 Samsung Mobile CPU based systems.
+
+config S3C2440_DMA
+ bool
+ depends on ARCH_S3C2410 && CPU_S3C24405B
+ help
+ Support for S3C2440 specific DMA code5A
+
+
+menu "S3C2440 Machines"
+
+config MACH_ANUBIS
+ bool "Simtec Electronics ANUBIS"
+ select CPU_S3C2440
+ select PM_SIMTEC if PM
+ help
+ Say Y here if you are using the Simtec Electronics ANUBIS
+ development system
+
+config MACH_OSIRIS
+ bool "Simtec IM2440D20 (OSIRIS) module"
+ select CPU_S3C2440
+ select PM_SIMTEC if PM
+ help
+ Say Y here if you are using the Simtec IM2440D20 module, also
+ known as the Osiris.
+
+config MACH_RX3715
+ bool "HP iPAQ rx3715"
+ select CPU_S3C2440
+ select PM_H1940 if PM
+ help
+ Say Y here if you are using the HP iPAQ rx3715.
+
+config ARCH_S3C2440
+ bool "SMDK2440"
+ select CPU_S3C2440
+ select MACH_SMDK
+ help
+ Say Y here if you are using the SMDK2440.
+
+config MACH_NEXCODER_2440
+ bool "NexVision NEXCODER 2440 Light Board"
+ select CPU_S3C2440
+ help
+ Say Y here if you are using the Nex Vision NEXCODER 2440 Light Board
+
+config SMDK2440_CPU2440
+ bool "SMDK2440 with S3C2440 CPU module"
+ depends on ARCH_S3C2440
+ default y if ARCH_S3C2440
+ select CPU_S3C2440
+
+
+endmenu
+
diff --git a/arch/arm/mach-s3c2440/Makefile b/arch/arm/mach-s3c2440/Makefile
new file mode 100644
index 00000000000..c81ed6248dc
--- /dev/null
+++ b/arch/arm/mach-s3c2440/Makefile
@@ -0,0 +1,23 @@
+# arch/arm/mach-s3c2440/Makefile
+#
+# Copyright 2007 Simtec Electronics
+#
+# Licensed under GPLv2
+
+obj-y :=
+obj-m :=
+obj-n :=
+obj- :=
+
+obj-$(CONFIG_CPU_S3C2440) += s3c2440.o dsc.o
+obj-$(CONFIG_CPU_S3C2440) += irq.o
+obj-$(CONFIG_CPU_S3C2440) += clock.o
+obj-$(CONFIG_S3C2440_DMA) += dma.o
+
+# Machine support
+
+obj-$(CONFIG_MACH_ANUBIS) += mach-anubis.o
+obj-$(CONFIG_MACH_OSIRIS) += mach-osiris.o
+obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o
+obj-$(CONFIG_ARCH_S3C2440) += mach-smdk2440.o
+obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o
diff --git a/arch/arm/mach-s3c2410/s3c2440-clock.c b/arch/arm/mach-s3c2440/clock.c
index ba13c1d079d..79e2ea4adaf 100644
--- a/arch/arm/mach-s3c2410/s3c2440-clock.c
+++ b/arch/arm/mach-s3c2440/clock.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/s3c2440-clock.c
+/* linux/arch/arm/mach-s3c2440/clock.c
*
* Copyright (c) 2004-2005 Simtec Electronics
* http://armlinux.simtec.co.uk/
@@ -41,8 +41,8 @@
#include <asm/arch/regs-clock.h>
-#include "clock.h"
-#include "cpu.h"
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/cpu.h>
/* S3C2440 extended clock support */
diff --git a/arch/arm/mach-s3c2410/s3c2440-dma.c b/arch/arm/mach-s3c2440/dma.c
index 47b861b9443..cd035a3ec87 100644
--- a/arch/arm/mach-s3c2410/s3c2440-dma.c
+++ b/arch/arm/mach-s3c2440/dma.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/s3c2440-dma.c
+/* linux/arch/arm/mach-s3c2440/dma.c
*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@@ -19,9 +19,9 @@
#include <asm/dma.h>
#include <asm/arch/dma.h>
-#include "dma.h"
-#include "cpu.h"
+#include <asm/plat-s3c24xx/dma.h>
+#include <asm/plat-s3c24xx/cpu.h>
#include <asm/arch/regs-serial.h>
#include <asm/arch/regs-gpio.h>
@@ -147,8 +147,53 @@ static struct s3c24xx_dma_selection __initdata s3c2440_dma_sel = {
.map_size = ARRAY_SIZE(s3c2440_dma_mappings),
};
+static struct s3c24xx_dma_order __initdata s3c2440_dma_order = {
+ .channels = {
+ [DMACH_SDI] = {
+ .list = {
+ [0] = 3 | DMA_CH_VALID,
+ [1] = 2 | DMA_CH_VALID,
+ [2] = 1 | DMA_CH_VALID,
+ [3] = 0 | DMA_CH_VALID,
+ },
+ },
+ [DMACH_I2S_IN] = {
+ .list = {
+ [0] = 1 | DMA_CH_VALID,
+ [1] = 2 | DMA_CH_VALID,
+ },
+ },
+ [DMACH_I2S_OUT] = {
+ .list = {
+ [0] = 2 | DMA_CH_VALID,
+ [1] = 1 | DMA_CH_VALID,
+ },
+ },
+ [DMACH_PCM_IN] = {
+ .list = {
+ [0] = 2 | DMA_CH_VALID,
+ [1] = 1 | DMA_CH_VALID,
+ },
+ },
+ [DMACH_PCM_OUT] = {
+ .list = {
+ [0] = 1 | DMA_CH_VALID,
+ [1] = 3 | DMA_CH_VALID,
+ },
+ },
+ [DMACH_MIC_IN] = {
+ .list = {
+ [0] = 3 | DMA_CH_VALID,
+ [1] = 2 | DMA_CH_VALID,
+ },
+ },
+ },
+};
+
static int s3c2440_dma_add(struct sys_device *sysdev)
{
+ s3c2410_dma_init();
+ s3c24xx_dma_order_set(&s3c2440_dma_order);
return s3c24xx_dma_init_map(&s3c2440_dma_sel);
}
diff --git a/arch/arm/mach-s3c2410/s3c2440-dsc.c b/arch/arm/mach-s3c2440/dsc.c
index c92ea66ba45..2995ff5681b 100644
--- a/arch/arm/mach-s3c2410/s3c2440-dsc.c
+++ b/arch/arm/mach-s3c2440/dsc.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/s3c2440-dsc.c
+/* linux/arch/arm/mach-s3c2440/dsc.c
*
* Copyright (c) 2004-2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@@ -27,8 +27,8 @@
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-dsc.h>
-#include "cpu.h"
-#include "s3c2440.h"
+#include <asm/plat-s3c24xx/cpu.h>
+#include <asm/plat-s3c24xx/s3c2440.h>
int s3c2440_set_dsc(unsigned int pin, unsigned int value)
{
diff --git a/arch/arm/mach-s3c2410/s3c2440-irq.c b/arch/arm/mach-s3c2440/irq.c
index 1ba19b27ab0..1069d13d8c5 100644
--- a/arch/arm/mach-s3c2410/s3c2440-irq.c
+++ b/arch/arm/mach-s3c2440/irq.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/s3c2440-irq.c
+/* linux/arch/arm/mach-s3c2440/irq.c
*
* Copyright (c) 2003,2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@@ -35,9 +35,9 @@
#include <asm/arch/regs-irq.h>
#include <asm/arch/regs-gpio.h>
-#include "cpu.h"
-#include "pm.h"
-#include "irq.h"
+#include <asm/plat-s3c24xx/cpu.h>
+#include <asm/plat-s3c24xx/pm.h>
+#include <asm/plat-s3c24xx/irq.h>
/* WDT/AC97 */
diff --git a/arch/arm/mach-s3c2410/mach-anubis.c b/arch/arm/mach-s3c2440/mach-anubis.c
index 0fad0c2fe07..3f0288eb1ed 100644
--- a/arch/arm/mach-s3c2410/mach-anubis.c
+++ b/arch/arm/mach-s3c2440/mach-anubis.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/mach-anubis.c
+/* linux/arch/arm/mach-s3c2440/mach-anubis.c
*
* Copyright (c) 2003-2005 Simtec Electronics
* http://armlinux.simtec.co.uk/
@@ -42,9 +42,9 @@
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h>
-#include "clock.h"
-#include "devs.h"
-#include "cpu.h"
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/cpu.h>
#define COPYRIGHT ", (c) 2005 Simtec Electronics"
diff --git a/arch/arm/mach-s3c2410/mach-nexcoder.c b/arch/arm/mach-s3c2440/mach-nexcoder.c
index d6dfdad8c90..6d551d88330 100644
--- a/arch/arm/mach-s3c2410/mach-nexcoder.c
+++ b/arch/arm/mach-s3c2440/mach-nexcoder.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/mach-nexcoder.c
+/* linux/arch/arm/mach-s3c2440/mach-nexcoder.c
*
* Copyright (c) 2004 Nex Vision
* Guillaume GOURAT <guillaume.gourat@nexvision.tv>
@@ -38,11 +38,11 @@
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-serial.h>
-#include "s3c2410.h"
-#include "s3c2440.h"
-#include "clock.h"
-#include "devs.h"
-#include "cpu.h"
+#include <asm/plat-s3c24xx/s3c2410.h>
+#include <asm/plat-s3c24xx/s3c2440.h>
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/cpu.h>
static struct map_desc nexcoder_iodesc[] __initdata = {
/* nothing here yet */
diff --git a/arch/arm/mach-s3c2410/mach-osiris.c b/arch/arm/mach-s3c2440/mach-osiris.c
index 37b40850c9b..2ed8e51f20c 100644
--- a/arch/arm/mach-s3c2410/mach-osiris.c
+++ b/arch/arm/mach-s3c2440/mach-osiris.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/mach-osiris.c
+/* linux/arch/arm/mach-s3c2440/mach-osiris.c
*
* Copyright (c) 2005 Simtec Electronics
* http://armlinux.simtec.co.uk/
@@ -41,9 +41,9 @@
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h>
-#include "clock.h"
-#include "devs.h"
-#include "cpu.h"
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/cpu.h>
/* onboard perihpheral map */
diff --git a/arch/arm/mach-s3c2410/mach-rx3715.c b/arch/arm/mach-s3c2440/mach-rx3715.c
index ecbcdf79d73..480ccde63fb 100644
--- a/arch/arm/mach-s3c2410/mach-rx3715.c
+++ b/arch/arm/mach-s3c2440/mach-rx3715.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/mach-rx3715.c
+/* linux/arch/arm/mach-s3c2440/mach-rx3715.c
*
* Copyright (c) 2003,2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@@ -33,7 +33,6 @@
#include <asm/mach/irq.h>
#include <asm/hardware.h>
-#include <asm/hardware/iomd.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
@@ -46,10 +45,10 @@
#include <asm/arch/nand.h>
#include <asm/arch/fb.h>
-#include "clock.h"
-#include "devs.h"
-#include "cpu.h"
-#include "pm.h"
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/cpu.h>
+#include <asm/plat-s3c24xx/pm.h>
static struct map_desc rx3715_iodesc[] __initdata = {
/* dump ISA space somewhere unused */
diff --git a/arch/arm/mach-s3c2410/mach-smdk2440.c b/arch/arm/mach-s3c2440/mach-smdk2440.c
index 2b61f4ed1da..c17eb5b1f6b 100644
--- a/arch/arm/mach-s3c2410/mach-smdk2440.c
+++ b/arch/arm/mach-s3c2440/mach-smdk2440.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/mach-smdk2440.c
+/* linux/arch/arm/mach-s3c2440/mach-smdk2440.c
*
* Copyright (c) 2004,2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@@ -27,12 +27,10 @@
#include <asm/mach/irq.h>
#include <asm/hardware.h>
-#include <asm/hardware/iomd.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
-//#include <asm/debug-ll.h>
#include <asm/arch/regs-serial.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-lcd.h>
@@ -40,13 +38,13 @@
#include <asm/arch/idle.h>
#include <asm/arch/fb.h>
-#include "s3c2410.h"
-#include "s3c2440.h"
-#include "clock.h"
-#include "devs.h"
-#include "cpu.h"
+#include <asm/plat-s3c24xx/s3c2410.h>
+#include <asm/plat-s3c24xx/s3c2440.h>
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/cpu.h>
-#include "common-smdk.h"
+#include <asm/plat-s3c24xx/common-smdk.h>
static struct map_desc smdk2440_iodesc[] __initdata = {
/* ISA IO Space map (memory space selected by A24) */
@@ -144,6 +142,7 @@ static struct s3c2410fb_mach_info smdk2440_lcd_cfg __initdata = {
#endif
.lpcsel = ((0xCE6) & ~7) | 1<<4,
+ .type = S3C2410_LCDCON1_TFT16BPP,
.width = 240,
.height = 320,
diff --git a/arch/arm/mach-s3c2410/s3c2440.c b/arch/arm/mach-s3c2440/s3c2440.c
index 344eb27cca4..90e1da61fbc 100644
--- a/arch/arm/mach-s3c2410/s3c2440.c
+++ b/arch/arm/mach-s3c2440/s3c2440.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/s3c2440.c
+/* linux/arch/arm/mach-s3c2440/s3c2440.c
*
* Copyright (c) 2004-2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@@ -29,9 +29,9 @@
#include <asm/io.h>
#include <asm/irq.h>
-#include "s3c2440.h"
-#include "devs.h"
-#include "cpu.h"
+#include <asm/plat-s3c24xx/s3c2440.h>
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/cpu.h>
static struct sys_device s3c2440_sysdev = {
.cls = &s3c2440_sysclass,
diff --git a/arch/arm/mach-s3c2442/Kconfig b/arch/arm/mach-s3c2442/Kconfig
new file mode 100644
index 00000000000..bf8d87abfab
--- /dev/null
+++ b/arch/arm/mach-s3c2442/Kconfig
@@ -0,0 +1,27 @@
+# arch/arm/mach-s3c2442/Kconfig
+#
+# Copyright 2007 Simtec Electronics
+#
+# Licensed under GPLv2
+
+config CPU_S3C2442
+ bool
+ depends on ARCH_S3C2420
+ select S3C2410_CLOCK
+ select S3C2410_GPIO
+ select S3C2410_PM if PM
+ select CPU_S3C244X
+ help
+ Support for S3C2442 Samsung Mobile CPU based systems.
+
+
+menu "S3C2442 Machines"
+
+config SMDK2440_CPU2442
+ bool "SMDM2440 with S3C2442 CPU module"
+ depends on ARCH_S3C2440
+ select CPU_S3C2442
+
+
+endmenu
+
diff --git a/arch/arm/mach-s3c2442/Makefile b/arch/arm/mach-s3c2442/Makefile
new file mode 100644
index 00000000000..2a909c6c579
--- /dev/null
+++ b/arch/arm/mach-s3c2442/Makefile
@@ -0,0 +1,16 @@
+# arch/arm/mach-s3c2442/Makefile
+#
+# Copyright 2007 Simtec Electronics
+#
+# Licensed under GPLv2
+
+obj-y :=
+obj-m :=
+obj-n :=
+obj- :=
+
+obj-$(CONFIG_CPU_S3C2442) += s3c2442.o
+obj-$(CONFIG_CPU_S3C2442) += clock.o
+
+# Machine support
+
diff --git a/arch/arm/mach-s3c2410/s3c2442-clock.c b/arch/arm/mach-s3c2442/clock.c
index 4e292ca7c9b..5b9e830ac4d 100644
--- a/arch/arm/mach-s3c2410/s3c2442-clock.c
+++ b/arch/arm/mach-s3c2442/clock.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/s3c2442-clock.c
+/* linux/arch/arm/mach-s3c2442/clock.c
*
* Copyright (c) 2004-2005 Simtec Electronics
* http://armlinux.simtec.co.uk/
@@ -41,8 +41,8 @@
#include <asm/arch/regs-clock.h>
-#include "clock.h"
-#include "cpu.h"
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/cpu.h>
/* S3C2442 extended clock support */
diff --git a/arch/arm/mach-s3c2410/s3c2442.c b/arch/arm/mach-s3c2442/s3c2442.c
index 428732ee68c..fbf8264249d 100644
--- a/arch/arm/mach-s3c2410/s3c2442.c
+++ b/arch/arm/mach-s3c2442/s3c2442.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/s3c2442.c
+/* linux/arch/arm/mach-s3c2442/s3c2442.c
*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@@ -19,8 +19,8 @@
#include <linux/serial_core.h>
#include <linux/sysdev.h>
-#include "s3c2442.h"
-#include "cpu.h"
+#include <asm/plat-s3c24xx/s3c2442.h>
+#include <asm/plat-s3c24xx/cpu.h>
static struct sys_device s3c2442_sysdev = {
.cls = &s3c2442_sysclass,
diff --git a/arch/arm/mach-s3c2443/Kconfig b/arch/arm/mach-s3c2443/Kconfig
new file mode 100644
index 00000000000..c649bb2e7ce
--- /dev/null
+++ b/arch/arm/mach-s3c2443/Kconfig
@@ -0,0 +1,29 @@
+# arch/arm/mach-s3c2443/Kconfig
+#
+# Copyright 2007 Simtec Electronics
+#
+# Licensed under GPLv2
+
+config CPU_S3C2443
+ bool
+ depends on ARCH_S3C2410
+ select S3C2443_DMA if S3C2410_DMA
+ help
+ Support for the S3C2443 SoC from the S3C24XX line
+
+config S3C2443_DMA
+ bool
+ depends on CPU_S3C2443
+ help
+ Internal config node for S3C2443 DMA support
+
+menu "S3C2443 Machines"
+
+config MACH_SMDK2443
+ bool "SMDK2443"
+ select CPU_S3C2443
+ select MACH_SMDK
+ help
+ Say Y here if you are using an SMDK2443
+
+endmenu
diff --git a/arch/arm/mach-s3c2443/Makefile b/arch/arm/mach-s3c2443/Makefile
new file mode 100644
index 00000000000..d1843c9eb8b
--- /dev/null
+++ b/arch/arm/mach-s3c2443/Makefile
@@ -0,0 +1,20 @@
+# arch/arm/mach-s3c2443/Makefile
+#
+# Copyright 2007 Simtec Electronics
+#
+# Licensed under GPLv2
+
+obj-y :=
+obj-m :=
+obj-n :=
+obj- :=
+
+obj-$(CONFIG_CPU_S3C2443) += s3c2443.o
+obj-$(CONFIG_CPU_S3C2443) += irq.o
+obj-$(CONFIG_CPU_S3C2443) += clock.o
+
+obj-$(CONFIG_S3C2443_DMA) += dma.o
+
+# Machine support
+
+obj-$(CONFIG_MACH_SMDK2443) += mach-smdk2443.o
diff --git a/arch/arm/mach-s3c2443/clock.c b/arch/arm/mach-s3c2443/clock.c
new file mode 100644
index 00000000000..dd2272fb113
--- /dev/null
+++ b/arch/arm/mach-s3c2443/clock.c
@@ -0,0 +1,1007 @@
+/* linux/arch/arm/mach-s3c2443/clock.c
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2443 Clock control 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 <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/sysdev.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/serial_core.h>
+
+#include <asm/mach/map.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+
+#include <asm/arch/regs-s3c2443-clock.h>
+
+#include <asm/plat-s3c24xx/s3c2443.h>
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/cpu.h>
+
+/* We currently have to assume that the system is running
+ * from the XTPll input, and that all ***REFCLKs are being
+ * fed from it, as we cannot read the state of OM[4] from
+ * software.
+ *
+ * It would be possible for each board initialisation to
+ * set the correct muxing at initialisation
+*/
+
+static int s3c2443_clkcon_enable_h(struct clk *clk, int enable)
+{
+ unsigned int clocks = clk->ctrlbit;
+ unsigned long clkcon;
+
+ clkcon = __raw_readl(S3C2443_HCLKCON);
+
+ if (enable)
+ clkcon |= clocks;
+ else
+ clkcon &= ~clocks;
+
+ __raw_writel(clkcon, S3C2443_HCLKCON);
+
+ return 0;
+}
+
+static int s3c2443_clkcon_enable_p(struct clk *clk, int enable)
+{
+ unsigned int clocks = clk->ctrlbit;
+ unsigned long clkcon;
+
+ clkcon = __raw_readl(S3C2443_PCLKCON);
+
+ if (enable)
+ clkcon |= clocks;
+ else
+ clkcon &= ~clocks;
+
+ __raw_writel(clkcon, S3C2443_HCLKCON);
+
+ return 0;
+}
+
+static int s3c2443_clkcon_enable_s(struct clk *clk, int enable)
+{
+ unsigned int clocks = clk->ctrlbit;
+ unsigned long clkcon;
+
+ clkcon = __raw_readl(S3C2443_SCLKCON);
+
+ if (enable)
+ clkcon |= clocks;
+ else
+ clkcon &= ~clocks;
+
+ __raw_writel(clkcon, S3C2443_SCLKCON);
+
+ return 0;
+}
+
+static unsigned long s3c2443_roundrate_clksrc(struct clk *clk,
+ unsigned long rate,
+ unsigned int max)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ int div;
+
+ if (rate > parent_rate)
+ return parent_rate;
+
+ /* note, we remove the +/- 1 calculations as they cancel out */
+
+ div = (rate / parent_rate);
+
+ if (div < 1)
+ div = 1;
+ else if (div > max)
+ div = max;
+
+ return parent_rate / div;
+}
+
+static unsigned long s3c2443_roundrate_clksrc4(struct clk *clk,
+ unsigned long rate)
+{
+ return s3c2443_roundrate_clksrc(clk, rate, 4);
+}
+
+static unsigned long s3c2443_roundrate_clksrc16(struct clk *clk,
+ unsigned long rate)
+{
+ return s3c2443_roundrate_clksrc(clk, rate, 16);
+}
+
+static unsigned long s3c2443_roundrate_clksrc256(struct clk *clk,
+ unsigned long rate)
+{
+ return s3c2443_roundrate_clksrc(clk, rate, 256);
+}
+
+/* clock selections */
+
+/* CPU EXTCLK input */
+static struct clk clk_ext = {
+ .name = "ext",
+ .id = -1,
+};
+
+static struct clk clk_mpllref = {
+ .name = "mpllref",
+ .parent = &clk_xtal,
+ .id = -1,
+};
+
+#if 0
+static struct clk clk_mpll = {
+ .name = "mpll",
+ .parent = &clk_mpllref,
+ .id = -1,
+};
+#endif
+
+static struct clk clk_epllref;
+
+static struct clk clk_epll = {
+ .name = "epll",
+ .parent = &clk_epllref,
+ .id = -1,
+};
+
+static struct clk clk_i2s_ext = {
+ .name = "i2s-ext",
+ .id = -1,
+};
+
+static int s3c2443_setparent_epllref(struct clk *clk, struct clk *parent)
+{
+ unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
+
+ clksrc &= ~S3C2443_CLKSRC_EPLLREF_MASK;
+
+ if (parent == &clk_xtal)
+ clksrc |= S3C2443_CLKSRC_EPLLREF_XTAL;
+ else if (parent == &clk_ext)
+ clksrc |= S3C2443_CLKSRC_EPLLREF_EXTCLK;
+ else if (parent != &clk_mpllref)
+ return -EINVAL;
+
+ __raw_writel(clksrc, S3C2443_CLKSRC);
+ clk->parent = parent;
+
+ return 0;
+}
+
+static struct clk clk_epllref = {
+ .name = "epllref",
+ .id = -1,
+ .set_parent = s3c2443_setparent_epllref,
+};
+
+static unsigned long s3c2443_getrate_mdivclk(struct clk *clk)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long div = __raw_readl(S3C2443_CLKDIV0);
+
+ div &= S3C2443_CLKDIV0_EXTDIV_MASK;
+ div >>= (S3C2443_CLKDIV0_EXTDIV_SHIFT-1); /* x2 */
+
+ return parent_rate / (div + 1);
+}
+
+static struct clk clk_mdivclk = {
+ .name = "mdivclk",
+ .parent = &clk_mpllref,
+ .id = -1,
+ .get_rate = s3c2443_getrate_mdivclk,
+};
+
+
+static int s3c2443_setparent_msysclk(struct clk *clk, struct clk *parent)
+{
+ unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
+
+ clksrc &= ~(S3C2443_CLKSRC_MSYSCLK_MPLL |
+ S3C2443_CLKSRC_EXTCLK_DIV);
+
+ if (parent == &clk_mpll)
+ clksrc |= S3C2443_CLKSRC_MSYSCLK_MPLL;
+ else if (parent == &clk_mdivclk)
+ clksrc |= S3C2443_CLKSRC_EXTCLK_DIV;
+ else if (parent != &clk_mpllref)
+ return -EINVAL;
+
+ __raw_writel(clksrc, S3C2443_CLKSRC);
+ clk->parent = parent;
+
+ return 0;
+}
+
+static struct clk clk_msysclk = {
+ .name = "msysclk",
+ .parent = &clk_xtal,
+ .id = -1,
+ .set_parent = s3c2443_setparent_msysclk,
+};
+
+
+/* esysclk
+ *
+ * this is sourced from either the EPLL or the EPLLref clock
+*/
+
+static int s3c2443_setparent_esysclk(struct clk *clk, struct clk *parent)
+{
+ unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
+
+ if (parent == &clk_epll)
+ clksrc |= S3C2443_CLKSRC_ESYSCLK_EPLL;
+ else if (parent == &clk_epllref)
+ clksrc &= ~S3C2443_CLKSRC_ESYSCLK_EPLL;
+ else
+ return -EINVAL;
+
+ __raw_writel(clksrc, S3C2443_CLKSRC);
+ clk->parent = parent;
+
+ return 0;
+}
+
+static struct clk clk_esysclk = {
+ .name = "esysclk",
+ .parent = &clk_epll,
+ .id = -1,
+ .set_parent = s3c2443_setparent_esysclk,
+};
+
+/* uartclk
+ *
+ * UART baud-rate clock sourced from esysclk via a divisor
+*/
+
+static unsigned long s3c2443_getrate_uart(struct clk *clk)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long div = __raw_readl(S3C2443_CLKDIV1);
+
+ div &= S3C2443_CLKDIV1_UARTDIV_MASK;
+ div >>= S3C2443_CLKDIV1_UARTDIV_SHIFT;
+
+ return parent_rate / (div + 1);
+}
+
+
+static int s3c2443_setrate_uart(struct clk *clk, unsigned long rate)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
+
+ rate = s3c2443_roundrate_clksrc16(clk, rate);
+ rate = parent_rate / rate;
+
+ clkdivn &= ~S3C2443_CLKDIV1_UARTDIV_MASK;
+ clkdivn |= (rate - 1) << S3C2443_CLKDIV1_UARTDIV_SHIFT;
+
+ __raw_writel(clkdivn, S3C2443_CLKDIV1);
+ return 0;
+}
+
+static struct clk clk_uart = {
+ .name = "uartclk",
+ .id = -1,
+ .parent = &clk_esysclk,
+ .get_rate = s3c2443_getrate_uart,
+ .set_rate = s3c2443_setrate_uart,
+ .round_rate = s3c2443_roundrate_clksrc16,
+};
+
+/* hsspi
+ *
+ * high-speed spi clock, sourced from esysclk
+*/
+
+static unsigned long s3c2443_getrate_hsspi(struct clk *clk)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long div = __raw_readl(S3C2443_CLKDIV1);
+
+ div &= S3C2443_CLKDIV1_HSSPIDIV_MASK;
+ div >>= S3C2443_CLKDIV1_HSSPIDIV_SHIFT;
+
+ return parent_rate / (div + 1);
+}
+
+
+static int s3c2443_setrate_hsspi(struct clk *clk, unsigned long rate)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
+
+ rate = s3c2443_roundrate_clksrc4(clk, rate);
+ rate = parent_rate / rate;
+
+ clkdivn &= ~S3C2443_CLKDIV1_HSSPIDIV_MASK;
+ clkdivn |= (rate - 1) << S3C2443_CLKDIV1_HSSPIDIV_SHIFT;
+
+ __raw_writel(clkdivn, S3C2443_CLKDIV1);
+ return 0;
+}
+
+static struct clk clk_hsspi = {
+ .name = "hsspi",
+ .id = -1,
+ .parent = &clk_esysclk,
+ .ctrlbit = S3C2443_SCLKCON_HSSPICLK,
+ .enable = s3c2443_clkcon_enable_s,
+ .get_rate = s3c2443_getrate_hsspi,
+ .set_rate = s3c2443_setrate_hsspi,
+ .round_rate = s3c2443_roundrate_clksrc4,
+};
+
+/* usbhost
+ *
+ * usb host bus-clock, usually 48MHz to provide USB bus clock timing
+*/
+
+static unsigned long s3c2443_getrate_usbhost(struct clk *clk)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long div = __raw_readl(S3C2443_CLKDIV1);
+
+ div &= S3C2443_CLKDIV1_USBHOSTDIV_MASK;
+ div >>= S3C2443_CLKDIV1_USBHOSTDIV_SHIFT;
+
+ return parent_rate / (div + 1);
+}
+
+static int s3c2443_setrate_usbhost(struct clk *clk, unsigned long rate)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
+
+ rate = s3c2443_roundrate_clksrc4(clk, rate);
+ rate = parent_rate / rate;
+
+ clkdivn &= ~S3C2443_CLKDIV1_USBHOSTDIV_MASK;
+ clkdivn |= (rate - 1) << S3C2443_CLKDIV1_USBHOSTDIV_SHIFT;
+
+ __raw_writel(clkdivn, S3C2443_CLKDIV1);
+ return 0;
+}
+
+struct clk clk_usb_bus_host = {
+ .name = "usb-bus-host-parent",
+ .id = -1,
+ .parent = &clk_esysclk,
+ .ctrlbit = S3C2443_SCLKCON_USBHOST,
+ .enable = s3c2443_clkcon_enable_s,
+ .get_rate = s3c2443_getrate_usbhost,
+ .set_rate = s3c2443_setrate_usbhost,
+ .round_rate = s3c2443_roundrate_clksrc4,
+};
+
+/* clk_hsmcc_div
+ *
+ * this clock is sourced from epll, and is fed through a divider,
+ * to a mux controlled by sclkcon where either it or a extclk can
+ * be fed to the hsmmc block
+*/
+
+static unsigned long s3c2443_getrate_hsmmc_div(struct clk *clk)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long div = __raw_readl(S3C2443_CLKDIV1);
+
+ div &= S3C2443_CLKDIV1_HSMMCDIV_MASK;
+ div >>= S3C2443_CLKDIV1_HSMMCDIV_SHIFT;
+
+ return parent_rate / (div + 1);
+}
+
+static int s3c2443_setrate_hsmmc_div(struct clk *clk, unsigned long rate)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
+
+ rate = s3c2443_roundrate_clksrc4(clk, rate);
+ rate = parent_rate / rate;
+
+ clkdivn &= ~S3C2443_CLKDIV1_HSMMCDIV_MASK;
+ clkdivn |= (rate - 1) << S3C2443_CLKDIV1_HSMMCDIV_SHIFT;
+
+ __raw_writel(clkdivn, S3C2443_CLKDIV1);
+ return 0;
+}
+
+static struct clk clk_hsmmc_div = {
+ .name = "hsmmc-div",
+ .id = -1,
+ .parent = &clk_esysclk,
+ .get_rate = s3c2443_getrate_hsmmc_div,
+ .set_rate = s3c2443_setrate_hsmmc_div,
+ .round_rate = s3c2443_roundrate_clksrc4,
+};
+
+static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent)
+{
+ unsigned long clksrc = __raw_readl(S3C2443_SCLKCON);
+
+ clksrc &= ~(S3C2443_SCLKCON_HSMMCCLK_EXT |
+ S3C2443_SCLKCON_HSMMCCLK_EPLL);
+
+ if (parent == &clk_epll)
+ clksrc |= S3C2443_SCLKCON_HSMMCCLK_EPLL;
+ else if (parent == &clk_ext)
+ clksrc |= S3C2443_SCLKCON_HSMMCCLK_EXT;
+ else
+ return -EINVAL;
+
+ if (clk->usage > 0) {
+ __raw_writel(clksrc, S3C2443_SCLKCON);
+ }
+
+ clk->parent = parent;
+ return 0;
+}
+
+static int s3c2443_enable_hsmmc(struct clk *clk, int enable)
+{
+ return s3c2443_setparent_hsmmc(clk, clk->parent);
+}
+
+static struct clk clk_hsmmc = {
+ .name = "hsmmc-if",
+ .id = -1,
+ .parent = &clk_hsmmc_div,
+ .enable = s3c2443_enable_hsmmc,
+ .set_parent = s3c2443_setparent_hsmmc,
+};
+
+/* i2s_eplldiv
+ *
+ * this clock is the output from the i2s divisor of esysclk
+*/
+
+static unsigned long s3c2443_getrate_i2s_eplldiv(struct clk *clk)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long div = __raw_readl(S3C2443_CLKDIV1);
+
+ div &= S3C2443_CLKDIV1_I2SDIV_MASK;
+ div >>= S3C2443_CLKDIV1_I2SDIV_SHIFT;
+
+ return parent_rate / (div + 1);
+}
+
+static int s3c2443_setrate_i2s_eplldiv(struct clk *clk, unsigned long rate)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
+
+ rate = s3c2443_roundrate_clksrc16(clk, rate);
+ rate = parent_rate / rate;
+
+ clkdivn &= ~S3C2443_CLKDIV1_I2SDIV_MASK;
+ clkdivn |= (rate - 1) << S3C2443_CLKDIV1_I2SDIV_SHIFT;
+
+ __raw_writel(clkdivn, S3C2443_CLKDIV1);
+ return 0;
+}
+
+static struct clk clk_i2s_eplldiv = {
+ .name = "i2s-eplldiv",
+ .id = -1,
+ .parent = &clk_esysclk,
+ .get_rate = s3c2443_getrate_i2s_eplldiv,
+ .set_rate = s3c2443_setrate_i2s_eplldiv,
+ .round_rate = s3c2443_roundrate_clksrc16,
+};
+
+/* i2s-ref
+ *
+ * i2s bus reference clock, selectable from external, esysclk or epllref
+*/
+
+static int s3c2443_setparent_i2s(struct clk *clk, struct clk *parent)
+{
+ unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
+
+ clksrc &= ~S3C2443_CLKSRC_I2S_MASK;
+
+ if (parent == &clk_epllref)
+ clksrc |= S3C2443_CLKSRC_I2S_EPLLREF;
+ else if (parent == &clk_i2s_ext)
+ clksrc |= S3C2443_CLKSRC_I2S_EXT;
+ else if (parent != &clk_i2s_eplldiv)
+ return -EINVAL;
+
+ clk->parent = parent;
+ __raw_writel(clksrc, S3C2443_CLKSRC);
+
+ return 0;
+}
+
+static struct clk clk_i2s = {
+ .name = "i2s-if",
+ .id = -1,
+ .parent = &clk_i2s_eplldiv,
+ .ctrlbit = S3C2443_SCLKCON_I2SCLK,
+ .enable = s3c2443_clkcon_enable_s,
+ .set_parent = s3c2443_setparent_i2s,
+};
+
+/* cam-if
+ *
+ * camera interface bus-clock, divided down from esysclk
+*/
+
+static unsigned long s3c2443_getrate_cam(struct clk *clk)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long div = __raw_readl(S3C2443_CLKDIV1);
+
+ div &= S3C2443_CLKDIV1_CAMDIV_MASK;
+ div >>= S3C2443_CLKDIV1_CAMDIV_SHIFT;
+
+ return parent_rate / (div + 1);
+}
+
+static int s3c2443_setrate_cam(struct clk *clk, unsigned long rate)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long clkdiv1 = __raw_readl(S3C2443_CLKDIV1);
+
+ rate = s3c2443_roundrate_clksrc16(clk, rate);
+ rate = parent_rate / rate;
+
+ clkdiv1 &= ~S3C2443_CLKDIV1_CAMDIV_MASK;
+ clkdiv1 |= (rate - 1) << S3C2443_CLKDIV1_CAMDIV_SHIFT;
+
+ __raw_writel(clkdiv1, S3C2443_CLKDIV1);
+ return 0;
+}
+
+static struct clk clk_cam = {
+ .name = "camif-upll", /* same as 2440 name */
+ .id = -1,
+ .parent = &clk_esysclk,
+ .ctrlbit = S3C2443_SCLKCON_CAMCLK,
+ .enable = s3c2443_clkcon_enable_s,
+ .get_rate = s3c2443_getrate_cam,
+ .set_rate = s3c2443_setrate_cam,
+ .round_rate = s3c2443_roundrate_clksrc16,
+};
+
+/* display-if
+ *
+ * display interface clock, divided from esysclk
+*/
+
+static unsigned long s3c2443_getrate_display(struct clk *clk)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long div = __raw_readl(S3C2443_CLKDIV1);
+
+ div &= S3C2443_CLKDIV1_DISPDIV_MASK;
+ div >>= S3C2443_CLKDIV1_DISPDIV_SHIFT;
+
+ return parent_rate / (div + 1);
+}
+
+static int s3c2443_setrate_display(struct clk *clk, unsigned long rate)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
+
+ rate = s3c2443_roundrate_clksrc256(clk, rate);
+ rate = parent_rate / rate;
+
+ clkdivn &= ~S3C2443_CLKDIV1_UARTDIV_MASK;
+ clkdivn |= (rate - 1) << S3C2443_CLKDIV1_UARTDIV_SHIFT;
+
+ __raw_writel(clkdivn, S3C2443_CLKDIV1);
+ return 0;
+}
+
+static struct clk clk_display = {
+ .name = "display-if",
+ .id = -1,
+ .parent = &clk_esysclk,
+ .ctrlbit = S3C2443_SCLKCON_DISPCLK,
+ .enable = s3c2443_clkcon_enable_s,
+ .get_rate = s3c2443_getrate_display,
+ .set_rate = s3c2443_setrate_display,
+ .round_rate = s3c2443_roundrate_clksrc256,
+};
+
+/* standard clock definitions */
+
+static struct clk init_clocks_disable[] = {
+ {
+ .name = "nand",
+ .id = -1,
+ .parent = &clk_h,
+ }, {
+ .name = "sdi",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2443_clkcon_enable_p,
+ .ctrlbit = S3C2443_PCLKCON_SDI,
+ }, {
+ .name = "adc",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2443_clkcon_enable_p,
+ .ctrlbit = S3C2443_PCLKCON_ADC,
+ }, {
+ .name = "i2c",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2443_clkcon_enable_p,
+ .ctrlbit = S3C2443_PCLKCON_IIC,
+ }, {
+ .name = "iis",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2443_clkcon_enable_p,
+ .ctrlbit = S3C2443_PCLKCON_IIS,
+ }, {
+ .name = "spi",
+ .id = 0,
+ .parent = &clk_p,
+ .enable = s3c2443_clkcon_enable_p,
+ .ctrlbit = S3C2443_PCLKCON_SPI0,
+ }, {
+ .name = "spi",
+ .id = 1,
+ .parent = &clk_p,
+ .enable = s3c2443_clkcon_enable_p,
+ .ctrlbit = S3C2443_PCLKCON_SPI1,
+ }
+};
+
+static struct clk init_clocks[] = {
+ {
+ .name = "dma",
+ .id = 0,
+ .parent = &clk_h,
+ .enable = s3c2443_clkcon_enable_h,
+ .ctrlbit = S3C2443_HCLKCON_DMA0,
+ }, {
+ .name = "dma",
+ .id = 1,
+ .parent = &clk_h,
+ .enable = s3c2443_clkcon_enable_h,
+ .ctrlbit = S3C2443_HCLKCON_DMA1,
+ }, {
+ .name = "dma",
+ .id = 2,
+ .parent = &clk_h,
+ .enable = s3c2443_clkcon_enable_h,
+ .ctrlbit = S3C2443_HCLKCON_DMA2,
+ }, {
+ .name = "dma",
+ .id = 3,
+ .parent = &clk_h,
+ .enable = s3c2443_clkcon_enable_h,
+ .ctrlbit = S3C2443_HCLKCON_DMA3,
+ }, {
+ .name = "dma",
+ .id = 4,
+ .parent = &clk_h,
+ .enable = s3c2443_clkcon_enable_h,
+ .ctrlbit = S3C2443_HCLKCON_DMA4,
+ }, {
+ .name = "dma",
+ .id = 5,
+ .parent = &clk_h,
+ .enable = s3c2443_clkcon_enable_h,
+ .ctrlbit = S3C2443_HCLKCON_DMA5,
+ }, {
+ .name = "lcd",
+ .id = -1,
+ .parent = &clk_h,
+ .enable = s3c2443_clkcon_enable_h,
+ .ctrlbit = S3C2443_HCLKCON_LCDC,
+ }, {
+ .name = "gpio",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2443_clkcon_enable_p,
+ .ctrlbit = S3C2443_PCLKCON_GPIO,
+ }, {
+ .name = "usb-host",
+ .id = -1,
+ .parent = &clk_h,
+ .enable = s3c2443_clkcon_enable_h,
+ .ctrlbit = S3C2443_HCLKCON_USBH,
+ }, {
+ .name = "usb-device",
+ .id = -1,
+ .parent = &clk_h,
+ .enable = s3c2443_clkcon_enable_h,
+ .ctrlbit = S3C2443_HCLKCON_USBD,
+ }, {
+ .name = "timers",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2443_clkcon_enable_p,
+ .ctrlbit = S3C2443_PCLKCON_PWMT,
+ }, {
+ .name = "uart",
+ .id = 0,
+ .parent = &clk_p,
+ .enable = s3c2443_clkcon_enable_p,
+ .ctrlbit = S3C2443_PCLKCON_UART0,
+ }, {
+ .name = "uart",
+ .id = 1,
+ .parent = &clk_p,
+ .enable = s3c2443_clkcon_enable_p,
+ .ctrlbit = S3C2443_PCLKCON_UART1,
+ }, {
+ .name = "uart",
+ .id = 2,
+ .parent = &clk_p,
+ .enable = s3c2443_clkcon_enable_p,
+ .ctrlbit = S3C2443_PCLKCON_UART2,
+ }, {
+ .name = "uart",
+ .id = 3,
+ .parent = &clk_p,
+ .enable = s3c2443_clkcon_enable_p,
+ .ctrlbit = S3C2443_PCLKCON_UART3,
+ }, {
+ .name = "rtc",
+ .id = -1,
+ .parent = &clk_p,
+ .enable = s3c2443_clkcon_enable_p,
+ .ctrlbit = S3C2443_PCLKCON_RTC,
+ }, {
+ .name = "watchdog",
+ .id = -1,
+ .parent = &clk_p,
+ .ctrlbit = S3C2443_PCLKCON_WDT,
+ }, {
+ .name = "usb-bus-host",
+ .id = -1,
+ .parent = &clk_usb_bus_host,
+ }
+};
+
+/* clocks to add where we need to check their parentage */
+
+/* s3c2443_clk_initparents
+ *
+ * Initialise the parents for the clocks that we get at start-time
+*/
+
+static int __init clk_init_set_parent(struct clk *clk, struct clk *parent)
+{
+ printk(KERN_DEBUG "clock %s: parent %s\n", clk->name, parent->name);
+ return clk_set_parent(clk, parent);
+}
+
+static void __init s3c2443_clk_initparents(void)
+{
+ unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
+ struct clk *parent;
+
+ switch (clksrc & S3C2443_CLKSRC_EPLLREF_MASK) {
+ case S3C2443_CLKSRC_EPLLREF_EXTCLK:
+ parent = &clk_ext;
+ break;
+
+ case S3C2443_CLKSRC_EPLLREF_XTAL:
+ default:
+ parent = &clk_xtal;
+ break;
+
+ case S3C2443_CLKSRC_EPLLREF_MPLLREF:
+ case S3C2443_CLKSRC_EPLLREF_MPLLREF2:
+ parent = &clk_mpllref;
+ break;
+ }
+
+ clk_init_set_parent(&clk_epllref, parent);
+
+ switch (clksrc & S3C2443_CLKSRC_I2S_MASK) {
+ case S3C2443_CLKSRC_I2S_EXT:
+ parent = &clk_i2s_ext;
+ break;
+
+ case S3C2443_CLKSRC_I2S_EPLLDIV:
+ default:
+ parent = &clk_i2s_eplldiv;
+ break;
+
+ case S3C2443_CLKSRC_I2S_EPLLREF:
+ case S3C2443_CLKSRC_I2S_EPLLREF3:
+ parent = &clk_epllref;
+ }
+
+ clk_init_set_parent(&clk_i2s, &clk_epllref);
+
+ /* esysclk source */
+
+ parent = (clksrc & S3C2443_CLKSRC_ESYSCLK_EPLL) ?
+ &clk_epll : &clk_epllref;
+
+ clk_init_set_parent(&clk_esysclk, parent);
+
+ /* msysclk source */
+
+ if (clksrc & S3C2443_CLKSRC_MSYSCLK_MPLL) {
+ parent = &clk_mpll;
+ } else {
+ parent = (clksrc & S3C2443_CLKSRC_EXTCLK_DIV) ?
+ &clk_mdivclk : &clk_mpllref;
+ }
+
+ clk_init_set_parent(&clk_msysclk, parent);
+}
+
+/* armdiv divisor table */
+
+static unsigned int armdiv[16] = {
+ [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 1,
+ [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 2,
+ [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 3,
+ [S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 4,
+ [S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 6,
+ [S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 8,
+ [S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 12,
+ [S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 16,
+};
+
+static inline unsigned int s3c2443_fclk_div(unsigned long clkcon0)
+{
+ clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK;
+
+ return armdiv[clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT];
+}
+
+static inline unsigned long s3c2443_get_prediv(unsigned long clkcon0)
+{
+ clkcon0 &= S3C2443_CLKDIV0_PREDIV_MASK;
+ clkcon0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT;
+
+ return clkcon0 + 1;
+}
+
+/* clocks to add straight away */
+
+static struct clk *clks[] __initdata = {
+ &clk_ext,
+ &clk_epll,
+ &clk_usb_bus_host,
+ &clk_usb_bus,
+ &clk_esysclk,
+ &clk_epllref,
+ &clk_mpllref,
+ &clk_msysclk,
+ &clk_uart,
+ &clk_display,
+ &clk_cam,
+ &clk_i2s_eplldiv,
+ &clk_i2s,
+ &clk_hsspi,
+ &clk_hsmmc_div,
+ &clk_hsmmc,
+};
+
+void __init s3c2443_init_clocks(int xtal)
+{
+ unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
+ unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON);
+ unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
+ unsigned long pll;
+ unsigned long fclk;
+ unsigned long hclk;
+ unsigned long pclk;
+ struct clk *clkp;
+ int ret;
+ int ptr;
+
+ pll = s3c2443_get_mpll(mpllcon, xtal);
+
+ fclk = pll / s3c2443_fclk_div(clkdiv0);
+ hclk = fclk / s3c2443_get_prediv(clkdiv0);
+ hclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_HCLK) ? 2 : 1);
+ pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1);
+
+ s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
+
+ printk("S3C2443: mpll %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n",
+ (mpllcon & S3C2443_PLLCON_OFF) ? "off":"on",
+ print_mhz(pll), print_mhz(fclk),
+ print_mhz(hclk), print_mhz(pclk));
+
+ s3c2443_clk_initparents();
+
+ for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
+ clkp = clks[ptr];
+
+ ret = s3c24xx_register_clock(clkp);
+ if (ret < 0) {
+ printk(KERN_ERR "Failed to register clock %s (%d)\n",
+ clkp->name, ret);
+ }
+ }
+
+ clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
+
+ clk_usb_bus.parent = &clk_usb_bus_host;
+
+ /* ensure usb bus clock is within correct rate of 48MHz */
+
+ if (clk_get_rate(&clk_usb_bus_host) != (48 * 1000 * 1000)) {
+ printk(KERN_INFO "Warning: USB host bus not at 48MHz\n");
+ clk_set_rate(&clk_usb_bus_host, 48*1000*1000);
+ }
+
+ printk("S3C2443: epll %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
+ (epllcon & S3C2443_PLLCON_OFF) ? "off":"on",
+ print_mhz(clk_get_rate(&clk_epll)),
+ print_mhz(clk_get_rate(&clk_usb_bus)));
+
+ /* register clocks from clock array */
+
+ clkp = init_clocks;
+ for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
+ ret = s3c24xx_register_clock(clkp);
+ if (ret < 0) {
+ printk(KERN_ERR "Failed to register clock %s (%d)\n",
+ clkp->name, ret);
+ }
+ }
+
+ /* We must be careful disabling the clocks we are not intending to
+ * be using at boot time, as subsytems such as the LCD which do
+ * their own DMA requests to the bus can cause the system to lockup
+ * if they where in the middle of requesting bus access.
+ *
+ * Disabling the LCD clock if the LCD is active is very dangerous,
+ * and therefore the bootloader should be careful to not enable
+ * the LCD clock if it is not needed.
+ */
+
+ /* install (and disable) the clocks we do not need immediately */
+
+ clkp = init_clocks_disable;
+ for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
+
+ ret = s3c24xx_register_clock(clkp);
+ if (ret < 0) {
+ printk(KERN_ERR "Failed to register clock %s (%d)\n",
+ clkp->name, ret);
+ }
+
+ (clkp->enable)(clkp, 0);
+ }
+}
diff --git a/arch/arm/mach-s3c2443/dma.c b/arch/arm/mach-s3c2443/dma.c
new file mode 100644
index 00000000000..f70e8ccffc3
--- /dev/null
+++ b/arch/arm/mach-s3c2443/dma.c
@@ -0,0 +1,180 @@
+/* linux/arch/arm/mach-s3c2443/dma.c
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2443 DMA selection
+ *
+ * http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sysdev.h>
+#include <linux/serial_core.h>
+
+#include <asm/dma.h>
+#include <asm/arch/dma.h>
+#include <asm/io.h>
+
+#include <asm/plat-s3c24xx/dma.h>
+#include <asm/plat-s3c24xx/cpu.h>
+
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-ac97.h>
+#include <asm/arch/regs-mem.h>
+#include <asm/arch/regs-lcd.h>
+#include <asm/arch/regs-sdi.h>
+#include <asm/arch/regs-iis.h>
+#include <asm/arch/regs-spi.h>
+
+#define MAP(x) { \
+ [0] = (x) | DMA_CH_VALID, \
+ [1] = (x) | DMA_CH_VALID, \
+ [2] = (x) | DMA_CH_VALID, \
+ [3] = (x) | DMA_CH_VALID, \
+ [4] = (x) | DMA_CH_VALID, \
+ [5] = (x) | DMA_CH_VALID, \
+ }
+
+static struct s3c24xx_dma_map __initdata s3c2443_dma_mappings[] = {
+ [DMACH_XD0] = {
+ .name = "xdreq0",
+ .channels = MAP(S3C2443_DMAREQSEL_XDREQ0),
+ },
+ [DMACH_XD1] = {
+ .name = "xdreq1",
+ .channels = MAP(S3C2443_DMAREQSEL_XDREQ1),
+ },
+ [DMACH_SDI] = {
+ .name = "sdi",
+ .channels = MAP(S3C2443_DMAREQSEL_SDI),
+ .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
+ .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
+ },
+ [DMACH_SPI0] = {
+ .name = "spi0",
+ .channels = MAP(S3C2443_DMAREQSEL_SPI0TX),
+ .hw_addr.to = S3C2410_PA_SPI + S3C2410_SPTDAT,
+ .hw_addr.from = S3C2410_PA_SPI + S3C2410_SPRDAT,
+ },
+ [DMACH_SPI1] = {
+ .name = "spi1",
+ .channels = MAP(S3C2443_DMAREQSEL_SPI1TX),
+ .hw_addr.to = S3C2410_PA_SPI + 0x20 + S3C2410_SPTDAT,
+ .hw_addr.from = S3C2410_PA_SPI + 0x20 + S3C2410_SPRDAT,
+ },
+ [DMACH_UART0] = {
+ .name = "uart0",
+ .channels = MAP(S3C2443_DMAREQSEL_UART0_0),
+ .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH,
+ .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH,
+ },
+ [DMACH_UART1] = {
+ .name = "uart1",
+ .channels = MAP(S3C2443_DMAREQSEL_UART1_0),
+ .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH,
+ .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH,
+ },
+ [DMACH_UART2] = {
+ .name = "uart2",
+ .channels = MAP(S3C2443_DMAREQSEL_UART2_0),
+ .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH,
+ .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH,
+ },
+ [DMACH_UART3] = {
+ .name = "uart3",
+ .channels = MAP(S3C2443_DMAREQSEL_UART3_0),
+ .hw_addr.to = S3C2443_PA_UART3 + S3C2410_UTXH,
+ .hw_addr.from = S3C2443_PA_UART3 + S3C2410_URXH,
+ },
+ [DMACH_UART0_SRC2] = {
+ .name = "uart0",
+ .channels = MAP(S3C2443_DMAREQSEL_UART0_1),
+ .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH,
+ .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH,
+ },
+ [DMACH_UART1_SRC2] = {
+ .name = "uart1",
+ .channels = MAP(S3C2443_DMAREQSEL_UART1_1),
+ .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH,
+ .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH,
+ },
+ [DMACH_UART2_SRC2] = {
+ .name = "uart2",
+ .channels = MAP(S3C2443_DMAREQSEL_UART2_1),
+ .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH,
+ .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH,
+ },
+ [DMACH_UART3_SRC2] = {
+ .name = "uart3",
+ .channels = MAP(S3C2443_DMAREQSEL_UART3_1),
+ .hw_addr.to = S3C2443_PA_UART3 + S3C2410_UTXH,
+ .hw_addr.from = S3C2443_PA_UART3 + S3C2410_URXH,
+ },
+ [DMACH_TIMER] = {
+ .name = "timer",
+ .channels = MAP(S3C2443_DMAREQSEL_TIMER),
+ },
+ [DMACH_I2S_IN] = {
+ .name = "i2s-sdi",
+ .channels = MAP(S3C2443_DMAREQSEL_I2SRX),
+ .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
+ },
+ [DMACH_I2S_OUT] = {
+ .name = "i2s-sdo",
+ .channels = MAP(S3C2443_DMAREQSEL_I2STX),
+ .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
+ },
+ [DMACH_PCM_IN] = {
+ .name = "pcm-in",
+ .channels = MAP(S3C2443_DMAREQSEL_PCMIN),
+ .hw_addr.from = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
+ },
+ [DMACH_PCM_OUT] = {
+ .name = "pcm-out",
+ .channels = MAP(S3C2443_DMAREQSEL_PCMOUT),
+ .hw_addr.to = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
+ },
+ [DMACH_MIC_IN] = {
+ .name = "mic-in",
+ .channels = MAP(S3C2443_DMAREQSEL_MICIN),
+ .hw_addr.from = S3C2440_PA_AC97 + S3C_AC97_MIC_DATA,
+ },
+};
+
+static void s3c2443_dma_select(struct s3c2410_dma_chan *chan,
+ struct s3c24xx_dma_map *map)
+{
+ writel(map->channels[0] | S3C2443_DMAREQSEL_HW,
+ chan->regs + S3C2443_DMA_DMAREQSEL);
+}
+
+static struct s3c24xx_dma_selection __initdata s3c2443_dma_sel = {
+ .select = s3c2443_dma_select,
+ .dcon_mask = 0,
+ .map = s3c2443_dma_mappings,
+ .map_size = ARRAY_SIZE(s3c2443_dma_mappings),
+};
+
+static int s3c2443_dma_add(struct sys_device *sysdev)
+{
+ s3c24xx_dma_init(6, IRQ_S3C2443_DMA0, 0x100);
+ return s3c24xx_dma_init_map(&s3c2443_dma_sel);
+}
+
+static struct sysdev_driver s3c2443_dma_driver = {
+ .add = s3c2443_dma_add,
+};
+
+static int __init s3c2443_dma_init(void)
+{
+ return sysdev_driver_register(&s3c2443_sysclass, &s3c2443_dma_driver);
+}
+
+arch_initcall(s3c2443_dma_init);
diff --git a/arch/arm/mach-s3c2443/irq.c b/arch/arm/mach-s3c2443/irq.c
new file mode 100644
index 00000000000..7a45b6dcb73
--- /dev/null
+++ b/arch/arm/mach-s3c2443/irq.c
@@ -0,0 +1,290 @@
+/* linux/arch/arm/mach-s3c2443/irq.c
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/ptrace.h>
+#include <linux/sysdev.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/mach/irq.h>
+
+#include <asm/arch/regs-irq.h>
+#include <asm/arch/regs-gpio.h>
+
+#include <asm/plat-s3c24xx/cpu.h>
+#include <asm/plat-s3c24xx/pm.h>
+#include <asm/plat-s3c24xx/irq.h>
+
+#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)
+
+static inline void s3c2443_irq_demux(unsigned int irq, unsigned int len)
+{
+ unsigned int subsrc, submsk;
+ unsigned int end;
+ struct irq_desc *mydesc;
+
+ /* read the current pending interrupts, and the mask
+ * for what it is available */
+
+ subsrc = __raw_readl(S3C2410_SUBSRCPND);
+ submsk = __raw_readl(S3C2410_INTSUBMSK);
+
+ subsrc &= ~submsk;
+ subsrc >>= (irq - S3C2410_IRQSUB(0));
+ subsrc &= (1 << len)-1;
+
+ end = len + irq;
+ mydesc = irq_desc + irq;
+
+ for (; irq < end && subsrc; irq++) {
+ if (subsrc & 1)
+ desc_handle_irq(irq, mydesc);
+
+ mydesc++;
+ subsrc >>= 1;
+ }
+}
+
+/* WDT/AC97 sub interrupts */
+
+static void s3c2443_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc)
+{
+ s3c2443_irq_demux(IRQ_S3C2443_WDT, 4);
+}
+
+#define INTMSK_WDTAC97 (1UL << (IRQ_WDT - IRQ_EINT0))
+#define SUBMSK_WDTAC97 INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97)
+
+static void s3c2443_irq_wdtac97_mask(unsigned int irqno)
+{
+ s3c_irqsub_mask(irqno, INTMSK_WDTAC97, SUBMSK_WDTAC97);
+}
+
+static void s3c2443_irq_wdtac97_unmask(unsigned int irqno)
+{
+ s3c_irqsub_unmask(irqno, INTMSK_WDTAC97);
+}
+
+static void s3c2443_irq_wdtac97_ack(unsigned int irqno)
+{
+ s3c_irqsub_maskack(irqno, INTMSK_WDTAC97, SUBMSK_WDTAC97);
+}
+
+static struct irq_chip s3c2443_irq_wdtac97 = {
+ .mask = s3c2443_irq_wdtac97_mask,
+ .unmask = s3c2443_irq_wdtac97_unmask,
+ .ack = s3c2443_irq_wdtac97_ack,
+};
+
+
+/* LCD sub interrupts */
+
+static void s3c2443_irq_demux_lcd(unsigned int irq, struct irq_desc *desc)
+{
+ s3c2443_irq_demux(IRQ_S3C2443_LCD1, 4);
+}
+
+#define INTMSK_LCD (1UL << (IRQ_LCD - IRQ_EINT0))
+#define SUBMSK_LCD INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4)
+
+static void s3c2443_irq_lcd_mask(unsigned int irqno)
+{
+ s3c_irqsub_mask(irqno, INTMSK_LCD, SUBMSK_LCD);
+}
+
+static void s3c2443_irq_lcd_unmask(unsigned int irqno)
+{
+ s3c_irqsub_unmask(irqno, INTMSK_LCD);
+}
+
+static void s3c2443_irq_lcd_ack(unsigned int irqno)
+{
+ s3c_irqsub_maskack(irqno, INTMSK_LCD, SUBMSK_LCD);
+}
+
+static struct irq_chip s3c2443_irq_lcd = {
+ .mask = s3c2443_irq_lcd_mask,
+ .unmask = s3c2443_irq_lcd_unmask,
+ .ack = s3c2443_irq_lcd_ack,
+};
+
+
+/* DMA sub interrupts */
+
+static void s3c2443_irq_demux_dma(unsigned int irq, struct irq_desc *desc)
+{
+ s3c2443_irq_demux(IRQ_S3C2443_DMA1, 6);
+}
+
+#define INTMSK_DMA (1UL << (IRQ_S3C2443_DMA - IRQ_EINT0))
+#define SUBMSK_DMA INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5)
+
+
+static void s3c2443_irq_dma_mask(unsigned int irqno)
+{
+ s3c_irqsub_mask(irqno, INTMSK_DMA, SUBMSK_DMA);
+}
+
+static void s3c2443_irq_dma_unmask(unsigned int irqno)
+{
+ s3c_irqsub_unmask(irqno, INTMSK_DMA);
+}
+
+static void s3c2443_irq_dma_ack(unsigned int irqno)
+{
+ s3c_irqsub_maskack(irqno, INTMSK_DMA, SUBMSK_DMA);
+}
+
+static struct irq_chip s3c2443_irq_dma = {
+ .mask = s3c2443_irq_dma_mask,
+ .unmask = s3c2443_irq_dma_unmask,
+ .ack = s3c2443_irq_dma_ack,
+};
+
+
+/* UART3 sub interrupts */
+
+static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
+{
+ s3c2443_irq_demux(IRQ_S3C2443_UART3, 3);
+}
+
+#define INTMSK_UART3 (1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
+#define SUBMSK_UART3 (0xf << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
+
+
+static void s3c2443_irq_uart3_mask(unsigned int irqno)
+{
+ s3c_irqsub_mask(irqno, INTMSK_UART3, SUBMSK_UART3);
+}
+
+static void s3c2443_irq_uart3_unmask(unsigned int irqno)
+{
+ s3c_irqsub_unmask(irqno, INTMSK_UART3);
+}
+
+static void s3c2443_irq_uart3_ack(unsigned int irqno)
+{
+ s3c_irqsub_maskack(irqno, INTMSK_UART3, SUBMSK_UART3);
+}
+
+static struct irq_chip s3c2443_irq_uart3 = {
+ .mask = s3c2443_irq_uart3_mask,
+ .unmask = s3c2443_irq_uart3_unmask,
+ .ack = s3c2443_irq_uart3_ack,
+};
+
+
+/* CAM sub interrupts */
+
+static void s3c2443_irq_demux_cam(unsigned int irq, struct irq_desc *desc)
+{
+ s3c2443_irq_demux(IRQ_S3C2440_CAM_C, 4);
+}
+
+#define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0))
+#define SUBMSK_CAM INTMSK(IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P)
+
+static void s3c2443_irq_cam_mask(unsigned int irqno)
+{
+ s3c_irqsub_mask(irqno, INTMSK_CAM, SUBMSK_CAM);
+}
+
+static void s3c2443_irq_cam_unmask(unsigned int irqno)
+{
+ s3c_irqsub_unmask(irqno, INTMSK_CAM);
+}
+
+static void s3c2443_irq_cam_ack(unsigned int irqno)
+{
+ s3c_irqsub_maskack(irqno, INTMSK_CAM, SUBMSK_CAM);
+}
+
+static struct irq_chip s3c2443_irq_cam = {
+ .mask = s3c2443_irq_cam_mask,
+ .unmask = s3c2443_irq_cam_unmask,
+ .ack = s3c2443_irq_cam_ack,
+};
+
+/* IRQ initialisation code */
+
+static int __init s3c2443_add_sub(unsigned int base,
+ void (*demux)(unsigned int,
+ struct irq_desc *),
+ struct irq_chip *chip,
+ unsigned int start, unsigned int end)
+{
+ unsigned int irqno;
+
+ set_irq_chip(base, &s3c_irq_level_chip);
+ set_irq_handler(base, handle_level_irq);
+ set_irq_chained_handler(base, demux);
+
+ for (irqno = start; irqno <= end; irqno++) {
+ set_irq_chip(irqno, chip);
+ set_irq_handler(irqno, handle_level_irq);
+ set_irq_flags(irqno, IRQF_VALID);
+ }
+
+ return 0;
+}
+
+static int s3c2443_irq_add(struct sys_device *sysdev)
+{
+ printk("S3C2443: IRQ Support\n");
+
+ s3c2443_add_sub(IRQ_CAM, s3c2443_irq_demux_cam, &s3c2443_irq_cam,
+ IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P);
+
+ s3c2443_add_sub(IRQ_LCD, s3c2443_irq_demux_lcd, &s3c2443_irq_lcd,
+ IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4);
+
+ s3c2443_add_sub(IRQ_S3C2443_DMA, s3c2443_irq_demux_dma,
+ &s3c2443_irq_dma, IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5);
+
+ s3c2443_add_sub(IRQ_S3C2443_UART3, s3c2443_irq_demux_uart3,
+ &s3c2443_irq_uart3,
+ IRQ_S3C2443_RX3, IRQ_S3C2443_ERR3);
+
+ s3c2443_add_sub(IRQ_WDT, s3c2443_irq_demux_wdtac97,
+ &s3c2443_irq_wdtac97,
+ IRQ_S3C2443_WDT, IRQ_S3C2443_AC97);
+
+ return 0;
+}
+
+static struct sysdev_driver s3c2443_irq_driver = {
+ .add = s3c2443_irq_add,
+};
+
+static int s3c2443_irq_init(void)
+{
+ return sysdev_driver_register(&s3c2443_sysclass, &s3c2443_irq_driver);
+}
+
+arch_initcall(s3c2443_irq_init);
+
diff --git a/arch/arm/mach-s3c2443/mach-smdk2443.c b/arch/arm/mach-s3c2443/mach-smdk2443.c
new file mode 100644
index 00000000000..e82aaff7dee
--- /dev/null
+++ b/arch/arm/mach-s3c2443/mach-smdk2443.c
@@ -0,0 +1,137 @@
+/* linux/arch/arm/mach-s3c2443/mach-smdk2443.c
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://www.fluff.org/ben/smdk2443/
+ *
+ * Thanks to Samsung for the loan of an SMDK2443
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-lcd.h>
+
+#include <asm/arch/idle.h>
+#include <asm/arch/fb.h>
+
+#include <asm/plat-s3c24xx/s3c2410.h>
+#include <asm/plat-s3c24xx/s3c2440.h>
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/cpu.h>
+
+#include <asm/plat-s3c24xx/common-smdk.h>
+
+static struct map_desc smdk2443_iodesc[] __initdata = {
+ /* ISA IO Space map (memory space selected by A24) */
+
+ {
+ .virtual = (u32)S3C24XX_VA_ISA_WORD,
+ .pfn = __phys_to_pfn(S3C2410_CS2),
+ .length = 0x10000,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = (u32)S3C24XX_VA_ISA_WORD + 0x10000,
+ .pfn = __phys_to_pfn(S3C2410_CS2 + (1<<24)),
+ .length = SZ_4M,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = (u32)S3C24XX_VA_ISA_BYTE,
+ .pfn = __phys_to_pfn(S3C2410_CS2),
+ .length = 0x10000,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = (u32)S3C24XX_VA_ISA_BYTE + 0x10000,
+ .pfn = __phys_to_pfn(S3C2410_CS2 + (1<<24)),
+ .length = SZ_4M,
+ .type = MT_DEVICE,
+ }
+};
+
+#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg smdk2443_uartcfgs[] __initdata = {
+ [0] = {
+ .hwport = 0,
+ .flags = 0,
+ .ucon = 0x3c5,
+ .ulcon = 0x03,
+ .ufcon = 0x51,
+ },
+ [1] = {
+ .hwport = 1,
+ .flags = 0,
+ .ucon = 0x3c5,
+ .ulcon = 0x03,
+ .ufcon = 0x51,
+ },
+ /* IR port */
+ [2] = {
+ .hwport = 2,
+ .flags = 0,
+ .ucon = 0x3c5,
+ .ulcon = 0x43,
+ .ufcon = 0x51,
+ }
+};
+
+static struct platform_device *smdk2443_devices[] __initdata = {
+ &s3c_device_wdt,
+ &s3c_device_i2c,
+};
+
+static struct s3c24xx_board smdk2443_board __initdata = {
+ .devices = smdk2443_devices,
+ .devices_count = ARRAY_SIZE(smdk2443_devices)
+};
+
+static void __init smdk2443_map_io(void)
+{
+ s3c24xx_init_io(smdk2443_iodesc, ARRAY_SIZE(smdk2443_iodesc));
+ s3c24xx_init_clocks(12000000);
+ s3c24xx_init_uarts(smdk2443_uartcfgs, ARRAY_SIZE(smdk2443_uartcfgs));
+ s3c24xx_set_board(&smdk2443_board);
+}
+
+static void __init smdk2443_machine_init(void)
+{
+ smdk_machine_init();
+}
+
+MACHINE_START(SMDK2443, "SMDK2443")
+ /* Maintainer: Ben Dooks <ben@fluff.org> */
+ .phys_io = S3C2410_PA_UART,
+ .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
+ .boot_params = S3C2410_SDRAM_PA + 0x100,
+
+ .init_irq = s3c24xx_init_irq,
+ .map_io = smdk2443_map_io,
+ .init_machine = smdk2443_machine_init,
+ .timer = &s3c24xx_timer,
+MACHINE_END
diff --git a/arch/arm/mach-s3c2443/s3c2443.c b/arch/arm/mach-s3c2443/s3c2443.c
new file mode 100644
index 00000000000..11b1d0b310c
--- /dev/null
+++ b/arch/arm/mach-s3c2443/s3c2443.c
@@ -0,0 +1,97 @@
+/* linux/arch/arm/mach-s3c2443/s3c2443.c
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Samsung S3C2443 Mobile CPU support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/sysdev.h>
+#include <linux/clk.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/arch/regs-s3c2443-clock.h>
+#include <asm/arch/reset.h>
+
+#include <asm/plat-s3c24xx/s3c2443.h>
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/cpu.h>
+
+static struct map_desc s3c2443_iodesc[] __initdata = {
+ IODESC_ENT(WATCHDOG),
+ IODESC_ENT(CLKPWR),
+ IODESC_ENT(TIMER),
+};
+
+struct sysdev_class s3c2443_sysclass = {
+ set_kset_name("s3c2443-core"),
+};
+
+static struct sys_device s3c2443_sysdev = {
+ .cls = &s3c2443_sysclass,
+};
+
+static void s3c2443_hard_reset(void)
+{
+ __raw_writel(S3C2443_SWRST_RESET, S3C2443_SWRST);
+}
+
+int __init s3c2443_init(void)
+{
+ printk("S3C2443: Initialising architecture\n");
+
+ s3c24xx_reset_hook = s3c2443_hard_reset;
+
+ s3c_device_nand.name = "s3c2412-nand";
+
+ return sysdev_register(&s3c2443_sysdev);
+}
+
+void __init s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+ s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no);
+}
+
+/* s3c2443_map_io
+ *
+ * register the standard cpu IO areas, and any passed in from the
+ * machine specific initialisation.
+ */
+
+void __init s3c2443_map_io(struct map_desc *mach_desc, int mach_size)
+{
+ iotable_init(s3c2443_iodesc, ARRAY_SIZE(s3c2443_iodesc));
+ iotable_init(mach_desc, mach_size);
+}
+
+/* need to register class before we actually register the device, and
+ * we also need to ensure that it has been initialised before any of the
+ * drivers even try to use it (even if not on an s3c2443 based system)
+ * as a driver which may support both 2443 and 2440 may try and use it.
+*/
+
+static int __init s3c2443_core_init(void)
+{
+ return sysdev_class_register(&s3c2443_sysclass);
+}
+
+core_initcall(s3c2443_core_init);
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index b305cbda8b8..da8f043dc2c 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -609,3 +609,10 @@ config NEEDS_SYSCALL_FOR_CMPXCHG
Forget about fast user space cmpxchg support.
It is just not possible.
+config OUTER_CACHE
+ bool
+ default n
+
+config CACHE_L2X0
+ bool
+ select OUTER_CACHE
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index d2f5672ecf6..2f8b9594777 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -66,3 +66,5 @@ obj-$(CONFIG_CPU_SA1100) += proc-sa1100.o
obj-$(CONFIG_CPU_XSCALE) += proc-xscale.o
obj-$(CONFIG_CPU_XSC3) += proc-xsc3.o
obj-$(CONFIG_CPU_V6) += proc-v6.o
+
+obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
new file mode 100644
index 00000000000..08a36f1b35d
--- /dev/null
+++ b/arch/arm/mm/cache-l2x0.c
@@ -0,0 +1,104 @@
+/*
+ * arch/arm/mm/cache-l2x0.c - L210/L220 cache controller support
+ *
+ * Copyright (C) 2007 ARM Limited
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/init.h>
+
+#include <asm/cacheflush.h>
+#include <asm/io.h>
+#include <asm/hardware/cache-l2x0.h>
+
+#define CACHE_LINE_SIZE 32
+
+static void __iomem *l2x0_base;
+
+static inline void sync_writel(unsigned long val, unsigned long reg,
+ unsigned long complete_mask)
+{
+ writel(val, l2x0_base + reg);
+ /* wait for the operation to complete */
+ while (readl(l2x0_base + reg) & complete_mask)
+ ;
+}
+
+static inline void cache_sync(void)
+{
+ sync_writel(0, L2X0_CACHE_SYNC, 1);
+}
+
+static inline void l2x0_inv_all(void)
+{
+ /* invalidate all ways */
+ sync_writel(0xff, L2X0_INV_WAY, 0xff);
+ cache_sync();
+}
+
+static void l2x0_inv_range(unsigned long start, unsigned long end)
+{
+ unsigned long addr;
+
+ start &= ~(CACHE_LINE_SIZE - 1);
+ for (addr = start; addr < end; addr += CACHE_LINE_SIZE)
+ sync_writel(addr, L2X0_INV_LINE_PA, 1);
+ cache_sync();
+}
+
+static void l2x0_clean_range(unsigned long start, unsigned long end)
+{
+ unsigned long addr;
+
+ start &= ~(CACHE_LINE_SIZE - 1);
+ for (addr = start; addr < end; addr += CACHE_LINE_SIZE)
+ sync_writel(addr, L2X0_CLEAN_LINE_PA, 1);
+ cache_sync();
+}
+
+static void l2x0_flush_range(unsigned long start, unsigned long end)
+{
+ unsigned long addr;
+
+ start &= ~(CACHE_LINE_SIZE - 1);
+ for (addr = start; addr < end; addr += CACHE_LINE_SIZE)
+ sync_writel(addr, L2X0_CLEAN_INV_LINE_PA, 1);
+ cache_sync();
+}
+
+void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
+{
+ __u32 aux;
+
+ l2x0_base = base;
+
+ /* disable L2X0 */
+ writel(0, l2x0_base + L2X0_CTRL);
+
+ aux = readl(l2x0_base + L2X0_AUX_CTRL);
+ aux &= aux_mask;
+ aux |= aux_val;
+ writel(aux, l2x0_base + L2X0_AUX_CTRL);
+
+ l2x0_inv_all();
+
+ /* enable L2X0 */
+ writel(1, l2x0_base + L2X0_CTRL);
+
+ outer_cache.inv_range = l2x0_inv_range;
+ outer_cache.clean_range = l2x0_clean_range;
+ outer_cache.flush_range = l2x0_flush_range;
+
+ printk(KERN_INFO "L2X0 cache controller enabled\n");
+}
diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c
index 6a9c362fef5..1f9f94f9af4 100644
--- a/arch/arm/mm/consistent.c
+++ b/arch/arm/mm/consistent.c
@@ -205,9 +205,10 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
* kernel direct-mapped region for device DMA.
*/
{
- unsigned long kaddr = (unsigned long)page_address(page);
- memset(page_address(page), 0, size);
- dmac_flush_range(kaddr, kaddr + size);
+ void *ptr = page_address(page);
+ memset(ptr, 0, size);
+ dmac_flush_range(ptr, ptr + size);
+ outer_flush_range(__pa(ptr), __pa(ptr) + size);
}
/*
@@ -480,20 +481,24 @@ core_initcall(consistent_init);
* platforms with CONFIG_DMABOUNCE.
* Use the driver DMA support - see dma-mapping.h (dma_sync_*)
*/
-void consistent_sync(void *vaddr, size_t size, int direction)
+void consistent_sync(const void *start, size_t size, int direction)
{
- unsigned long start = (unsigned long)vaddr;
- unsigned long end = start + size;
+ const void *end = start + size;
+
+ BUG_ON(!virt_addr_valid(start) || !virt_addr_valid(end - 1));
switch (direction) {
case DMA_FROM_DEVICE: /* invalidate only */
dmac_inv_range(start, end);
+ outer_inv_range(__pa(start), __pa(end));
break;
case DMA_TO_DEVICE: /* writeback only */
dmac_clean_range(start, end);
+ outer_clean_range(__pa(start), __pa(end));
break;
case DMA_BIDIRECTIONAL: /* writeback and invalidate */
dmac_flush_range(start, end);
+ outer_flush_range(__pa(start), __pa(end));
break;
default:
BUG();
diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c
index 79e80020242..9da43a0fdcd 100644
--- a/arch/arm/mm/context.c
+++ b/arch/arm/mm/context.c
@@ -19,7 +19,8 @@ unsigned int cpu_last_asid = { 1 << ASID_BITS };
/*
* We fork()ed a process, and we need a new context for the child
* to run in. We reserve version 0 for initial tasks so we will
- * always allocate an ASID.
+ * always allocate an ASID. The ASID 0 is reserved for the TTBR
+ * register changing sequence.
*/
void __init_new_context(struct task_struct *tsk, struct mm_struct *mm)
{
@@ -38,8 +39,15 @@ void __new_context(struct mm_struct *mm)
* If we've used up all our ASIDs, we need
* to start a new version and flush the TLB.
*/
- if ((asid & ~ASID_MASK) == 0)
+ if ((asid & ~ASID_MASK) == 0) {
+ asid = ++cpu_last_asid;
+ /* set the reserved ASID before flushing the TLB */
+ asm("mcr p15, 0, %0, c13, c0, 1 @ set reserved context ID\n"
+ :
+ : "r" (0));
+ isb();
flush_tlb_all();
+ }
mm->context.id = asid;
}
diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c
index cf95c5d0ce4..44558d5f931 100644
--- a/arch/arm/mm/fault-armv.c
+++ b/arch/arm/mm/fault-armv.c
@@ -119,8 +119,6 @@ make_coherent(struct address_space *mapping, struct vm_area_struct *vma, unsigne
flush_cache_page(vma, addr, pfn);
}
-void __flush_dcache_page(struct address_space *mapping, struct page *page);
-
/*
* Take care of architecture specific things when placing a new PTE into
* a page table, or changing an existing PTE. Basically, there are two
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 655c8376f0b..94fd4bf5cb9 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -49,8 +49,10 @@ pmd_t *top_pmd;
static unsigned int cachepolicy __initdata = CPOLICY_WRITEBACK;
static unsigned int ecc_mask __initdata = 0;
+pgprot_t pgprot_user;
pgprot_t pgprot_kernel;
+EXPORT_SYMBOL(pgprot_user);
EXPORT_SYMBOL(pgprot_kernel);
struct cachepolicy {
@@ -345,6 +347,7 @@ static void __init build_mem_type_table(void)
mem_types[MT_MINICLEAN].prot_sect &= ~PMD_SECT_TEX(1);
}
+ pgprot_user = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | user_pgprot);
pgprot_kernel = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG |
L_PTE_DIRTY | L_PTE_WRITE |
L_PTE_EXEC | kern_pgprot);
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index 7b1843befb9..eb42e5b9486 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -14,10 +14,13 @@
#include <asm/assembler.h>
#include <asm/asm-offsets.h>
#include <asm/elf.h>
-#include <asm/hardware/arm_scu.h>
#include <asm/pgtable-hwdef.h>
#include <asm/pgtable.h>
+#ifdef CONFIG_SMP
+#include <asm/hardware/arm_scu.h>
+#endif
+
#include "proc-macros.S"
#define D_CACHE_LINE_SIZE 32
@@ -30,6 +33,12 @@
#define TTB_RGN_WT (2 << 3)
#define TTB_RGN_WB (3 << 3)
+#ifndef CONFIG_SMP
+#define TTB_FLAGS TTB_RGN_WBWA
+#else
+#define TTB_FLAGS TTB_RGN_WBWA|TTB_S
+#endif
+
ENTRY(cpu_v6_proc_init)
mov pc, lr
@@ -92,9 +101,7 @@ ENTRY(cpu_v6_switch_mm)
#ifdef CONFIG_MMU
mov r2, #0
ldr r1, [r1, #MM_CONTEXT_ID] @ get mm->context.id
-#ifdef CONFIG_SMP
- orr r0, r0, #TTB_RGN_WBWA|TTB_S @ mark PTWs shared, outer cacheable
-#endif
+ orr r0, r0, #TTB_FLAGS
mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB
mcr p15, 0, r2, c7, c10, 4 @ drain write buffer
mcr p15, 0, r0, c2, c0, 0 @ set TTB 0
@@ -183,8 +190,7 @@ __v6_setup:
/* Set up the SCU on core 0 only */
mrc p15, 0, r0, c0, c0, 5 @ CPU core number
ands r0, r0, #15
- moveq r0, #0x10000000 @ SCU_BASE
- orreq r0, r0, #0x00100000
+ ldreq r0, =SCU_BASE
ldreq r5, [r0, #SCU_CTRL]
orreq r5, r5, #1
streq r5, [r0, #SCU_CTRL]
@@ -204,9 +210,7 @@ __v6_setup:
#ifdef CONFIG_MMU
mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs
mcr p15, 0, r0, c2, c0, 2 @ TTB control register
-#ifdef CONFIG_SMP
- orr r4, r4, #TTB_RGN_WBWA|TTB_S @ mark PTWs shared, outer cacheable
-#endif
+ orr r4, r4, #TTB_FLAGS
mcr p15, 0, r4, c2, c0, 1 @ load TTB1
#endif /* CONFIG_MMU */
adr r5, v6_crval
diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S
index 94a58455f34..d95921a2ab9 100644
--- a/arch/arm/mm/proc-xsc3.S
+++ b/arch/arm/mm/proc-xsc3.S
@@ -5,23 +5,23 @@
* Current Maintainer: Lennert Buytenhek <buytenh@wantstofly.org>
*
* Copyright 2004 (C) Intel Corp.
- * Copyright 2005 (c) MontaVista Software, Inc.
+ * Copyright 2005 (C) MontaVista Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * MMU functions for the Intel XScale3 Core (XSC3). The XSC3 core is an
- * extension to Intel's original XScale core that adds the following
+ * MMU functions for the Intel XScale3 Core (XSC3). The XSC3 core is
+ * an extension to Intel's original XScale core that adds the following
* features:
*
* - ARMv6 Supersections
* - Low Locality Reference pages (replaces mini-cache)
* - 36-bit addressing
* - L2 cache
- * - Cache-coherency if chipset supports it
+ * - Cache coherency if chipset supports it
*
- * Based on orignal XScale code by Nicolas Pitre
+ * Based on original XScale code by Nicolas Pitre.
*/
#include <linux/linkage.h>
@@ -42,12 +42,12 @@
#define MAX_AREA_SIZE 32768
/*
- * The cache line size of the I and D cache.
+ * The cache line size of the L1 I, L1 D and unified L2 cache.
*/
#define CACHELINESIZE 32
/*
- * The size of the data cache.
+ * The size of the L1 D cache.
*/
#define CACHESIZE 32768
@@ -57,9 +57,9 @@
#define L2_CACHE_ENABLE 1
/*
- * This macro is used to wait for a CP15 write and is needed
- * when we have to ensure that the last operation to the co-pro
- * was completed before continuing with operation.
+ * This macro is used to wait for a CP15 write and is needed when we
+ * have to ensure that the last operation to the coprocessor was
+ * completed before continuing with operation.
*/
.macro cpwait_ret, lr, rd
mrc p15, 0, \rd, c2, c0, 0 @ arbitrary read of cp15
@@ -68,13 +68,13 @@
.endm
/*
- * This macro cleans & invalidates the entire xsc3 dcache by set & way.
+ * This macro cleans and invalidates the entire L1 D cache.
*/
.macro clean_d_cache rd, rs
mov \rd, #0x1f00
orr \rd, \rd, #0x00e0
-1: mcr p15, 0, \rd, c7, c14, 2 @ clean/inv set/way
+1: mcr p15, 0, \rd, c7, c14, 2 @ clean/invalidate L1 D line
adds \rd, \rd, #0x40000000
bcc 1b
subs \rd, \rd, #0x20
@@ -119,15 +119,15 @@ ENTRY(cpu_xsc3_reset)
mov r1, #PSR_F_BIT|PSR_I_BIT|SVC_MODE
msr cpsr_c, r1 @ reset CPSR
mrc p15, 0, r1, c1, c0, 0 @ ctrl register
- bic r1, r1, #0x0086 @ ........B....CA.
bic r1, r1, #0x3900 @ ..VIZ..S........
+ bic r1, r1, #0x0086 @ ........B....CA.
mcr p15, 0, r1, c1, c0, 0 @ ctrl register
- mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches & BTB
+ mcr p15, 0, ip, c7, c7, 0 @ invalidate L1 caches and BTB
bic r1, r1, #0x0001 @ ...............M
mcr p15, 0, r1, c1, c0, 0 @ ctrl register
@ CAUTION: MMU turned off from this point. We count on the pipeline
@ already containing those two last instructions to survive.
- mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
+ mcr p15, 0, ip, c8, c7, 0 @ invalidate I and D TLBs
mov pc, r0
/*
@@ -139,14 +139,12 @@ ENTRY(cpu_xsc3_reset)
*
* XScale supports clock switching, but using idle mode support
* allows external hardware to react to system state changes.
-
- MMG: Come back to this one.
*/
.align 5
ENTRY(cpu_xsc3_do_idle)
mov r0, #1
- mcr p14, 0, r0, c7, c0, 0 @ Go to IDLE
+ mcr p14, 0, r0, c7, c0, 0 @ go to idle
mov pc, lr
/* ================================= CACHE ================================ */
@@ -171,9 +169,9 @@ ENTRY(xsc3_flush_kern_cache_all)
__flush_whole_cache:
clean_d_cache r0, r1
tst r2, #VM_EXEC
- mcrne p15, 0, ip, c7, c5, 0 @ Invalidate I cache & BTB
- mcrne p15, 0, ip, c7, c10, 4 @ Drain Write Buffer
- mcrne p15, 0, ip, c7, c5, 4 @ Prefetch Flush
+ mcrne p15, 0, ip, c7, c5, 0 @ invalidate L1 I cache and BTB
+ mcrne p15, 0, ip, c7, c10, 4 @ data write barrier
+ mcrne p15, 0, ip, c7, c5, 4 @ prefetch flush
mov pc, lr
/*
@@ -194,21 +192,21 @@ ENTRY(xsc3_flush_user_cache_range)
bhs __flush_whole_cache
1: tst r2, #VM_EXEC
- mcrne p15, 0, r0, c7, c5, 1 @ Invalidate I cache line
- mcr p15, 0, r0, c7, c14, 1 @ Clean/invalidate D cache line
+ mcrne p15, 0, r0, c7, c5, 1 @ invalidate L1 I line
+ mcr p15, 0, r0, c7, c14, 1 @ clean/invalidate L1 D line
add r0, r0, #CACHELINESIZE
cmp r0, r1
blo 1b
tst r2, #VM_EXEC
- mcrne p15, 0, ip, c7, c5, 6 @ Invalidate BTB
- mcrne p15, 0, ip, c7, c10, 4 @ Drain Write Buffer
- mcrne p15, 0, ip, c7, c5, 4 @ Prefetch Flush
+ mcrne p15, 0, ip, c7, c5, 6 @ invalidate BTB
+ mcrne p15, 0, ip, c7, c10, 4 @ data write barrier
+ mcrne p15, 0, ip, c7, c5, 4 @ prefetch flush
mov pc, lr
/*
* coherent_kern_range(start, end)
*
- * Ensure coherency between the Icache and the Dcache in the
+ * Ensure coherency between the I cache and the D cache in the
* region described by start. If you have non-snooping
* Harvard caches, you need to implement this function.
*
@@ -222,34 +220,34 @@ ENTRY(xsc3_coherent_kern_range)
/* FALLTHROUGH */
ENTRY(xsc3_coherent_user_range)
bic r0, r0, #CACHELINESIZE - 1
-1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
+1: mcr p15, 0, r0, c7, c10, 1 @ clean L1 D line
add r0, r0, #CACHELINESIZE
cmp r0, r1
blo 1b
mov r0, #0
- mcr p15, 0, r0, c7, c5, 0 @ Invalidate I cache & BTB
- mcr p15, 0, r0, c7, c10, 4 @ Drain Write Buffer
- mcr p15, 0, r0, c7, c5, 4 @ Prefetch Flush
+ mcr p15, 0, r0, c7, c5, 0 @ invalidate L1 I cache and BTB
+ mcr p15, 0, r0, c7, c10, 4 @ data write barrier
+ mcr p15, 0, r0, c7, c5, 4 @ prefetch flush
mov pc, lr
/*
* flush_kern_dcache_page(void *page)
*
* Ensure no D cache aliasing occurs, either with itself or
- * the I cache
+ * the I cache.
*
* - addr - page aligned address
*/
ENTRY(xsc3_flush_kern_dcache_page)
add r1, r0, #PAGE_SZ
-1: mcr p15, 0, r0, c7, c14, 1 @ Clean/Invalidate D Cache line
+1: mcr p15, 0, r0, c7, c14, 1 @ clean/invalidate L1 D line
add r0, r0, #CACHELINESIZE
cmp r0, r1
blo 1b
mov r0, #0
- mcr p15, 0, r0, c7, c5, 0 @ Invalidate I cache & BTB
- mcr p15, 0, r0, c7, c10, 4 @ Drain Write Buffer
- mcr p15, 0, r0, c7, c5, 4 @ Prefetch Flush
+ mcr p15, 0, r0, c7, c5, 0 @ invalidate L1 I cache and BTB
+ mcr p15, 0, r0, c7, c10, 4 @ data write barrier
+ mcr p15, 0, r0, c7, c5, 4 @ prefetch flush
mov pc, lr
/*
@@ -266,17 +264,17 @@ ENTRY(xsc3_flush_kern_dcache_page)
ENTRY(xsc3_dma_inv_range)
tst r0, #CACHELINESIZE - 1
bic r0, r0, #CACHELINESIZE - 1
- mcrne p15, 0, r0, c7, c10, 1 @ clean L1 D entry
- mcrne p15, 1, r0, c7, c11, 1 @ clean L2 D entry
+ mcrne p15, 0, r0, c7, c10, 1 @ clean L1 D line
+ mcrne p15, 1, r0, c7, c11, 1 @ clean L2 line
tst r1, #CACHELINESIZE - 1
- mcrne p15, 0, r1, c7, c10, 1 @ clean L1 D entry
- mcrne p15, 1, r1, c7, c11, 1 @ clean L2 D entry
-1: mcr p15, 0, r0, c7, c6, 1 @ invalidate L1 D entry
- mcr p15, 1, r0, c7, c7, 1 @ Invalidate L2 D cache line
+ mcrne p15, 0, r1, c7, c10, 1 @ clean L1 D line
+ mcrne p15, 1, r1, c7, c11, 1 @ clean L2 line
+1: mcr p15, 0, r0, c7, c6, 1 @ invalidate L1 D line
+ mcr p15, 1, r0, c7, c7, 1 @ invalidate L2 line
add r0, r0, #CACHELINESIZE
cmp r0, r1
blo 1b
- mcr p15, 0, r0, c7, c10, 4 @ Drain Write Buffer
+ mcr p15, 0, r0, c7, c10, 4 @ data write barrier
mov pc, lr
/*
@@ -289,12 +287,12 @@ ENTRY(xsc3_dma_inv_range)
*/
ENTRY(xsc3_dma_clean_range)
bic r0, r0, #CACHELINESIZE - 1
-1: mcr p15, 0, r0, c7, c10, 1 @ clean L1 D entry
- mcr p15, 1, r0, c7, c11, 1 @ clean L2 D entry
+1: mcr p15, 0, r0, c7, c10, 1 @ clean L1 D line
+ mcr p15, 1, r0, c7, c11, 1 @ clean L2 line
add r0, r0, #CACHELINESIZE
cmp r0, r1
blo 1b
- mcr p15, 0, r0, c7, c10, 4 @ Drain Write Buffer
+ mcr p15, 0, r0, c7, c10, 4 @ data write barrier
mov pc, lr
/*
@@ -307,13 +305,13 @@ ENTRY(xsc3_dma_clean_range)
*/
ENTRY(xsc3_dma_flush_range)
bic r0, r0, #CACHELINESIZE - 1
-1: mcr p15, 0, r0, c7, c14, 1 @ Clean/invalidate L1 D cache line
- mcr p15, 1, r0, c7, c11, 1 @ Clean L2 D cache line
- mcr p15, 1, r0, c7, c7, 1 @ Invalidate L2 D cache line
+1: mcr p15, 0, r0, c7, c14, 1 @ clean/invalidate L1 D line
+ mcr p15, 1, r0, c7, c11, 1 @ clean L2 line
+ mcr p15, 1, r0, c7, c7, 1 @ invalidate L2 line
add r0, r0, #CACHELINESIZE
cmp r0, r1
blo 1b
- mcr p15, 0, r0, c7, c10, 4 @ Drain Write Buffer
+ mcr p15, 0, r0, c7, c10, 4 @ data write barrier
mov pc, lr
ENTRY(xsc3_cache_fns)
@@ -328,7 +326,7 @@ ENTRY(xsc3_cache_fns)
.long xsc3_dma_flush_range
ENTRY(cpu_xsc3_dcache_clean_area)
-1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
+1: mcr p15, 0, r0, c7, c10, 1 @ clean L1 D line
add r0, r0, #CACHELINESIZE
subs r1, r1, #CACHELINESIZE
bhi 1b
@@ -346,14 +344,14 @@ ENTRY(cpu_xsc3_dcache_clean_area)
.align 5
ENTRY(cpu_xsc3_switch_mm)
clean_d_cache r1, r2
- mcr p15, 0, ip, c7, c5, 0 @ Invalidate I cache & BTB
- mcr p15, 0, ip, c7, c10, 4 @ Drain Write Buffer
- mcr p15, 0, ip, c7, c5, 4 @ Prefetch Flush
+ mcr p15, 0, ip, c7, c5, 0 @ invalidate L1 I cache and BTB
+ mcr p15, 0, ip, c7, c10, 4 @ data write barrier
+ mcr p15, 0, ip, c7, c5, 4 @ prefetch flush
#ifdef L2_CACHE_ENABLE
orr r0, r0, #0x18 @ cache the page table in L2
#endif
mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
- mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
+ mcr p15, 0, ip, c8, c7, 0 @ invalidate I and D TLBs
cpwait_ret lr, ip
/*
@@ -366,34 +364,34 @@ ENTRY(cpu_xsc3_switch_mm)
ENTRY(cpu_xsc3_set_pte_ext)
str r1, [r0], #-2048 @ linux version
- bic r2, r1, #0xff0 @ Keep C, B bits
+ bic r2, r1, #0xff0 @ keep C, B bits
orr r2, r2, #PTE_TYPE_EXT @ extended page
- tst r1, #L_PTE_SHARED @ Shared?
+ tst r1, #L_PTE_SHARED @ shared?
orrne r2, r2, #0x200
eor r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
- tst r3, #L_PTE_USER @ User?
+ tst r3, #L_PTE_USER @ user?
orrne r2, r2, #PTE_EXT_AP_URO_SRW @ yes -> user r/o, system r/w
- tst r3, #L_PTE_WRITE | L_PTE_DIRTY @ Write and Dirty?
+ tst r3, #L_PTE_WRITE | L_PTE_DIRTY @ write and dirty?
orreq r2, r2, #PTE_EXT_AP_UNO_SRW @ yes -> user n/a, system r/w
@ combined with user -> user r/w
#if L2_CACHE_ENABLE
- @ If its cacheable it needs to be in L2 also.
+ @ If it's cacheable, it needs to be in L2 also.
eor ip, r1, #L_PTE_CACHEABLE
tst ip, #L_PTE_CACHEABLE
orreq r2, r2, #PTE_EXT_TEX(0x5)
#endif
- tst r3, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young?
+ tst r3, #L_PTE_PRESENT | L_PTE_YOUNG @ present and young?
movne r2, #0 @ no -> fault
str r2, [r0] @ hardware version
mov ip, #0
- mcr p15, 0, r0, c7, c10, 1 @ Clean D cache line mcr
- mcr p15, 0, ip, c7, c10, 4 @ Drain Write Buffer
+ mcr p15, 0, r0, c7, c10, 1 @ clean L1 D line
+ mcr p15, 0, ip, c7, c10, 4 @ data write barrier
mov pc, lr
.ltorg
@@ -406,17 +404,18 @@ ENTRY(cpu_xsc3_set_pte_ext)
__xsc3_setup:
mov r0, #PSR_F_BIT|PSR_I_BIT|SVC_MODE
msr cpsr_c, r0
- mcr p15, 0, ip, c7, c7, 0 @ invalidate I, D caches & BTB
- mcr p15, 0, ip, c7, c10, 4 @ Drain Write Buffer
- mcr p15, 0, ip, c7, c5, 4 @ Prefetch Flush
- mcr p15, 0, ip, c8, c7, 0 @ invalidate I, D TLBs
+ mcr p15, 0, ip, c7, c7, 0 @ invalidate L1 caches and BTB
+ mcr p15, 0, ip, c7, c10, 4 @ data write barrier
+ mcr p15, 0, ip, c7, c5, 4 @ prefetch flush
+ mcr p15, 0, ip, c8, c7, 0 @ invalidate I and D TLBs
#if L2_CACHE_ENABLE
orr r4, r4, #0x18 @ cache the page table in L2
#endif
mcr p15, 0, r4, c2, c0, 0 @ load page table pointer
- mov r0, #1 @ Allow access to CP0 and CP13
- orr r0, r0, #1 << 13 @ Its undefined whether this
- mcr p15, 0, r0, c15, c1, 0 @ affects USR or SVC modes
+
+ mov r0, #0 @ don't allow CP access
+ mcr p15, 0, r0, c15, c1, 0 @ write CP access register
+
mrc p15, 0, r0, c1, c0, 1 @ get auxiliary control reg
and r0, r0, #2 @ preserve bit P bit setting
#if L2_CACHE_ENABLE
@@ -427,9 +426,9 @@ __xsc3_setup:
adr r5, xsc3_crval
ldmia r5, {r5, r6}
mrc p15, 0, r0, c1, c0, 0 @ get control register
- bic r0, r0, r5 @ .... .... .... ..A.
- orr r0, r0, r6 @ .... .... .... .C.M
- orr r0, r0, #0x00000800 @ ..VI Z..S .... ....
+ bic r0, r0, r5 @ ..V. ..R. .... ..A.
+ orr r0, r0, r6 @ ..VI Z..S .... .C.M (mmu)
+ @ ...I Z..S .... .... (uc)
#if L2_CACHE_ENABLE
orr r0, r0, #0x04000000 @ L2 enable
#endif
@@ -439,7 +438,7 @@ __xsc3_setup:
.type xsc3_crval, #object
xsc3_crval:
- crval clear=0x04003b02, mmuset=0x00003105, ucset=0x00001100
+ crval clear=0x04002202, mmuset=0x00003905, ucset=0x00001900
__INITDATA
@@ -474,7 +473,7 @@ cpu_elf_name:
.type cpu_xsc3_name, #object
cpu_xsc3_name:
- .asciz "XScale-Core3"
+ .asciz "XScale-V3 based processor"
.size cpu_xsc3_name, . - cpu_xsc3_name
.align
@@ -490,7 +489,7 @@ __xsc3_proc_info:
PMD_SECT_CACHEABLE | \
PMD_SECT_AP_WRITE | \
PMD_SECT_AP_READ
- .long PMD_TYPE_SECT | \
+ .long PMD_TYPE_SECT | \
PMD_SECT_AP_WRITE | \
PMD_SECT_AP_READ
b __xsc3_setup
diff --git a/arch/arm/mm/tlb-v6.S b/arch/arm/mm/tlb-v6.S
index fd6adde3909..20f84bbaa9b 100644
--- a/arch/arm/mm/tlb-v6.S
+++ b/arch/arm/mm/tlb-v6.S
@@ -53,6 +53,8 @@ ENTRY(v6wbi_flush_user_tlb_range)
add r0, r0, #PAGE_SZ
cmp r0, r1
blo 1b
+ mcr p15, 0, ip, c7, c5, 6 @ flush BTAC/BTB
+ mcr p15, 0, ip, c7, c10, 4 @ data synchronization barrier
mov pc, lr
/*
@@ -80,7 +82,9 @@ ENTRY(v6wbi_flush_kern_tlb_range)
add r0, r0, #PAGE_SZ
cmp r0, r1
blo 1b
+ mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB
mcr p15, 0, r2, c7, c10, 4 @ data synchronization barrier
+ mcr p15, 0, r2, c7, c5, 4 @ prefetch flush
mov pc, lr
.section ".text.init", #alloc, #execinstr
diff --git a/arch/arm/plat-s3c24xx/Kconfig b/arch/arm/plat-s3c24xx/Kconfig
new file mode 100644
index 00000000000..e2234316063
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/Kconfig
@@ -0,0 +1,99 @@
+# arch/arm/plat-s3c24xx/Kconfig
+#
+# Copyright 2007 Simtec Electronics
+#
+# Licensed under GPLv2
+
+config PLAT_S3C24XX
+ bool
+ depends on ARCH_S3C2410
+ default y if ARCH_S3C2410
+ help
+ Base platform code for any Samsung S3C device
+
+if PLAT_S3C24XX
+
+config CPU_S3C244X
+ bool
+ depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442)
+ help
+ Support for S3C2440 and S3C2442 Samsung Mobile CPU based systems.
+
+config PM_SIMTEC
+ bool
+ help
+ Common power management code for systems that are
+ compatible with the Simtec style of power management
+
+config S3C2410_BOOT_WATCHDOG
+ bool "S3C2410 Initialisation watchdog"
+ depends on ARCH_S3C2410 && S3C2410_WATCHDOG
+ help
+ Say y to enable the watchdog during the kernel decompression
+ stage. If the kernel fails to uncompress, then the watchdog
+ will trigger a reset and the system should restart.
+
+config S3C2410_BOOT_ERROR_RESET
+ bool "S3C2410 Reboot on decompression error"
+ depends on ARCH_S3C2410
+ help
+ Say y here to use the watchdog to reset the system if the
+ kernel decompressor detects an error during decompression.
+
+config S3C2410_PM_DEBUG
+ bool "S3C2410 PM Suspend debug"
+ depends on ARCH_S3C2410 && PM
+ help
+ Say Y here if you want verbose debugging from the PM Suspend and
+ Resume code. See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
+ for more information.
+
+config S3C2410_PM_CHECK
+ bool "S3C2410 PM Suspend Memory CRC"
+ depends on ARCH_S3C2410 && PM && CRC32
+ help
+ Enable the PM code's memory area checksum over sleep. This option
+ will generate CRCs of all blocks of memory, and store them before
+ going to sleep. The blocks are then checked on resume for any
+ errors.
+
+config S3C2410_PM_CHECK_CHUNKSIZE
+ int "S3C2410 PM Suspend CRC Chunksize (KiB)"
+ depends on ARCH_S3C2410 && PM && S3C2410_PM_CHECK
+ default 64
+ help
+ Set the chunksize in Kilobytes of the CRC for checking memory
+ corruption over suspend and resume. A smaller value will mean that
+ the CRC data block will take more memory, but wil identify any
+ faults with better precision.
+
+config S3C2410_LOWLEVEL_UART_PORT
+ int "S3C2410 UART to use for low-level messages"
+ default 0
+ help
+ Choice of which UART port to use for the low-level messages,
+ such as the `Uncompressing...` at start time. The value of
+ this configuration should be between zero and two. The port
+ must have been initialised by the boot-loader before use.
+
+config S3C2410_DMA
+ bool "S3C2410 DMA support"
+ depends on ARCH_S3C2410
+ help
+ S3C2410 DMA support. This is needed for drivers like sound which
+ use the S3C2410's DMA system to move data to and from the
+ peripheral blocks.
+
+config S3C2410_DMA_DEBUG
+ bool "S3C2410 DMA support debug"
+ depends on ARCH_S3C2410 && S3C2410_DMA
+ help
+ Enable debugging output for the DMA code. This option sends info
+ to the kernel log, at priority KERN_DEBUG.
+
+config MACH_SMDK
+ bool
+ help
+ Common machine code for SMDK2410 and SMDK2440
+
+endif
diff --git a/arch/arm/plat-s3c24xx/Makefile b/arch/arm/plat-s3c24xx/Makefile
new file mode 100644
index 00000000000..8e5ccaa1f03
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/Makefile
@@ -0,0 +1,30 @@
+# arch/arm/plat-s3c24xx/Makefile
+#
+# Copyright 2007 Simtec Electronics
+#
+# Licensed under GPLv2
+
+obj-y :=
+obj-m :=
+obj-n :=
+obj- :=
+
+
+# Core files
+
+obj-y += cpu.o
+obj-y += irq.o
+obj-y += devs.o
+obj-y += gpio.o
+obj-y += time.o
+obj-y += clock.o
+
+# Architecture dependant builds
+
+obj-$(CONFIG_CPU_S3C244X) += s3c244x.o
+obj-$(CONFIG_CPU_S3C244X) += s3c244x-irq.o
+obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o
+obj-$(CONFIG_PM) += pm.o
+obj-$(CONFIG_PM) += sleep.o
+obj-$(CONFIG_S3C2410_DMA) += dma.o
+obj-$(CONFIG_MACH_SMDK) += common-smdk.o
diff --git a/arch/arm/plat-s3c24xx/clock.c b/arch/arm/plat-s3c24xx/clock.c
new file mode 100644
index 00000000000..d3dc03a7383
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/clock.c
@@ -0,0 +1,449 @@
+/* linux/arch/arm/plat-s3c24xx/clock.c
+ *
+ * Copyright (c) 2004-2005 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX Core clock control support
+ *
+ * Based on, and code from linux/arch/arm/mach-versatile/clock.c
+ **
+ ** Copyright (C) 2004 ARM Limited.
+ ** Written by Deep Blue Solutions Limited.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/sysdev.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-gpio.h>
+
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/cpu.h>
+
+/* clock information */
+
+static LIST_HEAD(clocks);
+
+DEFINE_MUTEX(clocks_mutex);
+
+/* enable and disable calls for use with the clk struct */
+
+static int clk_null_enable(struct clk *clk, int enable)
+{
+ return 0;
+}
+
+/* Clock API calls */
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+ struct clk *p;
+ struct clk *clk = ERR_PTR(-ENOENT);
+ int idno;
+
+ if (dev == NULL || dev->bus != &platform_bus_type)
+ idno = -1;
+ else
+ idno = to_platform_device(dev)->id;
+
+ mutex_lock(&clocks_mutex);
+
+ list_for_each_entry(p, &clocks, list) {
+ if (p->id == idno &&
+ strcmp(id, p->name) == 0 &&
+ try_module_get(p->owner)) {
+ clk = p;
+ break;
+ }
+ }
+
+ /* check for the case where a device was supplied, but the
+ * clock that was being searched for is not device specific */
+
+ if (IS_ERR(clk)) {
+ list_for_each_entry(p, &clocks, list) {
+ if (p->id == -1 && strcmp(id, p->name) == 0 &&
+ try_module_get(p->owner)) {
+ clk = p;
+ break;
+ }
+ }
+ }
+
+ mutex_unlock(&clocks_mutex);
+ return clk;
+}
+
+void clk_put(struct clk *clk)
+{
+ module_put(clk->owner);
+}
+
+int clk_enable(struct clk *clk)
+{
+ if (IS_ERR(clk) || clk == NULL)
+ return -EINVAL;
+
+ clk_enable(clk->parent);
+
+ mutex_lock(&clocks_mutex);
+
+ if ((clk->usage++) == 0)
+ (clk->enable)(clk, 1);
+
+ mutex_unlock(&clocks_mutex);
+ return 0;
+}
+
+void clk_disable(struct clk *clk)
+{
+ if (IS_ERR(clk) || clk == NULL)
+ return;
+
+ mutex_lock(&clocks_mutex);
+
+ if ((--clk->usage) == 0)
+ (clk->enable)(clk, 0);
+
+ mutex_unlock(&clocks_mutex);
+ clk_disable(clk->parent);
+}
+
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ if (IS_ERR(clk))
+ return 0;
+
+ if (clk->rate != 0)
+ return clk->rate;
+
+ if (clk->get_rate != NULL)
+ return (clk->get_rate)(clk);
+
+ if (clk->parent != NULL)
+ return clk_get_rate(clk->parent);
+
+ return clk->rate;
+}
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ if (!IS_ERR(clk) && clk->round_rate)
+ return (clk->round_rate)(clk, rate);
+
+ return rate;
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ int ret;
+
+ if (IS_ERR(clk))
+ return -EINVAL;
+
+ mutex_lock(&clocks_mutex);
+ ret = (clk->set_rate)(clk, rate);
+ mutex_unlock(&clocks_mutex);
+
+ return ret;
+}
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+ return clk->parent;
+}
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ int ret = 0;
+
+ if (IS_ERR(clk))
+ return -EINVAL;
+
+ mutex_lock(&clocks_mutex);
+
+ if (clk->set_parent)
+ ret = (clk->set_parent)(clk, parent);
+
+ mutex_unlock(&clocks_mutex);
+
+ return ret;
+}
+
+EXPORT_SYMBOL(clk_get);
+EXPORT_SYMBOL(clk_put);
+EXPORT_SYMBOL(clk_enable);
+EXPORT_SYMBOL(clk_disable);
+EXPORT_SYMBOL(clk_get_rate);
+EXPORT_SYMBOL(clk_round_rate);
+EXPORT_SYMBOL(clk_set_rate);
+EXPORT_SYMBOL(clk_get_parent);
+EXPORT_SYMBOL(clk_set_parent);
+
+/* base clocks */
+
+struct clk clk_xtal = {
+ .name = "xtal",
+ .id = -1,
+ .rate = 0,
+ .parent = NULL,
+ .ctrlbit = 0,
+};
+
+struct clk clk_mpll = {
+ .name = "mpll",
+ .id = -1,
+};
+
+struct clk clk_upll = {
+ .name = "upll",
+ .id = -1,
+ .parent = NULL,
+ .ctrlbit = 0,
+};
+
+struct clk clk_f = {
+ .name = "fclk",
+ .id = -1,
+ .rate = 0,
+ .parent = &clk_mpll,
+ .ctrlbit = 0,
+};
+
+struct clk clk_h = {
+ .name = "hclk",
+ .id = -1,
+ .rate = 0,
+ .parent = NULL,
+ .ctrlbit = 0,
+};
+
+struct clk clk_p = {
+ .name = "pclk",
+ .id = -1,
+ .rate = 0,
+ .parent = NULL,
+ .ctrlbit = 0,
+};
+
+struct clk clk_usb_bus = {
+ .name = "usb-bus",
+ .id = -1,
+ .rate = 0,
+ .parent = &clk_upll,
+};
+
+/* clocks that could be registered by external code */
+
+static int s3c24xx_dclk_enable(struct clk *clk, int enable)
+{
+ unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON);
+
+ if (enable)
+ dclkcon |= clk->ctrlbit;
+ else
+ dclkcon &= ~clk->ctrlbit;
+
+ __raw_writel(dclkcon, S3C24XX_DCLKCON);
+
+ return 0;
+}
+
+static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
+{
+ unsigned long dclkcon;
+ unsigned int uclk;
+
+ if (parent == &clk_upll)
+ uclk = 1;
+ else if (parent == &clk_p)
+ uclk = 0;
+ else
+ return -EINVAL;
+
+ clk->parent = parent;
+
+ dclkcon = __raw_readl(S3C24XX_DCLKCON);
+
+ if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) {
+ if (uclk)
+ dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK;
+ else
+ dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK;
+ } else {
+ if (uclk)
+ dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK;
+ else
+ dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK;
+ }
+
+ __raw_writel(dclkcon, S3C24XX_DCLKCON);
+
+ return 0;
+}
+
+
+static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent)
+{
+ unsigned long mask;
+ unsigned long source;
+
+ /* calculate the MISCCR setting for the clock */
+
+ if (parent == &clk_xtal)
+ source = S3C2410_MISCCR_CLK0_MPLL;
+ else if (parent == &clk_upll)
+ source = S3C2410_MISCCR_CLK0_UPLL;
+ else if (parent == &clk_f)
+ source = S3C2410_MISCCR_CLK0_FCLK;
+ else if (parent == &clk_h)
+ source = S3C2410_MISCCR_CLK0_HCLK;
+ else if (parent == &clk_p)
+ source = S3C2410_MISCCR_CLK0_PCLK;
+ else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0)
+ source = S3C2410_MISCCR_CLK0_DCLK0;
+ else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1)
+ source = S3C2410_MISCCR_CLK0_DCLK0;
+ else
+ return -EINVAL;
+
+ clk->parent = parent;
+
+ if (clk == &s3c24xx_dclk0)
+ mask = S3C2410_MISCCR_CLK0_MASK;
+ else {
+ source <<= 4;
+ mask = S3C2410_MISCCR_CLK1_MASK;
+ }
+
+ s3c2410_modify_misccr(mask, source);
+ return 0;
+}
+
+/* external clock definitions */
+
+struct clk s3c24xx_dclk0 = {
+ .name = "dclk0",
+ .id = -1,
+ .ctrlbit = S3C2410_DCLKCON_DCLK0EN,
+ .enable = s3c24xx_dclk_enable,
+ .set_parent = s3c24xx_dclk_setparent,
+};
+
+struct clk s3c24xx_dclk1 = {
+ .name = "dclk1",
+ .id = -1,
+ .ctrlbit = S3C2410_DCLKCON_DCLK0EN,
+ .enable = s3c24xx_dclk_enable,
+ .set_parent = s3c24xx_dclk_setparent,
+};
+
+struct clk s3c24xx_clkout0 = {
+ .name = "clkout0",
+ .id = -1,
+ .set_parent = s3c24xx_clkout_setparent,
+};
+
+struct clk s3c24xx_clkout1 = {
+ .name = "clkout1",
+ .id = -1,
+ .set_parent = s3c24xx_clkout_setparent,
+};
+
+struct clk s3c24xx_uclk = {
+ .name = "uclk",
+ .id = -1,
+};
+
+/* initialise the clock system */
+
+int s3c24xx_register_clock(struct clk *clk)
+{
+ clk->owner = THIS_MODULE;
+
+ if (clk->enable == NULL)
+ clk->enable = clk_null_enable;
+
+ /* add to the list of available clocks */
+
+ mutex_lock(&clocks_mutex);
+ list_add(&clk->list, &clocks);
+ mutex_unlock(&clocks_mutex);
+
+ return 0;
+}
+
+/* initalise all the clocks */
+
+int __init s3c24xx_setup_clocks(unsigned long xtal,
+ unsigned long fclk,
+ unsigned long hclk,
+ unsigned long pclk)
+{
+ printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n");
+
+ /* initialise the main system clocks */
+
+ clk_xtal.rate = xtal;
+ clk_upll.rate = s3c2410_get_pll(__raw_readl(S3C2410_UPLLCON), xtal);
+
+ clk_mpll.rate = fclk;
+ clk_h.rate = hclk;
+ clk_p.rate = pclk;
+ clk_f.rate = fclk;
+
+ /* assume uart clocks are correctly setup */
+
+ /* register our clocks */
+
+ if (s3c24xx_register_clock(&clk_xtal) < 0)
+ printk(KERN_ERR "failed to register master xtal\n");
+
+ if (s3c24xx_register_clock(&clk_mpll) < 0)
+ printk(KERN_ERR "failed to register mpll clock\n");
+
+ if (s3c24xx_register_clock(&clk_upll) < 0)
+ printk(KERN_ERR "failed to register upll clock\n");
+
+ if (s3c24xx_register_clock(&clk_f) < 0)
+ printk(KERN_ERR "failed to register cpu fclk\n");
+
+ if (s3c24xx_register_clock(&clk_h) < 0)
+ printk(KERN_ERR "failed to register cpu hclk\n");
+
+ if (s3c24xx_register_clock(&clk_p) < 0)
+ printk(KERN_ERR "failed to register cpu pclk\n");
+
+ return 0;
+}
diff --git a/arch/arm/mach-s3c2410/common-smdk.c b/arch/arm/plat-s3c24xx/common-smdk.c
index a40eaa65617..908efa7d745 100644
--- a/arch/arm/mach-s3c2410/common-smdk.c
+++ b/arch/arm/plat-s3c24xx/common-smdk.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/common-smdk.c
+/* linux/arch/arm/plat-s3c24xx/common-smdk.c
*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@@ -38,9 +38,9 @@
#include <asm/arch/nand.h>
-#include "common-smdk.h"
-#include "devs.h"
-#include "pm.h"
+#include <asm/plat-s3c24xx/common-smdk.h>
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/pm.h>
/* LED devices */
diff --git a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/plat-s3c24xx/cpu.c
index ae1f5bb63f7..6a2d1070e5a 100644
--- a/arch/arm/mach-s3c2410/cpu.c
+++ b/arch/arm/plat-s3c24xx/cpu.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/cpu.c
+/* linux/arch/arm/plat-s3c24xx/cpu.c
*
* Copyright (c) 2004-2005 Simtec Electronics
* http://www.simtec.co.uk/products/SWLINUX/
@@ -40,15 +40,16 @@
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-serial.h>
-#include "cpu.h"
-#include "devs.h"
-#include "clock.h"
-#include "s3c2400.h"
-#include "s3c2410.h"
-#include "s3c2412.h"
+#include <asm/plat-s3c24xx/cpu.h>
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/s3c2400.h>
+#include <asm/plat-s3c24xx/s3c2410.h>
+#include <asm/plat-s3c24xx/s3c2412.h>
#include "s3c244x.h"
-#include "s3c2440.h"
-#include "s3c2442.h"
+#include <asm/plat-s3c24xx/s3c2440.h>
+#include <asm/plat-s3c24xx/s3c2442.h>
+#include <asm/plat-s3c24xx/s3c2443.h>
struct cpu_table {
unsigned long idcode;
@@ -67,6 +68,7 @@ static const char name_s3c2410[] = "S3C2410";
static const char name_s3c2412[] = "S3C2412";
static const char name_s3c2440[] = "S3C2440";
static const char name_s3c2442[] = "S3C2442";
+static const char name_s3c2443[] = "S3C2443";
static const char name_s3c2410a[] = "S3C2410A";
static const char name_s3c2440a[] = "S3C2440A";
@@ -135,6 +137,15 @@ static struct cpu_table cpu_ids[] __initdata = {
.name = name_s3c2412,
},
{
+ .idcode = 0x32443001,
+ .idmask = 0xffffffff,
+ .map_io = s3c2443_map_io,
+ .init_clocks = s3c2443_init_clocks,
+ .init_uarts = s3c2443_init_uarts,
+ .init = s3c2443_init,
+ .name = name_s3c2443,
+ },
+ {
.idcode = 0x0, /* S3C2400 doesn't have an idcode */
.idmask = 0xffffffff,
.map_io = s3c2400_map_io,
diff --git a/arch/arm/mach-s3c2410/devs.c b/arch/arm/plat-s3c24xx/devs.c
index faccde2092d..0fe53b39cb2 100644
--- a/arch/arm/mach-s3c2410/devs.c
+++ b/arch/arm/plat-s3c24xx/devs.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/devs.c
+/* linux/arch/arm/plat-s3c24xx/devs.c
*
* Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@@ -29,9 +29,10 @@
#include <asm/irq.h>
#include <asm/arch/regs-serial.h>
+#include <asm/arch/udc.h>
-#include "devs.h"
-#include "cpu.h"
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/cpu.h>
/* Serial port registrations */
@@ -230,6 +231,20 @@ struct platform_device s3c_device_usbgadget = {
EXPORT_SYMBOL(s3c_device_usbgadget);
+void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *pd)
+{
+ struct s3c2410_udc_mach_info *npd;
+
+ npd = kmalloc(sizeof(*npd), GFP_KERNEL);
+ if (npd) {
+ memcpy(npd, pd, sizeof(*npd));
+ s3c_device_usbgadget.dev.platform_data = npd;
+ } else {
+ printk(KERN_ERR "no memory for udc platform data\n");
+ }
+}
+
+
/* Watchdog */
static struct resource s3c_wdt_resource[] = {
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
new file mode 100644
index 00000000000..4540a806f52
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/dma.c
@@ -0,0 +1,1499 @@
+/* linux/arch/arm/plat-s3c24xx/dma.c
+ *
+ * Copyright (c) 2003-2005,2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 DMA core
+ *
+ * http://armlinux.simtec.co.uk/
+ *
+ * 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.
+*/
+
+
+#ifdef CONFIG_S3C2410_DMA_DEBUG
+#define DEBUG
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/sysdev.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <asm/mach/dma.h>
+#include <asm/arch/map.h>
+
+#include <asm/plat-s3c24xx/dma.h>
+
+/* io map for dma */
+static void __iomem *dma_base;
+static struct kmem_cache *dma_kmem;
+
+static int dma_channels;
+
+struct s3c24xx_dma_selection dma_sel;
+
+/* dma channel state information */
+struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
+
+/* debugging functions */
+
+#define BUF_MAGIC (0xcafebabe)
+
+#define dmawarn(fmt...) printk(KERN_DEBUG fmt)
+
+#define dma_regaddr(chan, reg) ((chan)->regs + (reg))
+
+#if 1
+#define dma_wrreg(chan, reg, val) writel((val), (chan)->regs + (reg))
+#else
+static inline void
+dma_wrreg(struct s3c2410_dma_chan *chan, int reg, unsigned long val)
+{
+ pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg);
+ writel(val, dma_regaddr(chan, reg));
+}
+#endif
+
+#define dma_rdreg(chan, reg) readl((chan)->regs + (reg))
+
+/* captured register state for debug */
+
+struct s3c2410_dma_regstate {
+ unsigned long dcsrc;
+ unsigned long disrc;
+ unsigned long dstat;
+ unsigned long dcon;
+ unsigned long dmsktrig;
+};
+
+#ifdef CONFIG_S3C2410_DMA_DEBUG
+
+/* dmadbg_showregs
+ *
+ * simple debug routine to print the current state of the dma registers
+*/
+
+static void
+dmadbg_capture(struct s3c2410_dma_chan *chan, struct s3c2410_dma_regstate *regs)
+{
+ regs->dcsrc = dma_rdreg(chan, S3C2410_DMA_DCSRC);
+ regs->disrc = dma_rdreg(chan, S3C2410_DMA_DISRC);
+ regs->dstat = dma_rdreg(chan, S3C2410_DMA_DSTAT);
+ regs->dcon = dma_rdreg(chan, S3C2410_DMA_DCON);
+ regs->dmsktrig = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
+}
+
+static void
+dmadbg_dumpregs(const char *fname, int line, struct s3c2410_dma_chan *chan,
+ struct s3c2410_dma_regstate *regs)
+{
+ printk(KERN_DEBUG "dma%d: %s:%d: DCSRC=%08lx, DISRC=%08lx, DSTAT=%08lx DMT=%02lx, DCON=%08lx\n",
+ chan->number, fname, line,
+ regs->dcsrc, regs->disrc, regs->dstat, regs->dmsktrig,
+ regs->dcon);
+}
+
+static void
+dmadbg_showchan(const char *fname, int line, struct s3c2410_dma_chan *chan)
+{
+ struct s3c2410_dma_regstate state;
+
+ dmadbg_capture(chan, &state);
+
+ printk(KERN_DEBUG "dma%d: %s:%d: ls=%d, cur=%p, %p %p\n",
+ chan->number, fname, line, chan->load_state,
+ chan->curr, chan->next, chan->end);
+
+ dmadbg_dumpregs(fname, line, chan, &state);
+}
+
+static void
+dmadbg_showregs(const char *fname, int line, struct s3c2410_dma_chan *chan)
+{
+ struct s3c2410_dma_regstate state;
+
+ dmadbg_capture(chan, &state);
+ dmadbg_dumpregs(fname, line, chan, &state);
+}
+
+#define dbg_showregs(chan) dmadbg_showregs(__FUNCTION__, __LINE__, (chan))
+#define dbg_showchan(chan) dmadbg_showchan(__FUNCTION__, __LINE__, (chan))
+#else
+#define dbg_showregs(chan) do { } while(0)
+#define dbg_showchan(chan) do { } while(0)
+#endif /* CONFIG_S3C2410_DMA_DEBUG */
+
+static struct s3c2410_dma_chan *dma_chan_map[DMACH_MAX];
+
+/* lookup_dma_channel
+ *
+ * change the dma channel number given into a real dma channel id
+*/
+
+static struct s3c2410_dma_chan *lookup_dma_channel(unsigned int channel)
+{
+ if (channel & DMACH_LOW_LEVEL)
+ return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL];
+ else
+ return dma_chan_map[channel];
+}
+
+/* s3c2410_dma_stats_timeout
+ *
+ * Update DMA stats from timeout info
+*/
+
+static void
+s3c2410_dma_stats_timeout(struct s3c2410_dma_stats *stats, int val)
+{
+ if (stats == NULL)
+ return;
+
+ if (val > stats->timeout_longest)
+ stats->timeout_longest = val;
+ if (val < stats->timeout_shortest)
+ stats->timeout_shortest = val;
+
+ stats->timeout_avg += val;
+}
+
+/* s3c2410_dma_waitforload
+ *
+ * wait for the DMA engine to load a buffer, and update the state accordingly
+*/
+
+static int
+s3c2410_dma_waitforload(struct s3c2410_dma_chan *chan, int line)
+{
+ int timeout = chan->load_timeout;
+ int took;
+
+ if (chan->load_state != S3C2410_DMALOAD_1LOADED) {
+ printk(KERN_ERR "dma%d: s3c2410_dma_waitforload() called in loadstate %d from line %d\n", chan->number, chan->load_state, line);
+ return 0;
+ }
+
+ if (chan->stats != NULL)
+ chan->stats->loads++;
+
+ while (--timeout > 0) {
+ if ((dma_rdreg(chan, S3C2410_DMA_DSTAT) << (32-20)) != 0) {
+ took = chan->load_timeout - timeout;
+
+ s3c2410_dma_stats_timeout(chan->stats, took);
+
+ switch (chan->load_state) {
+ case S3C2410_DMALOAD_1LOADED:
+ chan->load_state = S3C2410_DMALOAD_1RUNNING;
+ break;
+
+ default:
+ printk(KERN_ERR "dma%d: unknown load_state in s3c2410_dma_waitforload() %d\n", chan->number, chan->load_state);
+ }
+
+ return 1;
+ }
+ }
+
+ if (chan->stats != NULL) {
+ chan->stats->timeout_failed++;
+ }
+
+ return 0;
+}
+
+
+
+/* s3c2410_dma_loadbuffer
+ *
+ * load a buffer, and update the channel state
+*/
+
+static inline int
+s3c2410_dma_loadbuffer(struct s3c2410_dma_chan *chan,
+ struct s3c2410_dma_buf *buf)
+{
+ unsigned long reload;
+
+ pr_debug("s3c2410_chan_loadbuffer: loading buff %p (0x%08lx,0x%06x)\n",
+ buf, (unsigned long)buf->data, buf->size);
+
+ if (buf == NULL) {
+ dmawarn("buffer is NULL\n");
+ return -EINVAL;
+ }
+
+ /* check the state of the channel before we do anything */
+
+ if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
+ dmawarn("load_state is S3C2410_DMALOAD_1LOADED\n");
+ }
+
+ if (chan->load_state == S3C2410_DMALOAD_1LOADED_1RUNNING) {
+ dmawarn("state is S3C2410_DMALOAD_1LOADED_1RUNNING\n");
+ }
+
+ /* it would seem sensible if we are the last buffer to not bother
+ * with the auto-reload bit, so that the DMA engine will not try
+ * and load another transfer after this one has finished...
+ */
+ if (chan->load_state == S3C2410_DMALOAD_NONE) {
+ pr_debug("load_state is none, checking for noreload (next=%p)\n",
+ buf->next);
+ reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0;
+ } else {
+ //pr_debug("load_state is %d => autoreload\n", chan->load_state);
+ reload = S3C2410_DCON_AUTORELOAD;
+ }
+
+ if ((buf->data & 0xf0000000) != 0x30000000) {
+ dmawarn("dmaload: buffer is %p\n", (void *)buf->data);
+ }
+
+ writel(buf->data, chan->addr_reg);
+
+ dma_wrreg(chan, S3C2410_DMA_DCON,
+ chan->dcon | reload | (buf->size/chan->xfer_unit));
+
+ chan->next = buf->next;
+
+ /* update the state of the channel */
+
+ switch (chan->load_state) {
+ case S3C2410_DMALOAD_NONE:
+ chan->load_state = S3C2410_DMALOAD_1LOADED;
+ break;
+
+ case S3C2410_DMALOAD_1RUNNING:
+ chan->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING;
+ break;
+
+ default:
+ dmawarn("dmaload: unknown state %d in loadbuffer\n",
+ chan->load_state);
+ break;
+ }
+
+ return 0;
+}
+
+/* s3c2410_dma_call_op
+ *
+ * small routine to call the op routine with the given op if it has been
+ * registered
+*/
+
+static void
+s3c2410_dma_call_op(struct s3c2410_dma_chan *chan, enum s3c2410_chan_op op)
+{
+ if (chan->op_fn != NULL) {
+ (chan->op_fn)(chan, op);
+ }
+}
+
+/* s3c2410_dma_buffdone
+ *
+ * small wrapper to check if callback routine needs to be called, and
+ * if so, call it
+*/
+
+static inline void
+s3c2410_dma_buffdone(struct s3c2410_dma_chan *chan, struct s3c2410_dma_buf *buf,
+ enum s3c2410_dma_buffresult result)
+{
+#if 0
+ pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n",
+ chan->callback_fn, buf, buf->id, buf->size, result);
+#endif
+
+ if (chan->callback_fn != NULL) {
+ (chan->callback_fn)(chan, buf->id, buf->size, result);
+ }
+}
+
+/* s3c2410_dma_start
+ *
+ * start a dma channel going
+*/
+
+static int s3c2410_dma_start(struct s3c2410_dma_chan *chan)
+{
+ unsigned long tmp;
+ unsigned long flags;
+
+ pr_debug("s3c2410_start_dma: channel=%d\n", chan->number);
+
+ local_irq_save(flags);
+
+ if (chan->state == S3C2410_DMA_RUNNING) {
+ pr_debug("s3c2410_start_dma: already running (%d)\n", chan->state);
+ local_irq_restore(flags);
+ return 0;
+ }
+
+ chan->state = S3C2410_DMA_RUNNING;
+
+ /* check wether there is anything to load, and if not, see
+ * if we can find anything to load
+ */
+
+ if (chan->load_state == S3C2410_DMALOAD_NONE) {
+ if (chan->next == NULL) {
+ printk(KERN_ERR "dma%d: channel has nothing loaded\n",
+ chan->number);
+ chan->state = S3C2410_DMA_IDLE;
+ local_irq_restore(flags);
+ return -EINVAL;
+ }
+
+ s3c2410_dma_loadbuffer(chan, chan->next);
+ }
+
+ dbg_showchan(chan);
+
+ /* enable the channel */
+
+ if (!chan->irq_enabled) {
+ enable_irq(chan->irq);
+ chan->irq_enabled = 1;
+ }
+
+ /* start the channel going */
+
+ tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
+ tmp &= ~S3C2410_DMASKTRIG_STOP;
+ tmp |= S3C2410_DMASKTRIG_ON;
+ dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
+
+ pr_debug("dma%d: %08lx to DMASKTRIG\n", chan->number, tmp);
+
+#if 0
+ /* the dma buffer loads should take care of clearing the AUTO
+ * reloading feature */
+ tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
+ tmp &= ~S3C2410_DCON_NORELOAD;
+ dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
+#endif
+
+ s3c2410_dma_call_op(chan, S3C2410_DMAOP_START);
+
+ dbg_showchan(chan);
+
+ /* if we've only loaded one buffer onto the channel, then chec
+ * to see if we have another, and if so, try and load it so when
+ * the first buffer is finished, the new one will be loaded onto
+ * the channel */
+
+ if (chan->next != NULL) {
+ if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
+
+ if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
+ pr_debug("%s: buff not yet loaded, no more todo\n",
+ __FUNCTION__);
+ } else {
+ chan->load_state = S3C2410_DMALOAD_1RUNNING;
+ s3c2410_dma_loadbuffer(chan, chan->next);
+ }
+
+ } else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) {
+ s3c2410_dma_loadbuffer(chan, chan->next);
+ }
+ }
+
+
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+/* s3c2410_dma_canload
+ *
+ * work out if we can queue another buffer into the DMA engine
+*/
+
+static int
+s3c2410_dma_canload(struct s3c2410_dma_chan *chan)
+{
+ if (chan->load_state == S3C2410_DMALOAD_NONE ||
+ chan->load_state == S3C2410_DMALOAD_1RUNNING)
+ return 1;
+
+ return 0;
+}
+
+/* s3c2410_dma_enqueue
+ *
+ * queue an given buffer for dma transfer.
+ *
+ * id the device driver's id information for this buffer
+ * data the physical address of the buffer data
+ * size the size of the buffer in bytes
+ *
+ * If the channel is not running, then the flag S3C2410_DMAF_AUTOSTART
+ * is checked, and if set, the channel is started. If this flag isn't set,
+ * then an error will be returned.
+ *
+ * It is possible to queue more than one DMA buffer onto a channel at
+ * once, and the code will deal with the re-loading of the next buffer
+ * when necessary.
+*/
+
+int s3c2410_dma_enqueue(unsigned int channel, void *id,
+ dma_addr_t data, int size)
+{
+ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+ struct s3c2410_dma_buf *buf;
+ unsigned long flags;
+
+ if (chan == NULL)
+ return -EINVAL;
+
+ pr_debug("%s: id=%p, data=%08x, size=%d\n",
+ __FUNCTION__, id, (unsigned int)data, size);
+
+ buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC);
+ if (buf == NULL) {
+ pr_debug("%s: out of memory (%ld alloc)\n",
+ __FUNCTION__, (long)sizeof(*buf));
+ return -ENOMEM;
+ }
+
+ //pr_debug("%s: new buffer %p\n", __FUNCTION__, buf);
+ //dbg_showchan(chan);
+
+ buf->next = NULL;
+ buf->data = buf->ptr = data;
+ buf->size = size;
+ buf->id = id;
+ buf->magic = BUF_MAGIC;
+
+ local_irq_save(flags);
+
+ if (chan->curr == NULL) {
+ /* we've got nothing loaded... */
+ pr_debug("%s: buffer %p queued onto empty channel\n",
+ __FUNCTION__, buf);
+
+ chan->curr = buf;
+ chan->end = buf;
+ chan->next = NULL;
+ } else {
+ pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n",
+ chan->number, __FUNCTION__, buf);
+
+ if (chan->end == NULL)
+ pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n",
+ chan->number, __FUNCTION__, chan);
+
+ chan->end->next = buf;
+ chan->end = buf;
+ }
+
+ /* if necessary, update the next buffer field */
+ if (chan->next == NULL)
+ chan->next = buf;
+
+ /* check to see if we can load a buffer */
+ if (chan->state == S3C2410_DMA_RUNNING) {
+ if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) {
+ if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
+ printk(KERN_ERR "dma%d: loadbuffer:"
+ "timeout loading buffer\n",
+ chan->number);
+ dbg_showchan(chan);
+ local_irq_restore(flags);
+ return -EINVAL;
+ }
+ }
+
+ while (s3c2410_dma_canload(chan) && chan->next != NULL) {
+ s3c2410_dma_loadbuffer(chan, chan->next);
+ }
+ } else if (chan->state == S3C2410_DMA_IDLE) {
+ if (chan->flags & S3C2410_DMAF_AUTOSTART) {
+ s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_START);
+ }
+ }
+
+ local_irq_restore(flags);
+ return 0;
+}
+
+EXPORT_SYMBOL(s3c2410_dma_enqueue);
+
+static inline void
+s3c2410_dma_freebuf(struct s3c2410_dma_buf *buf)
+{
+ int magicok = (buf->magic == BUF_MAGIC);
+
+ buf->magic = -1;
+
+ if (magicok) {
+ kmem_cache_free(dma_kmem, buf);
+ } else {
+ printk("s3c2410_dma_freebuf: buff %p with bad magic\n", buf);
+ }
+}
+
+/* s3c2410_dma_lastxfer
+ *
+ * called when the system is out of buffers, to ensure that the channel
+ * is prepared for shutdown.
+*/
+
+static inline void
+s3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan)
+{
+#if 0
+ pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n",
+ chan->number, chan->load_state);
+#endif
+
+ switch (chan->load_state) {
+ case S3C2410_DMALOAD_NONE:
+ break;
+
+ case S3C2410_DMALOAD_1LOADED:
+ if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
+ /* flag error? */
+ printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
+ chan->number, __FUNCTION__);
+ return;
+ }
+ break;
+
+ case S3C2410_DMALOAD_1LOADED_1RUNNING:
+ /* I belive in this case we do not have anything to do
+ * until the next buffer comes along, and we turn off the
+ * reload */
+ return;
+
+ default:
+ pr_debug("dma%d: lastxfer: unhandled load_state %d with no next\n",
+ chan->number, chan->load_state);
+ return;
+
+ }
+
+ /* hopefully this'll shut the damned thing up after the transfer... */
+ dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD);
+}
+
+
+#define dmadbg2(x...)
+
+static irqreturn_t
+s3c2410_dma_irq(int irq, void *devpw)
+{
+ struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw;
+ struct s3c2410_dma_buf *buf;
+
+ buf = chan->curr;
+
+ dbg_showchan(chan);
+
+ /* modify the channel state */
+
+ switch (chan->load_state) {
+ case S3C2410_DMALOAD_1RUNNING:
+ /* TODO - if we are running only one buffer, we probably
+ * want to reload here, and then worry about the buffer
+ * callback */
+
+ chan->load_state = S3C2410_DMALOAD_NONE;
+ break;
+
+ case S3C2410_DMALOAD_1LOADED:
+ /* iirc, we should go back to NONE loaded here, we
+ * had a buffer, and it was never verified as being
+ * loaded.
+ */
+
+ chan->load_state = S3C2410_DMALOAD_NONE;
+ break;
+
+ case S3C2410_DMALOAD_1LOADED_1RUNNING:
+ /* we'll worry about checking to see if another buffer is
+ * ready after we've called back the owner. This should
+ * ensure we do not wait around too long for the DMA
+ * engine to start the next transfer
+ */
+
+ chan->load_state = S3C2410_DMALOAD_1LOADED;
+ break;
+
+ case S3C2410_DMALOAD_NONE:
+ printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n",
+ chan->number);
+ break;
+
+ default:
+ printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n",
+ chan->number, chan->load_state);
+ break;
+ }
+
+ if (buf != NULL) {
+ /* update the chain to make sure that if we load any more
+ * buffers when we call the callback function, things should
+ * work properly */
+
+ chan->curr = buf->next;
+ buf->next = NULL;
+
+ if (buf->magic != BUF_MAGIC) {
+ printk(KERN_ERR "dma%d: %s: buf %p incorrect magic\n",
+ chan->number, __FUNCTION__, buf);
+ return IRQ_HANDLED;
+ }
+
+ s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK);
+
+ /* free resouces */
+ s3c2410_dma_freebuf(buf);
+ } else {
+ }
+
+ /* only reload if the channel is still running... our buffer done
+ * routine may have altered the state by requesting the dma channel
+ * to stop or shutdown... */
+
+ /* todo: check that when the channel is shut-down from inside this
+ * function, we cope with unsetting reload, etc */
+
+ if (chan->next != NULL && chan->state != S3C2410_DMA_IDLE) {
+ unsigned long flags;
+
+ switch (chan->load_state) {
+ case S3C2410_DMALOAD_1RUNNING:
+ /* don't need to do anything for this state */
+ break;
+
+ case S3C2410_DMALOAD_NONE:
+ /* can load buffer immediately */
+ break;
+
+ case S3C2410_DMALOAD_1LOADED:
+ if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
+ /* flag error? */
+ printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
+ chan->number, __FUNCTION__);
+ return IRQ_HANDLED;
+ }
+
+ break;
+
+ case S3C2410_DMALOAD_1LOADED_1RUNNING:
+ goto no_load;
+
+ default:
+ printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n",
+ chan->number, chan->load_state);
+ return IRQ_HANDLED;
+ }
+
+ local_irq_save(flags);
+ s3c2410_dma_loadbuffer(chan, chan->next);
+ local_irq_restore(flags);
+ } else {
+ s3c2410_dma_lastxfer(chan);
+
+ /* see if we can stop this channel.. */
+ if (chan->load_state == S3C2410_DMALOAD_NONE) {
+ pr_debug("dma%d: end of transfer, stopping channel (%ld)\n",
+ chan->number, jiffies);
+ s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL,
+ S3C2410_DMAOP_STOP);
+ }
+ }
+
+ no_load:
+ return IRQ_HANDLED;
+}
+
+static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel);
+
+/* s3c2410_request_dma
+ *
+ * get control of an dma channel
+*/
+
+int s3c2410_dma_request(unsigned int channel,
+ struct s3c2410_dma_client *client,
+ void *dev)
+{
+ struct s3c2410_dma_chan *chan;
+ unsigned long flags;
+ int err;
+
+ pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n",
+ channel, client->name, dev);
+
+ local_irq_save(flags);
+
+ chan = s3c2410_dma_map_channel(channel);
+ if (chan == NULL) {
+ local_irq_restore(flags);
+ return -EBUSY;
+ }
+
+ dbg_showchan(chan);
+
+ chan->client = client;
+ chan->in_use = 1;
+
+ if (!chan->irq_claimed) {
+ pr_debug("dma%d: %s : requesting irq %d\n",
+ channel, __FUNCTION__, chan->irq);
+
+ chan->irq_claimed = 1;
+ local_irq_restore(flags);
+
+ err = request_irq(chan->irq, s3c2410_dma_irq, IRQF_DISABLED,
+ client->name, (void *)chan);
+
+ local_irq_save(flags);
+
+ if (err) {
+ chan->in_use = 0;
+ chan->irq_claimed = 0;
+ local_irq_restore(flags);
+
+ printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n",
+ client->name, chan->irq, chan->number);
+ return err;
+ }
+
+ chan->irq_enabled = 1;
+ }
+
+ local_irq_restore(flags);
+
+ /* need to setup */
+
+ pr_debug("%s: channel initialised, %p\n", __FUNCTION__, chan);
+
+ return 0;
+}
+
+EXPORT_SYMBOL(s3c2410_dma_request);
+
+/* s3c2410_dma_free
+ *
+ * release the given channel back to the system, will stop and flush
+ * any outstanding transfers, and ensure the channel is ready for the
+ * next claimant.
+ *
+ * Note, although a warning is currently printed if the freeing client
+ * info is not the same as the registrant's client info, the free is still
+ * allowed to go through.
+*/
+
+int s3c2410_dma_free(dmach_t channel, struct s3c2410_dma_client *client)
+{
+ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+ unsigned long flags;
+
+ if (chan == NULL)
+ return -EINVAL;
+
+ local_irq_save(flags);
+
+ if (chan->client != client) {
+ printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n",
+ channel, chan->client, client);
+ }
+
+ /* sort out stopping and freeing the channel */
+
+ if (chan->state != S3C2410_DMA_IDLE) {
+ pr_debug("%s: need to stop dma channel %p\n",
+ __FUNCTION__, chan);
+
+ /* possibly flush the channel */
+ s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STOP);
+ }
+
+ chan->client = NULL;
+ chan->in_use = 0;
+
+ if (chan->irq_claimed)
+ free_irq(chan->irq, (void *)chan);
+
+ chan->irq_claimed = 0;
+
+ if (!(channel & DMACH_LOW_LEVEL))
+ dma_chan_map[channel] = NULL;
+
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+EXPORT_SYMBOL(s3c2410_dma_free);
+
+static int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan)
+{
+ unsigned long flags;
+ unsigned long tmp;
+
+ pr_debug("%s:\n", __FUNCTION__);
+
+ dbg_showchan(chan);
+
+ local_irq_save(flags);
+
+ s3c2410_dma_call_op(chan, S3C2410_DMAOP_STOP);
+
+ tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
+ tmp |= S3C2410_DMASKTRIG_STOP;
+ //tmp &= ~S3C2410_DMASKTRIG_ON;
+ dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
+
+#if 0
+ /* should also clear interrupts, according to WinCE BSP */
+ tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
+ tmp |= S3C2410_DCON_NORELOAD;
+ dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
+#endif
+
+ /* should stop do this, or should we wait for flush? */
+ chan->state = S3C2410_DMA_IDLE;
+ chan->load_state = S3C2410_DMALOAD_NONE;
+
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+void s3c2410_dma_waitforstop(struct s3c2410_dma_chan *chan)
+{
+ unsigned long tmp;
+ unsigned int timeout = 0x10000;
+
+ while (timeout-- > 0) {
+ tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
+
+ if (!(tmp & S3C2410_DMASKTRIG_ON))
+ return;
+ }
+
+ pr_debug("dma%d: failed to stop?\n", chan->number);
+}
+
+
+/* s3c2410_dma_flush
+ *
+ * stop the channel, and remove all current and pending transfers
+*/
+
+static int s3c2410_dma_flush(struct s3c2410_dma_chan *chan)
+{
+ struct s3c2410_dma_buf *buf, *next;
+ unsigned long flags;
+
+ pr_debug("%s: chan %p (%d)\n", __FUNCTION__, chan, chan->number);
+
+ dbg_showchan(chan);
+
+ local_irq_save(flags);
+
+ if (chan->state != S3C2410_DMA_IDLE) {
+ pr_debug("%s: stopping channel...\n", __FUNCTION__ );
+ s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP);
+ }
+
+ buf = chan->curr;
+ if (buf == NULL)
+ buf = chan->next;
+
+ chan->curr = chan->next = chan->end = NULL;
+
+ if (buf != NULL) {
+ for ( ; buf != NULL; buf = next) {
+ next = buf->next;
+
+ pr_debug("%s: free buffer %p, next %p\n",
+ __FUNCTION__, buf, buf->next);
+
+ s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT);
+ s3c2410_dma_freebuf(buf);
+ }
+ }
+
+ dbg_showregs(chan);
+
+ s3c2410_dma_waitforstop(chan);
+
+#if 0
+ /* should also clear interrupts, according to WinCE BSP */
+ {
+ unsigned long tmp;
+
+ tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
+ tmp |= S3C2410_DCON_NORELOAD;
+ dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
+ }
+#endif
+
+ dbg_showregs(chan);
+
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+int
+s3c2410_dma_started(struct s3c2410_dma_chan *chan)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ dbg_showchan(chan);
+
+ /* if we've only loaded one buffer onto the channel, then chec
+ * to see if we have another, and if so, try and load it so when
+ * the first buffer is finished, the new one will be loaded onto
+ * the channel */
+
+ if (chan->next != NULL) {
+ if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
+
+ if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
+ pr_debug("%s: buff not yet loaded, no more todo\n",
+ __FUNCTION__);
+ } else {
+ chan->load_state = S3C2410_DMALOAD_1RUNNING;
+ s3c2410_dma_loadbuffer(chan, chan->next);
+ }
+
+ } else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) {
+ s3c2410_dma_loadbuffer(chan, chan->next);
+ }
+ }
+
+
+ local_irq_restore(flags);
+
+ return 0;
+
+}
+
+int
+s3c2410_dma_ctrl(dmach_t channel, enum s3c2410_chan_op op)
+{
+ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+
+ if (chan == NULL)
+ return -EINVAL;
+
+ switch (op) {
+ case S3C2410_DMAOP_START:
+ return s3c2410_dma_start(chan);
+
+ case S3C2410_DMAOP_STOP:
+ return s3c2410_dma_dostop(chan);
+
+ case S3C2410_DMAOP_PAUSE:
+ case S3C2410_DMAOP_RESUME:
+ return -ENOENT;
+
+ case S3C2410_DMAOP_FLUSH:
+ return s3c2410_dma_flush(chan);
+
+ case S3C2410_DMAOP_STARTED:
+ return s3c2410_dma_started(chan);
+
+ case S3C2410_DMAOP_TIMEOUT:
+ return 0;
+
+ }
+
+ return -ENOENT; /* unknown, don't bother */
+}
+
+EXPORT_SYMBOL(s3c2410_dma_ctrl);
+
+/* DMA configuration for each channel
+ *
+ * DISRCC -> source of the DMA (AHB,APB)
+ * DISRC -> source address of the DMA
+ * DIDSTC -> destination of the DMA (AHB,APD)
+ * DIDST -> destination address of the DMA
+*/
+
+/* s3c2410_dma_config
+ *
+ * xfersize: size of unit in bytes (1,2,4)
+ * dcon: base value of the DCONx register
+*/
+
+int s3c2410_dma_config(dmach_t channel,
+ int xferunit,
+ int dcon)
+{
+ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+
+ pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n",
+ __FUNCTION__, channel, xferunit, dcon);
+
+ if (chan == NULL)
+ return -EINVAL;
+
+ pr_debug("%s: Initial dcon is %08x\n", __FUNCTION__, dcon);
+
+ dcon |= chan->dcon & dma_sel.dcon_mask;
+
+ pr_debug("%s: New dcon is %08x\n", __FUNCTION__, dcon);
+
+ switch (xferunit) {
+ case 1:
+ dcon |= S3C2410_DCON_BYTE;
+ break;
+
+ case 2:
+ dcon |= S3C2410_DCON_HALFWORD;
+ break;
+
+ case 4:
+ dcon |= S3C2410_DCON_WORD;
+ break;
+
+ default:
+ pr_debug("%s: bad transfer size %d\n", __FUNCTION__, xferunit);
+ return -EINVAL;
+ }
+
+ dcon |= S3C2410_DCON_HWTRIG;
+ dcon |= S3C2410_DCON_INTREQ;
+
+ pr_debug("%s: dcon now %08x\n", __FUNCTION__, dcon);
+
+ chan->dcon = dcon;
+ chan->xfer_unit = xferunit;
+
+ return 0;
+}
+
+EXPORT_SYMBOL(s3c2410_dma_config);
+
+int s3c2410_dma_setflags(dmach_t channel, unsigned int flags)
+{
+ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+
+ if (chan == NULL)
+ return -EINVAL;
+
+ pr_debug("%s: chan=%p, flags=%08x\n", __FUNCTION__, chan, flags);
+
+ chan->flags = flags;
+
+ return 0;
+}
+
+EXPORT_SYMBOL(s3c2410_dma_setflags);
+
+
+/* do we need to protect the settings of the fields from
+ * irq?
+*/
+
+int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn)
+{
+ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+
+ if (chan == NULL)
+ return -EINVAL;
+
+ pr_debug("%s: chan=%p, op rtn=%p\n", __FUNCTION__, chan, rtn);
+
+ chan->op_fn = rtn;
+
+ return 0;
+}
+
+EXPORT_SYMBOL(s3c2410_dma_set_opfn);
+
+int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn)
+{
+ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+
+ if (chan == NULL)
+ return -EINVAL;
+
+ pr_debug("%s: chan=%p, callback rtn=%p\n", __FUNCTION__, chan, rtn);
+
+ chan->callback_fn = rtn;
+
+ return 0;
+}
+
+EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);
+
+/* s3c2410_dma_devconfig
+ *
+ * configure the dma source/destination hardware type and address
+ *
+ * source: S3C2410_DMASRC_HW: source is hardware
+ * S3C2410_DMASRC_MEM: source is memory
+ *
+ * hwcfg: the value for xxxSTCn register,
+ * bit 0: 0=increment pointer, 1=leave pointer
+ * bit 1: 0=soucre is AHB, 1=soucre is APB
+ *
+ * devaddr: physical address of the source
+*/
+
+int s3c2410_dma_devconfig(int channel,
+ enum s3c2410_dmasrc source,
+ int hwcfg,
+ unsigned long devaddr)
+{
+ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+
+ if (chan == NULL)
+ return -EINVAL;
+
+ pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n",
+ __FUNCTION__, (int)source, hwcfg, devaddr);
+
+ chan->source = source;
+ chan->dev_addr = devaddr;
+
+ switch (source) {
+ case S3C2410_DMASRC_HW:
+ /* source is hardware */
+ pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n",
+ __FUNCTION__, devaddr, hwcfg);
+ dma_wrreg(chan, S3C2410_DMA_DISRCC, hwcfg & 3);
+ dma_wrreg(chan, S3C2410_DMA_DISRC, devaddr);
+ dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0));
+
+ chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST);
+ return 0;
+
+ case S3C2410_DMASRC_MEM:
+ /* source is memory */
+ pr_debug( "%s: mem source, devaddr=%08lx, hwcfg=%d\n",
+ __FUNCTION__, devaddr, hwcfg);
+ dma_wrreg(chan, S3C2410_DMA_DISRCC, (0<<1) | (0<<0));
+ dma_wrreg(chan, S3C2410_DMA_DIDST, devaddr);
+ dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3);
+
+ chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC);
+ return 0;
+ }
+
+ printk(KERN_ERR "dma%d: invalid source type (%d)\n", channel, source);
+ return -EINVAL;
+}
+
+EXPORT_SYMBOL(s3c2410_dma_devconfig);
+
+/* s3c2410_dma_getposition
+ *
+ * returns the current transfer points for the dma source and destination
+*/
+
+int s3c2410_dma_getposition(dmach_t channel, dma_addr_t *src, dma_addr_t *dst)
+{
+ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
+
+ if (chan == NULL)
+ return -EINVAL;
+
+ if (src != NULL)
+ *src = dma_rdreg(chan, S3C2410_DMA_DCSRC);
+
+ if (dst != NULL)
+ *dst = dma_rdreg(chan, S3C2410_DMA_DCDST);
+
+ return 0;
+}
+
+EXPORT_SYMBOL(s3c2410_dma_getposition);
+
+
+/* system device class */
+
+#ifdef CONFIG_PM
+
+static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state)
+{
+ struct s3c2410_dma_chan *cp = container_of(dev, struct s3c2410_dma_chan, dev);
+
+ printk(KERN_DEBUG "suspending dma channel %d\n", cp->number);
+
+ if (dma_rdreg(cp, S3C2410_DMA_DMASKTRIG) & S3C2410_DMASKTRIG_ON) {
+ /* the dma channel is still working, which is probably
+ * a bad thing to do over suspend/resume. We stop the
+ * channel and assume that the client is either going to
+ * retry after resume, or that it is broken.
+ */
+
+ printk(KERN_INFO "dma: stopping channel %d due to suspend\n",
+ cp->number);
+
+ s3c2410_dma_dostop(cp);
+ }
+
+ return 0;
+}
+
+static int s3c2410_dma_resume(struct sys_device *dev)
+{
+ return 0;
+}
+
+#else
+#define s3c2410_dma_suspend NULL
+#define s3c2410_dma_resume NULL
+#endif /* CONFIG_PM */
+
+struct sysdev_class dma_sysclass = {
+ set_kset_name("s3c24xx-dma"),
+ .suspend = s3c2410_dma_suspend,
+ .resume = s3c2410_dma_resume,
+};
+
+/* kmem cache implementation */
+
+static void s3c2410_dma_cache_ctor(void *p, struct kmem_cache *c, unsigned long f)
+{
+ memset(p, 0, sizeof(struct s3c2410_dma_buf));
+}
+
+/* initialisation code */
+
+int __init s3c24xx_dma_sysclass_init(void)
+{
+ int ret = sysdev_class_register(&dma_sysclass);
+
+ if (ret != 0)
+ printk(KERN_ERR "dma sysclass registration failed\n");
+
+ return ret;
+}
+
+core_initcall(s3c24xx_dma_sysclass_init);
+
+int __init s3c24xx_dma_sysdev_register(void)
+{
+ struct s3c2410_dma_chan *cp = s3c2410_chans;
+ int channel, ret;
+
+ for (channel = 0; channel < dma_channels; cp++, channel++) {
+ cp->dev.cls = &dma_sysclass;
+ cp->dev.id = channel;
+ ret = sysdev_register(&cp->dev);
+
+ if (ret) {
+ printk(KERN_ERR "error registering dev for dma %d\n",
+ channel);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+late_initcall(s3c24xx_dma_sysdev_register);
+
+int __init s3c24xx_dma_init(unsigned int channels, unsigned int irq,
+ unsigned int stride)
+{
+ struct s3c2410_dma_chan *cp;
+ int channel;
+ int ret;
+
+ printk("S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics\n");
+
+ dma_channels = channels;
+
+ dma_base = ioremap(S3C24XX_PA_DMA, stride * channels);
+ if (dma_base == NULL) {
+ printk(KERN_ERR "dma failed to remap register block\n");
+ return -ENOMEM;
+ }
+
+ dma_kmem = kmem_cache_create("dma_desc",
+ sizeof(struct s3c2410_dma_buf), 0,
+ SLAB_HWCACHE_ALIGN,
+ s3c2410_dma_cache_ctor, NULL);
+
+ if (dma_kmem == NULL) {
+ printk(KERN_ERR "dma failed to make kmem cache\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (channel = 0; channel < channels; channel++) {
+ cp = &s3c2410_chans[channel];
+
+ memset(cp, 0, sizeof(struct s3c2410_dma_chan));
+
+ /* dma channel irqs are in order.. */
+ cp->number = channel;
+ cp->irq = channel + irq;
+ cp->regs = dma_base + (channel * stride);
+
+ /* point current stats somewhere */
+ cp->stats = &cp->stats_store;
+ cp->stats_store.timeout_shortest = LONG_MAX;
+
+ /* basic channel configuration */
+
+ cp->load_timeout = 1<<18;
+
+ printk("DMA channel %d at %p, irq %d\n",
+ cp->number, cp->regs, cp->irq);
+ }
+
+ return 0;
+
+ err:
+ kmem_cache_destroy(dma_kmem);
+ iounmap(dma_base);
+ dma_base = NULL;
+ return ret;
+}
+
+int s3c2410_dma_init(void)
+{
+ return s3c24xx_dma_init(4, IRQ_DMA0, 0x40);
+}
+
+static inline int is_channel_valid(unsigned int channel)
+{
+ return (channel & DMA_CH_VALID);
+}
+
+static struct s3c24xx_dma_order *dma_order;
+
+
+/* s3c2410_dma_map_channel()
+ *
+ * turn the virtual channel number into a real, and un-used hardware
+ * channel.
+ *
+ * first, try the dma ordering given to us by either the relevant
+ * dma code, or the board. Then just find the first usable free
+ * channel
+*/
+
+struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
+{
+ struct s3c24xx_dma_order_ch *ord = NULL;
+ struct s3c24xx_dma_map *ch_map;
+ struct s3c2410_dma_chan *dmach;
+ int ch;
+
+ if (dma_sel.map == NULL || channel > dma_sel.map_size)
+ return NULL;
+
+ ch_map = dma_sel.map + channel;
+
+ /* first, try the board mapping */
+
+ if (dma_order) {
+ ord = &dma_order->channels[channel];
+
+ for (ch = 0; ch < dma_channels; ch++) {
+ if (!is_channel_valid(ord->list[ch]))
+ continue;
+
+ if (s3c2410_chans[ord->list[ch]].in_use == 0) {
+ ch = ord->list[ch] & ~DMA_CH_VALID;
+ goto found;
+ }
+ }
+
+ if (ord->flags & DMA_CH_NEVER)
+ return NULL;
+ }
+
+ /* second, search the channel map for first free */
+
+ for (ch = 0; ch < dma_channels; ch++) {
+ if (!is_channel_valid(ch_map->channels[ch]))
+ continue;
+
+ if (s3c2410_chans[ch].in_use == 0) {
+ printk("mapped channel %d to %d\n", channel, ch);
+ break;
+ }
+ }
+
+ if (ch >= dma_channels)
+ return NULL;
+
+ /* update our channel mapping */
+
+ found:
+ dmach = &s3c2410_chans[ch];
+ dma_chan_map[channel] = dmach;
+
+ /* select the channel */
+
+ (dma_sel.select)(dmach, ch_map);
+
+ return dmach;
+}
+
+static int s3c24xx_dma_check_entry(struct s3c24xx_dma_map *map, int ch)
+{
+ return 0;
+}
+
+int __init s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel)
+{
+ struct s3c24xx_dma_map *nmap;
+ size_t map_sz = sizeof(*nmap) * sel->map_size;
+ int ptr;
+
+ nmap = kmalloc(map_sz, GFP_KERNEL);
+ if (nmap == NULL)
+ return -ENOMEM;
+
+ memcpy(nmap, sel->map, map_sz);
+ memcpy(&dma_sel, sel, sizeof(*sel));
+
+ dma_sel.map = nmap;
+
+ for (ptr = 0; ptr < sel->map_size; ptr++)
+ s3c24xx_dma_check_entry(nmap+ptr, ptr);
+
+ return 0;
+}
+
+int __init s3c24xx_dma_order_set(struct s3c24xx_dma_order *ord)
+{
+ struct s3c24xx_dma_order *nord = dma_order;
+
+ if (nord == NULL)
+ nord = kmalloc(sizeof(struct s3c24xx_dma_order), GFP_KERNEL);
+
+ if (nord == NULL) {
+ printk(KERN_ERR "no memory to store dma channel order\n");
+ return -ENOMEM;
+ }
+
+ dma_order = nord;
+ memcpy(nord, ord, sizeof(struct s3c24xx_dma_order));
+ return 0;
+}
diff --git a/arch/arm/plat-s3c24xx/gpio.c b/arch/arm/plat-s3c24xx/gpio.c
new file mode 100644
index 00000000000..ec3a09c4d18
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/gpio.c
@@ -0,0 +1,188 @@
+/* linux/arch/arm/plat-s3c24xx/gpio.c
+ *
+ * Copyright (c) 2004-2005 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX GPIO 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 <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/arch/regs-gpio.h>
+
+void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
+{
+ void __iomem *base = S3C24XX_GPIO_BASE(pin);
+ unsigned long mask;
+ unsigned long con;
+ unsigned long flags;
+
+ if (pin < S3C2410_GPIO_BANKB) {
+ mask = 1 << S3C2410_GPIO_OFFSET(pin);
+ } else {
+ mask = 3 << S3C2410_GPIO_OFFSET(pin)*2;
+ }
+
+ switch (function) {
+ case S3C2410_GPIO_LEAVE:
+ mask = 0;
+ function = 0;
+ break;
+
+ case S3C2410_GPIO_INPUT:
+ case S3C2410_GPIO_OUTPUT:
+ case S3C2410_GPIO_SFN2:
+ case S3C2410_GPIO_SFN3:
+ if (pin < S3C2410_GPIO_BANKB) {
+ function -= 1;
+ function &= 1;
+ function <<= S3C2410_GPIO_OFFSET(pin);
+ } else {
+ function &= 3;
+ function <<= S3C2410_GPIO_OFFSET(pin)*2;
+ }
+ }
+
+ /* modify the specified register wwith IRQs off */
+
+ local_irq_save(flags);
+
+ con = __raw_readl(base + 0x00);
+ con &= ~mask;
+ con |= function;
+
+ __raw_writel(con, base + 0x00);
+
+ local_irq_restore(flags);
+}
+
+EXPORT_SYMBOL(s3c2410_gpio_cfgpin);
+
+unsigned int s3c2410_gpio_getcfg(unsigned int pin)
+{
+ void __iomem *base = S3C24XX_GPIO_BASE(pin);
+ unsigned long val = __raw_readl(base);
+
+ if (pin < S3C2410_GPIO_BANKB) {
+ val >>= S3C2410_GPIO_OFFSET(pin);
+ val &= 1;
+ val += 1;
+ } else {
+ val >>= S3C2410_GPIO_OFFSET(pin)*2;
+ val &= 3;
+ }
+
+ return val | S3C2410_GPIO_INPUT;
+}
+
+EXPORT_SYMBOL(s3c2410_gpio_getcfg);
+
+void s3c2410_gpio_pullup(unsigned int pin, unsigned int to)
+{
+ void __iomem *base = S3C24XX_GPIO_BASE(pin);
+ unsigned long offs = S3C2410_GPIO_OFFSET(pin);
+ unsigned long flags;
+ unsigned long up;
+
+ if (pin < S3C2410_GPIO_BANKB)
+ return;
+
+ local_irq_save(flags);
+
+ up = __raw_readl(base + 0x08);
+ up &= ~(1L << offs);
+ up |= to << offs;
+ __raw_writel(up, base + 0x08);
+
+ local_irq_restore(flags);
+}
+
+EXPORT_SYMBOL(s3c2410_gpio_pullup);
+
+void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
+{
+ void __iomem *base = S3C24XX_GPIO_BASE(pin);
+ unsigned long offs = S3C2410_GPIO_OFFSET(pin);
+ unsigned long flags;
+ unsigned long dat;
+
+ local_irq_save(flags);
+
+ dat = __raw_readl(base + 0x04);
+ dat &= ~(1 << offs);
+ dat |= to << offs;
+ __raw_writel(dat, base + 0x04);
+
+ local_irq_restore(flags);
+}
+
+EXPORT_SYMBOL(s3c2410_gpio_setpin);
+
+unsigned int s3c2410_gpio_getpin(unsigned int pin)
+{
+ void __iomem *base = S3C24XX_GPIO_BASE(pin);
+ unsigned long offs = S3C2410_GPIO_OFFSET(pin);
+
+ return __raw_readl(base + 0x04) & (1<< offs);
+}
+
+EXPORT_SYMBOL(s3c2410_gpio_getpin);
+
+unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change)
+{
+ unsigned long flags;
+ unsigned long misccr;
+
+ local_irq_save(flags);
+ misccr = __raw_readl(S3C24XX_MISCCR);
+ misccr &= ~clear;
+ misccr ^= change;
+ __raw_writel(misccr, S3C24XX_MISCCR);
+ local_irq_restore(flags);
+
+ return misccr;
+}
+
+EXPORT_SYMBOL(s3c2410_modify_misccr);
+
+int s3c2410_gpio_getirq(unsigned int pin)
+{
+ if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15)
+ return -1; /* not valid interrupts */
+
+ if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7)
+ return -1; /* not valid pin */
+
+ if (pin < S3C2410_GPF4)
+ return (pin - S3C2410_GPF0) + IRQ_EINT0;
+
+ if (pin < S3C2410_GPG0)
+ return (pin - S3C2410_GPF4) + IRQ_EINT4;
+
+ return (pin - S3C2410_GPG0) + IRQ_EINT8;
+}
+
+EXPORT_SYMBOL(s3c2410_gpio_getirq);
diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
new file mode 100644
index 00000000000..ce186398e3f
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/irq.c
@@ -0,0 +1,801 @@
+/* linux/arch/arm/plat-s3c24xx/irq.c
+ *
+ * Copyright (c) 2003,2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * 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
+ *
+ * Changelog:
+ *
+ * 22-Jul-2004 Ben Dooks <ben@simtec.co.uk>
+ * Fixed compile warnings
+ *
+ * 22-Jul-2004 Roc Wu <cooloney@yahoo.com.cn>
+ * Fixed s3c_extirq_type
+ *
+ * 21-Jul-2004 Arnaud Patard (Rtp) <arnaud.patard@rtp-net.org>
+ * Addition of ADC/TC demux
+ *
+ * 04-Oct-2004 Klaus Fetscher <k.fetscher@fetron.de>
+ * Fix for set_irq_type() on low EINT numbers
+ *
+ * 05-Oct-2004 Ben Dooks <ben@simtec.co.uk>
+ * Tidy up KF's patch and sort out new release
+ *
+ * 05-Oct-2004 Ben Dooks <ben@simtec.co.uk>
+ * Add support for power management controls
+ *
+ * 04-Nov-2004 Ben Dooks
+ * Fix standard IRQ wake for EINT0..4 and RTC
+ *
+ * 22-Feb-2005 Ben Dooks
+ * Fixed edge-triggering on ADC IRQ
+ *
+ * 28-Jun-2005 Ben Dooks
+ * Mark IRQ_LCD valid
+ *
+ * 25-Jul-2005 Ben Dooks
+ * Split the S3C2440 IRQ code to seperate file
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/ptrace.h>
+#include <linux/sysdev.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/mach/irq.h>
+
+#include <asm/arch/regs-irq.h>
+#include <asm/arch/regs-gpio.h>
+
+#include <asm/plat-s3c24xx/cpu.h>
+#include <asm/plat-s3c24xx/pm.h>
+#include <asm/plat-s3c24xx/irq.h>
+
+/* wakeup irq control */
+
+#ifdef CONFIG_PM
+
+/* state for IRQs over sleep */
+
+/* default is to allow for EINT0..EINT15, and IRQ_RTC as wakeup sources
+ *
+ * set bit to 1 in allow bitfield to enable the wakeup settings on it
+*/
+
+unsigned long s3c_irqwake_intallow = 1L << (IRQ_RTC - IRQ_EINT0) | 0xfL;
+unsigned long s3c_irqwake_intmask = 0xffffffffL;
+unsigned long s3c_irqwake_eintallow = 0x0000fff0L;
+unsigned long s3c_irqwake_eintmask = 0xffffffffL;
+
+int
+s3c_irq_wake(unsigned int irqno, unsigned int state)
+{
+ unsigned long irqbit = 1 << (irqno - IRQ_EINT0);
+
+ if (!(s3c_irqwake_intallow & irqbit))
+ return -ENOENT;
+
+ printk(KERN_INFO "wake %s for irq %d\n",
+ state ? "enabled" : "disabled", irqno);
+
+ if (!state)
+ s3c_irqwake_intmask |= irqbit;
+ else
+ s3c_irqwake_intmask &= ~irqbit;
+
+ return 0;
+}
+
+static int
+s3c_irqext_wake(unsigned int irqno, unsigned int state)
+{
+ unsigned long bit = 1L << (irqno - EXTINT_OFF);
+
+ if (!(s3c_irqwake_eintallow & bit))
+ return -ENOENT;
+
+ printk(KERN_INFO "wake %s for irq %d\n",
+ state ? "enabled" : "disabled", irqno);
+
+ if (!state)
+ s3c_irqwake_eintmask |= bit;
+ else
+ s3c_irqwake_eintmask &= ~bit;
+
+ return 0;
+}
+
+#else
+#define s3c_irqext_wake NULL
+#define s3c_irq_wake NULL
+#endif
+
+
+static void
+s3c_irq_mask(unsigned int irqno)
+{
+ unsigned long mask;
+
+ irqno -= IRQ_EINT0;
+
+ mask = __raw_readl(S3C2410_INTMSK);
+ mask |= 1UL << irqno;
+ __raw_writel(mask, S3C2410_INTMSK);
+}
+
+static inline void
+s3c_irq_ack(unsigned int irqno)
+{
+ unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
+
+ __raw_writel(bitval, S3C2410_SRCPND);
+ __raw_writel(bitval, S3C2410_INTPND);
+}
+
+static inline void
+s3c_irq_maskack(unsigned int irqno)
+{
+ unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
+ unsigned long mask;
+
+ mask = __raw_readl(S3C2410_INTMSK);
+ __raw_writel(mask|bitval, S3C2410_INTMSK);
+
+ __raw_writel(bitval, S3C2410_SRCPND);
+ __raw_writel(bitval, S3C2410_INTPND);
+}
+
+
+static void
+s3c_irq_unmask(unsigned int irqno)
+{
+ unsigned long mask;
+
+ if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23)
+ irqdbf2("s3c_irq_unmask %d\n", irqno);
+
+ irqno -= IRQ_EINT0;
+
+ mask = __raw_readl(S3C2410_INTMSK);
+ mask &= ~(1UL << irqno);
+ __raw_writel(mask, S3C2410_INTMSK);
+}
+
+struct irq_chip s3c_irq_level_chip = {
+ .name = "s3c-level",
+ .ack = s3c_irq_maskack,
+ .mask = s3c_irq_mask,
+ .unmask = s3c_irq_unmask,
+ .set_wake = s3c_irq_wake
+};
+
+static struct irq_chip s3c_irq_chip = {
+ .name = "s3c",
+ .ack = s3c_irq_ack,
+ .mask = s3c_irq_mask,
+ .unmask = s3c_irq_unmask,
+ .set_wake = s3c_irq_wake
+};
+
+static void
+s3c_irqext_mask(unsigned int irqno)
+{
+ unsigned long mask;
+
+ irqno -= EXTINT_OFF;
+
+ mask = __raw_readl(S3C24XX_EINTMASK);
+ mask |= ( 1UL << irqno);
+ __raw_writel(mask, S3C24XX_EINTMASK);
+}
+
+static void
+s3c_irqext_ack(unsigned int irqno)
+{
+ unsigned long req;
+ unsigned long bit;
+ unsigned long mask;
+
+ bit = 1UL << (irqno - EXTINT_OFF);
+
+ mask = __raw_readl(S3C24XX_EINTMASK);
+
+ __raw_writel(bit, S3C24XX_EINTPEND);
+
+ req = __raw_readl(S3C24XX_EINTPEND);
+ req &= ~mask;
+
+ /* not sure if we should be acking the parent irq... */
+
+ if (irqno <= IRQ_EINT7 ) {
+ if ((req & 0xf0) == 0)
+ s3c_irq_ack(IRQ_EINT4t7);
+ } else {
+ if ((req >> 8) == 0)
+ s3c_irq_ack(IRQ_EINT8t23);
+ }
+}
+
+static void
+s3c_irqext_unmask(unsigned int irqno)
+{
+ unsigned long mask;
+
+ irqno -= EXTINT_OFF;
+
+ mask = __raw_readl(S3C24XX_EINTMASK);
+ mask &= ~( 1UL << irqno);
+ __raw_writel(mask, S3C24XX_EINTMASK);
+}
+
+int
+s3c_irqext_type(unsigned int irq, unsigned int type)
+{
+ void __iomem *extint_reg;
+ void __iomem *gpcon_reg;
+ unsigned long gpcon_offset, extint_offset;
+ unsigned long newvalue = 0, value;
+
+ if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3))
+ {
+ gpcon_reg = S3C2410_GPFCON;
+ extint_reg = S3C24XX_EXTINT0;
+ gpcon_offset = (irq - IRQ_EINT0) * 2;
+ extint_offset = (irq - IRQ_EINT0) * 4;
+ }
+ else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7))
+ {
+ gpcon_reg = S3C2410_GPFCON;
+ extint_reg = S3C24XX_EXTINT0;
+ gpcon_offset = (irq - (EXTINT_OFF)) * 2;
+ extint_offset = (irq - (EXTINT_OFF)) * 4;
+ }
+ else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15))
+ {
+ gpcon_reg = S3C2410_GPGCON;
+ extint_reg = S3C24XX_EXTINT1;
+ gpcon_offset = (irq - IRQ_EINT8) * 2;
+ extint_offset = (irq - IRQ_EINT8) * 4;
+ }
+ else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23))
+ {
+ gpcon_reg = S3C2410_GPGCON;
+ extint_reg = S3C24XX_EXTINT2;
+ gpcon_offset = (irq - IRQ_EINT8) * 2;
+ extint_offset = (irq - IRQ_EINT16) * 4;
+ } else
+ return -1;
+
+ /* Set the GPIO to external interrupt mode */
+ value = __raw_readl(gpcon_reg);
+ value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset);
+ __raw_writel(value, gpcon_reg);
+
+ /* Set the external interrupt to pointed trigger type */
+ switch (type)
+ {
+ case IRQT_NOEDGE:
+ printk(KERN_WARNING "No edge setting!\n");
+ break;
+
+ case IRQT_RISING:
+ newvalue = S3C2410_EXTINT_RISEEDGE;
+ break;
+
+ case IRQT_FALLING:
+ newvalue = S3C2410_EXTINT_FALLEDGE;
+ break;
+
+ case IRQT_BOTHEDGE:
+ newvalue = S3C2410_EXTINT_BOTHEDGE;
+ break;
+
+ case IRQT_LOW:
+ newvalue = S3C2410_EXTINT_LOWLEV;
+ break;
+
+ case IRQT_HIGH:
+ newvalue = S3C2410_EXTINT_HILEV;
+ break;
+
+ default:
+ printk(KERN_ERR "No such irq type %d", type);
+ return -1;
+ }
+
+ value = __raw_readl(extint_reg);
+ value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset);
+ __raw_writel(value, extint_reg);
+
+ return 0;
+}
+
+static struct irq_chip s3c_irqext_chip = {
+ .name = "s3c-ext",
+ .mask = s3c_irqext_mask,
+ .unmask = s3c_irqext_unmask,
+ .ack = s3c_irqext_ack,
+ .set_type = s3c_irqext_type,
+ .set_wake = s3c_irqext_wake
+};
+
+static struct irq_chip s3c_irq_eint0t4 = {
+ .name = "s3c-ext0",
+ .ack = s3c_irq_ack,
+ .mask = s3c_irq_mask,
+ .unmask = s3c_irq_unmask,
+ .set_wake = s3c_irq_wake,
+ .set_type = s3c_irqext_type,
+};
+
+/* mask values for the parent registers for each of the interrupt types */
+
+#define INTMSK_UART0 (1UL << (IRQ_UART0 - IRQ_EINT0))
+#define INTMSK_UART1 (1UL << (IRQ_UART1 - IRQ_EINT0))
+#define INTMSK_UART2 (1UL << (IRQ_UART2 - IRQ_EINT0))
+#define INTMSK_ADCPARENT (1UL << (IRQ_ADCPARENT - IRQ_EINT0))
+
+
+/* UART0 */
+
+static void
+s3c_irq_uart0_mask(unsigned int irqno)
+{
+ s3c_irqsub_mask(irqno, INTMSK_UART0, 7);
+}
+
+static void
+s3c_irq_uart0_unmask(unsigned int irqno)
+{
+ s3c_irqsub_unmask(irqno, INTMSK_UART0);
+}
+
+static void
+s3c_irq_uart0_ack(unsigned int irqno)
+{
+ s3c_irqsub_maskack(irqno, INTMSK_UART0, 7);
+}
+
+static struct irq_chip s3c_irq_uart0 = {
+ .name = "s3c-uart0",
+ .mask = s3c_irq_uart0_mask,
+ .unmask = s3c_irq_uart0_unmask,
+ .ack = s3c_irq_uart0_ack,
+};
+
+/* UART1 */
+
+static void
+s3c_irq_uart1_mask(unsigned int irqno)
+{
+ s3c_irqsub_mask(irqno, INTMSK_UART1, 7 << 3);
+}
+
+static void
+s3c_irq_uart1_unmask(unsigned int irqno)
+{
+ s3c_irqsub_unmask(irqno, INTMSK_UART1);
+}
+
+static void
+s3c_irq_uart1_ack(unsigned int irqno)
+{
+ s3c_irqsub_maskack(irqno, INTMSK_UART1, 7 << 3);
+}
+
+static struct irq_chip s3c_irq_uart1 = {
+ .name = "s3c-uart1",
+ .mask = s3c_irq_uart1_mask,
+ .unmask = s3c_irq_uart1_unmask,
+ .ack = s3c_irq_uart1_ack,
+};
+
+/* UART2 */
+
+static void
+s3c_irq_uart2_mask(unsigned int irqno)
+{
+ s3c_irqsub_mask(irqno, INTMSK_UART2, 7 << 6);
+}
+
+static void
+s3c_irq_uart2_unmask(unsigned int irqno)
+{
+ s3c_irqsub_unmask(irqno, INTMSK_UART2);
+}
+
+static void
+s3c_irq_uart2_ack(unsigned int irqno)
+{
+ s3c_irqsub_maskack(irqno, INTMSK_UART2, 7 << 6);
+}
+
+static struct irq_chip s3c_irq_uart2 = {
+ .name = "s3c-uart2",
+ .mask = s3c_irq_uart2_mask,
+ .unmask = s3c_irq_uart2_unmask,
+ .ack = s3c_irq_uart2_ack,
+};
+
+/* ADC and Touchscreen */
+
+static void
+s3c_irq_adc_mask(unsigned int irqno)
+{
+ s3c_irqsub_mask(irqno, INTMSK_ADCPARENT, 3 << 9);
+}
+
+static void
+s3c_irq_adc_unmask(unsigned int irqno)
+{
+ s3c_irqsub_unmask(irqno, INTMSK_ADCPARENT);
+}
+
+static void
+s3c_irq_adc_ack(unsigned int irqno)
+{
+ s3c_irqsub_ack(irqno, INTMSK_ADCPARENT, 3 << 9);
+}
+
+static struct irq_chip s3c_irq_adc = {
+ .name = "s3c-adc",
+ .mask = s3c_irq_adc_mask,
+ .unmask = s3c_irq_adc_unmask,
+ .ack = s3c_irq_adc_ack,
+};
+
+/* irq demux for adc */
+static void s3c_irq_demux_adc(unsigned int irq,
+ struct irq_desc *desc)
+{
+ unsigned int subsrc, submsk;
+ unsigned int offset = 9;
+ struct irq_desc *mydesc;
+
+ /* read the current pending interrupts, and the mask
+ * for what it is available */
+
+ subsrc = __raw_readl(S3C2410_SUBSRCPND);
+ submsk = __raw_readl(S3C2410_INTSUBMSK);
+
+ subsrc &= ~submsk;
+ subsrc >>= offset;
+ subsrc &= 3;
+
+ if (subsrc != 0) {
+ if (subsrc & 1) {
+ mydesc = irq_desc + IRQ_TC;
+ desc_handle_irq(IRQ_TC, mydesc);
+ }
+ if (subsrc & 2) {
+ mydesc = irq_desc + IRQ_ADC;
+ desc_handle_irq(IRQ_ADC, mydesc);
+ }
+ }
+}
+
+static void s3c_irq_demux_uart(unsigned int start)
+{
+ unsigned int subsrc, submsk;
+ unsigned int offset = start - IRQ_S3CUART_RX0;
+ struct irq_desc *desc;
+
+ /* read the current pending interrupts, and the mask
+ * for what it is available */
+
+ subsrc = __raw_readl(S3C2410_SUBSRCPND);
+ submsk = __raw_readl(S3C2410_INTSUBMSK);
+
+ irqdbf2("s3c_irq_demux_uart: start=%d (%d), subsrc=0x%08x,0x%08x\n",
+ start, offset, subsrc, submsk);
+
+ subsrc &= ~submsk;
+ subsrc >>= offset;
+ subsrc &= 7;
+
+ if (subsrc != 0) {
+ desc = irq_desc + start;
+
+ if (subsrc & 1)
+ desc_handle_irq(start, desc);
+
+ desc++;
+
+ if (subsrc & 2)
+ desc_handle_irq(start+1, desc);
+
+ desc++;
+
+ if (subsrc & 4)
+ desc_handle_irq(start+2, desc);
+ }
+}
+
+/* uart demux entry points */
+
+static void
+s3c_irq_demux_uart0(unsigned int irq,
+ struct irq_desc *desc)
+{
+ irq = irq;
+ s3c_irq_demux_uart(IRQ_S3CUART_RX0);
+}
+
+static void
+s3c_irq_demux_uart1(unsigned int irq,
+ struct irq_desc *desc)
+{
+ irq = irq;
+ s3c_irq_demux_uart(IRQ_S3CUART_RX1);
+}
+
+static void
+s3c_irq_demux_uart2(unsigned int irq,
+ struct irq_desc *desc)
+{
+ irq = irq;
+ s3c_irq_demux_uart(IRQ_S3CUART_RX2);
+}
+
+static void
+s3c_irq_demux_extint8(unsigned int irq,
+ struct irq_desc *desc)
+{
+ unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
+ unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
+
+ eintpnd &= ~eintmsk;
+ eintpnd &= ~0xff; /* ignore lower irqs */
+
+ /* we may as well handle all the pending IRQs here */
+
+ while (eintpnd) {
+ irq = __ffs(eintpnd);
+ eintpnd &= ~(1<<irq);
+
+ irq += (IRQ_EINT4 - 4);
+ desc_handle_irq(irq, irq_desc + irq);
+ }
+
+}
+
+static void
+s3c_irq_demux_extint4t7(unsigned int irq,
+ struct irq_desc *desc)
+{
+ unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
+ unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
+
+ eintpnd &= ~eintmsk;
+ eintpnd &= 0xff; /* only lower irqs */
+
+ /* we may as well handle all the pending IRQs here */
+
+ while (eintpnd) {
+ irq = __ffs(eintpnd);
+ eintpnd &= ~(1<<irq);
+
+ irq += (IRQ_EINT4 - 4);
+
+ desc_handle_irq(irq, irq_desc + irq);
+ }
+}
+
+#ifdef CONFIG_PM
+
+static struct sleep_save irq_save[] = {
+ SAVE_ITEM(S3C2410_INTMSK),
+ SAVE_ITEM(S3C2410_INTSUBMSK),
+};
+
+/* the extint values move between the s3c2410/s3c2440 and the s3c2412
+ * so we use an array to hold them, and to calculate the address of
+ * the register at run-time
+*/
+
+static unsigned long save_extint[3];
+static unsigned long save_eintflt[4];
+static unsigned long save_eintmask;
+
+int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(save_extint); i++)
+ save_extint[i] = __raw_readl(S3C24XX_EXTINT0 + (i*4));
+
+ for (i = 0; i < ARRAY_SIZE(save_eintflt); i++)
+ save_eintflt[i] = __raw_readl(S3C24XX_EINFLT0 + (i*4));
+
+ s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save));
+ save_eintmask = __raw_readl(S3C24XX_EINTMASK);
+
+ return 0;
+}
+
+int s3c24xx_irq_resume(struct sys_device *dev)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(save_extint); i++)
+ __raw_writel(save_extint[i], S3C24XX_EXTINT0 + (i*4));
+
+ for (i = 0; i < ARRAY_SIZE(save_eintflt); i++)
+ __raw_writel(save_eintflt[i], S3C24XX_EINFLT0 + (i*4));
+
+ s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
+ __raw_writel(save_eintmask, S3C24XX_EINTMASK);
+
+ return 0;
+}
+
+#else
+#define s3c24xx_irq_suspend NULL
+#define s3c24xx_irq_resume NULL
+#endif
+
+/* s3c24xx_init_irq
+ *
+ * Initialise S3C2410 IRQ system
+*/
+
+void __init s3c24xx_init_irq(void)
+{
+ unsigned long pend;
+ unsigned long last;
+ int irqno;
+ int i;
+
+ irqdbf("s3c2410_init_irq: clearing interrupt status flags\n");
+
+ /* first, clear all interrupts pending... */
+
+ last = 0;
+ for (i = 0; i < 4; i++) {
+ pend = __raw_readl(S3C24XX_EINTPEND);
+
+ if (pend == 0 || pend == last)
+ break;
+
+ __raw_writel(pend, S3C24XX_EINTPEND);
+ printk("irq: clearing pending ext status %08x\n", (int)pend);
+ last = pend;
+ }
+
+ last = 0;
+ for (i = 0; i < 4; i++) {
+ pend = __raw_readl(S3C2410_INTPND);
+
+ if (pend == 0 || pend == last)
+ break;
+
+ __raw_writel(pend, S3C2410_SRCPND);
+ __raw_writel(pend, S3C2410_INTPND);
+ printk("irq: clearing pending status %08x\n", (int)pend);
+ last = pend;
+ }
+
+ last = 0;
+ for (i = 0; i < 4; i++) {
+ pend = __raw_readl(S3C2410_SUBSRCPND);
+
+ if (pend == 0 || pend == last)
+ break;
+
+ printk("irq: clearing subpending status %08x\n", (int)pend);
+ __raw_writel(pend, S3C2410_SUBSRCPND);
+ last = pend;
+ }
+
+ /* register the main interrupts */
+
+ irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n");
+
+ for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) {
+ /* set all the s3c2410 internal irqs */
+
+ switch (irqno) {
+ /* deal with the special IRQs (cascaded) */
+
+ case IRQ_EINT4t7:
+ case IRQ_EINT8t23:
+ case IRQ_UART0:
+ case IRQ_UART1:
+ case IRQ_UART2:
+ case IRQ_ADCPARENT:
+ set_irq_chip(irqno, &s3c_irq_level_chip);
+ set_irq_handler(irqno, handle_level_irq);
+ break;
+
+ case IRQ_RESERVED6:
+ case IRQ_RESERVED24:
+ /* no IRQ here */
+ break;
+
+ default:
+ //irqdbf("registering irq %d (s3c irq)\n", irqno);
+ set_irq_chip(irqno, &s3c_irq_chip);
+ set_irq_handler(irqno, handle_edge_irq);
+ set_irq_flags(irqno, IRQF_VALID);
+ }
+ }
+
+ /* setup the cascade irq handlers */
+
+ set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7);
+ set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8);
+
+ set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
+ set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);
+ set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2);
+ set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc);
+
+ /* external interrupts */
+
+ for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
+ irqdbf("registering irq %d (ext int)\n", irqno);
+ set_irq_chip(irqno, &s3c_irq_eint0t4);
+ set_irq_handler(irqno, handle_edge_irq);
+ set_irq_flags(irqno, IRQF_VALID);
+ }
+
+ for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {
+ irqdbf("registering irq %d (extended s3c irq)\n", irqno);
+ set_irq_chip(irqno, &s3c_irqext_chip);
+ set_irq_handler(irqno, handle_edge_irq);
+ set_irq_flags(irqno, IRQF_VALID);
+ }
+
+ /* register the uart interrupts */
+
+ irqdbf("s3c2410: registering external interrupts\n");
+
+ for (irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) {
+ irqdbf("registering irq %d (s3c uart0 irq)\n", irqno);
+ set_irq_chip(irqno, &s3c_irq_uart0);
+ set_irq_handler(irqno, handle_level_irq);
+ set_irq_flags(irqno, IRQF_VALID);
+ }
+
+ for (irqno = IRQ_S3CUART_RX1; irqno <= IRQ_S3CUART_ERR1; irqno++) {
+ irqdbf("registering irq %d (s3c uart1 irq)\n", irqno);
+ set_irq_chip(irqno, &s3c_irq_uart1);
+ set_irq_handler(irqno, handle_level_irq);
+ set_irq_flags(irqno, IRQF_VALID);
+ }
+
+ for (irqno = IRQ_S3CUART_RX2; irqno <= IRQ_S3CUART_ERR2; irqno++) {
+ irqdbf("registering irq %d (s3c uart2 irq)\n", irqno);
+ set_irq_chip(irqno, &s3c_irq_uart2);
+ set_irq_handler(irqno, handle_level_irq);
+ set_irq_flags(irqno, IRQF_VALID);
+ }
+
+ for (irqno = IRQ_TC; irqno <= IRQ_ADC; irqno++) {
+ irqdbf("registering irq %d (s3c adc irq)\n", irqno);
+ set_irq_chip(irqno, &s3c_irq_adc);
+ set_irq_handler(irqno, handle_edge_irq);
+ set_irq_flags(irqno, IRQF_VALID);
+ }
+
+ irqdbf("s3c2410: registered interrupt handlers\n");
+}
diff --git a/arch/arm/mach-s3c2410/pm-simtec.c b/arch/arm/plat-s3c24xx/pm-simtec.c
index 619133eb716..bd965f2feec 100644
--- a/arch/arm/mach-s3c2410/pm-simtec.c
+++ b/arch/arm/plat-s3c24xx/pm-simtec.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/pm-simtec.c
+/* linux/arch/arm/plat-s3c24xx/pm-simtec.c
*
* Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@@ -32,7 +32,7 @@
#include <asm/mach-types.h>
-#include "pm.h"
+#include <asm/plat-s3c24xx/pm.h>
#define COPYRIGHT ", (c) 2005 Simtec Electronics"
diff --git a/arch/arm/plat-s3c24xx/pm.c b/arch/arm/plat-s3c24xx/pm.c
new file mode 100644
index 00000000000..ecf68d61190
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/pm.c
@@ -0,0 +1,659 @@
+/* linux/arch/arm/plat-s3c24xx/pm.c
+ *
+ * Copyright (c) 2004,2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX Power Manager (Suspend-To-RAM) support
+ *
+ * See Documentation/arm/Samsung-S3C24XX/Suspend.txt for more information
+ *
+ * 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
+ *
+ * Parts based on arch/arm/mach-pxa/pm.c
+ *
+ * Thanks to Dimitry Andric for debugging
+*/
+
+#include <linux/init.h>
+#include <linux/suspend.h>
+#include <linux/errno.h>
+#include <linux/time.h>
+#include <linux/interrupt.h>
+#include <linux/crc32.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/serial_core.h>
+
+#include <asm/cacheflush.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-mem.h>
+#include <asm/arch/regs-irq.h>
+
+#include <asm/mach/time.h>
+
+#include <asm/plat-s3c24xx/pm.h>
+
+/* for external use */
+
+unsigned long s3c_pm_flags;
+
+#define PFX "s3c24xx-pm: "
+
+static struct sleep_save core_save[] = {
+ SAVE_ITEM(S3C2410_LOCKTIME),
+ SAVE_ITEM(S3C2410_CLKCON),
+
+ /* we restore the timings here, with the proviso that the board
+ * brings the system up in an slower, or equal frequency setting
+ * to the original system.
+ *
+ * if we cannot guarantee this, then things are going to go very
+ * wrong here, as we modify the refresh and both pll settings.
+ */
+
+ SAVE_ITEM(S3C2410_BWSCON),
+ SAVE_ITEM(S3C2410_BANKCON0),
+ SAVE_ITEM(S3C2410_BANKCON1),
+ SAVE_ITEM(S3C2410_BANKCON2),
+ SAVE_ITEM(S3C2410_BANKCON3),
+ SAVE_ITEM(S3C2410_BANKCON4),
+ SAVE_ITEM(S3C2410_BANKCON5),
+
+ SAVE_ITEM(S3C2410_CLKDIVN),
+ SAVE_ITEM(S3C2410_MPLLCON),
+ SAVE_ITEM(S3C2410_UPLLCON),
+ SAVE_ITEM(S3C2410_CLKSLOW),
+ SAVE_ITEM(S3C2410_REFRESH),
+};
+
+static struct sleep_save gpio_save[] = {
+ SAVE_ITEM(S3C2410_GPACON),
+ SAVE_ITEM(S3C2410_GPADAT),
+
+ SAVE_ITEM(S3C2410_GPBCON),
+ SAVE_ITEM(S3C2410_GPBDAT),
+ SAVE_ITEM(S3C2410_GPBUP),
+
+ SAVE_ITEM(S3C2410_GPCCON),
+ SAVE_ITEM(S3C2410_GPCDAT),
+ SAVE_ITEM(S3C2410_GPCUP),
+
+ SAVE_ITEM(S3C2410_GPDCON),
+ SAVE_ITEM(S3C2410_GPDDAT),
+ SAVE_ITEM(S3C2410_GPDUP),
+
+ SAVE_ITEM(S3C2410_GPECON),
+ SAVE_ITEM(S3C2410_GPEDAT),
+ SAVE_ITEM(S3C2410_GPEUP),
+
+ SAVE_ITEM(S3C2410_GPFCON),
+ SAVE_ITEM(S3C2410_GPFDAT),
+ SAVE_ITEM(S3C2410_GPFUP),
+
+ SAVE_ITEM(S3C2410_GPGCON),
+ SAVE_ITEM(S3C2410_GPGDAT),
+ SAVE_ITEM(S3C2410_GPGUP),
+
+ SAVE_ITEM(S3C2410_GPHCON),
+ SAVE_ITEM(S3C2410_GPHDAT),
+ SAVE_ITEM(S3C2410_GPHUP),
+
+ SAVE_ITEM(S3C2410_DCLKCON),
+};
+
+#ifdef CONFIG_S3C2410_PM_DEBUG
+
+#define SAVE_UART(va) \
+ SAVE_ITEM((va) + S3C2410_ULCON), \
+ SAVE_ITEM((va) + S3C2410_UCON), \
+ SAVE_ITEM((va) + S3C2410_UFCON), \
+ SAVE_ITEM((va) + S3C2410_UMCON), \
+ SAVE_ITEM((va) + S3C2410_UBRDIV)
+
+static struct sleep_save uart_save[] = {
+ SAVE_UART(S3C24XX_VA_UART0),
+ SAVE_UART(S3C24XX_VA_UART1),
+#ifndef CONFIG_CPU_S3C2400
+ SAVE_UART(S3C24XX_VA_UART2),
+#endif
+};
+
+/* debug
+ *
+ * we send the debug to printascii() to allow it to be seen if the
+ * system never wakes up from the sleep
+*/
+
+extern void printascii(const char *);
+
+void pm_dbg(const char *fmt, ...)
+{
+ va_list va;
+ char buff[256];
+
+ va_start(va, fmt);
+ vsprintf(buff, fmt, va);
+ va_end(va);
+
+ printascii(buff);
+}
+
+static void s3c2410_pm_debug_init(void)
+{
+ unsigned long tmp = __raw_readl(S3C2410_CLKCON);
+
+ /* re-start uart clocks */
+ tmp |= S3C2410_CLKCON_UART0;
+ tmp |= S3C2410_CLKCON_UART1;
+ tmp |= S3C2410_CLKCON_UART2;
+
+ __raw_writel(tmp, S3C2410_CLKCON);
+ udelay(10);
+}
+
+#define DBG(fmt...) pm_dbg(fmt)
+#else
+#define DBG(fmt...) printk(KERN_DEBUG fmt)
+
+#define s3c2410_pm_debug_init() do { } while(0)
+
+static struct sleep_save uart_save[] = {};
+#endif
+
+#if defined(CONFIG_S3C2410_PM_CHECK) && CONFIG_S3C2410_PM_CHECK_CHUNKSIZE != 0
+
+/* suspend checking code...
+ *
+ * this next area does a set of crc checks over all the installed
+ * memory, so the system can verify if the resume was ok.
+ *
+ * CONFIG_S3C2410_PM_CHECK_CHUNKSIZE defines the block-size for the CRC,
+ * increasing it will mean that the area corrupted will be less easy to spot,
+ * and reducing the size will cause the CRC save area to grow
+*/
+
+#define CHECK_CHUNKSIZE (CONFIG_S3C2410_PM_CHECK_CHUNKSIZE * 1024)
+
+static u32 crc_size; /* size needed for the crc block */
+static u32 *crcs; /* allocated over suspend/resume */
+
+typedef u32 *(run_fn_t)(struct resource *ptr, u32 *arg);
+
+/* s3c2410_pm_run_res
+ *
+ * go thorugh the given resource list, and look for system ram
+*/
+
+static void s3c2410_pm_run_res(struct resource *ptr, run_fn_t fn, u32 *arg)
+{
+ while (ptr != NULL) {
+ if (ptr->child != NULL)
+ s3c2410_pm_run_res(ptr->child, fn, arg);
+
+ if ((ptr->flags & IORESOURCE_MEM) &&
+ strcmp(ptr->name, "System RAM") == 0) {
+ DBG("Found system RAM at %08lx..%08lx\n",
+ ptr->start, ptr->end);
+ arg = (fn)(ptr, arg);
+ }
+
+ ptr = ptr->sibling;
+ }
+}
+
+static void s3c2410_pm_run_sysram(run_fn_t fn, u32 *arg)
+{
+ s3c2410_pm_run_res(&iomem_resource, fn, arg);
+}
+
+static u32 *s3c2410_pm_countram(struct resource *res, u32 *val)
+{
+ u32 size = (u32)(res->end - res->start)+1;
+
+ size += CHECK_CHUNKSIZE-1;
+ size /= CHECK_CHUNKSIZE;
+
+ DBG("Area %08lx..%08lx, %d blocks\n", res->start, res->end, size);
+
+ *val += size * sizeof(u32);
+ return val;
+}
+
+/* s3c2410_pm_prepare_check
+ *
+ * prepare the necessary information for creating the CRCs. This
+ * must be done before the final save, as it will require memory
+ * allocating, and thus touching bits of the kernel we do not
+ * know about.
+*/
+
+static void s3c2410_pm_check_prepare(void)
+{
+ crc_size = 0;
+
+ s3c2410_pm_run_sysram(s3c2410_pm_countram, &crc_size);
+
+ DBG("s3c2410_pm_prepare_check: %u checks needed\n", crc_size);
+
+ crcs = kmalloc(crc_size+4, GFP_KERNEL);
+ if (crcs == NULL)
+ printk(KERN_ERR "Cannot allocated CRC save area\n");
+}
+
+static u32 *s3c2410_pm_makecheck(struct resource *res, u32 *val)
+{
+ unsigned long addr, left;
+
+ for (addr = res->start; addr < res->end;
+ addr += CHECK_CHUNKSIZE) {
+ left = res->end - addr;
+
+ if (left > CHECK_CHUNKSIZE)
+ left = CHECK_CHUNKSIZE;
+
+ *val = crc32_le(~0, phys_to_virt(addr), left);
+ val++;
+ }
+
+ return val;
+}
+
+/* s3c2410_pm_check_store
+ *
+ * compute the CRC values for the memory blocks before the final
+ * sleep.
+*/
+
+static void s3c2410_pm_check_store(void)
+{
+ if (crcs != NULL)
+ s3c2410_pm_run_sysram(s3c2410_pm_makecheck, crcs);
+}
+
+/* in_region
+ *
+ * return TRUE if the area defined by ptr..ptr+size contatins the
+ * what..what+whatsz
+*/
+
+static inline int in_region(void *ptr, int size, void *what, size_t whatsz)
+{
+ if ((what+whatsz) < ptr)
+ return 0;
+
+ if (what > (ptr+size))
+ return 0;
+
+ return 1;
+}
+
+static u32 *s3c2410_pm_runcheck(struct resource *res, u32 *val)
+{
+ void *save_at = phys_to_virt(s3c2410_sleep_save_phys);
+ unsigned long addr;
+ unsigned long left;
+ void *ptr;
+ u32 calc;
+
+ for (addr = res->start; addr < res->end;
+ addr += CHECK_CHUNKSIZE) {
+ left = res->end - addr;
+
+ if (left > CHECK_CHUNKSIZE)
+ left = CHECK_CHUNKSIZE;
+
+ ptr = phys_to_virt(addr);
+
+ if (in_region(ptr, left, crcs, crc_size)) {
+ DBG("skipping %08lx, has crc block in\n", addr);
+ goto skip_check;
+ }
+
+ if (in_region(ptr, left, save_at, 32*4 )) {
+ DBG("skipping %08lx, has save block in\n", addr);
+ goto skip_check;
+ }
+
+ /* calculate and check the checksum */
+
+ calc = crc32_le(~0, ptr, left);
+ if (calc != *val) {
+ printk(KERN_ERR PFX "Restore CRC error at "
+ "%08lx (%08x vs %08x)\n", addr, calc, *val);
+
+ DBG("Restore CRC error at %08lx (%08x vs %08x)\n",
+ addr, calc, *val);
+ }
+
+ skip_check:
+ val++;
+ }
+
+ return val;
+}
+
+/* s3c2410_pm_check_restore
+ *
+ * check the CRCs after the restore event and free the memory used
+ * to hold them
+*/
+
+static void s3c2410_pm_check_restore(void)
+{
+ if (crcs != NULL) {
+ s3c2410_pm_run_sysram(s3c2410_pm_runcheck, crcs);
+ kfree(crcs);
+ crcs = NULL;
+ }
+}
+
+#else
+
+#define s3c2410_pm_check_prepare() do { } while(0)
+#define s3c2410_pm_check_restore() do { } while(0)
+#define s3c2410_pm_check_store() do { } while(0)
+#endif
+
+/* helper functions to save and restore register state */
+
+void s3c2410_pm_do_save(struct sleep_save *ptr, int count)
+{
+ for (; count > 0; count--, ptr++) {
+ ptr->val = __raw_readl(ptr->reg);
+ DBG("saved %p value %08lx\n", ptr->reg, ptr->val);
+ }
+}
+
+/* s3c2410_pm_do_restore
+ *
+ * restore the system from the given list of saved registers
+ *
+ * Note, we do not use DBG() in here, as the system may not have
+ * restore the UARTs state yet
+*/
+
+void s3c2410_pm_do_restore(struct sleep_save *ptr, int count)
+{
+ for (; count > 0; count--, ptr++) {
+ printk(KERN_DEBUG "restore %p (restore %08lx, was %08x)\n",
+ ptr->reg, ptr->val, __raw_readl(ptr->reg));
+
+ __raw_writel(ptr->val, ptr->reg);
+ }
+}
+
+/* s3c2410_pm_do_restore_core
+ *
+ * similar to s3c2410_pm_do_restore_core
+ *
+ * WARNING: Do not put any debug in here that may effect memory or use
+ * peripherals, as things may be changing!
+*/
+
+static void s3c2410_pm_do_restore_core(struct sleep_save *ptr, int count)
+{
+ for (; count > 0; count--, ptr++) {
+ __raw_writel(ptr->val, ptr->reg);
+ }
+}
+
+/* s3c2410_pm_show_resume_irqs
+ *
+ * print any IRQs asserted at resume time (ie, we woke from)
+*/
+
+static void s3c2410_pm_show_resume_irqs(int start, unsigned long which,
+ unsigned long mask)
+{
+ int i;
+
+ which &= ~mask;
+
+ for (i = 0; i <= 31; i++) {
+ if ((which) & (1L<<i)) {
+ DBG("IRQ %d asserted at resume\n", start+i);
+ }
+ }
+}
+
+/* s3c2410_pm_check_resume_pin
+ *
+ * check to see if the pin is configured correctly for sleep mode, and
+ * make any necessary adjustments if it is not
+*/
+
+static void s3c2410_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs)
+{
+ unsigned long irqstate;
+ unsigned long pinstate;
+ int irq = s3c2410_gpio_getirq(pin);
+
+ if (irqoffs < 4)
+ irqstate = s3c_irqwake_intmask & (1L<<irqoffs);
+ else
+ irqstate = s3c_irqwake_eintmask & (1L<<irqoffs);
+
+ pinstate = s3c2410_gpio_getcfg(pin);
+
+ if (!irqstate) {
+ if (pinstate == S3C2410_GPIO_IRQ)
+ DBG("Leaving IRQ %d (pin %d) enabled\n", irq, pin);
+ } else {
+ if (pinstate == S3C2410_GPIO_IRQ) {
+ DBG("Disabling IRQ %d (pin %d)\n", irq, pin);
+ s3c2410_gpio_cfgpin(pin, S3C2410_GPIO_INPUT);
+ }
+ }
+}
+
+/* s3c2410_pm_configure_extint
+ *
+ * configure all external interrupt pins
+*/
+
+static void s3c2410_pm_configure_extint(void)
+{
+ int pin;
+
+ /* for each of the external interrupts (EINT0..EINT15) we
+ * need to check wether it is an external interrupt source,
+ * and then configure it as an input if it is not
+ */
+
+ for (pin = S3C2410_GPF0; pin <= S3C2410_GPF7; pin++) {
+ s3c2410_pm_check_resume_pin(pin, pin - S3C2410_GPF0);
+ }
+
+ for (pin = S3C2410_GPG0; pin <= S3C2410_GPG7; pin++) {
+ s3c2410_pm_check_resume_pin(pin, (pin - S3C2410_GPG0)+8);
+ }
+}
+
+void (*pm_cpu_prep)(void);
+void (*pm_cpu_sleep)(void);
+
+#define any_allowed(mask, allow) (((mask) & (allow)) != (allow))
+
+/* s3c2410_pm_enter
+ *
+ * central control for sleep/resume process
+*/
+
+static int s3c2410_pm_enter(suspend_state_t state)
+{
+ unsigned long regs_save[16];
+
+ /* ensure the debug is initialised (if enabled) */
+
+ s3c2410_pm_debug_init();
+
+ DBG("s3c2410_pm_enter(%d)\n", state);
+
+ if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) {
+ printk(KERN_ERR PFX "error: no cpu sleep functions set\n");
+ return -EINVAL;
+ }
+
+ if (state != PM_SUSPEND_MEM) {
+ printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n");
+ return -EINVAL;
+ }
+
+ /* check if we have anything to wake-up with... bad things seem
+ * to happen if you suspend with no wakeup (system will often
+ * require a full power-cycle)
+ */
+
+ if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) &&
+ !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) {
+ printk(KERN_ERR PFX "No sources enabled for wake-up!\n");
+ printk(KERN_ERR PFX "Aborting sleep\n");
+ return -EINVAL;
+ }
+
+ /* prepare check area if configured */
+
+ s3c2410_pm_check_prepare();
+
+ /* store the physical address of the register recovery block */
+
+ s3c2410_sleep_save_phys = virt_to_phys(regs_save);
+
+ DBG("s3c2410_sleep_save_phys=0x%08lx\n", s3c2410_sleep_save_phys);
+
+ /* save all necessary core registers not covered by the drivers */
+
+ s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save));
+ s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save));
+ s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save));
+
+ /* set the irq configuration for wake */
+
+ s3c2410_pm_configure_extint();
+
+ DBG("sleep: irq wakeup masks: %08lx,%08lx\n",
+ s3c_irqwake_intmask, s3c_irqwake_eintmask);
+
+ __raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK);
+ __raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK);
+
+ /* ack any outstanding external interrupts before we go to sleep */
+
+ __raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND);
+ __raw_writel(__raw_readl(S3C2410_INTPND), S3C2410_INTPND);
+ __raw_writel(__raw_readl(S3C2410_SRCPND), S3C2410_SRCPND);
+
+ /* call cpu specific preperation */
+
+ pm_cpu_prep();
+
+ /* flush cache back to ram */
+
+ flush_cache_all();
+
+ s3c2410_pm_check_store();
+
+ /* send the cpu to sleep... */
+
+ __raw_writel(0x00, S3C2410_CLKCON); /* turn off clocks over sleep */
+
+ /* s3c2410_cpu_save will also act as our return point from when
+ * we resume as it saves its own register state, so use the return
+ * code to differentiate return from save and return from sleep */
+
+ if (s3c2410_cpu_save(regs_save) == 0) {
+ flush_cache_all();
+ pm_cpu_sleep();
+ }
+
+ /* restore the cpu state */
+
+ cpu_init();
+
+ /* restore the system state */
+
+ s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save));
+ s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save));
+ s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save));
+
+ s3c2410_pm_debug_init();
+
+ /* check what irq (if any) restored the system */
+
+ DBG("post sleep: IRQs 0x%08x, 0x%08x\n",
+ __raw_readl(S3C2410_SRCPND),
+ __raw_readl(S3C2410_EINTPEND));
+
+ s3c2410_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND),
+ s3c_irqwake_intmask);
+
+ s3c2410_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND),
+ s3c_irqwake_eintmask);
+
+ DBG("post sleep, preparing to return\n");
+
+ s3c2410_pm_check_restore();
+
+ /* ok, let's return from sleep */
+
+ DBG("S3C2410 PM Resume (post-restore)\n");
+ return 0;
+}
+
+/*
+ * Called after processes are frozen, but before we shut down devices.
+ */
+static int s3c2410_pm_prepare(suspend_state_t state)
+{
+ return 0;
+}
+
+/*
+ * Called after devices are re-setup, but before processes are thawed.
+ */
+static int s3c2410_pm_finish(suspend_state_t state)
+{
+ return 0;
+}
+
+/*
+ * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
+ */
+static struct pm_ops s3c2410_pm_ops = {
+ .pm_disk_mode = PM_DISK_FIRMWARE,
+ .prepare = s3c2410_pm_prepare,
+ .enter = s3c2410_pm_enter,
+ .finish = s3c2410_pm_finish,
+};
+
+/* s3c2410_pm_init
+ *
+ * Attach the power management functions. This should be called
+ * from the board specific initialisation if the board supports
+ * it.
+*/
+
+int __init s3c2410_pm_init(void)
+{
+ printk("S3C2410 Power Management, (c) 2004 Simtec Electronics\n");
+
+ pm_set_ops(&s3c2410_pm_ops);
+ return 0;
+}
diff --git a/arch/arm/mach-s3c2410/s3c244x-irq.c b/arch/arm/plat-s3c24xx/s3c244x-irq.c
index ede94636a72..a0e39d89401 100644
--- a/arch/arm/mach-s3c2410/s3c244x-irq.c
+++ b/arch/arm/plat-s3c24xx/s3c244x-irq.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/s3c244x-irq.c
+/* linux/arch/arm/plat-s3c24xx/s3c244x-irq.c
*
* Copyright (c) 2003,2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@@ -35,9 +35,9 @@
#include <asm/arch/regs-irq.h>
#include <asm/arch/regs-gpio.h>
-#include "cpu.h"
-#include "pm.h"
-#include "irq.h"
+#include <asm/plat-s3c24xx/cpu.h>
+#include <asm/plat-s3c24xx/pm.h>
+#include <asm/plat-s3c24xx/irq.h>
/* camera irq */
diff --git a/arch/arm/mach-s3c2410/s3c244x.c b/arch/arm/plat-s3c24xx/s3c244x.c
index 23c7494ad10..767f2e9a3a5 100644
--- a/arch/arm/mach-s3c2410/s3c244x.c
+++ b/arch/arm/plat-s3c24xx/s3c244x.c
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-s3c2410/s3c244x.c
+/* linux/arch/arm/plat-s3c24xx/s3c244x.c
*
* Copyright (c) 2004-2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
- * Samsung S3C2440 and S3C2442 Mobile CPU support
+ * Samsung S3C2440 and S3C2442 Mobile CPU support (not S3C2443)
*
* 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
@@ -35,13 +35,13 @@
#include <asm/arch/regs-gpioj.h>
#include <asm/arch/regs-dsc.h>
-#include "s3c2410.h"
-#include "s3c2440.h"
+#include <asm/plat-s3c24xx/s3c2410.h>
+#include <asm/plat-s3c24xx/s3c2440.h>
#include "s3c244x.h"
-#include "clock.h"
-#include "devs.h"
-#include "cpu.h"
-#include "pm.h"
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/devs.h>
+#include <asm/plat-s3c24xx/cpu.h>
+#include <asm/plat-s3c24xx/pm.h>
static struct map_desc s3c244x_iodesc[] __initdata = {
IODESC_ENT(CLKPWR),
diff --git a/arch/arm/mach-s3c2410/s3c244x.h b/arch/arm/plat-s3c24xx/s3c244x.h
index 1488c1eb37e..f8ed17676a3 100644
--- a/arch/arm/mach-s3c2410/s3c244x.h
+++ b/arch/arm/plat-s3c24xx/s3c244x.h
@@ -1,4 +1,4 @@
-/* arch/arm/mach-s3c2410/s3c244x.h
+/* linux/arch/arm/plat-s3c24xx/s3c244x.h
*
* Copyright (c) 2004-2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/plat-s3c24xx/sleep.S b/arch/arm/plat-s3c24xx/sleep.S
new file mode 100644
index 00000000000..435349dc324
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/sleep.S
@@ -0,0 +1,157 @@
+/* linux/arch/arm/mach-s3c2410/sleep.S
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 Power Manager (Suspend-To-RAM) support
+ *
+ * Based on PXA/SA1100 sleep code by:
+ * Nicolas Pitre, (c) 2002 Monta Vista Software Inc
+ * Cliff Brake, (c) 2001
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/hardware.h>
+#include <asm/arch/map.h>
+
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-mem.h>
+#include <asm/arch/regs-serial.h>
+
+/* CONFIG_DEBUG_RESUME is dangerous if your bootloader does not
+ * reset the UART configuration, only enable if you really need this!
+*/
+//#define CONFIG_DEBUG_RESUME
+
+ .text
+
+ /* s3c2410_cpu_save
+ *
+ * save enough of the CPU state to allow us to re-start
+ * pm.c code. as we store items like the sp/lr, we will
+ * end up returning from this function when the cpu resumes
+ * so the return value is set to mark this.
+ *
+ * This arangement means we avoid having to flush the cache
+ * from this code.
+ *
+ * entry:
+ * r0 = pointer to save block
+ *
+ * exit:
+ * r0 = 0 => we stored everything
+ * 1 => resumed from sleep
+ */
+
+ENTRY(s3c2410_cpu_save)
+ stmfd sp!, { r4 - r12, lr }
+
+ @@ store co-processor registers
+
+ mrc p15, 0, r4, c13, c0, 0 @ PID
+ mrc p15, 0, r5, c3, c0, 0 @ Domain ID
+ mrc p15, 0, r6, c2, c0, 0 @ translation table base address
+ mrc p15, 0, r7, c1, c0, 0 @ control register
+
+ stmia r0, { r4 - r13 }
+
+ mov r0, #0
+ ldmfd sp, { r4 - r12, pc }
+
+ @@ return to the caller, after having the MMU
+ @@ turned on, this restores the last bits from the
+ @@ stack
+resume_with_mmu:
+ mov r0, #1
+ ldmfd sp!, { r4 - r12, pc }
+
+ .ltorg
+
+ @@ the next bits sit in the .data segment, even though they
+ @@ happen to be code... the s3c2410_sleep_save_phys needs to be
+ @@ accessed by the resume code before it can restore the MMU.
+ @@ This means that the variable has to be close enough for the
+ @@ code to read it... since the .text segment needs to be RO,
+ @@ the data segment can be the only place to put this code.
+
+ .data
+
+ .global s3c2410_sleep_save_phys
+s3c2410_sleep_save_phys:
+ .word 0
+
+ /* s3c2410_cpu_resume
+ *
+ * resume code entry for bootloader to call
+ *
+ * we must put this code here in the data segment as we have no
+ * other way of restoring the stack pointer after sleep, and we
+ * must not write to the code segment (code is read-only)
+ */
+
+ENTRY(s3c2410_cpu_resume)
+ mov r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE
+ msr cpsr_c, r0
+
+ @@ load UART to allow us to print the two characters for
+ @@ resume debug
+
+ mov r2, #S3C24XX_PA_UART & 0xff000000
+ orr r2, r2, #S3C24XX_PA_UART & 0xff000
+
+#if 0
+ /* SMDK2440 LED set */
+ mov r14, #S3C24XX_PA_GPIO
+ ldr r12, [ r14, #0x54 ]
+ bic r12, r12, #3<<4
+ orr r12, r12, #1<<7
+ str r12, [ r14, #0x54 ]
+#endif
+
+#ifdef CONFIG_DEBUG_RESUME
+ mov r3, #'L'
+ strb r3, [ r2, #S3C2410_UTXH ]
+1001:
+ ldrb r14, [ r3, #S3C2410_UTRSTAT ]
+ tst r14, #S3C2410_UTRSTAT_TXE
+ beq 1001b
+#endif /* CONFIG_DEBUG_RESUME */
+
+ mov r1, #0
+ mcr p15, 0, r1, c8, c7, 0 @@ invalidate I & D TLBs
+ mcr p15, 0, r1, c7, c7, 0 @@ invalidate I & D caches
+
+ ldr r0, s3c2410_sleep_save_phys @ address of restore block
+ ldmia r0, { r4 - r13 }
+
+ mcr p15, 0, r4, c13, c0, 0 @ PID
+ mcr p15, 0, r5, c3, c0, 0 @ Domain ID
+ mcr p15, 0, r6, c2, c0, 0 @ translation table base
+
+#ifdef CONFIG_DEBUG_RESUME
+ mov r3, #'R'
+ strb r3, [ r2, #S3C2410_UTXH ]
+#endif
+
+ ldr r2, =resume_with_mmu
+ mcr p15, 0, r7, c1, c0, 0 @ turn on MMU, etc
+ nop @ second-to-last before mmu
+ mov pc, r2 @ go back to virtual address
+
+ .ltorg
diff --git a/arch/arm/mach-s3c2410/time.c b/arch/arm/plat-s3c24xx/time.c
index 9910bf0f2ce..c523d1c9cce 100644
--- a/arch/arm/mach-s3c2410/time.c
+++ b/arch/arm/plat-s3c24xx/time.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/time.c
+/* linux/arch/arm/plat-s3c24xx/time.c
*
* Copyright (C) 2003-2005 Simtec Electronics
* Ben Dooks, <ben@simtec.co.uk>
@@ -37,8 +37,8 @@
#include <asm/arch/regs-irq.h>
#include <asm/mach/time.h>
-#include "clock.h"
-#include "cpu.h"
+#include <asm/plat-s3c24xx/clock.h>
+#include <asm/plat-s3c24xx/cpu.h>
static unsigned long timer_startval;
static unsigned long timer_usec_ticks;
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index c3b1567c852..14e83d0aac8 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -34,6 +34,7 @@
#include <asm/hardware.h>
#include <asm/irq.h>
+#include <asm/io.h>
#include <asm/arch/i2c.h>
#include <asm/arch/pxa-regs.h>
@@ -54,8 +55,21 @@ struct pxa_i2c {
unsigned int irqlogidx;
u32 isrlog[32];
u32 icrlog[32];
+
+ void __iomem *reg_base;
+
+ unsigned long iobase;
+ unsigned long iosize;
+
+ int irq;
};
+#define _IBMR(i2c) ((i2c)->reg_base + 0)
+#define _IDBR(i2c) ((i2c)->reg_base + 8)
+#define _ICR(i2c) ((i2c)->reg_base + 0x10)
+#define _ISR(i2c) ((i2c)->reg_base + 0x18)
+#define _ISAR(i2c) ((i2c)->reg_base + 0x20)
+
/*
* I2C Slave mode address
*/
@@ -130,7 +144,8 @@ static unsigned int i2c_debug = DEBUG;
static void i2c_pxa_show_state(struct pxa_i2c *i2c, int lno, const char *fname)
{
- dev_dbg(&i2c->adap.dev, "state:%s:%d: ISR=%08x, ICR=%08x, IBMR=%02x\n", fname, lno, ISR, ICR, IBMR);
+ dev_dbg(&i2c->adap.dev, "state:%s:%d: ISR=%08x, ICR=%08x, IBMR=%02x\n", fname, lno,
+ readl(_ISR(i2c)), readl(_ICR(i2c)), readl(_IBMR(i2c)));
}
#define show_state(i2c) i2c_pxa_show_state(i2c, __LINE__, __FUNCTION__)
@@ -153,7 +168,7 @@ static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why)
printk("i2c: msg_num: %d msg_idx: %d msg_ptr: %d\n",
i2c->msg_num, i2c->msg_idx, i2c->msg_ptr);
printk("i2c: ICR: %08x ISR: %08x\n"
- "i2c: log: ", ICR, ISR);
+ "i2c: log: ", readl(_ICR(i2c)), readl(_ISR(i2c)));
for (i = 0; i < i2c->irqlogidx; i++)
printk("[%08x:%08x] ", i2c->isrlog[i], i2c->icrlog[i]);
printk("\n");
@@ -161,7 +176,7 @@ static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why)
static inline int i2c_pxa_is_slavemode(struct pxa_i2c *i2c)
{
- return !(ICR & ICR_SCLE);
+ return !(readl(_ICR(i2c)) & ICR_SCLE);
}
static void i2c_pxa_abort(struct pxa_i2c *i2c)
@@ -173,28 +188,29 @@ static void i2c_pxa_abort(struct pxa_i2c *i2c)
return;
}
- while (time_before(jiffies, timeout) && (IBMR & 0x1) == 0) {
- unsigned long icr = ICR;
+ while (time_before(jiffies, timeout) && (readl(_IBMR(i2c)) & 0x1) == 0) {
+ unsigned long icr = readl(_ICR(i2c));
icr &= ~ICR_START;
icr |= ICR_ACKNAK | ICR_STOP | ICR_TB;
- ICR = icr;
+ writel(icr, _ICR(i2c));
show_state(i2c);
msleep(1);
}
- ICR &= ~(ICR_MA | ICR_START | ICR_STOP);
+ writel(readl(_ICR(i2c)) & ~(ICR_MA | ICR_START | ICR_STOP),
+ _ICR(i2c));
}
static int i2c_pxa_wait_bus_not_busy(struct pxa_i2c *i2c)
{
int timeout = DEF_TIMEOUT;
- while (timeout-- && ISR & (ISR_IBB | ISR_UB)) {
- if ((ISR & ISR_SAD) != 0)
+ while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) {
+ if ((readl(_ISR(i2c)) & ISR_SAD) != 0)
timeout += 4;
msleep(2);
@@ -214,9 +230,9 @@ static int i2c_pxa_wait_master(struct pxa_i2c *i2c)
while (time_before(jiffies, timeout)) {
if (i2c_debug > 1)
dev_dbg(&i2c->adap.dev, "%s: %ld: ISR=%08x, ICR=%08x, IBMR=%02x\n",
- __func__, (long)jiffies, ISR, ICR, IBMR);
+ __func__, (long)jiffies, readl(_ISR(i2c)), readl(_ICR(i2c)), readl(_IBMR(i2c)));
- if (ISR & ISR_SAD) {
+ if (readl(_ISR(i2c)) & ISR_SAD) {
if (i2c_debug > 0)
dev_dbg(&i2c->adap.dev, "%s: Slave detected\n", __func__);
goto out;
@@ -226,7 +242,7 @@ static int i2c_pxa_wait_master(struct pxa_i2c *i2c)
* quick check of the i2c lines themselves to ensure they've
* gone high...
*/
- if ((ISR & (ISR_UB | ISR_IBB)) == 0 && IBMR == 3) {
+ if ((readl(_ISR(i2c)) & (ISR_UB | ISR_IBB)) == 0 && readl(_IBMR(i2c)) == 3) {
if (i2c_debug > 0)
dev_dbg(&i2c->adap.dev, "%s: done\n", __func__);
return 1;
@@ -246,7 +262,7 @@ static int i2c_pxa_set_master(struct pxa_i2c *i2c)
if (i2c_debug)
dev_dbg(&i2c->adap.dev, "setting to bus master\n");
- if ((ISR & (ISR_UB | ISR_IBB)) != 0) {
+ if ((readl(_ISR(i2c)) & (ISR_UB | ISR_IBB)) != 0) {
dev_dbg(&i2c->adap.dev, "%s: unit is busy\n", __func__);
if (!i2c_pxa_wait_master(i2c)) {
dev_dbg(&i2c->adap.dev, "%s: error: unit busy\n", __func__);
@@ -254,7 +270,7 @@ static int i2c_pxa_set_master(struct pxa_i2c *i2c)
}
}
- ICR |= ICR_SCLE;
+ writel(readl(_ICR(i2c)) | ICR_SCLE, _ICR(i2c));
return 0;
}
@@ -270,11 +286,11 @@ static int i2c_pxa_wait_slave(struct pxa_i2c *i2c)
while (time_before(jiffies, timeout)) {
if (i2c_debug > 1)
dev_dbg(&i2c->adap.dev, "%s: %ld: ISR=%08x, ICR=%08x, IBMR=%02x\n",
- __func__, (long)jiffies, ISR, ICR, IBMR);
+ __func__, (long)jiffies, readl(_ISR(i2c)), readl(_ICR(i2c)), readl(_IBMR(i2c)));
- if ((ISR & (ISR_UB|ISR_IBB)) == 0 ||
- (ISR & ISR_SAD) != 0 ||
- (ICR & ICR_SCLE) == 0) {
+ if ((readl(_ISR(i2c)) & (ISR_UB|ISR_IBB)) == 0 ||
+ (readl(_ISR(i2c)) & ISR_SAD) != 0 ||
+ (readl(_ICR(i2c)) & ICR_SCLE) == 0) {
if (i2c_debug > 1)
dev_dbg(&i2c->adap.dev, "%s: done\n", __func__);
return 1;
@@ -302,9 +318,9 @@ static void i2c_pxa_set_slave(struct pxa_i2c *i2c, int errcode)
/* we need to wait for the stop condition to end */
/* if we where in stop, then clear... */
- if (ICR & ICR_STOP) {
+ if (readl(_ICR(i2c)) & ICR_STOP) {
udelay(100);
- ICR &= ~ICR_STOP;
+ writel(readl(_ICR(i2c)) & ~ICR_STOP, _ICR(i2c));
}
if (!i2c_pxa_wait_slave(i2c)) {
@@ -314,12 +330,12 @@ static void i2c_pxa_set_slave(struct pxa_i2c *i2c, int errcode)
}
}
- ICR &= ~(ICR_STOP|ICR_ACKNAK|ICR_MA);
- ICR &= ~ICR_SCLE;
+ writel(readl(_ICR(i2c)) & ~(ICR_STOP|ICR_ACKNAK|ICR_MA), _ICR(i2c));
+ writel(readl(_ICR(i2c)) & ~ICR_SCLE, _ICR(i2c));
if (i2c_debug) {
- dev_dbg(&i2c->adap.dev, "ICR now %08x, ISR %08x\n", ICR, ISR);
- decode_ICR(ICR);
+ dev_dbg(&i2c->adap.dev, "ICR now %08x, ISR %08x\n", readl(_ICR(i2c)), readl(_ISR(i2c)));
+ decode_ICR(readl(_ICR(i2c)));
}
}
#else
@@ -334,24 +350,24 @@ static void i2c_pxa_reset(struct pxa_i2c *i2c)
i2c_pxa_abort(i2c);
/* reset according to 9.8 */
- ICR = ICR_UR;
- ISR = I2C_ISR_INIT;
- ICR &= ~ICR_UR;
+ writel(ICR_UR, _ICR(i2c));
+ writel(I2C_ISR_INIT, _ISR(i2c));
+ writel(readl(_ICR(i2c)) & ~ICR_UR, _ICR(i2c));
- ISAR = i2c->slave_addr;
+ writel(i2c->slave_addr, _ISAR(i2c));
/* set control register values */
- ICR = I2C_ICR_INIT;
+ writel(I2C_ICR_INIT, _ICR(i2c));
#ifdef CONFIG_I2C_PXA_SLAVE
dev_info(&i2c->adap.dev, "Enabling slave mode\n");
- ICR |= ICR_SADIE | ICR_ALDIE | ICR_SSDIE;
+ writel(readl(_ICR(i2c)) | ICR_SADIE | ICR_ALDIE | ICR_SSDIE, _ICR(i2c));
#endif
i2c_pxa_set_slave(i2c, 0);
/* enable unit */
- ICR |= ICR_IUE;
+ writel(readl(_ICR(i2c)) | ICR_IUE, _ICR(i2c));
udelay(100);
}
@@ -371,19 +387,19 @@ static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr)
if (i2c->slave != NULL)
ret = i2c->slave->read(i2c->slave->data);
- IDBR = ret;
- ICR |= ICR_TB; /* allow next byte */
+ writel(ret, _IDBR(i2c));
+ writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c)); /* allow next byte */
}
}
static void i2c_pxa_slave_rxfull(struct pxa_i2c *i2c, u32 isr)
{
- unsigned int byte = IDBR;
+ unsigned int byte = readl(_IDBR(i2c));
if (i2c->slave != NULL)
i2c->slave->write(i2c->slave->data, byte);
- ICR |= ICR_TB;
+ writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c));
}
static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr)
@@ -403,13 +419,13 @@ static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr)
* start condition... if this happens, we'd better back off
* and stop holding the poor thing up
*/
- ICR &= ~(ICR_START|ICR_STOP);
- ICR |= ICR_TB;
+ writel(readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP), _ICR(i2c));
+ writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c));
timeout = 0x10000;
while (1) {
- if ((IBMR & 2) == 2)
+ if ((readl(_IBMR(i2c)) & 2) == 2)
break;
timeout--;
@@ -420,7 +436,7 @@ static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr)
}
}
- ICR &= ~ICR_SCLE;
+ writel(readl(_ICR(i2c)) & ~ICR_SCLE, _ICR(i2c));
}
static void i2c_pxa_slave_stop(struct pxa_i2c *i2c)
@@ -447,14 +463,14 @@ static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr)
if (isr & ISR_BED) {
/* what should we do here? */
} else {
- IDBR = 0;
- ICR |= ICR_TB;
+ writel(0, _IDBR(i2c));
+ writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c));
}
}
static void i2c_pxa_slave_rxfull(struct pxa_i2c *i2c, u32 isr)
{
- ICR |= ICR_TB | ICR_ACKNAK;
+ writel(readl(_ICR(i2c)) | ICR_TB | ICR_ACKNAK, _ICR(i2c));
}
static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr)
@@ -466,13 +482,13 @@ static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr)
* start condition... if this happens, we'd better back off
* and stop holding the poor thing up
*/
- ICR &= ~(ICR_START|ICR_STOP);
- ICR |= ICR_TB | ICR_ACKNAK;
+ writel(readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP), _ICR(i2c));
+ writel(readl(_ICR(i2c)) | ICR_TB | ICR_ACKNAK, _ICR(i2c));
timeout = 0x10000;
while (1) {
- if ((IBMR & 2) == 2)
+ if ((readl(_IBMR(i2c)) & 2) == 2)
break;
timeout--;
@@ -483,7 +499,7 @@ static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr)
}
}
- ICR &= ~ICR_SCLE;
+ writel(readl(_ICR(i2c)) & ~ICR_SCLE, _ICR(i2c));
}
static void i2c_pxa_slave_stop(struct pxa_i2c *i2c)
@@ -514,13 +530,13 @@ static inline void i2c_pxa_start_message(struct pxa_i2c *i2c)
/*
* Step 1: target slave address into IDBR
*/
- IDBR = i2c_pxa_addr_byte(i2c->msg);
+ writel(i2c_pxa_addr_byte(i2c->msg), _IDBR(i2c));
/*
* Step 2: initiate the write.
*/
- icr = ICR & ~(ICR_STOP | ICR_ALDIE);
- ICR = icr | ICR_START | ICR_TB;
+ icr = readl(_ICR(i2c)) & ~(ICR_STOP | ICR_ALDIE);
+ writel(icr | ICR_START | ICR_TB, _ICR(i2c));
}
/*
@@ -594,7 +610,7 @@ static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret)
static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr)
{
- u32 icr = ICR & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB);
+ u32 icr = readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB);
again:
/*
@@ -645,7 +661,7 @@ static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr)
/*
* Write mode. Write the next data byte.
*/
- IDBR = i2c->msg->buf[i2c->msg_ptr++];
+ writel(i2c->msg->buf[i2c->msg_ptr++], _IDBR(i2c));
icr |= ICR_ALDIE | ICR_TB;
@@ -675,7 +691,7 @@ static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr)
/*
* Write the next address.
*/
- IDBR = i2c_pxa_addr_byte(i2c->msg);
+ writel(i2c_pxa_addr_byte(i2c->msg), _IDBR(i2c));
/*
* And trigger a repeated start, and send the byte.
@@ -696,18 +712,18 @@ static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr)
i2c->icrlog[i2c->irqlogidx-1] = icr;
- ICR = icr;
+ writel(icr, _ICR(i2c));
show_state(i2c);
}
static void i2c_pxa_irq_rxfull(struct pxa_i2c *i2c, u32 isr)
{
- u32 icr = ICR & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB);
+ u32 icr = readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB);
/*
* Read the byte.
*/
- i2c->msg->buf[i2c->msg_ptr++] = IDBR;
+ i2c->msg->buf[i2c->msg_ptr++] = readl(_IDBR(i2c));
if (i2c->msg_ptr < i2c->msg->len) {
/*
@@ -724,17 +740,17 @@ static void i2c_pxa_irq_rxfull(struct pxa_i2c *i2c, u32 isr)
i2c->icrlog[i2c->irqlogidx-1] = icr;
- ICR = icr;
+ writel(icr, _ICR(i2c));
}
static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id)
{
struct pxa_i2c *i2c = dev_id;
- u32 isr = ISR;
+ u32 isr = readl(_ISR(i2c));
if (i2c_debug > 2 && 0) {
dev_dbg(&i2c->adap.dev, "%s: ISR=%08x, ICR=%08x, IBMR=%02x\n",
- __func__, isr, ICR, IBMR);
+ __func__, isr, readl(_ICR(i2c)), readl(_IBMR(i2c)));
decode_ISR(isr);
}
@@ -746,7 +762,7 @@ static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id)
/*
* Always clear all pending IRQs.
*/
- ISR = isr & (ISR_SSD|ISR_ALD|ISR_ITE|ISR_IRF|ISR_SAD|ISR_BED);
+ writel(isr & (ISR_SSD|ISR_ALD|ISR_ITE|ISR_IRF|ISR_SAD|ISR_BED), _ISR(i2c));
if (isr & ISR_SAD)
i2c_pxa_slave_start(i2c, isr);
@@ -779,7 +795,7 @@ static int i2c_pxa_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num
/* If the I2C controller is disabled we need to reset it (probably due
to a suspend/resume destroying state). We do this here as we can then
avoid worrying about resuming the controller before its users. */
- if (!(ICR & ICR_IUE))
+ if (!(readl(_ICR(i2c)) & ICR_IUE))
i2c_pxa_reset(i2c);
for (i = adap->retries; i >= 0; i--) {
@@ -810,28 +826,53 @@ static const struct i2c_algorithm i2c_pxa_algorithm = {
static struct pxa_i2c i2c_pxa = {
.lock = SPIN_LOCK_UNLOCKED,
- .wait = __WAIT_QUEUE_HEAD_INITIALIZER(i2c_pxa.wait),
.adap = {
.owner = THIS_MODULE,
.algo = &i2c_pxa_algorithm,
- .name = "pxa2xx-i2c",
+ .name = "pxa2xx-i2c.0",
.retries = 5,
},
};
+#define res_len(r) ((r)->end - (r)->start + 1)
static int i2c_pxa_probe(struct platform_device *dev)
{
struct pxa_i2c *i2c = &i2c_pxa;
+ struct resource *res;
#ifdef CONFIG_I2C_PXA_SLAVE
struct i2c_pxa_platform_data *plat = dev->dev.platform_data;
#endif
int ret;
+ int irq;
-#ifdef CONFIG_PXA27x
- pxa_gpio_mode(GPIO117_I2CSCL_MD);
- pxa_gpio_mode(GPIO118_I2CSDA_MD);
- udelay(100);
-#endif
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(dev, 0);
+ if (res == NULL || irq < 0)
+ return -ENODEV;
+
+ if (!request_mem_region(res->start, res_len(res), res->name))
+ return -ENOMEM;
+
+ i2c = kmalloc(sizeof(struct pxa_i2c), GFP_KERNEL);
+ if (!i2c) {
+ ret = -ENOMEM;
+ goto emalloc;
+ }
+
+ memcpy(i2c, &i2c_pxa, sizeof(struct pxa_i2c));
+ init_waitqueue_head(&i2c->wait);
+ i2c->adap.name[strlen(i2c->adap.name) - 1] = '0' + dev->id % 10;
+
+ i2c->reg_base = ioremap(res->start, res_len(res));
+ if (!i2c->reg_base) {
+ ret = -EIO;
+ goto eremap;
+ }
+
+ i2c->iobase = res->start;
+ i2c->iosize = res_len(res);
+
+ i2c->irq = irq;
i2c->slave_addr = I2C_PXA_SLAVE_ADDR;
@@ -842,11 +883,28 @@ static int i2c_pxa_probe(struct platform_device *dev)
}
#endif
- pxa_set_cken(CKEN14_I2C, 1);
- ret = request_irq(IRQ_I2C, i2c_pxa_handler, IRQF_DISABLED,
- "pxa2xx-i2c", i2c);
+ switch (dev->id) {
+ case 0:
+#ifdef CONFIG_PXA27x
+ pxa_gpio_mode(GPIO117_I2CSCL_MD);
+ pxa_gpio_mode(GPIO118_I2CSDA_MD);
+#endif
+ pxa_set_cken(CKEN14_I2C, 1);
+ break;
+#ifdef CONFIG_PXA27x
+ case 1:
+ local_irq_disable();
+ PCFR |= PCFR_PI2CEN;
+ local_irq_enable();
+ pxa_set_cken(CKEN15_PWRI2C, 1);
+#endif
+ }
+
+ ret = request_irq(irq, i2c_pxa_handler, IRQF_DISABLED,
+ i2c->adap.name, i2c);
if (ret)
- goto out;
+ goto ereqirq;
+
i2c_pxa_reset(i2c);
@@ -856,7 +914,7 @@ static int i2c_pxa_probe(struct platform_device *dev)
ret = i2c_add_adapter(&i2c->adap);
if (ret < 0) {
printk(KERN_INFO "I2C: Failed to add bus\n");
- goto err_irq;
+ goto eadapt;
}
platform_set_drvdata(dev, i2c);
@@ -870,9 +928,25 @@ static int i2c_pxa_probe(struct platform_device *dev)
#endif
return 0;
- err_irq:
- free_irq(IRQ_I2C, i2c);
- out:
+eadapt:
+ free_irq(irq, i2c);
+ereqirq:
+ switch (dev->id) {
+ case 0:
+ pxa_set_cken(CKEN14_I2C, 0);
+ break;
+#ifdef CONFIG_PXA27x
+ case 1:
+ pxa_set_cken(CKEN15_PWRI2C, 0);
+ local_irq_disable();
+ PCFR &= ~PCFR_PI2CEN;
+ local_irq_enable();
+#endif
+ }
+eremap:
+ kfree(i2c);
+emalloc:
+ release_mem_region(res->start, res_len(res));
return ret;
}
@@ -883,8 +957,21 @@ static int i2c_pxa_remove(struct platform_device *dev)
platform_set_drvdata(dev, NULL);
i2c_del_adapter(&i2c->adap);
- free_irq(IRQ_I2C, i2c);
- pxa_set_cken(CKEN14_I2C, 0);
+ free_irq(i2c->irq, i2c);
+ switch (dev->id) {
+ case 0:
+ pxa_set_cken(CKEN14_I2C, 0);
+ break;
+#ifdef CONFIG_PXA27x
+ case 1:
+ pxa_set_cken(CKEN15_PWRI2C, 0);
+ local_irq_disable();
+ PCFR &= ~PCFR_PI2CEN;
+ local_irq_enable();
+#endif
+ }
+ release_mem_region(i2c->iobase, i2c->iosize);
+ kfree(i2c);
return 0;
}
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 2978c09860e..09f8bff1fbd 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -262,7 +262,8 @@ config SERIAL_AMBA_PL010
select SERIAL_CORE
help
This selects the ARM(R) AMBA(R) PrimeCell PL010 UART. If you have
- an Integrator/AP or Integrator/PP2 platform, say Y or M here.
+ an Integrator/AP or Integrator/PP2 platform, or if you have a
+ Cirrus Logic EP93xx CPU, say Y or M here.
If unsure, say N.
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index e216dcf2937..04cc88cc528 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -154,7 +154,7 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
{
struct circ_buf *xmit = &sport->port.info->xmit;
- do {
+ while (!(UTS((u32)sport->port.membase) & UTS_TXFULL)) {
/* send xmit->buf[xmit->tail]
* out the port here */
URTX0((u32)sport->port.membase) = xmit->buf[xmit->tail];
@@ -163,7 +163,7 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
sport->port.icount.tx++;
if (uart_circ_empty(xmit))
break;
- } while (!(UTS((u32)sport->port.membase) & UTS_TXFULL));
+ }
if (uart_circ_empty(xmit))
imx_stop_tx(&sport->port);
@@ -178,8 +178,7 @@ static void imx_start_tx(struct uart_port *port)
UCR1((u32)sport->port.membase) |= UCR1_TXMPTYEN;
- if(UTS((u32)sport->port.membase) & UTS_TXEMPTY)
- imx_transmit_buffer(sport);
+ imx_transmit_buffer(sport);
}
static irqreturn_t imx_rtsint(int irq, void *dev_id)
@@ -404,7 +403,8 @@ static int imx_startup(struct uart_port *port)
if (retval) goto error_out2;
retval = request_irq(sport->rtsirq, imx_rtsint,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ (sport->rtsirq < IMX_IRQS) ? 0 :
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
DRIVER_NAME, sport);
if (retval) goto error_out3;
@@ -678,7 +678,7 @@ static struct imx_port imx_ports[] = {
.mapbase = IMX_UART1_BASE, /* FIXME */
.irq = UART1_MINT_RX,
.uartclk = 16000000,
- .fifosize = 8,
+ .fifosize = 32,
.flags = UPF_BOOT_AUTOCONF,
.ops = &imx_pops,
.line = 0,
@@ -694,7 +694,7 @@ static struct imx_port imx_ports[] = {
.mapbase = IMX_UART2_BASE, /* FIXME */
.irq = UART2_MINT_RX,
.uartclk = 16000000,
- .fifosize = 8,
+ .fifosize = 32,
.flags = UPF_BOOT_AUTOCONF,
.ops = &imx_pops,
.line = 1,
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index b78de969466..3547f049237 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -156,7 +156,7 @@ static int is_vbus_present(void)
struct pxa2xx_udc_mach_info *mach = the_controller->mach;
if (mach->gpio_vbus)
- return pxa_gpio_get(mach->gpio_vbus);
+ return udc_gpio_get(mach->gpio_vbus);
if (mach->udc_is_connected)
return mach->udc_is_connected();
return 1;
@@ -168,7 +168,7 @@ static void pullup_off(void)
struct pxa2xx_udc_mach_info *mach = the_controller->mach;
if (mach->gpio_pullup)
- pxa_gpio_set(mach->gpio_pullup, 0);
+ udc_gpio_set(mach->gpio_pullup, 0);
else if (mach->udc_command)
mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
}
@@ -178,7 +178,7 @@ static void pullup_on(void)
struct pxa2xx_udc_mach_info *mach = the_controller->mach;
if (mach->gpio_pullup)
- pxa_gpio_set(mach->gpio_pullup, 1);
+ udc_gpio_set(mach->gpio_pullup, 1);
else if (mach->udc_command)
mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
}
@@ -1756,7 +1756,7 @@ lubbock_vbus_irq(int irq, void *_dev)
static irqreturn_t udc_vbus_irq(int irq, void *_dev)
{
struct pxa2xx_udc *dev = _dev;
- int vbus = pxa_gpio_get(dev->mach->gpio_vbus);
+ int vbus = udc_gpio_get(dev->mach->gpio_vbus);
pxa2xx_udc_vbus_session(&dev->gadget, vbus);
return IRQ_HANDLED;
@@ -2546,15 +2546,13 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
dev->dev = &pdev->dev;
dev->mach = pdev->dev.platform_data;
if (dev->mach->gpio_vbus) {
- vbus_irq = IRQ_GPIO(dev->mach->gpio_vbus & GPIO_MD_MASK_NR);
- pxa_gpio_mode((dev->mach->gpio_vbus & GPIO_MD_MASK_NR)
- | GPIO_IN);
+ udc_gpio_init_vbus(dev->mach->gpio_vbus);
+ vbus_irq = udc_gpio_to_irq(dev->mach->gpio_vbus);
set_irq_type(vbus_irq, IRQT_BOTHEDGE);
} else
vbus_irq = 0;
if (dev->mach->gpio_pullup)
- pxa_gpio_mode((dev->mach->gpio_pullup & GPIO_MD_MASK_NR)
- | GPIO_OUT | GPIO_DFLT_LOW);
+ udc_gpio_init_pullup(dev->mach->gpio_pullup);
init_timer(&dev->timer);
dev->timer.function = udc_watchdog;
diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h
index 8e598c8bf4e..773e549aff3 100644
--- a/drivers/usb/gadget/pxa2xx_udc.h
+++ b/drivers/usb/gadget/pxa2xx_udc.h
@@ -177,21 +177,6 @@ struct pxa2xx_udc {
static struct pxa2xx_udc *the_controller;
-static inline int pxa_gpio_get(unsigned gpio)
-{
- return (GPLR(gpio) & GPIO_bit(gpio)) != 0;
-}
-
-static inline void pxa_gpio_set(unsigned gpio, int is_on)
-{
- int mask = GPIO_bit(gpio);
-
- if (is_on)
- GPSR(gpio) = mask;
- else
- GPCR(gpio) = mask;
-}
-
/*-------------------------------------------------------------------------*/
/*
diff --git a/include/asm-arm/.gitignore b/include/asm-arm/.gitignore
new file mode 100644
index 00000000000..e02c15d158f
--- /dev/null
+++ b/include/asm-arm/.gitignore
@@ -0,0 +1,2 @@
+arch
+mach-types.h
diff --git a/include/asm-arm/arch-ep93xx/ep93xx-regs.h b/include/asm-arm/arch-ep93xx/ep93xx-regs.h
index 593f562f85c..625c6f0abc0 100644
--- a/include/asm-arm/arch-ep93xx/ep93xx-regs.h
+++ b/include/asm-arm/arch-ep93xx/ep93xx-regs.h
@@ -73,6 +73,11 @@
#define EP93XX_GPIO_BASE (EP93XX_APB_VIRT_BASE + 0x00040000)
#define EP93XX_GPIO_REG(x) (EP93XX_GPIO_BASE + (x))
+#define EP93XX_GPIO_F_INT_TYPE1 EP93XX_GPIO_REG(0x4c)
+#define EP93XX_GPIO_F_INT_TYPE2 EP93XX_GPIO_REG(0x50)
+#define EP93XX_GPIO_F_INT_ACK EP93XX_GPIO_REG(0x54)
+#define EP93XX_GPIO_F_INT_ENABLE EP93XX_GPIO_REG(0x58)
+#define EP93XX_GPIO_F_INT_STATUS EP93XX_GPIO_REG(0x5c)
#define EP93XX_GPIO_A_INT_TYPE1 EP93XX_GPIO_REG(0x90)
#define EP93XX_GPIO_A_INT_TYPE2 EP93XX_GPIO_REG(0x94)
#define EP93XX_GPIO_A_INT_ACK EP93XX_GPIO_REG(0x98)
diff --git a/include/asm-arm/arch-ep93xx/irqs.h b/include/asm-arm/arch-ep93xx/irqs.h
index ae532e304bf..2a8c63638c5 100644
--- a/include/asm-arm/arch-ep93xx/irqs.h
+++ b/include/asm-arm/arch-ep93xx/irqs.h
@@ -67,9 +67,13 @@
#define IRQ_EP93XX_SAI 60
#define EP93XX_VIC2_VALID_IRQ_MASK 0x1fffffff
-#define IRQ_EP93XX_GPIO(x) (64 + (x))
+/*
+ * Map GPIO A0..A7 to irq 64..71, B0..B7 to 72..79, and
+ * F0..F7 to 80..87.
+ */
+#define IRQ_EP93XX_GPIO(x) (64 + (((x) + (((x) >> 2) & 8)) & 0x1f))
-#define NR_EP93XX_IRQS IRQ_EP93XX_GPIO(16)
+#define NR_EP93XX_IRQS (64 + 24)
#define EP93XX_BOARD_IRQ(x) (NR_EP93XX_IRQS + (x))
#define EP93XX_BOARD_IRQS 32
diff --git a/include/asm-arm/arch-ep93xx/platform.h b/include/asm-arm/arch-ep93xx/platform.h
index b4a8deb8bde..44eccec2cba 100644
--- a/include/asm-arm/arch-ep93xx/platform.h
+++ b/include/asm-arm/arch-ep93xx/platform.h
@@ -8,7 +8,6 @@ void ep93xx_map_io(void);
void ep93xx_init_irq(void);
void ep93xx_init_time(unsigned long);
void ep93xx_init_devices(void);
-void ep93xx_clock_init(void);
extern struct sys_timer ep93xx_timer;
struct ep93xx_eth_data
diff --git a/include/asm-arm/arch-imx/entry-macro.S b/include/asm-arm/arch-imx/entry-macro.S
index 3b9ef691462..61bb0bdc1b1 100644
--- a/include/asm-arm/arch-imx/entry-macro.S
+++ b/include/asm-arm/arch-imx/entry-macro.S
@@ -13,19 +13,13 @@
.endm
#define AITC_NIVECSR 0x40
.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
- ldr \irqstat, =IO_ADDRESS(IMX_AITC_BASE)
+ ldr \base, =IO_ADDRESS(IMX_AITC_BASE)
@ Load offset & priority of the highest priority
@ interrupt pending.
- ldr \irqnr, [\irqstat, #AITC_NIVECSR]
+ ldr \irqstat, [\base, #AITC_NIVECSR]
@ Shift off the priority leaving the offset or
- @ "interrupt number"
- mov \irqnr, \irqnr, lsr #16
- ldr \irqstat, =1 @ dummy compare
- ldr \base, =0xFFFF // invalid interrupt
- cmp \irqnr, \base
- bne 1001f
- ldr \irqstat, =0
-1001:
- tst \irqstat, #1 @ to make the condition code = TRUE
+ @ "interrupt number", use arithmetic shift to
+ @ transform illegal source (0xffff) as -1
+ mov \irqnr, \irqstat, asr #16
+ adds \tmp, \irqnr, #1
.endm
-
diff --git a/include/asm-arm/arch-ixp4xx/udc.h b/include/asm-arm/arch-ixp4xx/udc.h
index dbdec36ff0d..79b850a3be4 100644
--- a/include/asm-arm/arch-ixp4xx/udc.h
+++ b/include/asm-arm/arch-ixp4xx/udc.h
@@ -6,3 +6,25 @@
extern void ixp4xx_set_udc_info(struct pxa2xx_udc_mach_info *info);
+static inline int udc_gpio_to_irq(unsigned gpio)
+{
+ return 0;
+}
+
+static inline void udc_gpio_init_vbus(unsigned gpio)
+{
+}
+
+static inline void udc_gpio_init_pullup(unsigned gpio)
+{
+}
+
+static inline int udc_gpio_get(unsigned gpio)
+{
+ return 0;
+}
+
+static inline void udc_gpio_set(unsigned gpio, int is_on)
+{
+}
+
diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h
index e24f6b6c79a..aec835b6f05 100644
--- a/include/asm-arm/arch-pxa/pxa-regs.h
+++ b/include/asm-arm/arch-pxa/pxa-regs.h
@@ -463,9 +463,6 @@
* Serial Audio Controller
*/
-/* FIXME: This clash with SA1111 defines */
-#ifndef _ASM_ARCH_SA1111
-
#define SACR0 __REG(0x40400000) /* Global Control Register */
#define SACR1 __REG(0x40400004) /* Serial Audio I 2 S/MSB-Justified Control Register */
#define SASR0 __REG(0x4040000C) /* Serial Audio I 2 S/MSB-Justified Interface and FIFO Status Register */
@@ -474,8 +471,8 @@
#define SADIV __REG(0x40400060) /* Audio Clock Divider Register. */
#define SADR __REG(0x40400080) /* Serial Audio Data Register (TX and RX FIFO access Register). */
-#define SACR0_RFTH(x) (x << 12) /* Rx FIFO Interrupt or DMA Trigger Threshold */
-#define SACR0_TFTH(x) (x << 8) /* Tx FIFO Interrupt or DMA Trigger Threshold */
+#define SACR0_RFTH(x) ((x) << 12) /* Rx FIFO Interrupt or DMA Trigger Threshold */
+#define SACR0_TFTH(x) ((x) << 8) /* Tx FIFO Interrupt or DMA Trigger Threshold */
#define SACR0_STRF (1 << 5) /* FIFO Select for EFWR Special Function */
#define SACR0_EFWR (1 << 4) /* Enable EFWR Function */
#define SACR0_RST (1 << 3) /* FIFO, i2s Register Reset */
@@ -503,8 +500,6 @@
#define SAIMR_RFS (1 << 4) /* Enable Rx FIFO Service Interrupt */
#define SAIMR_TFS (1 << 3) /* Enable Tx FIFO Service Interrupt */
-#endif
-
/*
* AC97 Controller registers
*/
@@ -1682,15 +1677,18 @@
#define SSSR_PINT (1 << 18) /* Peripheral Trailing Byte Interrupt */
#define SSPSP_FSRT (1 << 25) /* Frame Sync Relative Timing */
-#define SSPSP_DMYSTOP(x) (x << 23) /* Dummy Stop */
-#define SSPSP_SFRMWDTH(x) (x << 16) /* Serial Frame Width */
-#define SSPSP_SFRMDLY(x) (x << 9) /* Serial Frame Delay */
-#define SSPSP_DMYSTRT(x) (x << 7) /* Dummy Start */
-#define SSPSP_STRTDLY(x) (x << 4) /* Start Delay */
+#define SSPSP_DMYSTOP(x) ((x) << 23) /* Dummy Stop */
+#define SSPSP_SFRMWDTH(x) ((x) << 16) /* Serial Frame Width */
+#define SSPSP_SFRMDLY(x) ((x) << 9) /* Serial Frame Delay */
+#define SSPSP_DMYSTRT(x) ((x) << 7) /* Dummy Start */
+#define SSPSP_STRTDLY(x) ((x) << 4) /* Start Delay */
#define SSPSP_ETDS (1 << 3) /* End of Transfer data State */
#define SSPSP_SFRMP (1 << 2) /* Serial Frame Polarity */
-#define SSPSP_SCMODE(x) (x << 0) /* Serial Bit Rate Clock Mode */
+#define SSPSP_SCMODE(x) ((x) << 0) /* Serial Bit Rate Clock Mode */
+#define SSACD_SCDB (1 << 3) /* SSPSYSCLK Divider Bypass */
+#define SSACD_ACPS(x) ((x) << 4) /* Audio clock PLL select */
+#define SSACD_ACDS(x) ((x) << 0) /* Audio clock divider select */
#define SSCR0_P1 __REG(0x41000000) /* SSP Port 1 Control Register 0 */
#define SSCR1_P1 __REG(0x41000004) /* SSP Port 1 Control Register 1 */
diff --git a/include/asm-arm/arch-pxa/udc.h b/include/asm-arm/arch-pxa/udc.h
index 646480d3725..8bc6f9c3e3e 100644
--- a/include/asm-arm/arch-pxa/udc.h
+++ b/include/asm-arm/arch-pxa/udc.h
@@ -9,3 +9,33 @@
extern void pxa_set_udc_info(struct pxa2xx_udc_mach_info *info);
+static inline int udc_gpio_to_irq(unsigned gpio)
+{
+ return IRQ_GPIO(gpio & GPIO_MD_MASK_NR);
+}
+
+static inline void udc_gpio_init_vbus(unsigned gpio)
+{
+ pxa_gpio_mode((gpio & GPIO_MD_MASK_NR) | GPIO_IN);
+}
+
+static inline void udc_gpio_init_pullup(unsigned gpio)
+{
+ pxa_gpio_mode((gpio & GPIO_MD_MASK_NR) | GPIO_OUT | GPIO_DFLT_LOW);
+}
+
+static inline int udc_gpio_get(unsigned gpio)
+{
+ return (GPLR(gpio) & GPIO_bit(gpio)) != 0;
+}
+
+static inline void udc_gpio_set(unsigned gpio, int is_on)
+{
+ int mask = GPIO_bit(gpio);
+
+ if (is_on)
+ GPSR(gpio) = mask;
+ else
+ GPCR(gpio) = mask;
+}
+
diff --git a/include/asm-arm/arch-realview/hardware.h b/include/asm-arm/arch-realview/hardware.h
index 9ca76dc3a7a..aa78fe087ab 100644
--- a/include/asm-arm/arch-realview/hardware.h
+++ b/include/asm-arm/arch-realview/hardware.h
@@ -26,7 +26,7 @@
#include <asm/arch/platform.h>
/* macro to get at IO space when running virtually */
-#define IO_ADDRESS(x) (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000)
+#define IO_ADDRESS(x) ((((x) & 0x0effffff) | (((x) >> 4) & 0x0f000000)) + 0xf0000000)
#define __io_address(n) __io(IO_ADDRESS(n))
#endif
diff --git a/include/asm-arm/arch-realview/irqs.h b/include/asm-arm/arch-realview/irqs.h
index 76b498eb20a..5a5db56f86b 100644
--- a/include/asm-arm/arch-realview/irqs.h
+++ b/include/asm-arm/arch-realview/irqs.h
@@ -78,6 +78,9 @@
#define IRQ_PMU_SCU6 (IRQ_GIC_START + INT_PMU_SCU6)
#define IRQ_PMU_SCU7 (IRQ_GIC_START + INT_PMU_SCU7)
+#define IRQ_EB_IRQ1 (IRQ_GIC_START + INT_EB_IRQ1)
+#define IRQ_EB_IRQ2 (IRQ_GIC_START + INT_EB_IRQ2)
+
#define IRQMASK_WDOGINT INTMASK_WDOGINT
#define IRQMASK_SOFTINT INTMASK_SOFTINT
#define IRQMASK_COMMRx INTMASK_COMMRx
@@ -115,4 +118,4 @@
#define IRQMASK_ETH INTMASK_ETH
#define IRQMASK_USB INTMASK_USB
-#define NR_IRQS (IRQ_GIC_START + 64)
+#define NR_IRQS (IRQ_GIC_START + 96)
diff --git a/include/asm-arm/arch-realview/platform.h b/include/asm-arm/arch-realview/platform.h
index 18d7c18b738..6e0eab95a3a 100644
--- a/include/asm-arm/arch-realview/platform.h
+++ b/include/asm-arm/arch-realview/platform.h
@@ -207,11 +207,25 @@
#define REALVIEW_GIC_CPU_BASE 0x10040000 /* Generic interrupt controller CPU interface */
#define REALVIEW_GIC_DIST_BASE 0x10041000 /* Generic interrupt controller distributor */
#else
+#ifdef CONFIG_REALVIEW_MPCORE_REVB
#define REALVIEW_MPCORE_SCU_BASE 0x10100000 /* SCU registers */
#define REALVIEW_GIC_CPU_BASE 0x10100100 /* Generic interrupt controller CPU interface */
#define REALVIEW_TWD_BASE 0x10100700
#define REALVIEW_TWD_SIZE 0x00000100
#define REALVIEW_GIC_DIST_BASE 0x10101000 /* Generic interrupt controller distributor */
+#define REALVIEW_MPCORE_L220_BASE 0x10102000 /* L220 registers */
+#define REALVIEW_MPCORE_SYS_PLD_CTRL1 0xD8 /* Register offset for MPCore sysctl */
+#else
+#define REALVIEW_MPCORE_SCU_BASE 0x1F000000 /* SCU registers */
+#define REALVIEW_GIC_CPU_BASE 0x1F000100 /* Generic interrupt controller CPU interface */
+#define REALVIEW_TWD_BASE 0x1F000700
+#define REALVIEW_TWD_SIZE 0x00000100
+#define REALVIEW_GIC_DIST_BASE 0x1F001000 /* Generic interrupt controller distributor */
+#define REALVIEW_MPCORE_L220_BASE 0x1F002000 /* L220 registers */
+#define REALVIEW_MPCORE_SYS_PLD_CTRL1 0x74 /* Register offset for MPCore sysctl */
+#endif
+#define REALVIEW_GIC1_CPU_BASE 0x10040000 /* Generic interrupt controller CPU interface */
+#define REALVIEW_GIC1_DIST_BASE 0x10041000 /* Generic interrupt controller distributor */
#endif
#define REALVIEW_SMC_BASE 0x10080000 /* SMC */
/* Reserved 0x10090000 - 0x100EFFFF */
@@ -306,7 +320,11 @@
#define INT_USB 29 /* USB controller */
#define INT_TSPENINT 30 /* Touchscreen pen */
#define INT_TSKPADINT 31 /* Touchscreen keypad */
+
#else
+
+#define MAX_GIC_NR 2
+
#define INT_AACI 0
#define INT_TIMERINT0_1 1
#define INT_TIMERINT2_3 2
diff --git a/include/asm-arm/arch-realview/scu.h b/include/asm-arm/arch-realview/scu.h
new file mode 100644
index 00000000000..cc293640178
--- /dev/null
+++ b/include/asm-arm/arch-realview/scu.h
@@ -0,0 +1,8 @@
+#ifndef __ASMARM_ARCH_SCU_H
+#define __ASMARM_ARCH_SCU_H
+
+#include <asm/arch/platform.h>
+
+#define SCU_BASE REALVIEW_MPCORE_SCU_BASE
+
+#endif
diff --git a/include/asm-arm/arch-s3c2410/dma.h b/include/asm-arm/arch-s3c2410/dma.h
index 58ffa7ba3c8..c6e8d8f6493 100644
--- a/include/asm-arm/arch-s3c2410/dma.h
+++ b/include/asm-arm/arch-s3c2410/dma.h
@@ -51,13 +51,19 @@ enum dma_ch {
DMACH_UART0_SRC2, /* s3c2412 second uart sources */
DMACH_UART1_SRC2,
DMACH_UART2_SRC2,
+ DMACH_UART3, /* s3c2443 has extra uart */
+ DMACH_UART3_SRC2,
DMACH_MAX, /* the end entry */
};
#define DMACH_LOW_LEVEL (1<<28) /* use this to specifiy hardware ch no */
/* we have 4 dma channels */
-#define S3C2410_DMA_CHANNELS (4)
+#ifndef CONFIG_CPU_S3C2443
+#define S3C2410_DMA_CHANNELS (4)
+#else
+#define S3C2410_DMA_CHANNELS (6)
+#endif
/* types */
@@ -321,6 +327,7 @@ extern int s3c2410_dma_set_buffdone_fn(dmach_t, s3c2410_dma_cbfn_t rtn);
#define S3C2410_DMA_DCDST (0x1C)
#define S3C2410_DMA_DMASKTRIG (0x20)
#define S3C2412_DMA_DMAREQSEL (0x24)
+#define S3C2443_DMA_DMAREQSEL (0x24)
#define S3C2410_DISRCC_INC (1<<0)
#define S3C2410_DISRCC_APB (1<<1)
@@ -415,4 +422,31 @@ extern int s3c2410_dma_set_buffdone_fn(dmach_t, s3c2410_dma_cbfn_t rtn);
#define S3C2412_DMAREQSEL_UART2_1 S3C2412_DMAREQSEL_SRC(24)
#endif
+
+#define S3C2443_DMAREQSEL_SRC(x) ((x)<<1)
+
+#define S3C2443_DMAREQSEL_HW (1)
+
+#define S3C2443_DMAREQSEL_SPI0TX S3C2443_DMAREQSEL_SRC(0)
+#define S3C2443_DMAREQSEL_SPI0RX S3C2443_DMAREQSEL_SRC(1)
+#define S3C2443_DMAREQSEL_SPI1TX S3C2443_DMAREQSEL_SRC(2)
+#define S3C2443_DMAREQSEL_SPI1RX S3C2443_DMAREQSEL_SRC(3)
+#define S3C2443_DMAREQSEL_I2STX S3C2443_DMAREQSEL_SRC(4)
+#define S3C2443_DMAREQSEL_I2SRX S3C2443_DMAREQSEL_SRC(5)
+#define S3C2443_DMAREQSEL_TIMER S3C2443_DMAREQSEL_SRC(9)
+#define S3C2443_DMAREQSEL_SDI S3C2443_DMAREQSEL_SRC(10)
+#define S3C2443_DMAREQSEL_XDREQ0 S3C2443_DMAREQSEL_SRC(17)
+#define S3C2443_DMAREQSEL_XDREQ1 S3C2443_DMAREQSEL_SRC(18)
+#define S3C2443_DMAREQSEL_UART0_0 S3C2443_DMAREQSEL_SRC(19)
+#define S3C2443_DMAREQSEL_UART0_1 S3C2443_DMAREQSEL_SRC(20)
+#define S3C2443_DMAREQSEL_UART1_0 S3C2443_DMAREQSEL_SRC(21)
+#define S3C2443_DMAREQSEL_UART1_1 S3C2443_DMAREQSEL_SRC(22)
+#define S3C2443_DMAREQSEL_UART2_0 S3C2443_DMAREQSEL_SRC(23)
+#define S3C2443_DMAREQSEL_UART2_1 S3C2443_DMAREQSEL_SRC(24)
+#define S3C2443_DMAREQSEL_UART3_0 S3C2443_DMAREQSEL_SRC(25)
+#define S3C2443_DMAREQSEL_UART3_1 S3C2443_DMAREQSEL_SRC(26)
+#define S3C2443_DMAREQSEL_PCMOUT S3C2443_DMAREQSEL_SRC(27)
+#define S3C2443_DMAREQSEL_PCMIN S3C2443_DMAREQSEL_SRC(28)
+#define S3C2443_DMAREQSEL_MICIN S3C2443_DMAREQSEL_SRC(29)
+
#endif /* __ASM_ARCH_DMA_H */
diff --git a/include/asm-arm/arch-s3c2410/irqs.h b/include/asm-arm/arch-s3c2410/irqs.h
index 4b7cff456c4..c79cb181991 100644
--- a/include/asm-arm/arch-s3c2410/irqs.h
+++ b/include/asm-arm/arch-s3c2410/irqs.h
@@ -34,10 +34,10 @@
#define IRQ_EINT4t7 S3C2410_IRQ(4) /* 20 */
#define IRQ_EINT8t23 S3C2410_IRQ(5)
#define IRQ_RESERVED6 S3C2410_IRQ(6) /* for s3c2410 */
-#define IRQ_CAM S3C2410_IRQ(6) /* for s3c2440 */
+#define IRQ_CAM S3C2410_IRQ(6) /* for s3c2440,s3c2443 */
#define IRQ_BATT_FLT S3C2410_IRQ(7)
#define IRQ_TICK S3C2410_IRQ(8) /* 24 */
-#define IRQ_WDT S3C2410_IRQ(9)
+#define IRQ_WDT S3C2410_IRQ(9) /* WDT/AC97 for s3c2443 */
#define IRQ_TIMER0 S3C2410_IRQ(10)
#define IRQ_TIMER1 S3C2410_IRQ(11)
#define IRQ_TIMER2 S3C2410_IRQ(12)
@@ -45,7 +45,7 @@
#define IRQ_TIMER4 S3C2410_IRQ(14)
#define IRQ_UART2 S3C2410_IRQ(15)
#define IRQ_LCD S3C2410_IRQ(16) /* 32 */
-#define IRQ_DMA0 S3C2410_IRQ(17)
+#define IRQ_DMA0 S3C2410_IRQ(17) /* IRQ_DMA for s3c2443 */
#define IRQ_DMA1 S3C2410_IRQ(18)
#define IRQ_DMA2 S3C2410_IRQ(19)
#define IRQ_DMA3 S3C2410_IRQ(20)
@@ -94,29 +94,63 @@
* these need to be ordered in number of appearance in the
* SUBSRC mask register
*/
-#define IRQ_S3CUART_RX0 S3C2410_IRQ(54) /* 70 */
-#define IRQ_S3CUART_TX0 S3C2410_IRQ(55) /* 71 */
-#define IRQ_S3CUART_ERR0 S3C2410_IRQ(56)
-#define IRQ_S3CUART_RX1 S3C2410_IRQ(57)
-#define IRQ_S3CUART_TX1 S3C2410_IRQ(58)
-#define IRQ_S3CUART_ERR1 S3C2410_IRQ(59)
+#define S3C2410_IRQSUB(x) S3C2410_IRQ((x)+54)
-#define IRQ_S3CUART_RX2 S3C2410_IRQ(60)
-#define IRQ_S3CUART_TX2 S3C2410_IRQ(61)
-#define IRQ_S3CUART_ERR2 S3C2410_IRQ(62)
+#define IRQ_S3CUART_RX0 S3C2410_IRQSUB(0) /* 70 */
+#define IRQ_S3CUART_TX0 S3C2410_IRQSUB(1)
+#define IRQ_S3CUART_ERR0 S3C2410_IRQSUB(2)
-#define IRQ_TC S3C2410_IRQ(63)
-#define IRQ_ADC S3C2410_IRQ(64)
+#define IRQ_S3CUART_RX1 S3C2410_IRQSUB(3) /* 73 */
+#define IRQ_S3CUART_TX1 S3C2410_IRQSUB(4)
+#define IRQ_S3CUART_ERR1 S3C2410_IRQSUB(5)
-/* extra irqs for s3c2440 */
+#define IRQ_S3CUART_RX2 S3C2410_IRQSUB(6) /* 76 */
+#define IRQ_S3CUART_TX2 S3C2410_IRQSUB(7)
+#define IRQ_S3CUART_ERR2 S3C2410_IRQSUB(8)
-#define IRQ_S3C2440_CAM_C S3C2410_IRQ(65)
-#define IRQ_S3C2440_CAM_P S3C2410_IRQ(66)
-#define IRQ_S3C2440_WDT S3C2410_IRQ(67)
-#define IRQ_S3C2440_AC97 S3C2410_IRQ(68)
+#define IRQ_TC S3C2410_IRQSUB(9)
+#define IRQ_ADC S3C2410_IRQSUB(10)
-#define NR_IRQS (IRQ_S3C2440_AC97+1)
+/* extra irqs for s3c2440 */
+#define IRQ_S3C2440_CAM_C S3C2410_IRQSUB(11) /* S3C2443 too */
+#define IRQ_S3C2440_CAM_P S3C2410_IRQSUB(12) /* S3C2443 too */
+#define IRQ_S3C2440_WDT S3C2410_IRQSUB(13)
+#define IRQ_S3C2440_AC97 S3C2410_IRQSUB(14)
+
+/* irqs for s3c2443 */
+
+#define IRQ_S3C2443_DMA S3C2410_IRQ(17) /* IRQ_DMA1 */
+#define IRQ_S3C2443_UART3 S3C2410_IRQ(18) /* IRQ_DMA2 */
+#define IRQ_S3C2443_CFCON S3C2410_IRQ(19) /* IRQ_DMA3 */
+#define IRQ_S3C2443_SDI1 S3C2410_IRQ(20) /* IRQ_SDI */
+#define IRQ_S3C2443_NAND S3C2410_IRQ(24) /* reserved */
+
+#define IRQ_S3C2443_LCD1 S3C2410_IRQSUB(14)
+#define IRQ_S3C2443_LCD2 S3C2410_IRQSUB(15)
+#define IRQ_S3C2443_LCD3 S3C2410_IRQSUB(16)
+#define IRQ_S3C2443_LCD4 S3C2410_IRQSUB(17)
+
+#define IRQ_S3C2443_DMA0 S3C2410_IRQSUB(18)
+#define IRQ_S3C2443_DMA1 S3C2410_IRQSUB(19)
+#define IRQ_S3C2443_DMA2 S3C2410_IRQSUB(20)
+#define IRQ_S3C2443_DMA3 S3C2410_IRQSUB(21)
+#define IRQ_S3C2443_DMA4 S3C2410_IRQSUB(22)
+#define IRQ_S3C2443_DMA5 S3C2410_IRQSUB(23)
+
+/* UART3 */
+#define IRQ_S3C2443_RX3 S3C2410_IRQSUB(24)
+#define IRQ_S3C2443_TX3 S3C2410_IRQSUB(25)
+#define IRQ_S3C2443_ERR3 S3C2410_IRQSUB(26)
+
+#define IRQ_S3C2443_WDT S3C2410_IRQSUB(27)
+#define IRQ_S3C2443_AC97 S3C2410_IRQSUB(28)
+
+#ifdef CONFIG_CPU_S3C2443
+#define NR_IRQS (IRQ_S3C2443_AC97+1)
+#else
+#define NR_IRQS (IRQ_S3C2440_AC97+1)
+#endif
#endif /* __ASM_ARCH_IRQ_H */
diff --git a/include/asm-arm/arch-s3c2410/regs-adc.h b/include/asm-arm/arch-s3c2410/regs-adc.h
index 3196a2849e8..c7f231963e7 100644
--- a/include/asm-arm/arch-s3c2410/regs-adc.h
+++ b/include/asm-arm/arch-s3c2410/regs-adc.h
@@ -41,7 +41,7 @@
#define S3C2410_ADCTSC_XP_SEN (1<<4)
#define S3C2410_ADCTSC_PULL_UP_DISABLE (1<<3)
#define S3C2410_ADCTSC_AUTO_PST (1<<2)
-#define S3C2410_ADCTSC_XY_PST (0x3<<0)
+#define S3C2410_ADCTSC_XY_PST(x) (((x)&0x3)<<0)
/* ADCDAT0 Bits */
#define S3C2410_ADCDAT0_UPDOWN (1<<15)
diff --git a/include/asm-arm/arch-s3c2410/regs-gpio.h b/include/asm-arm/arch-s3c2410/regs-gpio.h
index eae91694edc..dea578b8f7f 100644
--- a/include/asm-arm/arch-s3c2410/regs-gpio.h
+++ b/include/asm-arm/arch-s3c2410/regs-gpio.h
@@ -201,7 +201,7 @@
#define S3C2400_GPBDAT S3C2410_GPIOREG(0x0C)
#define S3C2400_GPBUP S3C2410_GPIOREG(0x10)
-/* no i/o pin in port b can have value 3! */
+/* no i/o pin in port b can have value 3 (unless it is a s3c2443) ! */
#define S3C2410_GPB0 S3C2410_GPIONO(S3C2410_GPIO_BANKB, 0)
#define S3C2410_GPB0_INP (0x00 << 0)
@@ -242,6 +242,7 @@
#define S3C2410_GPB5_INP (0x00 << 10)
#define S3C2410_GPB5_OUTP (0x01 << 10)
#define S3C2410_GPB5_nXBACK (0x02 << 10)
+#define S3C2443_GPB5_XBACK (0x03 << 10)
#define S3C2400_GPB5_DATA21 (0x02 << 10)
#define S3C2400_GPB5_nCTS1 (0x03 << 10)
@@ -249,6 +250,7 @@
#define S3C2410_GPB6_INP (0x00 << 12)
#define S3C2410_GPB6_OUTP (0x01 << 12)
#define S3C2410_GPB6_nXBREQ (0x02 << 12)
+#define S3C2443_GPB6_XBREQ (0x03 << 12)
#define S3C2400_GPB6_DATA22 (0x02 << 12)
#define S3C2400_GPB6_nRTS1 (0x03 << 12)
@@ -256,6 +258,7 @@
#define S3C2410_GPB7_INP (0x00 << 14)
#define S3C2410_GPB7_OUTP (0x01 << 14)
#define S3C2410_GPB7_nXDACK1 (0x02 << 14)
+#define S3C2443_GPB7_XDACK1 (0x03 << 14)
#define S3C2400_GPB7_DATA23 (0x02 << 14)
#define S3C2410_GPB8 S3C2410_GPIONO(S3C2410_GPIO_BANKB, 8)
@@ -268,6 +271,7 @@
#define S3C2410_GPB9_INP (0x00 << 18)
#define S3C2410_GPB9_OUTP (0x01 << 18)
#define S3C2410_GPB9_nXDACK0 (0x02 << 18)
+#define S3C2443_GPB9_XDACK0 (0x03 << 18)
#define S3C2400_GPB9_DATA25 (0x02 << 18)
#define S3C2400_GPB9_I2SSDI (0x03 << 18)
@@ -275,6 +279,7 @@
#define S3C2410_GPB10_INP (0x00 << 20)
#define S3C2410_GPB10_OUTP (0x01 << 20)
#define S3C2410_GPB10_nXDRE0 (0x02 << 20)
+#define S3C2443_GPB10_XDREQ0 (0x03 << 20)
#define S3C2400_GPB10_DATA26 (0x02 << 20)
#define S3C2400_GPB10_nSS (0x03 << 20)
@@ -556,6 +561,7 @@
#define S3C2410_GPE0_INP (0x00 << 0)
#define S3C2410_GPE0_OUTP (0x01 << 0)
#define S3C2410_GPE0_I2SLRCK (0x02 << 0)
+#define S3C2443_GPE0_AC_nRESET (0x03 << 0)
#define S3C2400_GPE0_EINT0 (0x02 << 0)
#define S3C2410_GPE0_MASK (0x03 << 0)
@@ -563,6 +569,7 @@
#define S3C2410_GPE1_INP (0x00 << 2)
#define S3C2410_GPE1_OUTP (0x01 << 2)
#define S3C2410_GPE1_I2SSCLK (0x02 << 2)
+#define S3C2443_GPE1_AC_SYNC (0x03 << 2)
#define S3C2400_GPE1_EINT1 (0x02 << 2)
#define S3C2400_GPE1_nSS (0x03 << 2)
#define S3C2410_GPE1_MASK (0x03 << 2)
@@ -571,6 +578,7 @@
#define S3C2410_GPE2_INP (0x00 << 4)
#define S3C2410_GPE2_OUTP (0x01 << 4)
#define S3C2410_GPE2_CDCLK (0x02 << 4)
+#define S3C2443_GPE2_AC_BITCLK (0x03 << 4)
#define S3C2400_GPE2_EINT2 (0x02 << 4)
#define S3C2400_GPE2_I2SSDI (0x03 << 4)
@@ -578,6 +586,7 @@
#define S3C2410_GPE3_INP (0x00 << 6)
#define S3C2410_GPE3_OUTP (0x01 << 6)
#define S3C2410_GPE3_I2SSDI (0x02 << 6)
+#define S3C2443_GPE3_AC_SDI (0x03 << 6)
#define S3C2400_GPE3_EINT3 (0x02 << 6)
#define S3C2400_GPE3_nCTS1 (0x03 << 6)
#define S3C2410_GPE3_nSS0 (0x03 << 6)
@@ -587,6 +596,7 @@
#define S3C2410_GPE4_INP (0x00 << 8)
#define S3C2410_GPE4_OUTP (0x01 << 8)
#define S3C2410_GPE4_I2SSDO (0x02 << 8)
+#define S3C2443_GPE4_AC_SDO (0x03 << 8)
#define S3C2400_GPE4_EINT4 (0x02 << 8)
#define S3C2400_GPE4_nRTS1 (0x03 << 8)
#define S3C2410_GPE4_I2SSDI (0x03 << 8)
@@ -596,6 +606,7 @@
#define S3C2410_GPE5_INP (0x00 << 10)
#define S3C2410_GPE5_OUTP (0x01 << 10)
#define S3C2410_GPE5_SDCLK (0x02 << 10)
+#define S3C2443_GPE5_SD1_CLK (0x02 << 10)
#define S3C2400_GPE5_EINT5 (0x02 << 10)
#define S3C2400_GPE5_TCLK1 (0x03 << 10)
@@ -603,24 +614,32 @@
#define S3C2410_GPE6_INP (0x00 << 12)
#define S3C2410_GPE6_OUTP (0x01 << 12)
#define S3C2410_GPE6_SDCMD (0x02 << 12)
+#define S3C2443_GPE6_SD1_CMD (0x02 << 12)
+#define S3C2443_GPE6_AC_BITCLK (0x03 << 12)
#define S3C2400_GPE6_EINT6 (0x02 << 12)
#define S3C2410_GPE7 S3C2410_GPIONO(S3C2410_GPIO_BANKE, 7)
#define S3C2410_GPE7_INP (0x00 << 14)
#define S3C2410_GPE7_OUTP (0x01 << 14)
#define S3C2410_GPE7_SDDAT0 (0x02 << 14)
+#define S3C2443_GPE5_SD1_DAT0 (0x02 << 14)
+#define S3C2443_GPE7_AC_SDI (0x03 << 14)
#define S3C2400_GPE7_EINT7 (0x02 << 14)
#define S3C2410_GPE8 S3C2410_GPIONO(S3C2410_GPIO_BANKE, 8)
#define S3C2410_GPE8_INP (0x00 << 16)
#define S3C2410_GPE8_OUTP (0x01 << 16)
#define S3C2410_GPE8_SDDAT1 (0x02 << 16)
+#define S3C2443_GPE8_SD1_DAT1 (0x02 << 16)
+#define S3C2443_GPE8_AC_SDO (0x03 << 16)
#define S3C2400_GPE8_nXDACK0 (0x02 << 16)
#define S3C2410_GPE9 S3C2410_GPIONO(S3C2410_GPIO_BANKE, 9)
#define S3C2410_GPE9_INP (0x00 << 18)
#define S3C2410_GPE9_OUTP (0x01 << 18)
#define S3C2410_GPE9_SDDAT2 (0x02 << 18)
+#define S3C2443_GPE9_SD1_DAT2 (0x02 << 18)
+#define S3C2443_GPE9_AC_SYNC (0x03 << 18)
#define S3C2400_GPE9_nXDACK1 (0x02 << 18)
#define S3C2400_GPE9_nXBACK (0x03 << 18)
@@ -628,6 +647,8 @@
#define S3C2410_GPE10_INP (0x00 << 20)
#define S3C2410_GPE10_OUTP (0x01 << 20)
#define S3C2410_GPE10_SDDAT3 (0x02 << 20)
+#define S3C2443_GPE10_SD1_DAT3 (0x02 << 20)
+#define S3C2443_GPE10_AC_nRESET (0x03 << 20)
#define S3C2400_GPE10_nXDREQ0 (0x02 << 20)
#define S3C2410_GPE11 S3C2410_GPIONO(S3C2410_GPIO_BANKE, 11)
@@ -796,6 +817,7 @@
#define S3C2400_GPG4_MMCCLK (0x02 << 8)
#define S3C2400_GPG4_I2SSDI (0x03 << 8)
#define S3C2410_GPG4_LCDPWREN (0x03 << 8)
+#define S3C2443_GPG4_LCDPWRDN (0x03 << 8)
#define S3C2410_GPG5 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 5)
#define S3C2410_GPG5_INP (0x00 << 10)
@@ -803,7 +825,7 @@
#define S3C2410_GPG5_EINT13 (0x02 << 10)
#define S3C2400_GPG5_MMCCMD (0x02 << 10)
#define S3C2400_GPG5_IICSDA (0x03 << 10)
-#define S3C2410_GPG5_SPIMISO1 (0x03 << 10)
+#define S3C2410_GPG5_SPIMISO1 (0x03 << 10) /* not s3c2443 */
#define S3C2410_GPG6 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 6)
#define S3C2410_GPG6_INP (0x00 << 12)
@@ -845,6 +867,7 @@
#define S3C2410_GPG11_OUTP (0x01 << 22)
#define S3C2410_GPG11_EINT19 (0x02 << 22)
#define S3C2410_GPG11_TCLK1 (0x03 << 22)
+#define S3C2443_GPG11_CF_nIREQ (0x03 << 22)
#define S3C2410_GPG12 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 12)
#define S3C2410_GPG12_INP (0x00 << 24)
@@ -852,25 +875,28 @@
#define S3C2410_GPG12_EINT20 (0x02 << 24)
#define S3C2410_GPG12_XMON (0x03 << 24)
#define S3C2442_GPG12_nSPICS0 (0x03 << 24)
+#define S3C2443_GPG12_nINPACK (0x03 << 24)
#define S3C2410_GPG13 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 13)
#define S3C2410_GPG13_INP (0x00 << 26)
#define S3C2410_GPG13_OUTP (0x01 << 26)
#define S3C2410_GPG13_EINT21 (0x02 << 26)
#define S3C2410_GPG13_nXPON (0x03 << 26)
+#define S3C2443_GPG13_CF_nREG (0x03 << 26)
#define S3C2410_GPG14 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 14)
#define S3C2410_GPG14_INP (0x00 << 28)
#define S3C2410_GPG14_OUTP (0x01 << 28)
#define S3C2410_GPG14_EINT22 (0x02 << 28)
#define S3C2410_GPG14_YMON (0x03 << 28)
+#define S3C2443_GPG14_CF_RESET (0x03 << 28)
#define S3C2410_GPG15 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 15)
#define S3C2410_GPG15_INP (0x00 << 30)
#define S3C2410_GPG15_OUTP (0x01 << 30)
#define S3C2410_GPG15_EINT23 (0x02 << 30)
#define S3C2410_GPG15_nYPON (0x03 << 30)
-
+#define S3C2443_GPG15_CF_PWR (0x03 << 30)
#define S3C2410_GPG_PUPDIS(x) (1<<(x))
diff --git a/include/asm-arm/arch-s3c2410/regs-s3c2443-clock.h b/include/asm-arm/arch-s3c2410/regs-s3c2443-clock.h
new file mode 100644
index 00000000000..ff0536d2de4
--- /dev/null
+++ b/include/asm-arm/arch-s3c2410/regs-s3c2443-clock.h
@@ -0,0 +1,194 @@
+/* linux/include/asm-arm/arch-s3c2410/regs-clock.h
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ * http://armlinux.simtec.co.uk/
+ *
+ * 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.
+ *
+ * S3C2443 clock register definitions
+*/
+
+#ifndef __ASM_ARM_REGS_S3C2443_CLOCK
+#define __ASM_ARM_REGS_S3C2443_CLOCK
+
+#define S3C2443_CLKREG(x) ((x) + S3C24XX_VA_CLKPWR)
+
+#define S3C2443_PLLCON_MDIVSHIFT 16
+#define S3C2443_PLLCON_PDIVSHIFT 8
+#define S3C2443_PLLCON_SDIVSHIFT 0
+#define S3C2443_PLLCON_MDIVMASK ((1<<(1+(23-16)))-1)
+#define S3C2443_PLLCON_PDIVMASK ((1<<(1+(9-8)))-1)
+#define S3C2443_PLLCON_SDIVMASK (3)
+
+#define S3C2443_MPLLCON S3C2443_CLKREG(0x10)
+#define S3C2443_EPLLCON S3C2443_CLKREG(0x18)
+#define S3C2443_CLKSRC S3C2443_CLKREG(0x20)
+#define S3C2443_CLKDIV0 S3C2443_CLKREG(0x24)
+#define S3C2443_CLKDIV1 S3C2443_CLKREG(0x28)
+#define S3C2443_HCLKCON S3C2443_CLKREG(0x30)
+#define S3C2443_PCLKCON S3C2443_CLKREG(0x34)
+#define S3C2443_SCLKCON S3C2443_CLKREG(0x38)
+#define S3C2443_PWRMODE S3C2443_CLKREG(0x40)
+#define S3C2443_SWRST S3C2443_CLKREG(0x44)
+#define S3C2443_BUSPRI0 S3C2443_CLKREG(0x50)
+#define S3C2443_SYSID S3C2443_CLKREG(0x5C)
+#define S3C2443_PWRCFG S3C2443_CLKREG(0x60)
+#define S3C2443_RSTCON S3C2443_CLKREG(0x64)
+
+#define S3C2443_SWRST_RESET (0x533c2443)
+
+#define S3C2443_PLLCON_OFF (1<<24)
+
+#define S3C2443_CLKSRC_I2S_EXT (1<<14)
+#define S3C2443_CLKSRC_I2S_EPLLDIV (0<<14)
+#define S3C2443_CLKSRC_I2S_EPLLREF (2<<14)
+#define S3C2443_CLKSRC_I2S_EPLLREF3 (3<<14)
+#define S3C2443_CLKSRC_I2S_MASK (3<<14)
+
+#define S3C2443_CLKSRC_EPLLREF_XTAL (2<<8)
+#define S3C2443_CLKSRC_EPLLREF_EXTCLK (3<<8)
+#define S3C2443_CLKSRC_EPLLREF_MPLLREF (0<<8)
+#define S3C2443_CLKSRC_EPLLREF_MPLLREF2 (1<<8)
+#define S3C2443_CLKSRC_EPLLREF_MASK (3<<8)
+
+#define S3C2443_CLKSRC_ESYSCLK_EPLL (1<<6)
+#define S3C2443_CLKSRC_MSYSCLK_MPLL (1<<4)
+#define S3C2443_CLKSRC_EXTCLK_DIV (1<<3)
+
+#define S3C2443_CLKDIV0_DVS (1<<13)
+#define S3C2443_CLKDIV0_HALF_HCLK (1<<3)
+#define S3C2443_CLKDIV0_HALF_PCLK (1<<2)
+
+#define S3C2443_CLKDIV0_HCLKDIV_MASK (3<<0)
+
+#define S3C2443_CLKDIV0_EXTDIV_MASK (3<<6)
+#define S3C2443_CLKDIV0_EXTDIV_SHIFT (6)
+
+#define S3C2443_CLKDIV0_PREDIV_MASK (3<<4)
+#define S3C2443_CLKDIV0_PREDIV_SHIFT (4)
+
+#define S3C2443_CLKDIV0_ARMDIV_MASK (15<<9)
+#define S3C2443_CLKDIV0_ARMDIV_SHIFT (9)
+#define S3C2443_CLKDIV0_ARMDIV_1 (0<<9)
+#define S3C2443_CLKDIV0_ARMDIV_2 (8<<9)
+#define S3C2443_CLKDIV0_ARMDIV_3 (2<<9)
+#define S3C2443_CLKDIV0_ARMDIV_4 (9<<9)
+#define S3C2443_CLKDIV0_ARMDIV_6 (10<<9)
+#define S3C2443_CLKDIV0_ARMDIV_8 (11<<9)
+#define S3C2443_CLKDIV0_ARMDIV_12 (13<<9)
+#define S3C2443_CLKDIV0_ARMDIV_16 (15<<9)
+
+/* S3C2443_CLKDIV1 */
+
+#define S3C2443_CLKDIV1_CAMDIV_MASK (15<<26)
+#define S3C2443_CLKDIV1_CAMDIV_SHIFT (26)
+
+#define S3C2443_CLKDIV1_HSSPIDIV_MASK (3<<24)
+#define S3C2443_CLKDIV1_HSSPIDIV_SHIFT (24)
+
+#define S3C2443_CLKDIV1_DISPDIV_MASK (0xff<<16)
+#define S3C2443_CLKDIV1_DISPDIV_SHIFT (16)
+
+#define S3C2443_CLKDIV1_I2SDIV_MASK (15<<12)
+#define S3C2443_CLKDIV1_I2SDIV_SHIFT (12)
+
+#define S3C2443_CLKDIV1_UARTDIV_MASK (15<<8)
+#define S3C2443_CLKDIV1_UARTDIV_SHIFT (8)
+
+#define S3C2443_CLKDIV1_HSMMCDIV_MASK (3<<6)
+#define S3C2443_CLKDIV1_HSMMCDIV_SHIFT (6)
+
+#define S3C2443_CLKDIV1_USBHOSTDIV_MASK (3<<4)
+#define S3C2443_CLKDIV1_USBHOSTDIV_SHIFT (4)
+
+#define S3C2443_CLKCON_NAND
+
+#define S3C2443_HCLKCON_DMA0 (1<<0)
+#define S3C2443_HCLKCON_DMA1 (1<<1)
+#define S3C2443_HCLKCON_DMA2 (1<<2)
+#define S3C2443_HCLKCON_DMA3 (1<<3)
+#define S3C2443_HCLKCON_DMA4 (1<<4)
+#define S3C2443_HCLKCON_DMA5 (1<<5)
+#define S3C2443_HCLKCON_CAMIF (1<<8)
+#define S3C2443_HCLKCON_DISP (1<<9)
+#define S3C2443_HCLKCON_LCDC (1<<10)
+#define S3C2443_HCLKCON_USBH (1<<11)
+#define S3C2443_HCLKCON_USBD (1<<12)
+#define S3C2443_HCLKCON_HSMMC (1<<16)
+#define S3C2443_HCLKCON_CFC (1<<17)
+#define S3C2443_HCLKCON_SSMC (1<<18)
+#define S3C2443_HCLKCON_DRAMC (1<<19)
+
+#define S3C2443_PCLKCON_UART0 (1<<0)
+#define S3C2443_PCLKCON_UART1 (1<<1)
+#define S3C2443_PCLKCON_UART2 (1<<2)
+#define S3C2443_PCLKCON_UART3 (1<<3)
+#define S3C2443_PCLKCON_IIC (1<<4)
+#define S3C2443_PCLKCON_SDI (1<<5)
+#define S3C2443_PCLKCON_ADC (1<<7)
+#define S3C2443_PCLKCON_IIS (1<<9)
+#define S3C2443_PCLKCON_PWMT (1<<10)
+#define S3C2443_PCLKCON_WDT (1<<11)
+#define S3C2443_PCLKCON_RTC (1<<12)
+#define S3C2443_PCLKCON_GPIO (1<<13)
+#define S3C2443_PCLKCON_SPI0 (1<<14)
+#define S3C2443_PCLKCON_SPI1 (1<<15)
+
+#define S3C2443_SCLKCON_DDRCLK (1<<16)
+#define S3C2443_SCLKCON_SSMCCLK (1<<15)
+#define S3C2443_SCLKCON_HSSPICLK (1<<14)
+#define S3C2443_SCLKCON_HSMMCCLK_EXT (1<<13)
+#define S3C2443_SCLKCON_HSMMCCLK_EPLL (1<<12)
+#define S3C2443_SCLKCON_CAMCLK (1<<11)
+#define S3C2443_SCLKCON_DISPCLK (1<<10)
+#define S3C2443_SCLKCON_I2SCLK (1<<9)
+#define S3C2443_SCLKCON_UARTCLK (1<<8)
+#define S3C2443_SCLKCON_USBHOST (1<<1)
+
+#include <asm/div64.h>
+
+static inline unsigned int
+s3c2443_get_mpll(unsigned int pllval, unsigned int baseclk)
+{
+ unsigned int mdiv, pdiv, sdiv;
+ uint64_t fvco;
+
+ mdiv = pllval >> S3C2443_PLLCON_MDIVSHIFT;
+ pdiv = pllval >> S3C2443_PLLCON_PDIVSHIFT;
+ sdiv = pllval >> S3C2443_PLLCON_SDIVSHIFT;
+
+ mdiv &= S3C2443_PLLCON_MDIVMASK;
+ pdiv &= S3C2443_PLLCON_PDIVMASK;
+ sdiv &= S3C2443_PLLCON_SDIVMASK;
+
+ fvco = (uint64_t)baseclk * (2 * (mdiv + 8));
+ do_div(fvco, pdiv << sdiv);
+
+ return (unsigned int)fvco;
+}
+
+static inline unsigned int
+s3c2443_get_epll(unsigned int pllval, unsigned int baseclk)
+{
+ unsigned int mdiv, pdiv, sdiv;
+ uint64_t fvco;
+
+ mdiv = pllval >> S3C2443_PLLCON_MDIVSHIFT;
+ pdiv = pllval >> S3C2443_PLLCON_PDIVSHIFT;
+ sdiv = pllval >> S3C2443_PLLCON_SDIVSHIFT;
+
+ mdiv &= S3C2443_PLLCON_MDIVMASK;
+ pdiv &= S3C2443_PLLCON_PDIVMASK;
+ sdiv &= S3C2443_PLLCON_SDIVMASK;
+
+ fvco = (uint64_t)baseclk * (mdiv + 8);
+ do_div(fvco, (pdiv + 2) << sdiv);
+
+ return (unsigned int)fvco;
+}
+
+#endif /* __ASM_ARM_REGS_S3C2443_CLOCK */
+
diff --git a/include/asm-arm/arch-s3c2410/regs-serial.h b/include/asm-arm/arch-s3c2410/regs-serial.h
index 46f52401d13..8946702a87f 100644
--- a/include/asm-arm/arch-s3c2410/regs-serial.h
+++ b/include/asm-arm/arch-s3c2410/regs-serial.h
@@ -35,10 +35,12 @@
#define S3C24XX_VA_UART0 (S3C24XX_VA_UART)
#define S3C24XX_VA_UART1 (S3C24XX_VA_UART + 0x4000 )
#define S3C24XX_VA_UART2 (S3C24XX_VA_UART + 0x8000 )
+#define S3C24XX_VA_UART3 (S3C24XX_VA_UART + 0xC000 )
#define S3C2410_PA_UART0 (S3C24XX_PA_UART)
#define S3C2410_PA_UART1 (S3C24XX_PA_UART + 0x4000 )
#define S3C2410_PA_UART2 (S3C24XX_PA_UART + 0x8000 )
+#define S3C2443_PA_UART3 (S3C24XX_PA_UART + 0xC000 )
#define S3C2410_URXH (0x24)
#define S3C2410_UTXH (0x20)
@@ -73,6 +75,8 @@
#define S3C2440_UCON_UCLK (1<<10)
#define S3C2440_UCON_PCLK2 (2<<10)
#define S3C2440_UCON_FCLK (3<<10)
+#define S3C2443_UCON_EPLL (3<<10)
+
#define S3C2440_UCON2_FCLK_EN (1<<15)
#define S3C2440_UCON0_DIVMASK (15 << 12)
#define S3C2440_UCON1_DIVMASK (15 << 12)
@@ -93,6 +97,8 @@
#define S3C2410_UCON_TXIRQMODE (1<<2)
#define S3C2410_UCON_RXIRQMODE (1<<0)
#define S3C2410_UCON_RXFIFO_TOI (1<<7)
+#define S3C2443_UCON_RXERR_IRQEN (1<<6)
+#define S3C2443_UCON_LOOPBACK (1<<5)
#define S3C2410_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
S3C2410_UCON_RXILEVEL | \
@@ -127,7 +133,7 @@
#define S3C2410_UMCOM_AFC (1<<4)
#define S3C2410_UMCOM_RTS_LOW (1<<0)
-#define S3C2412_UMCON_AFC_63 (0<<5)
+#define S3C2412_UMCON_AFC_63 (0<<5) /* same as s3c2443 */
#define S3C2412_UMCON_AFC_56 (1<<5)
#define S3C2412_UMCON_AFC_48 (2<<5)
#define S3C2412_UMCON_AFC_40 (3<<5)
@@ -143,6 +149,7 @@
#define S3C2410_UFSTAT_RXMASK (15<<0)
#define S3C2410_UFSTAT_RXSHIFT (0)
+/* UFSTAT S3C2443 same as S3C2440 */
#define S3C2440_UFSTAT_TXFULL (1<<14)
#define S3C2440_UFSTAT_RXFULL (1<<6)
#define S3C2440_UFSTAT_TXSHIFT (8)
@@ -157,6 +164,8 @@
#define S3C2410_UERSTAT_OVERRUN (1<<0)
#define S3C2410_UERSTAT_FRAME (1<<2)
#define S3C2410_UERSTAT_BREAK (1<<3)
+#define S3C2443_UERSTAT_PARITY (1<<1)
+
#define S3C2410_UERSTAT_ANY (S3C2410_UERSTAT_OVERRUN | \
S3C2410_UERSTAT_FRAME | \
S3C2410_UERSTAT_BREAK)
@@ -164,6 +173,8 @@
#define S3C2410_UMSTAT_CTS (1<<0)
#define S3C2410_UMSTAT_DeltaCTS (1<<2)
+#define S3C2443_DIVSLOT (0x2C)
+
#ifndef __ASSEMBLY__
/* struct s3c24xx_uart_clksrc
diff --git a/include/asm-arm/arch-s3c2410/reset.h b/include/asm-arm/arch-s3c2410/reset.h
new file mode 100644
index 00000000000..4f866cdecab
--- /dev/null
+++ b/include/asm-arm/arch-s3c2410/reset.h
@@ -0,0 +1,22 @@
+/* linux/include/asm-arm/arch-s3c2410/reset.h
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ * http://armlinux.simtec.co.uk/
+ *
+ * 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.
+ *
+ * S3C2410 CPU reset controls
+*/
+
+#ifndef __ASM_ARCH_RESET_H
+#define __ASM_ARCH_RESET_H __FILE__
+
+/* This allows the over-ride of the default reset code
+*/
+
+extern void (*s3c24xx_reset_hook)(void);
+
+#endif /* __ASM_ARCH_RESET_H */
diff --git a/include/asm-arm/arch-s3c2410/system.h b/include/asm-arm/arch-s3c2410/system.h
index ecf250db45f..1c74ef17da3 100644
--- a/include/asm-arm/arch-s3c2410/system.h
+++ b/include/asm-arm/arch-s3c2410/system.h
@@ -15,15 +15,16 @@
#include <asm/arch/map.h>
#include <asm/arch/idle.h>
+#include <asm/arch/reset.h>
#include <asm/arch/regs-watchdog.h>
#include <asm/arch/regs-clock.h>
void (*s3c24xx_idle)(void);
+void (*s3c24xx_reset_hook)(void);
void s3c24xx_default_idle(void)
{
- void __iomem *reg = S3C2410_CLKCON;
unsigned long tmp;
int i;
@@ -33,16 +34,18 @@ void s3c24xx_default_idle(void)
/* Warning: going into idle state upsets jtag scanning */
- __raw_writel(__raw_readl(reg) | (1<<2), reg);
+ __raw_writel(__raw_readl(S3C2410_CLKCON) | S3C2410_CLKCON_IDLE,
+ S3C2410_CLKCON);
/* the samsung port seems to do a loop and then unset idle.. */
for (i = 0; i < 50; i++) {
- tmp += __raw_readl(reg); /* ensure loop not optimised out */
+ tmp += __raw_readl(S3C2410_CLKCON); /* ensure loop not optimised out */
}
/* this bit is not cleared on re-start... */
- __raw_writel(__raw_readl(reg) & ~(1<<2), reg);
+ __raw_writel(__raw_readl(S3C2410_CLKCON) & ~S3C2410_CLKCON_IDLE,
+ S3C2410_CLKCON);
}
static void arch_idle(void)
@@ -53,7 +56,6 @@ static void arch_idle(void)
s3c24xx_default_idle();
}
-
static void
arch_reset(char mode)
{
@@ -61,6 +63,9 @@ arch_reset(char mode)
cpu_reset(0);
}
+ if (s3c24xx_reset_hook)
+ s3c24xx_reset_hook();
+
printk("arch_reset: attempting watchdog reset\n");
__raw_writel(0, S3C2410_WTCON); /* disable watchdog, to be safe */
diff --git a/include/asm-arm/arch-s3c2410/udc.h b/include/asm-arm/arch-s3c2410/udc.h
new file mode 100644
index 00000000000..e59ec339d61
--- /dev/null
+++ b/include/asm-arm/arch-s3c2410/udc.h
@@ -0,0 +1,36 @@
+/* linux/include/asm/arch-s3c2410/udc.h
+ *
+ * Copyright (c) 2005 Arnaud Patard <arnaud.patard@rtp-net.org>
+ *
+ *
+ * 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.
+ *
+ *
+ * Changelog:
+ * 14-Mar-2005 RTP Created file
+ * 02-Aug-2005 RTP File rename
+ * 07-Sep-2005 BJD Minor cleanups, changed cmd to enum
+ * 18-Jan-2007 HMW Add per-platform vbus_draw function
+*/
+
+#ifndef __ASM_ARM_ARCH_UDC_H
+#define __ASM_ARM_ARCH_UDC_H
+
+enum s3c2410_udc_cmd_e {
+ S3C2410_UDC_P_ENABLE = 1, /* Pull-up enable */
+ S3C2410_UDC_P_DISABLE = 2, /* Pull-up disable */
+ S3C2410_UDC_P_RESET = 3, /* UDC reset, in case of */
+};
+
+struct s3c2410_udc_mach_info {
+ void (*udc_command)(enum s3c2410_udc_cmd_e);
+ void (*vbus_draw)(unsigned int ma);
+ unsigned int vbus_pin;
+ unsigned char vbus_pin_inverted;
+};
+
+extern void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *);
+
+#endif /* __ASM_ARM_ARCH_UDC_H */
diff --git a/include/asm-arm/cacheflush.h b/include/asm-arm/cacheflush.h
index 5f531ea0305..afad32c76e6 100644
--- a/include/asm-arm/cacheflush.h
+++ b/include/asm-arm/cacheflush.h
@@ -185,9 +185,15 @@ struct cpu_cache_fns {
void (*coherent_user_range)(unsigned long, unsigned long);
void (*flush_kern_dcache_page)(void *);
- void (*dma_inv_range)(unsigned long, unsigned long);
- void (*dma_clean_range)(unsigned long, unsigned long);
- void (*dma_flush_range)(unsigned long, unsigned long);
+ void (*dma_inv_range)(const void *, const void *);
+ void (*dma_clean_range)(const void *, const void *);
+ void (*dma_flush_range)(const void *, const void *);
+};
+
+struct outer_cache_fns {
+ void (*inv_range)(unsigned long, unsigned long);
+ void (*clean_range)(unsigned long, unsigned long);
+ void (*flush_range)(unsigned long, unsigned long);
};
/*
@@ -240,9 +246,40 @@ extern void __cpuc_flush_dcache_page(void *);
#define dmac_clean_range __glue(_CACHE,_dma_clean_range)
#define dmac_flush_range __glue(_CACHE,_dma_flush_range)
-extern void dmac_inv_range(unsigned long, unsigned long);
-extern void dmac_clean_range(unsigned long, unsigned long);
-extern void dmac_flush_range(unsigned long, unsigned long);
+extern void dmac_inv_range(const void *, const void *);
+extern void dmac_clean_range(const void *, const void *);
+extern void dmac_flush_range(const void *, const void *);
+
+#endif
+
+#ifdef CONFIG_OUTER_CACHE
+
+extern struct outer_cache_fns outer_cache;
+
+static inline void outer_inv_range(unsigned long start, unsigned long end)
+{
+ if (outer_cache.inv_range)
+ outer_cache.inv_range(start, end);
+}
+static inline void outer_clean_range(unsigned long start, unsigned long end)
+{
+ if (outer_cache.clean_range)
+ outer_cache.clean_range(start, end);
+}
+static inline void outer_flush_range(unsigned long start, unsigned long end)
+{
+ if (outer_cache.flush_range)
+ outer_cache.flush_range(start, end);
+}
+
+#else
+
+static inline void outer_inv_range(unsigned long start, unsigned long end)
+{ }
+static inline void outer_clean_range(unsigned long start, unsigned long end)
+{ }
+static inline void outer_flush_range(unsigned long start, unsigned long end)
+{ }
#endif
diff --git a/include/asm-arm/device.h b/include/asm-arm/device.h
index d8f9872b0e2..c61642b4060 100644
--- a/include/asm-arm/device.h
+++ b/include/asm-arm/device.h
@@ -3,5 +3,13 @@
*
* This file is released under the GPLv2
*/
-#include <asm-generic/device.h>
+#ifndef ASMARM_DEVICE_H
+#define ASMARM_DEVICE_H
+struct dev_archdata {
+#ifdef CONFIG_DMABOUNCE
+ struct dmabounce_device_info *dmabounce;
+#endif
+};
+
+#endif
diff --git a/include/asm-arm/dma-mapping.h b/include/asm-arm/dma-mapping.h
index 9bc46b486af..abfb75b654c 100644
--- a/include/asm-arm/dma-mapping.h
+++ b/include/asm-arm/dma-mapping.h
@@ -17,7 +17,7 @@
* platforms with CONFIG_DMABOUNCE.
* Use the driver DMA support - see dma-mapping.h (dma_sync_*)
*/
-extern void consistent_sync(void *kaddr, size_t size, int rw);
+extern void consistent_sync(const void *kaddr, size_t size, int rw);
/*
* Return whether the given device DMA address mask can be supported
@@ -61,6 +61,22 @@ static inline int dma_mapping_error(dma_addr_t dma_addr)
return dma_addr == ~0;
}
+/*
+ * Dummy noncoherent implementation. We don't provide a dma_cache_sync
+ * function so drivers using this API are highlighted with build warnings.
+ */
+static inline void *
+dma_alloc_noncoherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
+{
+ return NULL;
+}
+
+static inline void
+dma_free_noncoherent(struct device *dev, size_t size, void *cpu_addr,
+ dma_addr_t handle)
+{
+}
+
/**
* dma_alloc_coherent - allocate consistent memory for DMA
* @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
diff --git a/include/asm-arm/domain.h b/include/asm-arm/domain.h
index 4c2885abbe6..3c12a762530 100644
--- a/include/asm-arm/domain.h
+++ b/include/asm-arm/domain.h
@@ -57,6 +57,7 @@
__asm__ __volatile__( \
"mcr p15, 0, %0, c3, c0 @ set domain" \
: : "r" (x)); \
+ isb(); \
} while (0)
#define modify_domain(dom,type) \
diff --git a/include/asm-arm/hardware/arm_scu.h b/include/asm-arm/hardware/arm_scu.h
index 9903f60c84b..7d28eb5a175 100644
--- a/include/asm-arm/hardware/arm_scu.h
+++ b/include/asm-arm/hardware/arm_scu.h
@@ -1,6 +1,8 @@
#ifndef ASMARM_HARDWARE_ARM_SCU_H
#define ASMARM_HARDWARE_ARM_SCU_H
+#include <asm/arch/scu.h>
+
/*
* SCU registers
*/
diff --git a/include/asm-arm/hardware/cache-l2x0.h b/include/asm-arm/hardware/cache-l2x0.h
new file mode 100644
index 00000000000..54029a74039
--- /dev/null
+++ b/include/asm-arm/hardware/cache-l2x0.h
@@ -0,0 +1,56 @@
+/*
+ * include/asm-arm/hardware/cache-l2x0.h
+ *
+ * Copyright (C) 2007 ARM Limited
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __ASM_ARM_HARDWARE_L2X0_H
+#define __ASM_ARM_HARDWARE_L2X0_H
+
+#define L2X0_CACHE_ID 0x000
+#define L2X0_CACHE_TYPE 0x004
+#define L2X0_CTRL 0x100
+#define L2X0_AUX_CTRL 0x104
+#define L2X0_EVENT_CNT_CTRL 0x200
+#define L2X0_EVENT_CNT1_CFG 0x204
+#define L2X0_EVENT_CNT0_CFG 0x208
+#define L2X0_EVENT_CNT1_VAL 0x20C
+#define L2X0_EVENT_CNT0_VAL 0x210
+#define L2X0_INTR_MASK 0x214
+#define L2X0_MASKED_INTR_STAT 0x218
+#define L2X0_RAW_INTR_STAT 0x21C
+#define L2X0_INTR_CLEAR 0x220
+#define L2X0_CACHE_SYNC 0x730
+#define L2X0_INV_LINE_PA 0x770
+#define L2X0_INV_WAY 0x77C
+#define L2X0_CLEAN_LINE_PA 0x7B0
+#define L2X0_CLEAN_LINE_IDX 0x7B8
+#define L2X0_CLEAN_WAY 0x7BC
+#define L2X0_CLEAN_INV_LINE_PA 0x7F0
+#define L2X0_CLEAN_INV_LINE_IDX 0x7F8
+#define L2X0_CLEAN_INV_WAY 0x7FC
+#define L2X0_LOCKDOWN_WAY_D 0x900
+#define L2X0_LOCKDOWN_WAY_I 0x904
+#define L2X0_TEST_OPERATION 0xF00
+#define L2X0_LINE_DATA 0xF10
+#define L2X0_LINE_TAG 0xF30
+#define L2X0_DEBUG_CTRL 0xF40
+
+#ifndef __ASSEMBLY__
+extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask);
+#endif
+
+#endif
diff --git a/include/asm-arm/hardware/gic.h b/include/asm-arm/hardware/gic.h
index 3fa5eb70f64..966e428ad32 100644
--- a/include/asm-arm/hardware/gic.h
+++ b/include/asm-arm/hardware/gic.h
@@ -33,8 +33,9 @@
#define GIC_DIST_SOFTINT 0xf00
#ifndef __ASSEMBLY__
-void gic_dist_init(void __iomem *base);
-void gic_cpu_init(void __iomem *base);
+void gic_dist_init(unsigned int gic_nr, void __iomem *base, unsigned int irq_start);
+void gic_cpu_init(unsigned int gic_nr, void __iomem *base);
+void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
void gic_raise_softirq(cpumask_t cpumask, unsigned int irq);
#endif
diff --git a/include/asm-arm/hardware/sa1111.h b/include/asm-arm/hardware/sa1111.h
index 6aa0a5b75b6..61b1d05c7df 100644
--- a/include/asm-arm/hardware/sa1111.h
+++ b/include/asm-arm/hardware/sa1111.h
@@ -29,6 +29,9 @@
#define _SA1111(x) ((x) + sa1111->resource.start)
#endif
+#define sa1111_writel(val,addr) __raw_writel(val, addr)
+#define sa1111_readl(addr) __raw_readl(addr)
+
/*
* 26 bits of the SA-1110 address bus are available to the SA-1111.
* Use these when feeding target addresses to the DMA engines.
@@ -45,14 +48,6 @@
#define SA1111_SAC_DMA_MIN_XFER (0x800)
/*
- * SA1111 register definitions.
- */
-#define __CCREG(x) __REGP(SA1111_VBASE + (x))
-
-#define sa1111_writel(val,addr) __raw_writel(val, addr)
-#define sa1111_readl(addr) __raw_readl(addr)
-
-/*
* System Bus Interface (SBI)
*
* Registers
@@ -194,55 +189,37 @@
* SADR Serial Audio Data Register (16 x 32-bit)
*/
-#define _SACR0 _SA1111( 0x0600 )
-#define _SACR1 _SA1111( 0x0604 )
-#define _SACR2 _SA1111( 0x0608 )
-#define _SASR0 _SA1111( 0x060c )
-#define _SASR1 _SA1111( 0x0610 )
-#define _SASCR _SA1111( 0x0618 )
-#define _L3_CAR _SA1111( 0x061c )
-#define _L3_CDR _SA1111( 0x0620 )
-#define _ACCAR _SA1111( 0x0624 )
-#define _ACCDR _SA1111( 0x0628 )
-#define _ACSAR _SA1111( 0x062c )
-#define _ACSDR _SA1111( 0x0630 )
-#define _SADTCS _SA1111( 0x0634 )
-#define _SADTSA _SA1111( 0x0638 )
-#define _SADTCA _SA1111( 0x063c )
-#define _SADTSB _SA1111( 0x0640 )
-#define _SADTCB _SA1111( 0x0644 )
-#define _SADRCS _SA1111( 0x0648 )
-#define _SADRSA _SA1111( 0x064c )
-#define _SADRCA _SA1111( 0x0650 )
-#define _SADRSB _SA1111( 0x0654 )
-#define _SADRCB _SA1111( 0x0658 )
-#define _SAITR _SA1111( 0x065c )
-#define _SADR _SA1111( 0x0680 )
-
-#define SACR0 __CCREG(0x0600)
-#define SACR1 __CCREG(0x0604)
-#define SACR2 __CCREG(0x0608)
-#define SASR0 __CCREG(0x060c)
-#define SASR1 __CCREG(0x0610)
-#define SASCR __CCREG(0x0618)
-#define L3_CAR __CCREG(0x061c)
-#define L3_CDR __CCREG(0x0620)
-#define ACCAR __CCREG(0x0624)
-#define ACCDR __CCREG(0x0628)
-#define ACSAR __CCREG(0x062c)
-#define ACSDR __CCREG(0x0630)
-#define SADTCS __CCREG(0x0634)
-#define SADTSA __CCREG(0x0638)
-#define SADTCA __CCREG(0x063c)
-#define SADTSB __CCREG(0x0640)
-#define SADTCB __CCREG(0x0644)
-#define SADRCS __CCREG(0x0648)
-#define SADRSA __CCREG(0x064c)
-#define SADRCA __CCREG(0x0650)
-#define SADRSB __CCREG(0x0654)
-#define SADRCB __CCREG(0x0658)
-#define SAITR __CCREG(0x065c)
-#define SADR __CCREG(0x0680)
+#define SA1111_SERAUDIO 0x0600
+
+/*
+ * These are offsets from the above base.
+ */
+#define SA1111_SACR0 0x00
+#define SA1111_SACR1 0x04
+#define SA1111_SACR2 0x08
+#define SA1111_SASR0 0x0c
+#define SA1111_SASR1 0x10
+#define SA1111_SASCR 0x18
+#define SA1111_L3_CAR 0x1c
+#define SA1111_L3_CDR 0x20
+#define SA1111_ACCAR 0x24
+#define SA1111_ACCDR 0x28
+#define SA1111_ACSAR 0x2c
+#define SA1111_ACSDR 0x30
+#define SA1111_SADTCS 0x34
+#define SA1111_SADTSA 0x38
+#define SA1111_SADTCA 0x3c
+#define SA1111_SADTSB 0x40
+#define SA1111_SADTCB 0x44
+#define SA1111_SADRCS 0x48
+#define SA1111_SADRSA 0x4c
+#define SA1111_SADRCA 0x50
+#define SA1111_SADRSB 0x54
+#define SA1111_SADRCB 0x58
+#define SA1111_SAITR 0x5c
+#define SA1111_SADR 0x80
+
+#ifndef CONFIG_ARCH_PXA
#define SACR0_ENB (1<<0)
#define SACR0_BCKD (1<<2)
@@ -330,6 +307,8 @@
#define SAITR_RDBDA (1<<10)
#define SAITR_RDBDB (1<<11)
+#endif /* !CONFIG_ARCH_PXA */
+
/*
* General-Purpose I/O Interface
*
diff --git a/include/asm-arm/kexec.h b/include/asm-arm/kexec.h
new file mode 100644
index 00000000000..8c1c6162a80
--- /dev/null
+++ b/include/asm-arm/kexec.h
@@ -0,0 +1,30 @@
+#ifndef _ARM_KEXEC_H
+#define _ARM_KEXEC_H
+
+#ifdef CONFIG_KEXEC
+
+/* Maximum physical address we can use pages from */
+#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
+/* Maximum address we can reach in physical address mode */
+#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
+/* Maximum address we can use for the control code buffer */
+#define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE
+
+#define KEXEC_CONTROL_CODE_SIZE 4096
+
+#define KEXEC_ARCH KEXEC_ARCH_ARM
+
+#ifndef __ASSEMBLY__
+
+#define MAX_NOTE_BYTES 1024
+
+struct kimage;
+/* Provide a dummy definition to avoid build failures. */
+static inline void crash_setup_regs(struct pt_regs *newregs,
+ struct pt_regs *oldregs) { }
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* CONFIG_KEXEC */
+
+#endif /* _ARM_KEXEC_H */
diff --git a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h
index b8cf2d5ec30..7b2bafce21a 100644
--- a/include/asm-arm/pgtable.h
+++ b/include/asm-arm/pgtable.h
@@ -175,19 +175,29 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
#ifndef __ASSEMBLY__
/*
- * The following macros handle the cache and bufferable bits...
+ * The pgprot_* and protection_map entries will be fixed up in runtime
+ * to include the cachable and bufferable bits based on memory policy,
+ * as well as any architecture dependent bits like global/ASID and SMP
+ * shared mapping bits.
*/
#define _L_PTE_DEFAULT L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_CACHEABLE | L_PTE_BUFFERABLE
#define _L_PTE_READ L_PTE_USER | L_PTE_EXEC
+extern pgprot_t pgprot_user;
extern pgprot_t pgprot_kernel;
-#define PAGE_NONE __pgprot(_L_PTE_DEFAULT)
-#define PAGE_COPY __pgprot(_L_PTE_DEFAULT | _L_PTE_READ)
-#define PAGE_SHARED __pgprot(_L_PTE_DEFAULT | _L_PTE_READ | L_PTE_WRITE)
-#define PAGE_READONLY __pgprot(_L_PTE_DEFAULT | _L_PTE_READ)
+#define PAGE_NONE pgprot_user
+#define PAGE_COPY __pgprot(pgprot_val(pgprot_user) | _L_PTE_READ)
+#define PAGE_SHARED __pgprot(pgprot_val(pgprot_user) | _L_PTE_READ | \
+ L_PTE_WRITE)
+#define PAGE_READONLY __pgprot(pgprot_val(pgprot_user) | _L_PTE_READ)
#define PAGE_KERNEL pgprot_kernel
+#define __PAGE_NONE __pgprot(_L_PTE_DEFAULT)
+#define __PAGE_COPY __pgprot(_L_PTE_DEFAULT | _L_PTE_READ)
+#define __PAGE_SHARED __pgprot(_L_PTE_DEFAULT | _L_PTE_READ | L_PTE_WRITE)
+#define __PAGE_READONLY __pgprot(_L_PTE_DEFAULT | _L_PTE_READ)
+
#endif /* __ASSEMBLY__ */
/*
@@ -198,23 +208,23 @@ extern pgprot_t pgprot_kernel;
* 2) If we could do execute protection, then read is implied
* 3) write implies read permissions
*/
-#define __P000 PAGE_NONE
-#define __P001 PAGE_READONLY
-#define __P010 PAGE_COPY
-#define __P011 PAGE_COPY
-#define __P100 PAGE_READONLY
-#define __P101 PAGE_READONLY
-#define __P110 PAGE_COPY
-#define __P111 PAGE_COPY
-
-#define __S000 PAGE_NONE
-#define __S001 PAGE_READONLY
-#define __S010 PAGE_SHARED
-#define __S011 PAGE_SHARED
-#define __S100 PAGE_READONLY
-#define __S101 PAGE_READONLY
-#define __S110 PAGE_SHARED
-#define __S111 PAGE_SHARED
+#define __P000 __PAGE_NONE
+#define __P001 __PAGE_READONLY
+#define __P010 __PAGE_COPY
+#define __P011 __PAGE_COPY
+#define __P100 __PAGE_READONLY
+#define __P101 __PAGE_READONLY
+#define __P110 __PAGE_COPY
+#define __P111 __PAGE_COPY
+
+#define __S000 __PAGE_NONE
+#define __S001 __PAGE_READONLY
+#define __S010 __PAGE_SHARED
+#define __S011 __PAGE_SHARED
+#define __S100 __PAGE_READONLY
+#define __S101 __PAGE_READONLY
+#define __S110 __PAGE_SHARED
+#define __S111 __PAGE_SHARED
#ifndef __ASSEMBLY__
/*
diff --git a/arch/arm/mach-s3c2410/clock.h b/include/asm-arm/plat-s3c24xx/clock.h
index 7f0ea03e1d4..f6135dbb9fa 100644
--- a/arch/arm/mach-s3c2410/clock.h
+++ b/include/asm-arm/plat-s3c24xx/clock.h
@@ -1,4 +1,4 @@
-/*
+/* linux/include/asm-arm/plat-s3c24xx/clock.h
* linux/arch/arm/mach-s3c2410/clock.h
*
* Copyright (c) 2004-2005 Simtec Electronics
diff --git a/arch/arm/mach-s3c2410/common-smdk.h b/include/asm-arm/plat-s3c24xx/common-smdk.h
index 0e3a3be330a..58d9094c935 100644
--- a/arch/arm/mach-s3c2410/common-smdk.h
+++ b/include/asm-arm/plat-s3c24xx/common-smdk.h
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/common-smdk.h
+/* linux/include/asm-arm/plat-s3c24xx/common-smdk.h
*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c2410/cpu.h b/include/asm-arm/plat-s3c24xx/cpu.h
index be42e4032a6..15dd1881090 100644
--- a/arch/arm/mach-s3c2410/cpu.h
+++ b/include/asm-arm/plat-s3c24xx/cpu.h
@@ -1,4 +1,4 @@
-/* arch/arm/mach-s3c2410/cpu.h
+/* linux/include/asm-arm/plat-s3c24xx/cpu.h
*
* Copyright (c) 2004-2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@@ -67,3 +67,4 @@ extern struct sysdev_class s3c2410_sysclass;
extern struct sysdev_class s3c2412_sysclass;
extern struct sysdev_class s3c2440_sysclass;
extern struct sysdev_class s3c2442_sysclass;
+extern struct sysdev_class s3c2443_sysclass;
diff --git a/arch/arm/mach-s3c2410/devs.h b/include/asm-arm/plat-s3c24xx/devs.h
index 14fb0bade71..dddf485fc06 100644
--- a/arch/arm/mach-s3c2410/devs.h
+++ b/include/asm-arm/plat-s3c24xx/devs.h
@@ -1,4 +1,4 @@
-/* arch/arm/mach-s3c2410/devs.h
+/* linux/include/asm-arm/plat-s3c24xx/devs.h
*
* Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c2410/dma.h b/include/asm-arm/plat-s3c24xx/dma.h
index 0ebfe0aab80..2c59406435e 100644
--- a/arch/arm/mach-s3c2410/dma.h
+++ b/include/asm-arm/plat-s3c24xx/dma.h
@@ -1,4 +1,4 @@
-/* arch/arm/mach-s3c2410/dma.h
+/* linux/include/asm-arm/plat-s3c24xx/dma.h
*
* Copyright (C) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@@ -14,6 +14,7 @@ extern struct sysdev_class dma_sysclass;
extern struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
#define DMA_CH_VALID (1<<31)
+#define DMA_CH_NEVER (1<<30)
struct s3c24xx_dma_addr {
unsigned long from;
@@ -43,3 +44,34 @@ struct s3c24xx_dma_selection {
};
extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel);
+
+/* struct s3c24xx_dma_order_ch
+ *
+ * channel map for one of the `enum dma_ch` dma channels. the list
+ * entry contains a set of low-level channel numbers, orred with
+ * DMA_CH_VALID, which are checked in the order in the array.
+*/
+
+struct s3c24xx_dma_order_ch {
+ unsigned int list[S3C2410_DMA_CHANNELS]; /* list of channels */
+ unsigned int flags; /* flags */
+};
+
+/* struct s3c24xx_dma_order
+ *
+ * information provided by either the core or the board to give the
+ * dma system a hint on how to allocate channels
+*/
+
+struct s3c24xx_dma_order {
+ struct s3c24xx_dma_order_ch channels[DMACH_MAX];
+};
+
+extern int s3c24xx_dma_order_set(struct s3c24xx_dma_order *map);
+
+/* DMA init code, called from the cpu support code */
+
+extern int s3c2410_dma_init(void);
+
+extern int s3c24xx_dma_init(unsigned int channels, unsigned int irq,
+ unsigned int stride);
diff --git a/arch/arm/mach-s3c2410/irq.h b/include/asm-arm/plat-s3c24xx/irq.h
index e5913da3b91..8af6d9579b3 100644
--- a/arch/arm/mach-s3c2410/irq.h
+++ b/include/asm-arm/plat-s3c24xx/irq.h
@@ -1,4 +1,4 @@
-/* arch/arm/mach-s3c2410/irq.h
+/* linux/include/asm-arm/plat-s3c24xx/irq.h
*
* Copyright (c) 2004-2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c2410/pm.h b/include/asm-arm/plat-s3c24xx/pm.h
index ffe197a119f..cc623667e48 100644
--- a/arch/arm/mach-s3c2410/pm.h
+++ b/include/asm-arm/plat-s3c24xx/pm.h
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/pm.h
+/* linux/include/asm-arm/plat-s3c24xx/pm.h
*
* Copyright (c) 2004 Simtec Electronics
* Written by Ben Dooks, <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c2410/s3c2400.h b/include/asm-arm/plat-s3c24xx/s3c2400.h
index 8b2394e1ed4..3a5a16821af 100644
--- a/arch/arm/mach-s3c2410/s3c2400.h
+++ b/include/asm-arm/plat-s3c24xx/s3c2400.h
@@ -1,4 +1,4 @@
-/* arch/arm/mach-s3c2410/s3c2400.h
+/* linux/include/asm-arm/plat-s3c24xx/s3c2400.h
*
* Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c2410/s3c2410.h b/include/asm-arm/plat-s3c24xx/s3c2410.h
index fbed084f26d..36de0b83587 100644
--- a/arch/arm/mach-s3c2410/s3c2410.h
+++ b/include/asm-arm/plat-s3c24xx/s3c2410.h
@@ -1,4 +1,4 @@
-/* arch/arm/mach-s3c2410/s3c2410.h
+/* linux/include/asm-arm/plat-s3c24xx/s3c2410.h
*
* Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c2410/s3c2412.h b/include/asm-arm/plat-s3c24xx/s3c2412.h
index c6e56032a6e..3ec97685e78 100644
--- a/arch/arm/mach-s3c2410/s3c2412.h
+++ b/include/asm-arm/plat-s3c24xx/s3c2412.h
@@ -1,4 +1,4 @@
-/* arch/arm/mach-s3c2410/s3c2412.h
+/* linux/include/asm-arm/plat-s3c24xx/s3c2412.h
*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c2410/s3c2440.h b/include/asm-arm/plat-s3c24xx/s3c2440.h
index dcd316076c5..107853bf948 100644
--- a/arch/arm/mach-s3c2410/s3c2440.h
+++ b/include/asm-arm/plat-s3c24xx/s3c2440.h
@@ -1,4 +1,4 @@
-/* arch/arm/mach-s3c2410/s3c2440.h
+/* linux/include/asm-arm/plat-s3c24xx/s3c2440.h
*
* Copyright (c) 2004-2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c2410/s3c2442.h b/include/asm-arm/plat-s3c24xx/s3c2442.h
index 0ae37d24866..451a23a2092 100644
--- a/arch/arm/mach-s3c2410/s3c2442.h
+++ b/include/asm-arm/plat-s3c24xx/s3c2442.h
@@ -1,4 +1,4 @@
-/* arch/arm/mach-s3c2410/s3c2442.h
+/* linux/include/asm-arm/plat-s3c24xx/s3c2442.h
*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
diff --git a/include/asm-arm/plat-s3c24xx/s3c2443.h b/include/asm-arm/plat-s3c24xx/s3c2443.h
new file mode 100644
index 00000000000..11d83b5c84e
--- /dev/null
+++ b/include/asm-arm/plat-s3c24xx/s3c2443.h
@@ -0,0 +1,32 @@
+/* linux/include/asm-arm/plat-s3c24xx/s3c2443.h
+ *
+ * Copyright (c) 2004-2005 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Header file for s3c2443 cpu support
+ *
+ * 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.
+*/
+
+#ifdef CONFIG_CPU_S3C2443
+
+struct s3c2410_uartcfg;
+
+extern int s3c2443_init(void);
+
+extern void s3c2443_map_io(struct map_desc *mach_desc, int size);
+
+extern void s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no);
+
+extern void s3c2443_init_clocks(int xtal);
+
+extern int s3c2443_baseclk_add(void);
+
+#else
+#define s3c2443_init_clocks NULL
+#define s3c2443_init_uarts NULL
+#define s3c2443_map_io NULL
+#define s3c2443_init NULL
+#endif
diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h
index aa223fc546a..f4386906b20 100644
--- a/include/asm-arm/system.h
+++ b/include/asm-arm/system.h
@@ -140,6 +140,40 @@ static inline int cpu_is_xsc3(void)
#define cpu_is_xscale() 1
#endif
+#define UDBG_UNDEFINED (1 << 0)
+#define UDBG_SYSCALL (1 << 1)
+#define UDBG_BADABORT (1 << 2)
+#define UDBG_SEGV (1 << 3)
+#define UDBG_BUS (1 << 4)
+
+extern unsigned int user_debug;
+
+#if __LINUX_ARM_ARCH__ >= 4
+#define vectors_high() (cr_alignment & CR_V)
+#else
+#define vectors_high() (0)
+#endif
+
+#if __LINUX_ARM_ARCH__ >= 6
+#define isb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \
+ : : "r" (0) : "memory")
+#define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
+ : : "r" (0) : "memory")
+#define dmb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \
+ : : "r" (0) : "memory")
+#else
+#define isb() __asm__ __volatile__ ("" : : : "memory")
+#define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
+ : : "r" (0) : "memory")
+#define dmb() __asm__ __volatile__ ("" : : : "memory")
+#endif
+#define mb() dmb()
+#define rmb() mb()
+#define wmb() mb()
+#define read_barrier_depends() do { } while(0)
+#define set_mb(var, value) do { var = value; mb(); } while (0)
+#define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t");
+
extern unsigned long cr_no_alignment; /* defined in entry-armv.S */
extern unsigned long cr_alignment; /* defined in entry-armv.S */
@@ -154,6 +188,7 @@ static inline void set_cr(unsigned int val)
{
asm volatile("mcr p15, 0, %0, c1, c0, 0 @ set CR"
: : "r" (val) : "cc");
+ isb();
}
#ifndef CONFIG_SMP
@@ -176,34 +211,9 @@ static inline void set_copro_access(unsigned int val)
{
asm volatile("mcr p15, 0, %0, c1, c0, 2 @ set copro access"
: : "r" (val) : "cc");
+ isb();
}
-#define UDBG_UNDEFINED (1 << 0)
-#define UDBG_SYSCALL (1 << 1)
-#define UDBG_BADABORT (1 << 2)
-#define UDBG_SEGV (1 << 3)
-#define UDBG_BUS (1 << 4)
-
-extern unsigned int user_debug;
-
-#if __LINUX_ARM_ARCH__ >= 4
-#define vectors_high() (cr_alignment & CR_V)
-#else
-#define vectors_high() (0)
-#endif
-
-#if __LINUX_ARM_ARCH__ >= 6
-#define mb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \
- : : "r" (0) : "memory")
-#else
-#define mb() __asm__ __volatile__ ("" : : : "memory")
-#endif
-#define rmb() mb()
-#define wmb() mb()
-#define read_barrier_depends() do { } while(0)
-#define set_mb(var, value) do { var = value; mb(); } while (0)
-#define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t");
-
/*
* switch_mm() may do a full cache flush over the context switch,
* so enable interrupts over the context switch to avoid high
diff --git a/include/asm-arm/tlbflush.h b/include/asm-arm/tlbflush.h
index cd10a0b5f8a..08c6991dc9c 100644
--- a/include/asm-arm/tlbflush.h
+++ b/include/asm-arm/tlbflush.h
@@ -247,7 +247,7 @@ static inline void local_flush_tlb_all(void)
const unsigned int __tlb_flag = __cpu_tlb_flags;
if (tlb_flag(TLB_WB))
- asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (zero) : "cc");
+ dsb();
if (tlb_flag(TLB_V3_FULL))
asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (zero) : "cc");
@@ -257,6 +257,15 @@ static inline void local_flush_tlb_all(void)
asm("mcr p15, 0, %0, c8, c6, 0" : : "r" (zero) : "cc");
if (tlb_flag(TLB_V4_I_FULL | TLB_V6_I_FULL))
asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
+
+ if (tlb_flag(TLB_V6_I_FULL | TLB_V6_D_FULL |
+ TLB_V6_I_PAGE | TLB_V6_D_PAGE |
+ TLB_V6_I_ASID | TLB_V6_D_ASID)) {
+ /* flush the branch target cache */
+ asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
+ dsb();
+ isb();
+ }
}
static inline void local_flush_tlb_mm(struct mm_struct *mm)
@@ -266,7 +275,7 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm)
const unsigned int __tlb_flag = __cpu_tlb_flags;
if (tlb_flag(TLB_WB))
- asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (zero) : "cc");
+ dsb();
if (cpu_isset(smp_processor_id(), mm->cpu_vm_mask)) {
if (tlb_flag(TLB_V3_FULL))
@@ -285,6 +294,14 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm)
asm("mcr p15, 0, %0, c8, c6, 2" : : "r" (asid) : "cc");
if (tlb_flag(TLB_V6_I_ASID))
asm("mcr p15, 0, %0, c8, c5, 2" : : "r" (asid) : "cc");
+
+ if (tlb_flag(TLB_V6_I_FULL | TLB_V6_D_FULL |
+ TLB_V6_I_PAGE | TLB_V6_D_PAGE |
+ TLB_V6_I_ASID | TLB_V6_D_ASID)) {
+ /* flush the branch target cache */
+ asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
+ dsb();
+ }
}
static inline void
@@ -296,7 +313,7 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
uaddr = (uaddr & PAGE_MASK) | ASID(vma->vm_mm);
if (tlb_flag(TLB_WB))
- asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (zero));
+ dsb();
if (cpu_isset(smp_processor_id(), vma->vm_mm->cpu_vm_mask)) {
if (tlb_flag(TLB_V3_PAGE))
@@ -317,6 +334,14 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (uaddr) : "cc");
if (tlb_flag(TLB_V6_I_PAGE))
asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (uaddr) : "cc");
+
+ if (tlb_flag(TLB_V6_I_FULL | TLB_V6_D_FULL |
+ TLB_V6_I_PAGE | TLB_V6_D_PAGE |
+ TLB_V6_I_ASID | TLB_V6_D_ASID)) {
+ /* flush the branch target cache */
+ asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
+ dsb();
+ }
}
static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
@@ -327,7 +352,7 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
kaddr &= PAGE_MASK;
if (tlb_flag(TLB_WB))
- asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (zero) : "cc");
+ dsb();
if (tlb_flag(TLB_V3_PAGE))
asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (kaddr) : "cc");
@@ -347,11 +372,14 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
if (tlb_flag(TLB_V6_I_PAGE))
asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (kaddr) : "cc");
- /* The ARM ARM states that the completion of a TLB maintenance
- * operation is only guaranteed by a DSB instruction
- */
- if (tlb_flag(TLB_V6_U_PAGE | TLB_V6_D_PAGE | TLB_V6_I_PAGE))
- asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (zero) : "cc");
+ if (tlb_flag(TLB_V6_I_FULL | TLB_V6_D_FULL |
+ TLB_V6_I_PAGE | TLB_V6_D_PAGE |
+ TLB_V6_I_ASID | TLB_V6_D_ASID)) {
+ /* flush the branch target cache */
+ asm("mcr p15, 0, %0, c7, c5, 6" : : "r" (zero) : "cc");
+ dsb();
+ isb();
+ }
}
/*
@@ -369,15 +397,13 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
*/
static inline void flush_pmd_entry(pmd_t *pmd)
{
- const unsigned int zero = 0;
const unsigned int __tlb_flag = __cpu_tlb_flags;
if (tlb_flag(TLB_DCLEAN))
asm("mcr p15, 0, %0, c7, c10, 1 @ flush_pmd"
: : "r" (pmd) : "cc");
if (tlb_flag(TLB_WB))
- asm("mcr p15, 0, %0, c7, c10, 4 @ flush_pmd"
- : : "r" (zero) : "cc");
+ dsb();
}
static inline void clean_pmd_entry(pmd_t *pmd)
diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h
index 97e7060000c..0991b7bc3f7 100644
--- a/include/asm-arm/unistd.h
+++ b/include/asm-arm/unistd.h
@@ -372,6 +372,7 @@
#define __NR_move_pages (__NR_SYSCALL_BASE+344)
#define __NR_getcpu (__NR_SYSCALL_BASE+345)
/* 346 for epoll_pwait */
+#define __NR_sys_kexec_load (__NR_SYSCALL_BASE+347)
/*
* The following SWIs are ARM private.
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index d02425cdd80..696e5ec63f7 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -125,6 +125,7 @@ extern struct kimage *kexec_crash_image;
#define KEXEC_ARCH_PPC (20 << 16)
#define KEXEC_ARCH_PPC64 (21 << 16)
#define KEXEC_ARCH_IA_64 (50 << 16)
+#define KEXEC_ARCH_ARM (40 << 16)
#define KEXEC_ARCH_S390 (22 << 16)
#define KEXEC_ARCH_SH (42 << 16)
#define KEXEC_ARCH_MIPS_LE (10 << 16)