aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Dooks <ben-linux@fluff.org>2007-02-11 12:31:01 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2007-02-11 12:36:09 -0500
commita21765a70ec06be175d3997320a83fa66fcc8955 (patch)
tree24bdbf437a9bd5b7c1af05898f5aa25dccf67fe9
parentd19494b187b20e363f9b434b9ceab4159ac88324 (diff)
[ARM] 4157/2: S3C24XX: move arch/arch/mach-s3c2410 into cpu components
The following patch and script moves the arch/arm/mach-s3c2410 directory into arch/arm/plat-s3c24xx for the generic core code and inti arch/arm/mach-s3c{cpu} for the cpu/machine support files Include directory include/asm-arm/plat-s3c24xx is added for the core include files. Signed-off-by: Ben Dooks <ben-linux@fluff.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/Kconfig8
-rw-r--r--arch/arm/Makefile7
-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/Kconfig356
-rw-r--r--arch/arm/mach-s3c2410/Makefile95
-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.c1528
-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.c6
-rw-r--r--arch/arm/mach-s3c2410/mach-bast.c6
-rw-r--r--arch/arm/mach-s3c2410/mach-h1940.c8
-rw-r--r--arch/arm/mach-s3c2410/mach-n30.c8
-rw-r--r--arch/arm/mach-s3c2410/mach-otom.c8
-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.c8
-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)6
-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)14
-rw-r--r--arch/arm/mach-s3c2412/mach-vstms.c (renamed from arch/arm/mach-s3c2410/mach-vstms.c)12
-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)6
-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)10
-rw-r--r--arch/arm/mach-s3c2440/mach-smdk2440.c (renamed from arch/arm/mach-s3c2410/mach-smdk2440.c)14
-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/plat-s3c24xx/Kconfig96
-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)18
-rw-r--r--arch/arm/plat-s3c24xx/devs.c (renamed from arch/arm/mach-s3c2410/devs.c)6
-rw-r--r--arch/arm/plat-s3c24xx/dma.c1441
-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)14
-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.S159
-rw-r--r--arch/arm/plat-s3c24xx/time.c (renamed from arch/arm/mach-s3c2410/time.c)6
-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)2
-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)2
-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
83 files changed, 4783 insertions, 4689 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 6783c2e5512d..51ee13e7c74c 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -363,7 +363,15 @@ source "arch/arm/mach-omap1/Kconfig"
363 363
364source "arch/arm/mach-omap2/Kconfig" 364source "arch/arm/mach-omap2/Kconfig"
365 365
366source "arch/arm/plat-s3c24xx/Kconfig"
367
368if ARCH_S3C2410
369source "arch/arm/mach-s3c2400/Kconfig"
366source "arch/arm/mach-s3c2410/Kconfig" 370source "arch/arm/mach-s3c2410/Kconfig"
371source "arch/arm/mach-s3c2412/Kconfig"
372source "arch/arm/mach-s3c2440/Kconfig"
373source "arch/arm/mach-s3c2442/Kconfig"
374endif
367 375
368source "arch/arm/mach-lh7a40x/Kconfig" 376source "arch/arm/mach-lh7a40x/Kconfig"
369 377
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 000f1100b553..2df1ea0a0c2d 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -149,7 +149,7 @@ MACHINE := arch/arm/mach-$(machine-y)/
149else 149else
150MACHINE := 150MACHINE :=
151endif 151endif
152 152
153export TEXT_OFFSET GZFLAGS MMUEXT 153export TEXT_OFFSET GZFLAGS MMUEXT
154 154
155# Do we have FASTFPE? 155# Do we have FASTFPE?
@@ -161,6 +161,10 @@ endif
161# If we have a machine-specific directory, then include it in the build. 161# If we have a machine-specific directory, then include it in the build.
162core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ 162core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
163core-y += $(MACHINE) 163core-y += $(MACHINE)
164core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2400/
165core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2412/
166core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2440/
167core-$(CONFIG_ARCH_S3C2410) += arch/arm/mach-s3c2442/
164core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/ 168core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/
165core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ) 169core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ)
166core-$(CONFIG_VFP) += arch/arm/vfp/ 170core-$(CONFIG_VFP) += arch/arm/vfp/
@@ -168,6 +172,7 @@ core-$(CONFIG_VFP) += arch/arm/vfp/
168# If we have a common platform directory, then include it in the build. 172# If we have a common platform directory, then include it in the build.
169core-$(CONFIG_PLAT_IOP) += arch/arm/plat-iop/ 173core-$(CONFIG_PLAT_IOP) += arch/arm/plat-iop/
170core-$(CONFIG_ARCH_OMAP) += arch/arm/plat-omap/ 174core-$(CONFIG_ARCH_OMAP) += arch/arm/plat-omap/
175core-$(CONFIG_PLAT_S3C24XX) += arch/arm/plat-s3c24xx/
171 176
172drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/ 177drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/
173drivers-$(CONFIG_ARCH_CLPS7500) += drivers/acorn/char/ 178drivers-$(CONFIG_ARCH_CLPS7500) += drivers/acorn/char/
diff --git a/arch/arm/mach-s3c2400/Kconfig b/arch/arm/mach-s3c2400/Kconfig
new file mode 100644
index 000000000000..deab0722836e
--- /dev/null
+++ b/arch/arm/mach-s3c2400/Kconfig
@@ -0,0 +1,13 @@
1# arch/arm/mach-s3c2400/Kconfig
2#
3# Copyright 2007 Simtec Electronics
4#
5# Licensed under GPLv2
6
7
8
9menu "S3C2400 Machines"
10
11
12endmenu
13
diff --git a/arch/arm/mach-s3c2400/Makefile b/arch/arm/mach-s3c2400/Makefile
new file mode 100644
index 000000000000..7e23f4e13766
--- /dev/null
+++ b/arch/arm/mach-s3c2400/Makefile
@@ -0,0 +1,15 @@
1# arch/arm/mach-s3c2400/Makefile
2#
3# Copyright 2007 Simtec Electronics
4#
5# Licensed under GPLv2
6
7obj-y :=
8obj-m :=
9obj-n :=
10obj- :=
11
12obj-$(CONFIG_CPU_S3C2400) += gpio.o
13
14# Machine support
15
diff --git a/arch/arm/mach-s3c2410/s3c2400-gpio.c b/arch/arm/mach-s3c2400/gpio.c
index 1576d01d5f82..758e160410e9 100644
--- a/arch/arm/mach-s3c2410/s3c2400-gpio.c
+++ b/arch/arm/mach-s3c2400/gpio.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/s3c2400-gpio.c 1/* linux/arch/arm/mach-s3c2400/gpio.c
2 * 2 *
3 * Copyright (c) 2006 Lucas Correia Villa Real <lucasvr@gobolinux.org> 3 * Copyright (c) 2006 Lucas Correia Villa Real <lucasvr@gobolinux.org>
4 * 4 *
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
index 0ab590ec4582..016b53f5d6fc 100644
--- a/arch/arm/mach-s3c2410/Kconfig
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -1,54 +1,51 @@
1if ARCH_S3C2410 1# arch/arm/mach-s3c2410/Kconfig
2#
3# Copyright 2007 Simtec Electronics
4#
5# Licensed under GPLv2
2 6
3menu "S3C24XX Implementations" 7config CPU_S3C2410
8 bool
9 depends on ARCH_S3C2410
10 select S3C2410_CLOCK
11 select S3C2410_GPIO
12 select S3C2410_PM if PM
13 help
14 Support for S3C2410 and S3C2410A family from the S3C24XX line
15 of Samsung Mobile CPUs.
4 16
5config MACH_AML_M5900 17config CPU_S3C2410_DMA
6 bool "AML M5900 Series" 18 bool
7 select CPU_S3C2410 19 depends on S3C2410_DMA && (CPU_S3C2410 || CPU_S3C2442)
8 select PM_SIMTEC if PM 20 default y if CPU_S3C2410 || CPU_S3C2442
9 help 21 help
10 Say Y here if you are using the American Microsystems M5900 Series 22 DMA device selection for S3C2410 and compatible CPUs
11 <http://www.amltd.com>
12 23
13config MACH_ANUBIS 24config S3C2410_PM
14 bool "Simtec Electronics ANUBIS" 25 bool
15 select CPU_S3C2440
16 select PM_SIMTEC if PM
17 help 26 help
18 Say Y here if you are using the Simtec Electronics ANUBIS 27 Power Management code common to S3C2410 and better
19 development system
20 28
21config MACH_OSIRIS 29config S3C2410_GPIO
22 bool "Simtec IM2440D20 (OSIRIS) module" 30 bool
23 select CPU_S3C2440
24 select PM_SIMTEC if PM
25 help 31 help
26 Say Y here if you are using the Simtec IM2440D20 module, also 32 GPIO code for S3C2410 and similar processors
27 known as the Osiris.
28 33
29config ARCH_BAST 34config S3C2410_CLOCK
30 bool "Simtec Electronics BAST (EB2410ITX)" 35 bool
31 select CPU_S3C2410
32 select PM_SIMTEC if PM
33 select ISA
34 help 36 help
35 Say Y here if you are using the Simtec Electronics EB2410ITX 37 Clock code for the S3C2410, and similar processors
36 development board (also known as BAST)
37 38
38 Product page: <http://www.simtec.co.uk/products/EB2410ITX/>.
39 39
40config BAST_PC104_IRQ 40menu "S3C2410 Machines"
41 bool "BAST PC104 IRQ support"
42 depends on ARCH_BAST
43 default y
44 help
45 Say Y here to enable the PC104 IRQ routing on the
46 Simtec BAST (EB2410ITX)
47 41
48config PM_H1940 42config ARCH_SMDK2410
49 bool 43 bool "SMDK2410/A9M2410"
44 select CPU_S3C2410
45 select MACH_SMDK
50 help 46 help
51 Internal node for H1940 and related PM 47 Say Y here if you are using the SMDK2410 or the derived module A9M2410
48 <http://www.fsforth.de>
52 49
53config ARCH_H1940 50config ARCH_H1940
54 bool "IPAQ H1940" 51 bool "IPAQ H1940"
@@ -57,7 +54,10 @@ config ARCH_H1940
57 help 54 help
58 Say Y here if you are using the HP IPAQ H1940 55 Say Y here if you are using the HP IPAQ H1940
59 56
60 <http://www.handhelds.org/projects/h1940.html>. 57config PM_H1940
58 bool
59 help
60 Internal node for H1940 and related PM
61 61
62config MACH_N30 62config MACH_N30
63 bool "Acer N30" 63 bool "Acer N30"
@@ -65,53 +65,36 @@ config MACH_N30
65 help 65 help
66 Say Y here if you are using the Acer N30 66 Say Y here if you are using the Acer N30
67 67
68 <http://zoo.weinigel.se/n30>. 68config ARCH_BAST
69 69 bool "Simtec Electronics BAST (EB2410ITX)"
70config MACH_SMDK
71 bool
72 help
73 Common machine code for SMDK2410 and SMDK2440
74
75config ARCH_SMDK2410
76 bool "SMDK2410/A9M2410"
77 select CPU_S3C2410 70 select CPU_S3C2410
78 select MACH_SMDK 71 select PM_SIMTEC if PM
72 select ISA
79 help 73 help
80 Say Y here if you are using the SMDK2410 or the derived module A9M2410 74 Say Y here if you are using the Simtec Electronics EB2410ITX
81 <http://www.fsforth.de> 75 development board (also known as BAST)
82 76
83config ARCH_S3C2440 77config MACH_OTOM
84 bool "SMDK2440" 78 bool "NexVision OTOM Board"
85 select CPU_S3C2440 79 select CPU_S3C2410
86 select MACH_SMDK
87 help 80 help
88 Say Y here if you are using the SMDK2440. 81 Say Y here if you are using the Nex Vision OTOM board
89
90config SMDK2440_CPU2440
91 bool "SMDK2440 with S3C2440 CPU module"
92 depends on ARCH_S3C2440
93 default y if ARCH_S3C2440
94 select CPU_S3C2440
95
96config SMDK2440_CPU2442
97 bool "SMDM2440 with S3C2442 CPU module"
98 depends on ARCH_S3C2440
99 select CPU_S3C2442
100 82
101config MACH_S3C2413 83config MACH_AML_M5900
102 bool 84 bool "AML M5900 Series"
85 select CPU_S3C2410
86 select PM_SIMTEC if PM
103 help 87 help
104 Internal node for S3C2413 version of SMDK2413, so that 88 Say Y here if you are using the American Microsystems M5900 Series
105 machine_is_s3c2413() will work when MACH_SMDK2413 is 89 <http://www.amltd.com>
106 selected
107 90
108config MACH_SMDK2413 91config BAST_PC104_IRQ
109 bool "SMDK2413" 92 bool "BAST PC104 IRQ support"
110 select CPU_S3C2412 93 depends on ARCH_BAST
111 select MACH_S3C2413 94 default y
112 select MACH_SMDK
113 help 95 help
114 Say Y here if you are using an SMDK2413 96 Say Y here to enable the PC104 IRQ routing on the
97 Simtec BAST (EB2410ITX)
115 98
116config MACH_VR1000 99config MACH_VR1000
117 bool "Thorcom VR1000" 100 bool "Thorcom VR1000"
@@ -120,223 +103,6 @@ config MACH_VR1000
120 help 103 help
121 Say Y here if you are using the Thorcom VR1000 board. 104 Say Y here if you are using the Thorcom VR1000 board.
122 105
123 This linux port is currently being maintained by Simtec, on behalf
124 of Thorcom. Any queries, please contact Thorcom first.
125
126config MACH_RX3715
127 bool "HP iPAQ rx3715"
128 select CPU_S3C2440
129 select PM_H1940 if PM
130 help
131 Say Y here if you are using the HP iPAQ rx3715.
132
133 See <http://www.handhelds.org/projects/rx3715.html> for more
134 information on this project
135
136config MACH_OTOM
137 bool "NexVision OTOM Board"
138 select CPU_S3C2410
139 help
140 Say Y here if you are using the Nex Vision OTOM board
141
142config MACH_NEXCODER_2440
143 bool "NexVision NEXCODER 2440 Light Board"
144 select CPU_S3C2440
145 help
146 Say Y here if you are using the Nex Vision NEXCODER 2440 Light Board
147
148config MACH_VSTMS
149 bool "VMSTMS"
150 select CPU_S3C2412
151 help
152 Say Y here if you are using an VSTMS board
153 106
154endmenu 107endmenu
155 108
156config S3C2410_CLOCK
157 bool
158 help
159 Clock code for the S3C2410, and similar processors
160
161config S3C2410_GPIO
162 bool
163 help
164 GPIO code for S3C2410 and similar processors
165
166config S3C2410_PM
167 bool
168 help
169 Power Management code common to S3C2410 and better
170
171config CPU_S3C2410_DMA
172 bool
173 depends on S3C2410_DMA && (CPU_S3C2410 || CPU_S3C2442)
174 default y if CPU_S3C2410 || CPU_S3C2442
175 help
176 DMA device selection for S3C2410 and compatible CPUs
177
178config CPU_S3C2410
179 bool
180 depends on ARCH_S3C2410
181 select S3C2410_CLOCK
182 select S3C2410_GPIO
183 select S3C2410_PM if PM
184 help
185 Support for S3C2410 and S3C2410A family from the S3C24XX line
186 of Samsung Mobile CPUs.
187
188# internal node to signify if we are only dealing with an S3C2412
189
190config CPU_S3C2412_ONLY
191 bool
192 depends on ARCH_S3C2410 && !CPU_S3C2400 && !CPU_S3C2410 && \
193 !CPU_S3C2440 && !CPU_S3C2442 && CPU_S3C2412
194 default y if CPU_S3C2412
195
196config S3C2412_PM
197 bool
198 help
199 Internal config node to apply S3C2412 power management
200
201config S3C2412_DMA
202 bool
203 depends on CPU_S3C2412
204 help
205 Internal config node for S3C2412 DMA support
206
207config CPU_S3C2412
208 bool
209 depends on ARCH_S3C2410
210 select S3C2412_PM if PM
211 select S3C2412_DMA if S3C2410_DMA
212 help
213 Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line
214
215config CPU_S3C244X
216 bool
217 depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442)
218 help
219 Support for S3C2440 and S3C2442 Samsung Mobile CPU based systems.
220
221config S3C2440_DMA
222 bool
223 depends on ARCH_S3C2410 && CPU_S3C24405B
224 help
225 Support for S3C2440 specific DMA code5A
226
227config CPU_S3C2440
228 bool
229 depends on ARCH_S3C2410
230 select S3C2410_CLOCK
231 select S3C2410_PM if PM
232 select S3C2410_GPIO
233 select S3C2440_DMA if S3C2410_DMA
234 select CPU_S3C244X
235 help
236 Support for S3C2440 Samsung Mobile CPU based systems.
237
238config CPU_S3C2442
239 bool
240 depends on ARCH_S3C2420
241 select S3C2410_CLOCK
242 select S3C2410_GPIO
243 select S3C2410_PM if PM
244 select CPU_S3C244X
245 help
246 Support for S3C2442 Samsung Mobile CPU based systems.
247
248comment "S3C2410 Boot"
249
250config S3C2410_BOOT_WATCHDOG
251 bool "S3C2410 Initialisation watchdog"
252 depends on ARCH_S3C2410 && S3C2410_WATCHDOG
253 help
254 Say y to enable the watchdog during the kernel decompression
255 stage. If the kernel fails to uncompress, then the watchdog
256 will trigger a reset and the system should restart.
257
258 Although this uses the same hardware unit as the kernel watchdog
259 driver, it is not a replacement for it. If you use this option,
260 you will have to use the watchdg driver to either stop the timeout
261 or restart it. If you do not, then your kernel will reboot after
262 startup.
263
264 The driver uses a fixed timeout value, so the exact time till the
265 system resets depends on the value of PCLK. The timeout on an
266 200MHz s3c2410 should be about 30 seconds.
267
268config S3C2410_BOOT_ERROR_RESET
269 bool "S3C2410 Reboot on decompression error"
270 depends on ARCH_S3C2410
271 help
272 Say y here to use the watchdog to reset the system if the
273 kernel decompressor detects an error during decompression.
274
275
276comment "S3C2410 Setup"
277
278config S3C2410_DMA
279 bool "S3C2410 DMA support"
280 depends on ARCH_S3C2410
281 help
282 S3C2410 DMA support. This is needed for drivers like sound which
283 use the S3C2410's DMA system to move data to and from the
284 peripheral blocks.
285
286config S3C2410_DMA_DEBUG
287 bool "S3C2410 DMA support debug"
288 depends on ARCH_S3C2410 && S3C2410_DMA
289 help
290 Enable debugging output for the DMA code. This option sends info
291 to the kernel log, at priority KERN_DEBUG.
292
293 Note, it is easy to create and fill the log buffer in a small
294 amount of time, as well as using an significant percentage of
295 the CPU time doing so.
296
297config S3C2410_PM_DEBUG
298 bool "S3C2410 PM Suspend debug"
299 depends on ARCH_S3C2410 && PM
300 help
301 Say Y here if you want verbose debugging from the PM Suspend and
302 Resume code. See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
303 for more information.
304
305config S3C2410_PM_CHECK
306 bool "S3C2410 PM Suspend Memory CRC"
307 depends on ARCH_S3C2410 && PM && CRC32
308 help
309 Enable the PM code's memory area checksum over sleep. This option
310 will generate CRCs of all blocks of memory, and store them before
311 going to sleep. The blocks are then checked on resume for any
312 errors.
313
314config S3C2410_PM_CHECK_CHUNKSIZE
315 int "S3C2410 PM Suspend CRC Chunksize (KiB)"
316 depends on ARCH_S3C2410 && PM && S3C2410_PM_CHECK
317 default 64
318 help
319 Set the chunksize in Kilobytes of the CRC for checking memory
320 corruption over suspend and resume. A smaller value will mean that
321 the CRC data block will take more memory, but wil identify any
322 faults with better precision.
323
324config PM_SIMTEC
325 bool
326 help
327 Common power management code for systems that are
328 compatible with the Simtec style of power management
329
330config S3C2410_LOWLEVEL_UART_PORT
331 int "S3C2410 UART to use for low-level messages"
332 default 0
333 help
334 Choice of which UART port to use for the low-level messages,
335 such as the `Uncompressing...` at start time. The value of
336 this configuration should be between zero and two. The port
337 must have been initialised by the boot-loader before use.
338
339 Note, this does not affect the port used by the debug messages,
340 which is a separate configuration.
341
342endif
diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
index 1cc5febdaabd..b33ac5b84773 100644
--- a/arch/arm/mach-s3c2410/Makefile
+++ b/arch/arm/mach-s3c2410/Makefile
@@ -1,85 +1,30 @@
1 1# arch/arm/mach-s3c2410/Makefile
2# 2#
3# Makefile for the linux kernel. 3# Copyright 2007 Simtec Electronics
4# 4#
5# Licensed under GPLv2
5 6
6# Object file lists. 7obj-y :=
7 8obj-m :=
8obj-y := cpu.o irq.o time.o gpio.o clock.o devs.o 9obj-n :=
9obj-m := 10obj- :=
10obj-n :=
11obj- :=
12
13# DMA
14obj-$(CONFIG_S3C2410_DMA) += dma.o
15
16# S3C2400 support files
17obj-$(CONFIG_CPU_S3C2400) += s3c2400-gpio.o
18
19# S3C2410 support files
20 11
21obj-$(CONFIG_CPU_S3C2410) += s3c2410.o 12obj-$(CONFIG_CPU_S3C2410) += s3c2410.o
22obj-$(CONFIG_CPU_S3C2410) += s3c2410-irq.o 13obj-$(CONFIG_CPU_S3C2410) += irq.o
23 14obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o
24obj-$(CONFIG_S3C2410_PM) += s3c2410-pm.o s3c2410-sleep.o 15obj-$(CONFIG_CPU_S3C2410_DMA) += dma.o
25obj-$(CONFIG_S3C2410_GPIO) += s3c2410-gpio.o 16obj-$(CONFIG_S3C2410_PM) += pm.o sleep.o
26obj-$(CONFIG_CPU_S3C2410_DMA) += s3c2410-dma.o 17obj-$(CONFIG_S3C2410_GPIO) += gpio.o
27 18obj-$(CONFIG_S3C2410_CLOCK) += clock.o
28# Power Management support
29
30obj-$(CONFIG_PM) += pm.o sleep.o
31obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o
32obj-$(CONFIG_PM_H1940) += pm-h1940.o
33
34# S3C2412 support
35obj-$(CONFIG_CPU_S3C2412) += s3c2412.o
36obj-$(CONFIG_CPU_S3C2412) += s3c2412-irq.o
37obj-$(CONFIG_CPU_S3C2412) += s3c2412-clock.o
38
39obj-$(CONFIG_S3C2412_PM) += s3c2412-pm.o
40obj-$(CONFIG_S3C2412_DMA) += s3c2412-dma.o
41
42#
43# S3C244X support
44
45obj-$(CONFIG_CPU_S3C244X) += s3c244x.o
46obj-$(CONFIG_CPU_S3C244X) += s3c244x-irq.o
47
48# Clock control
49
50obj-$(CONFIG_S3C2410_CLOCK) += s3c2410-clock.o
51
52# S3C2440 support
53 19
54obj-$(CONFIG_CPU_S3C2440) += s3c2440.o s3c2440-dsc.o 20# Machine support
55obj-$(CONFIG_CPU_S3C2440) += s3c2440-irq.o
56obj-$(CONFIG_CPU_S3C2440) += s3c2440-clock.o
57obj-$(CONFIG_S3C2440_DMA) += s3c2440-dma.o
58 21
59# S3C2442 support 22obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o
60
61obj-$(CONFIG_CPU_S3C2442) += s3c2442.o
62obj-$(CONFIG_CPU_S3C2442) += s3c2442-clock.o
63
64# bast extras
65
66obj-$(CONFIG_BAST_PC104_IRQ) += bast-irq.o
67
68# machine specific support
69
70obj-$(CONFIG_MACH_AML_M5900) += mach-amlm5900.o
71obj-$(CONFIG_MACH_ANUBIS) += mach-anubis.o
72obj-$(CONFIG_MACH_OSIRIS) += mach-osiris.o
73obj-$(CONFIG_ARCH_BAST) += mach-bast.o usb-simtec.o
74obj-$(CONFIG_ARCH_H1940) += mach-h1940.o 23obj-$(CONFIG_ARCH_H1940) += mach-h1940.o
24obj-$(CONFIG_PM_H1940) += pm-h1940.o
75obj-$(CONFIG_MACH_N30) += mach-n30.o 25obj-$(CONFIG_MACH_N30) += mach-n30.o
76obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o 26obj-$(CONFIG_ARCH_BAST) += mach-bast.o usb-simtec.o
77obj-$(CONFIG_MACH_SMDK2413) += mach-smdk2413.o
78obj-$(CONFIG_ARCH_S3C2440) += mach-smdk2440.o
79obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o
80obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o
81obj-$(CONFIG_MACH_OTOM) += mach-otom.o 27obj-$(CONFIG_MACH_OTOM) += mach-otom.o
82obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o 28obj-$(CONFIG_MACH_AML_M5900) += mach-amlm5900.o
83obj-$(CONFIG_MACH_VSTMS) += mach-vstms.o 29obj-$(CONFIG_BAST_PC104_IRQ) += bast-irq.o
84 30obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o
85obj-$(CONFIG_MACH_SMDK) += common-smdk.o \ No newline at end of file
diff --git a/arch/arm/mach-s3c2410/bast-irq.c b/arch/arm/mach-s3c2410/bast-irq.c
index 379efe70778c..daeba427d781 100644
--- a/arch/arm/mach-s3c2410/bast-irq.c
+++ b/arch/arm/mach-s3c2410/bast-irq.c
@@ -39,7 +39,7 @@
39#include <asm/arch/bast-map.h> 39#include <asm/arch/bast-map.h>
40#include <asm/arch/bast-irq.h> 40#include <asm/arch/bast-irq.h>
41 41
42#include "irq.h" 42#include <asm/plat-s3c24xx/irq.h>
43 43
44#if 0 44#if 0
45#include <asm/debug-ll.h> 45#include <asm/debug-ll.h>
diff --git a/arch/arm/mach-s3c2410/bast.h b/arch/arm/mach-s3c2410/bast.h
index e5d03311752c..e98543742eb9 100644
--- a/arch/arm/mach-s3c2410/bast.h
+++ b/arch/arm/mach-s3c2410/bast.h
@@ -1,2 +1,2 @@
1 1/* linux/arch/arm/mach-s3c2410/bast.h
2extern void bast_init_irq(void); 2extern void bast_init_irq(void);
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c
index e13fb6778890..5b4831c4c1d8 100644
--- a/arch/arm/mach-s3c2410/clock.c
+++ b/arch/arm/mach-s3c2410/clock.c
@@ -1,15 +1,9 @@
1/* linux/arch/arm/mach-s3c2410/clock.c 1/* linux/arch/arm/mach-s3c2410/clock.c
2 * 2 *
3 * Copyright (c) 2004-2005 Simtec Electronics 3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
5 * 5 *
6 * S3C24XX Core clock control support 6 * S3C2410,S3C2440,S3C2442 Clock control support
7 *
8 * Based on, and code from linux/arch/arm/mach-versatile/clock.c
9 **
10 ** Copyright (C) 2004 ARM Limited.
11 ** Written by Deep Blue Solutions Limited.
12 *
13 * 7 *
14 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -32,418 +26,251 @@
32#include <linux/list.h> 26#include <linux/list.h>
33#include <linux/errno.h> 27#include <linux/errno.h>
34#include <linux/err.h> 28#include <linux/err.h>
35#include <linux/platform_device.h>
36#include <linux/sysdev.h> 29#include <linux/sysdev.h>
37#include <linux/interrupt.h>
38#include <linux/ioport.h>
39#include <linux/clk.h> 30#include <linux/clk.h>
40#include <linux/mutex.h> 31#include <linux/mutex.h>
41#include <linux/delay.h> 32#include <linux/delay.h>
33#include <linux/serial_core.h>
34
35#include <asm/mach/map.h>
42 36
43#include <asm/hardware.h> 37#include <asm/hardware.h>
44#include <asm/irq.h>
45#include <asm/io.h> 38#include <asm/io.h>
46 39
40#include <asm/arch/regs-serial.h>
47#include <asm/arch/regs-clock.h> 41#include <asm/arch/regs-clock.h>
48#include <asm/arch/regs-gpio.h> 42#include <asm/arch/regs-gpio.h>
49 43
50#include "clock.h" 44#include <asm/plat-s3c24xx/s3c2410.h>
51#include "cpu.h" 45#include <asm/plat-s3c24xx/clock.h>
52 46#include <asm/plat-s3c24xx/cpu.h>
53/* clock information */
54 47
55static LIST_HEAD(clocks); 48int s3c2410_clkcon_enable(struct clk *clk, int enable)
56
57DEFINE_MUTEX(clocks_mutex);
58
59/* enable and disable calls for use with the clk struct */
60
61static int clk_null_enable(struct clk *clk, int enable)
62{ 49{
63 return 0; 50 unsigned int clocks = clk->ctrlbit;
64} 51 unsigned long clkcon;
65
66/* Clock API calls */
67 52
68struct clk *clk_get(struct device *dev, const char *id) 53 clkcon = __raw_readl(S3C2410_CLKCON);
69{
70 struct clk *p;
71 struct clk *clk = ERR_PTR(-ENOENT);
72 int idno;
73 54
74 if (dev == NULL || dev->bus != &platform_bus_type) 55 if (enable)
75 idno = -1; 56 clkcon |= clocks;
76 else 57 else
77 idno = to_platform_device(dev)->id; 58 clkcon &= ~clocks;
78
79 mutex_lock(&clocks_mutex);
80
81 list_for_each_entry(p, &clocks, list) {
82 if (p->id == idno &&
83 strcmp(id, p->name) == 0 &&
84 try_module_get(p->owner)) {
85 clk = p;
86 break;
87 }
88 }
89
90 /* check for the case where a device was supplied, but the
91 * clock that was being searched for is not device specific */
92
93 if (IS_ERR(clk)) {
94 list_for_each_entry(p, &clocks, list) {
95 if (p->id == -1 && strcmp(id, p->name) == 0 &&
96 try_module_get(p->owner)) {
97 clk = p;
98 break;
99 }
100 }
101 }
102 59
103 mutex_unlock(&clocks_mutex); 60 /* ensure none of the special function bits set */
104 return clk; 61 clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER);
105}
106 62
107void clk_put(struct clk *clk) 63 __raw_writel(clkcon, S3C2410_CLKCON);
108{
109 module_put(clk->owner);
110}
111 64
112int clk_enable(struct clk *clk)
113{
114 if (IS_ERR(clk) || clk == NULL)
115 return -EINVAL;
116
117 clk_enable(clk->parent);
118
119 mutex_lock(&clocks_mutex);
120
121 if ((clk->usage++) == 0)
122 (clk->enable)(clk, 1);
123
124 mutex_unlock(&clocks_mutex);
125 return 0; 65 return 0;
126} 66}
127 67
128void clk_disable(struct clk *clk) 68static int s3c2410_upll_enable(struct clk *clk, int enable)
129{
130 if (IS_ERR(clk) || clk == NULL)
131 return;
132
133 mutex_lock(&clocks_mutex);
134
135 if ((--clk->usage) == 0)
136 (clk->enable)(clk, 0);
137
138 mutex_unlock(&clocks_mutex);
139 clk_disable(clk->parent);
140}
141
142
143unsigned long clk_get_rate(struct clk *clk)
144{
145 if (IS_ERR(clk))
146 return 0;
147
148 if (clk->rate != 0)
149 return clk->rate;
150
151 if (clk->get_rate != NULL)
152 return (clk->get_rate)(clk);
153
154 if (clk->parent != NULL)
155 return clk_get_rate(clk->parent);
156
157 return clk->rate;
158}
159
160long clk_round_rate(struct clk *clk, unsigned long rate)
161{
162 if (!IS_ERR(clk) && clk->round_rate)
163 return (clk->round_rate)(clk, rate);
164
165 return rate;
166}
167
168int clk_set_rate(struct clk *clk, unsigned long rate)
169{
170 int ret;
171
172 if (IS_ERR(clk))
173 return -EINVAL;
174
175 mutex_lock(&clocks_mutex);
176 ret = (clk->set_rate)(clk, rate);
177 mutex_unlock(&clocks_mutex);
178
179 return ret;
180}
181
182struct clk *clk_get_parent(struct clk *clk)
183{ 69{
184 return clk->parent; 70 unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
185} 71 unsigned long orig = clkslow;
186
187int clk_set_parent(struct clk *clk, struct clk *parent)
188{
189 int ret = 0;
190
191 if (IS_ERR(clk))
192 return -EINVAL;
193
194 mutex_lock(&clocks_mutex);
195
196 if (clk->set_parent)
197 ret = (clk->set_parent)(clk, parent);
198
199 mutex_unlock(&clocks_mutex);
200
201 return ret;
202}
203
204EXPORT_SYMBOL(clk_get);
205EXPORT_SYMBOL(clk_put);
206EXPORT_SYMBOL(clk_enable);
207EXPORT_SYMBOL(clk_disable);
208EXPORT_SYMBOL(clk_get_rate);
209EXPORT_SYMBOL(clk_round_rate);
210EXPORT_SYMBOL(clk_set_rate);
211EXPORT_SYMBOL(clk_get_parent);
212EXPORT_SYMBOL(clk_set_parent);
213
214/* base clocks */
215
216struct clk clk_xtal = {
217 .name = "xtal",
218 .id = -1,
219 .rate = 0,
220 .parent = NULL,
221 .ctrlbit = 0,
222};
223
224struct clk clk_mpll = {
225 .name = "mpll",
226 .id = -1,
227};
228
229struct clk clk_upll = {
230 .name = "upll",
231 .id = -1,
232 .parent = NULL,
233 .ctrlbit = 0,
234};
235
236struct clk clk_f = {
237 .name = "fclk",
238 .id = -1,
239 .rate = 0,
240 .parent = &clk_mpll,
241 .ctrlbit = 0,
242};
243
244struct clk clk_h = {
245 .name = "hclk",
246 .id = -1,
247 .rate = 0,
248 .parent = NULL,
249 .ctrlbit = 0,
250};
251
252struct clk clk_p = {
253 .name = "pclk",
254 .id = -1,
255 .rate = 0,
256 .parent = NULL,
257 .ctrlbit = 0,
258};
259
260struct clk clk_usb_bus = {
261 .name = "usb-bus",
262 .id = -1,
263 .rate = 0,
264 .parent = &clk_upll,
265};
266
267/* clocks that could be registered by external code */
268
269static int s3c24xx_dclk_enable(struct clk *clk, int enable)
270{
271 unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON);
272 72
273 if (enable) 73 if (enable)
274 dclkcon |= clk->ctrlbit; 74 clkslow &= ~S3C2410_CLKSLOW_UCLK_OFF;
275 else 75 else
276 dclkcon &= ~clk->ctrlbit; 76 clkslow |= S3C2410_CLKSLOW_UCLK_OFF;
277 77
278 __raw_writel(dclkcon, S3C24XX_DCLKCON); 78 __raw_writel(clkslow, S3C2410_CLKSLOW);
279 79
280 return 0; 80 /* if we started the UPLL, then allow to settle */
281}
282 81
283static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent) 82 if (enable && (orig & S3C2410_CLKSLOW_UCLK_OFF))
284{ 83 udelay(200);
285 unsigned long dclkcon;
286 unsigned int uclk;
287
288 if (parent == &clk_upll)
289 uclk = 1;
290 else if (parent == &clk_p)
291 uclk = 0;
292 else
293 return -EINVAL;
294
295 clk->parent = parent;
296
297 dclkcon = __raw_readl(S3C24XX_DCLKCON);
298
299 if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) {
300 if (uclk)
301 dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK;
302 else
303 dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK;
304 } else {
305 if (uclk)
306 dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK;
307 else
308 dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK;
309 }
310
311 __raw_writel(dclkcon, S3C24XX_DCLKCON);
312 84
313 return 0; 85 return 0;
314} 86}
315 87
316 88/* standard clock definitions */
317static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent) 89
318{ 90static struct clk init_clocks_disable[] = {
319 unsigned long mask; 91 {
320 unsigned long source; 92 .name = "nand",
321 93 .id = -1,
322 /* calculate the MISCCR setting for the clock */ 94 .parent = &clk_h,
323 95 .enable = s3c2410_clkcon_enable,
324 if (parent == &clk_xtal) 96 .ctrlbit = S3C2410_CLKCON_NAND,
325 source = S3C2410_MISCCR_CLK0_MPLL; 97 }, {
326 else if (parent == &clk_upll) 98 .name = "sdi",
327 source = S3C2410_MISCCR_CLK0_UPLL; 99 .id = -1,
328 else if (parent == &clk_f) 100 .parent = &clk_p,
329 source = S3C2410_MISCCR_CLK0_FCLK; 101 .enable = s3c2410_clkcon_enable,
330 else if (parent == &clk_h) 102 .ctrlbit = S3C2410_CLKCON_SDI,
331 source = S3C2410_MISCCR_CLK0_HCLK; 103 }, {
332 else if (parent == &clk_p) 104 .name = "adc",
333 source = S3C2410_MISCCR_CLK0_PCLK; 105 .id = -1,
334 else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0) 106 .parent = &clk_p,
335 source = S3C2410_MISCCR_CLK0_DCLK0; 107 .enable = s3c2410_clkcon_enable,
336 else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1) 108 .ctrlbit = S3C2410_CLKCON_ADC,
337 source = S3C2410_MISCCR_CLK0_DCLK0; 109 }, {
338 else 110 .name = "i2c",
339 return -EINVAL; 111 .id = -1,
340 112 .parent = &clk_p,
341 clk->parent = parent; 113 .enable = s3c2410_clkcon_enable,
342 114 .ctrlbit = S3C2410_CLKCON_IIC,
343 if (clk == &s3c24xx_dclk0) 115 }, {
344 mask = S3C2410_MISCCR_CLK0_MASK; 116 .name = "iis",
345 else { 117 .id = -1,
346 source <<= 4; 118 .parent = &clk_p,
347 mask = S3C2410_MISCCR_CLK1_MASK; 119 .enable = s3c2410_clkcon_enable,
120 .ctrlbit = S3C2410_CLKCON_IIS,
121 }, {
122 .name = "spi",
123 .id = -1,
124 .parent = &clk_p,
125 .enable = s3c2410_clkcon_enable,
126 .ctrlbit = S3C2410_CLKCON_SPI,
348 } 127 }
349
350 s3c2410_modify_misccr(mask, source);
351 return 0;
352}
353
354/* external clock definitions */
355
356struct clk s3c24xx_dclk0 = {
357 .name = "dclk0",
358 .id = -1,
359 .ctrlbit = S3C2410_DCLKCON_DCLK0EN,
360 .enable = s3c24xx_dclk_enable,
361 .set_parent = s3c24xx_dclk_setparent,
362};
363
364struct clk s3c24xx_dclk1 = {
365 .name = "dclk1",
366 .id = -1,
367 .ctrlbit = S3C2410_DCLKCON_DCLK0EN,
368 .enable = s3c24xx_dclk_enable,
369 .set_parent = s3c24xx_dclk_setparent,
370}; 128};
371 129
372struct clk s3c24xx_clkout0 = { 130static struct clk init_clocks[] = {
373 .name = "clkout0", 131 {
374 .id = -1, 132 .name = "lcd",
375 .set_parent = s3c24xx_clkout_setparent, 133 .id = -1,
134 .parent = &clk_h,
135 .enable = s3c2410_clkcon_enable,
136 .ctrlbit = S3C2410_CLKCON_LCDC,
137 }, {
138 .name = "gpio",
139 .id = -1,
140 .parent = &clk_p,
141 .enable = s3c2410_clkcon_enable,
142 .ctrlbit = S3C2410_CLKCON_GPIO,
143 }, {
144 .name = "usb-host",
145 .id = -1,
146 .parent = &clk_h,
147 .enable = s3c2410_clkcon_enable,
148 .ctrlbit = S3C2410_CLKCON_USBH,
149 }, {
150 .name = "usb-device",
151 .id = -1,
152 .parent = &clk_h,
153 .enable = s3c2410_clkcon_enable,
154 .ctrlbit = S3C2410_CLKCON_USBD,
155 }, {
156 .name = "timers",
157 .id = -1,
158 .parent = &clk_p,
159 .enable = s3c2410_clkcon_enable,
160 .ctrlbit = S3C2410_CLKCON_PWMT,
161 }, {
162 .name = "uart",
163 .id = 0,
164 .parent = &clk_p,
165 .enable = s3c2410_clkcon_enable,
166 .ctrlbit = S3C2410_CLKCON_UART0,
167 }, {
168 .name = "uart",
169 .id = 1,
170 .parent = &clk_p,
171 .enable = s3c2410_clkcon_enable,
172 .ctrlbit = S3C2410_CLKCON_UART1,
173 }, {
174 .name = "uart",
175 .id = 2,
176 .parent = &clk_p,
177 .enable = s3c2410_clkcon_enable,
178 .ctrlbit = S3C2410_CLKCON_UART2,
179 }, {
180 .name = "rtc",
181 .id = -1,
182 .parent = &clk_p,
183 .enable = s3c2410_clkcon_enable,
184 .ctrlbit = S3C2410_CLKCON_RTC,
185 }, {
186 .name = "watchdog",
187 .id = -1,
188 .parent = &clk_p,
189 .ctrlbit = 0,
190 }, {
191 .name = "usb-bus-host",
192 .id = -1,
193 .parent = &clk_usb_bus,
194 }, {
195 .name = "usb-bus-gadget",
196 .id = -1,
197 .parent = &clk_usb_bus,
198 },
376}; 199};
377 200
378struct clk s3c24xx_clkout1 = { 201/* s3c2410_baseclk_add()
379 .name = "clkout1", 202 *
380 .id = -1, 203 * Add all the clocks used by the s3c2410 or compatible CPUs
381 .set_parent = s3c24xx_clkout_setparent, 204 * such as the S3C2440 and S3C2442.
382}; 205 *
383 206 * We cannot use a system device as we are needed before any
384struct clk s3c24xx_uclk = { 207 * of the init-calls that initialise the devices are actually
385 .name = "uclk", 208 * done.
386 .id = -1, 209*/
387};
388
389/* initialise the clock system */
390
391int s3c24xx_register_clock(struct clk *clk)
392{
393 clk->owner = THIS_MODULE;
394
395 if (clk->enable == NULL)
396 clk->enable = clk_null_enable;
397
398 /* add to the list of available clocks */
399
400 mutex_lock(&clocks_mutex);
401 list_add(&clk->list, &clocks);
402 mutex_unlock(&clocks_mutex);
403
404 return 0;
405}
406
407/* initalise all the clocks */
408 210
409int __init s3c24xx_setup_clocks(unsigned long xtal, 211int __init s3c2410_baseclk_add(void)
410 unsigned long fclk,
411 unsigned long hclk,
412 unsigned long pclk)
413{ 212{
414 printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n"); 213 unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
214 unsigned long clkcon = __raw_readl(S3C2410_CLKCON);
215 struct clk *clkp;
216 struct clk *xtal;
217 int ret;
218 int ptr;
415 219
416 /* initialise the main system clocks */ 220 clk_upll.enable = s3c2410_upll_enable;
417 221
418 clk_xtal.rate = xtal; 222 if (s3c24xx_register_clock(&clk_usb_bus) < 0)
419 clk_upll.rate = s3c2410_get_pll(__raw_readl(S3C2410_UPLLCON), xtal); 223 printk(KERN_ERR "failed to register usb bus clock\n");
420 224
421 clk_mpll.rate = fclk; 225 /* register clocks from clock array */
422 clk_h.rate = hclk;
423 clk_p.rate = pclk;
424 clk_f.rate = fclk;
425 226
426 /* assume uart clocks are correctly setup */ 227 clkp = init_clocks;
228 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
229 /* ensure that we note the clock state */
427 230
428 /* register our clocks */ 231 clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0;
429 232
430 if (s3c24xx_register_clock(&clk_xtal) < 0) 233 ret = s3c24xx_register_clock(clkp);
431 printk(KERN_ERR "failed to register master xtal\n"); 234 if (ret < 0) {
235 printk(KERN_ERR "Failed to register clock %s (%d)\n",
236 clkp->name, ret);
237 }
238 }
432 239
433 if (s3c24xx_register_clock(&clk_mpll) < 0) 240 /* We must be careful disabling the clocks we are not intending to
434 printk(KERN_ERR "failed to register mpll clock\n"); 241 * be using at boot time, as subsytems such as the LCD which do
242 * their own DMA requests to the bus can cause the system to lockup
243 * if they where in the middle of requesting bus access.
244 *
245 * Disabling the LCD clock if the LCD is active is very dangerous,
246 * and therefore the bootloader should be careful to not enable
247 * the LCD clock if it is not needed.
248 */
249
250 /* install (and disable) the clocks we do not need immediately */
251
252 clkp = init_clocks_disable;
253 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
254
255 ret = s3c24xx_register_clock(clkp);
256 if (ret < 0) {
257 printk(KERN_ERR "Failed to register clock %s (%d)\n",
258 clkp->name, ret);
259 }
435 260
436 if (s3c24xx_register_clock(&clk_upll) < 0) 261 s3c2410_clkcon_enable(clkp, 0);
437 printk(KERN_ERR "failed to register upll clock\n"); 262 }
438 263
439 if (s3c24xx_register_clock(&clk_f) < 0) 264 /* show the clock-slow value */
440 printk(KERN_ERR "failed to register cpu fclk\n");
441 265
442 if (s3c24xx_register_clock(&clk_h) < 0) 266 xtal = clk_get(NULL, "xtal");
443 printk(KERN_ERR "failed to register cpu hclk\n");
444 267
445 if (s3c24xx_register_clock(&clk_p) < 0) 268 printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n",
446 printk(KERN_ERR "failed to register cpu pclk\n"); 269 print_mhz(clk_get_rate(xtal) /
270 ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))),
271 (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast",
272 (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on",
273 (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on");
447 274
448 return 0; 275 return 0;
449} 276}
diff --git a/arch/arm/mach-s3c2410/dma.c b/arch/arm/mach-s3c2410/dma.c
index fa860e716b4f..22c613600caa 100644
--- a/arch/arm/mach-s3c2410/dma.c
+++ b/arch/arm/mach-s3c2410/dma.c
@@ -1,9 +1,9 @@
1/* linux/arch/arm/mach-s3c2410/dma.c 1/* linux/arch/arm/mach-s3c2410/dma.c
2 * 2 *
3 * Copyright (c) 2003-2005,2006 Simtec Electronics 3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
5 * 5 *
6 * S3C2410 DMA core 6 * S3C2410 DMA selection
7 * 7 *
8 * http://armlinux.simtec.co.uk/ 8 * http://armlinux.simtec.co.uk/
9 * 9 *
@@ -12,1430 +12,150 @@
12 * published by the Free Software Foundation. 12 * published by the Free Software Foundation.
13*/ 13*/
14 14
15 15#include <linux/kernel.h>
16#ifdef CONFIG_S3C2410_DMA_DEBUG
17#define DEBUG
18#endif
19
20#include <linux/module.h>
21#include <linux/init.h> 16#include <linux/init.h>
22#include <linux/sched.h>
23#include <linux/spinlock.h>
24#include <linux/interrupt.h>
25#include <linux/sysdev.h> 17#include <linux/sysdev.h>
26#include <linux/slab.h> 18#include <linux/serial_core.h>
27#include <linux/errno.h>
28#include <linux/delay.h>
29 19
30#include <asm/system.h>
31#include <asm/irq.h>
32#include <asm/hardware.h>
33#include <asm/io.h>
34#include <asm/dma.h> 20#include <asm/dma.h>
35 21#include <asm/arch/dma.h>
36#include <asm/mach/dma.h> 22#include <asm/plat-s3c24xx/dma.h>
37#include <asm/arch/map.h> 23
38 24#include <asm/plat-s3c24xx/cpu.h>
39#include "dma.h" 25
40 26#include <asm/arch/regs-serial.h>
41/* io map for dma */ 27#include <asm/arch/regs-gpio.h>
42static void __iomem *dma_base; 28#include <asm/arch/regs-ac97.h>
43static struct kmem_cache *dma_kmem; 29#include <asm/arch/regs-mem.h>
44 30#include <asm/arch/regs-lcd.h>
45struct s3c24xx_dma_selection dma_sel; 31#include <asm/arch/regs-sdi.h>
46 32#include <asm/arch/regs-iis.h>
47/* dma channel state information */ 33#include <asm/arch/regs-spi.h>
48struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS]; 34
49 35static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = {
50/* debugging functions */ 36 [DMACH_XD0] = {
51 37 .name = "xdreq0",
52#define BUF_MAGIC (0xcafebabe) 38 .channels[0] = S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID,
53 39 },
54#define dmawarn(fmt...) printk(KERN_DEBUG fmt) 40 [DMACH_XD1] = {
55 41 .name = "xdreq1",
56#define dma_regaddr(chan, reg) ((chan)->regs + (reg)) 42 .channels[1] = S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID,
57 43 },
58#if 1 44 [DMACH_SDI] = {
59#define dma_wrreg(chan, reg, val) writel((val), (chan)->regs + (reg)) 45 .name = "sdi",
60#else 46 .channels[0] = S3C2410_DCON_CH0_SDI | DMA_CH_VALID,
61static inline void 47 .channels[2] = S3C2410_DCON_CH2_SDI | DMA_CH_VALID,
62dma_wrreg(struct s3c2410_dma_chan *chan, int reg, unsigned long val) 48 .channels[3] = S3C2410_DCON_CH3_SDI | DMA_CH_VALID,
63{ 49 .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
64 pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg); 50 .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
65 writel(val, dma_regaddr(chan, reg)); 51 },
66} 52 [DMACH_SPI0] = {
67#endif 53 .name = "spi0",
68 54 .channels[1] = S3C2410_DCON_CH1_SPI | DMA_CH_VALID,
69#define dma_rdreg(chan, reg) readl((chan)->regs + (reg)) 55 .hw_addr.to = S3C2410_PA_SPI + S3C2410_SPTDAT,
70 56 .hw_addr.from = S3C2410_PA_SPI + S3C2410_SPRDAT,
71/* captured register state for debug */ 57 },
72 58 [DMACH_SPI1] = {
73struct s3c2410_dma_regstate { 59 .name = "spi1",
74 unsigned long dcsrc; 60 .channels[3] = S3C2410_DCON_CH3_SPI | DMA_CH_VALID,
75 unsigned long disrc; 61 .hw_addr.to = S3C2410_PA_SPI + 0x20 + S3C2410_SPTDAT,
76 unsigned long dstat; 62 .hw_addr.from = S3C2410_PA_SPI + 0x20 + S3C2410_SPRDAT,
77 unsigned long dcon; 63 },
78 unsigned long dmsktrig; 64 [DMACH_UART0] = {
65 .name = "uart0",
66 .channels[0] = S3C2410_DCON_CH0_UART0 | DMA_CH_VALID,
67 .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH,
68 .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH,
69 },
70 [DMACH_UART1] = {
71 .name = "uart1",
72 .channels[1] = S3C2410_DCON_CH1_UART1 | DMA_CH_VALID,
73 .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH,
74 .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH,
75 },
76 [DMACH_UART2] = {
77 .name = "uart2",
78 .channels[3] = S3C2410_DCON_CH3_UART2 | DMA_CH_VALID,
79 .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH,
80 .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH,
81 },
82 [DMACH_TIMER] = {
83 .name = "timer",
84 .channels[0] = S3C2410_DCON_CH0_TIMER | DMA_CH_VALID,
85 .channels[2] = S3C2410_DCON_CH2_TIMER | DMA_CH_VALID,
86 .channels[3] = S3C2410_DCON_CH3_TIMER | DMA_CH_VALID,
87 },
88 [DMACH_I2S_IN] = {
89 .name = "i2s-sdi",
90 .channels[1] = S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID,
91 .channels[2] = S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID,
92 .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
93 },
94 [DMACH_I2S_OUT] = {
95 .name = "i2s-sdo",
96 .channels[2] = S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID,
97 .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
98 },
99 [DMACH_USB_EP1] = {
100 .name = "usb-ep1",
101 .channels[0] = S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID,
102 },
103 [DMACH_USB_EP2] = {
104 .name = "usb-ep2",
105 .channels[1] = S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID,
106 },
107 [DMACH_USB_EP3] = {
108 .name = "usb-ep3",
109 .channels[2] = S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID,
110 },
111 [DMACH_USB_EP4] = {
112 .name = "usb-ep4",
113 .channels[3] =S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID,
114 },
79}; 115};
80 116
81#ifdef CONFIG_S3C2410_DMA_DEBUG 117static void s3c2410_dma_select(struct s3c2410_dma_chan *chan,
82 118 struct s3c24xx_dma_map *map)
83/* dmadbg_showregs
84 *
85 * simple debug routine to print the current state of the dma registers
86*/
87
88static void
89dmadbg_capture(struct s3c2410_dma_chan *chan, struct s3c2410_dma_regstate *regs)
90{
91 regs->dcsrc = dma_rdreg(chan, S3C2410_DMA_DCSRC);
92 regs->disrc = dma_rdreg(chan, S3C2410_DMA_DISRC);
93 regs->dstat = dma_rdreg(chan, S3C2410_DMA_DSTAT);
94 regs->dcon = dma_rdreg(chan, S3C2410_DMA_DCON);
95 regs->dmsktrig = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
96}
97
98static void
99dmadbg_dumpregs(const char *fname, int line, struct s3c2410_dma_chan *chan,
100 struct s3c2410_dma_regstate *regs)
101{
102 printk(KERN_DEBUG "dma%d: %s:%d: DCSRC=%08lx, DISRC=%08lx, DSTAT=%08lx DMT=%02lx, DCON=%08lx\n",
103 chan->number, fname, line,
104 regs->dcsrc, regs->disrc, regs->dstat, regs->dmsktrig,
105 regs->dcon);
106}
107
108static void
109dmadbg_showchan(const char *fname, int line, struct s3c2410_dma_chan *chan)
110{
111 struct s3c2410_dma_regstate state;
112
113 dmadbg_capture(chan, &state);
114
115 printk(KERN_DEBUG "dma%d: %s:%d: ls=%d, cur=%p, %p %p\n",
116 chan->number, fname, line, chan->load_state,
117 chan->curr, chan->next, chan->end);
118
119 dmadbg_dumpregs(fname, line, chan, &state);
120}
121
122static void
123dmadbg_showregs(const char *fname, int line, struct s3c2410_dma_chan *chan)
124{
125 struct s3c2410_dma_regstate state;
126
127 dmadbg_capture(chan, &state);
128 dmadbg_dumpregs(fname, line, chan, &state);
129}
130
131#define dbg_showregs(chan) dmadbg_showregs(__FUNCTION__, __LINE__, (chan))
132#define dbg_showchan(chan) dmadbg_showchan(__FUNCTION__, __LINE__, (chan))
133#else
134#define dbg_showregs(chan) do { } while(0)
135#define dbg_showchan(chan) do { } while(0)
136#endif /* CONFIG_S3C2410_DMA_DEBUG */
137
138static struct s3c2410_dma_chan *dma_chan_map[DMACH_MAX];
139
140/* lookup_dma_channel
141 *
142 * change the dma channel number given into a real dma channel id
143*/
144
145static struct s3c2410_dma_chan *lookup_dma_channel(unsigned int channel)
146{
147 if (channel & DMACH_LOW_LEVEL)
148 return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL];
149 else
150 return dma_chan_map[channel];
151}
152
153/* s3c2410_dma_stats_timeout
154 *
155 * Update DMA stats from timeout info
156*/
157
158static void
159s3c2410_dma_stats_timeout(struct s3c2410_dma_stats *stats, int val)
160{ 119{
161 if (stats == NULL) 120 chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID;
162 return;
163
164 if (val > stats->timeout_longest)
165 stats->timeout_longest = val;
166 if (val < stats->timeout_shortest)
167 stats->timeout_shortest = val;
168
169 stats->timeout_avg += val;
170} 121}
171 122
172/* s3c2410_dma_waitforload 123static struct s3c24xx_dma_selection __initdata s3c2410_dma_sel = {
173 * 124 .select = s3c2410_dma_select,
174 * wait for the DMA engine to load a buffer, and update the state accordingly 125 .dcon_mask = 7 << 24,
175*/ 126 .map = s3c2410_dma_mappings,
176 127 .map_size = ARRAY_SIZE(s3c2410_dma_mappings),
177static int 128};
178s3c2410_dma_waitforload(struct s3c2410_dma_chan *chan, int line)
179{
180 int timeout = chan->load_timeout;
181 int took;
182
183 if (chan->load_state != S3C2410_DMALOAD_1LOADED) {
184 printk(KERN_ERR "dma%d: s3c2410_dma_waitforload() called in loadstate %d from line %d\n", chan->number, chan->load_state, line);
185 return 0;
186 }
187
188 if (chan->stats != NULL)
189 chan->stats->loads++;
190
191 while (--timeout > 0) {
192 if ((dma_rdreg(chan, S3C2410_DMA_DSTAT) << (32-20)) != 0) {
193 took = chan->load_timeout - timeout;
194
195 s3c2410_dma_stats_timeout(chan->stats, took);
196
197 switch (chan->load_state) {
198 case S3C2410_DMALOAD_1LOADED:
199 chan->load_state = S3C2410_DMALOAD_1RUNNING;
200 break;
201
202 default:
203 printk(KERN_ERR "dma%d: unknown load_state in s3c2410_dma_waitforload() %d\n", chan->number, chan->load_state);
204 }
205
206 return 1;
207 }
208 }
209
210 if (chan->stats != NULL) {
211 chan->stats->timeout_failed++;
212 }
213
214 return 0;
215}
216
217
218
219/* s3c2410_dma_loadbuffer
220 *
221 * load a buffer, and update the channel state
222*/
223
224static inline int
225s3c2410_dma_loadbuffer(struct s3c2410_dma_chan *chan,
226 struct s3c2410_dma_buf *buf)
227{
228 unsigned long reload;
229
230 pr_debug("s3c2410_chan_loadbuffer: loading buff %p (0x%08lx,0x%06x)\n",
231 buf, (unsigned long)buf->data, buf->size);
232
233 if (buf == NULL) {
234 dmawarn("buffer is NULL\n");
235 return -EINVAL;
236 }
237
238 /* check the state of the channel before we do anything */
239
240 if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
241 dmawarn("load_state is S3C2410_DMALOAD_1LOADED\n");
242 }
243
244 if (chan->load_state == S3C2410_DMALOAD_1LOADED_1RUNNING) {
245 dmawarn("state is S3C2410_DMALOAD_1LOADED_1RUNNING\n");
246 }
247
248 /* it would seem sensible if we are the last buffer to not bother
249 * with the auto-reload bit, so that the DMA engine will not try
250 * and load another transfer after this one has finished...
251 */
252 if (chan->load_state == S3C2410_DMALOAD_NONE) {
253 pr_debug("load_state is none, checking for noreload (next=%p)\n",
254 buf->next);
255 reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0;
256 } else {
257 //pr_debug("load_state is %d => autoreload\n", chan->load_state);
258 reload = S3C2410_DCON_AUTORELOAD;
259 }
260
261 if ((buf->data & 0xf0000000) != 0x30000000) {
262 dmawarn("dmaload: buffer is %p\n", (void *)buf->data);
263 }
264
265 writel(buf->data, chan->addr_reg);
266
267 dma_wrreg(chan, S3C2410_DMA_DCON,
268 chan->dcon | reload | (buf->size/chan->xfer_unit));
269
270 chan->next = buf->next;
271
272 /* update the state of the channel */
273
274 switch (chan->load_state) {
275 case S3C2410_DMALOAD_NONE:
276 chan->load_state = S3C2410_DMALOAD_1LOADED;
277 break;
278
279 case S3C2410_DMALOAD_1RUNNING:
280 chan->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING;
281 break;
282
283 default:
284 dmawarn("dmaload: unknown state %d in loadbuffer\n",
285 chan->load_state);
286 break;
287 }
288
289 return 0;
290}
291
292/* s3c2410_dma_call_op
293 *
294 * small routine to call the op routine with the given op if it has been
295 * registered
296*/
297
298static void
299s3c2410_dma_call_op(struct s3c2410_dma_chan *chan, enum s3c2410_chan_op op)
300{
301 if (chan->op_fn != NULL) {
302 (chan->op_fn)(chan, op);
303 }
304}
305
306/* s3c2410_dma_buffdone
307 *
308 * small wrapper to check if callback routine needs to be called, and
309 * if so, call it
310*/
311
312static inline void
313s3c2410_dma_buffdone(struct s3c2410_dma_chan *chan, struct s3c2410_dma_buf *buf,
314 enum s3c2410_dma_buffresult result)
315{
316#if 0
317 pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n",
318 chan->callback_fn, buf, buf->id, buf->size, result);
319#endif
320
321 if (chan->callback_fn != NULL) {
322 (chan->callback_fn)(chan, buf->id, buf->size, result);
323 }
324}
325
326/* s3c2410_dma_start
327 *
328 * start a dma channel going
329*/
330
331static int s3c2410_dma_start(struct s3c2410_dma_chan *chan)
332{
333 unsigned long tmp;
334 unsigned long flags;
335
336 pr_debug("s3c2410_start_dma: channel=%d\n", chan->number);
337
338 local_irq_save(flags);
339
340 if (chan->state == S3C2410_DMA_RUNNING) {
341 pr_debug("s3c2410_start_dma: already running (%d)\n", chan->state);
342 local_irq_restore(flags);
343 return 0;
344 }
345
346 chan->state = S3C2410_DMA_RUNNING;
347
348 /* check wether there is anything to load, and if not, see
349 * if we can find anything to load
350 */
351
352 if (chan->load_state == S3C2410_DMALOAD_NONE) {
353 if (chan->next == NULL) {
354 printk(KERN_ERR "dma%d: channel has nothing loaded\n",
355 chan->number);
356 chan->state = S3C2410_DMA_IDLE;
357 local_irq_restore(flags);
358 return -EINVAL;
359 }
360
361 s3c2410_dma_loadbuffer(chan, chan->next);
362 }
363
364 dbg_showchan(chan);
365
366 /* enable the channel */
367
368 if (!chan->irq_enabled) {
369 enable_irq(chan->irq);
370 chan->irq_enabled = 1;
371 }
372
373 /* start the channel going */
374
375 tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
376 tmp &= ~S3C2410_DMASKTRIG_STOP;
377 tmp |= S3C2410_DMASKTRIG_ON;
378 dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
379
380 pr_debug("dma%d: %08lx to DMASKTRIG\n", chan->number, tmp);
381
382#if 0
383 /* the dma buffer loads should take care of clearing the AUTO
384 * reloading feature */
385 tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
386 tmp &= ~S3C2410_DCON_NORELOAD;
387 dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
388#endif
389
390 s3c2410_dma_call_op(chan, S3C2410_DMAOP_START);
391
392 dbg_showchan(chan);
393
394 /* if we've only loaded one buffer onto the channel, then chec
395 * to see if we have another, and if so, try and load it so when
396 * the first buffer is finished, the new one will be loaded onto
397 * the channel */
398
399 if (chan->next != NULL) {
400 if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
401
402 if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
403 pr_debug("%s: buff not yet loaded, no more todo\n",
404 __FUNCTION__);
405 } else {
406 chan->load_state = S3C2410_DMALOAD_1RUNNING;
407 s3c2410_dma_loadbuffer(chan, chan->next);
408 }
409
410 } else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) {
411 s3c2410_dma_loadbuffer(chan, chan->next);
412 }
413 }
414
415
416 local_irq_restore(flags);
417
418 return 0;
419}
420
421/* s3c2410_dma_canload
422 *
423 * work out if we can queue another buffer into the DMA engine
424*/
425
426static int
427s3c2410_dma_canload(struct s3c2410_dma_chan *chan)
428{
429 if (chan->load_state == S3C2410_DMALOAD_NONE ||
430 chan->load_state == S3C2410_DMALOAD_1RUNNING)
431 return 1;
432
433 return 0;
434}
435
436/* s3c2410_dma_enqueue
437 *
438 * queue an given buffer for dma transfer.
439 *
440 * id the device driver's id information for this buffer
441 * data the physical address of the buffer data
442 * size the size of the buffer in bytes
443 *
444 * If the channel is not running, then the flag S3C2410_DMAF_AUTOSTART
445 * is checked, and if set, the channel is started. If this flag isn't set,
446 * then an error will be returned.
447 *
448 * It is possible to queue more than one DMA buffer onto a channel at
449 * once, and the code will deal with the re-loading of the next buffer
450 * when necessary.
451*/
452
453int s3c2410_dma_enqueue(unsigned int channel, void *id,
454 dma_addr_t data, int size)
455{
456 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
457 struct s3c2410_dma_buf *buf;
458 unsigned long flags;
459
460 if (chan == NULL)
461 return -EINVAL;
462
463 pr_debug("%s: id=%p, data=%08x, size=%d\n",
464 __FUNCTION__, id, (unsigned int)data, size);
465
466 buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC);
467 if (buf == NULL) {
468 pr_debug("%s: out of memory (%ld alloc)\n",
469 __FUNCTION__, (long)sizeof(*buf));
470 return -ENOMEM;
471 }
472
473 //pr_debug("%s: new buffer %p\n", __FUNCTION__, buf);
474 //dbg_showchan(chan);
475
476 buf->next = NULL;
477 buf->data = buf->ptr = data;
478 buf->size = size;
479 buf->id = id;
480 buf->magic = BUF_MAGIC;
481
482 local_irq_save(flags);
483
484 if (chan->curr == NULL) {
485 /* we've got nothing loaded... */
486 pr_debug("%s: buffer %p queued onto empty channel\n",
487 __FUNCTION__, buf);
488
489 chan->curr = buf;
490 chan->end = buf;
491 chan->next = NULL;
492 } else {
493 pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n",
494 chan->number, __FUNCTION__, buf);
495
496 if (chan->end == NULL)
497 pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n",
498 chan->number, __FUNCTION__, chan);
499
500 chan->end->next = buf;
501 chan->end = buf;
502 }
503
504 /* if necessary, update the next buffer field */
505 if (chan->next == NULL)
506 chan->next = buf;
507
508 /* check to see if we can load a buffer */
509 if (chan->state == S3C2410_DMA_RUNNING) {
510 if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) {
511 if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
512 printk(KERN_ERR "dma%d: loadbuffer:"
513 "timeout loading buffer\n",
514 chan->number);
515 dbg_showchan(chan);
516 local_irq_restore(flags);
517 return -EINVAL;
518 }
519 }
520
521 while (s3c2410_dma_canload(chan) && chan->next != NULL) {
522 s3c2410_dma_loadbuffer(chan, chan->next);
523 }
524 } else if (chan->state == S3C2410_DMA_IDLE) {
525 if (chan->flags & S3C2410_DMAF_AUTOSTART) {
526 s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_START);
527 }
528 }
529
530 local_irq_restore(flags);
531 return 0;
532}
533
534EXPORT_SYMBOL(s3c2410_dma_enqueue);
535
536static inline void
537s3c2410_dma_freebuf(struct s3c2410_dma_buf *buf)
538{
539 int magicok = (buf->magic == BUF_MAGIC);
540
541 buf->magic = -1;
542
543 if (magicok) {
544 kmem_cache_free(dma_kmem, buf);
545 } else {
546 printk("s3c2410_dma_freebuf: buff %p with bad magic\n", buf);
547 }
548}
549
550/* s3c2410_dma_lastxfer
551 *
552 * called when the system is out of buffers, to ensure that the channel
553 * is prepared for shutdown.
554*/
555
556static inline void
557s3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan)
558{
559#if 0
560 pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n",
561 chan->number, chan->load_state);
562#endif
563
564 switch (chan->load_state) {
565 case S3C2410_DMALOAD_NONE:
566 break;
567
568 case S3C2410_DMALOAD_1LOADED:
569 if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
570 /* flag error? */
571 printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
572 chan->number, __FUNCTION__);
573 return;
574 }
575 break;
576
577 case S3C2410_DMALOAD_1LOADED_1RUNNING:
578 /* I belive in this case we do not have anything to do
579 * until the next buffer comes along, and we turn off the
580 * reload */
581 return;
582
583 default:
584 pr_debug("dma%d: lastxfer: unhandled load_state %d with no next\n",
585 chan->number, chan->load_state);
586 return;
587
588 }
589
590 /* hopefully this'll shut the damned thing up after the transfer... */
591 dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD);
592}
593
594
595#define dmadbg2(x...)
596
597static irqreturn_t
598s3c2410_dma_irq(int irq, void *devpw)
599{
600 struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw;
601 struct s3c2410_dma_buf *buf;
602
603 buf = chan->curr;
604
605 dbg_showchan(chan);
606
607 /* modify the channel state */
608
609 switch (chan->load_state) {
610 case S3C2410_DMALOAD_1RUNNING:
611 /* TODO - if we are running only one buffer, we probably
612 * want to reload here, and then worry about the buffer
613 * callback */
614
615 chan->load_state = S3C2410_DMALOAD_NONE;
616 break;
617
618 case S3C2410_DMALOAD_1LOADED:
619 /* iirc, we should go back to NONE loaded here, we
620 * had a buffer, and it was never verified as being
621 * loaded.
622 */
623
624 chan->load_state = S3C2410_DMALOAD_NONE;
625 break;
626
627 case S3C2410_DMALOAD_1LOADED_1RUNNING:
628 /* we'll worry about checking to see if another buffer is
629 * ready after we've called back the owner. This should
630 * ensure we do not wait around too long for the DMA
631 * engine to start the next transfer
632 */
633
634 chan->load_state = S3C2410_DMALOAD_1LOADED;
635 break;
636
637 case S3C2410_DMALOAD_NONE:
638 printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n",
639 chan->number);
640 break;
641
642 default:
643 printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n",
644 chan->number, chan->load_state);
645 break;
646 }
647
648 if (buf != NULL) {
649 /* update the chain to make sure that if we load any more
650 * buffers when we call the callback function, things should
651 * work properly */
652
653 chan->curr = buf->next;
654 buf->next = NULL;
655
656 if (buf->magic != BUF_MAGIC) {
657 printk(KERN_ERR "dma%d: %s: buf %p incorrect magic\n",
658 chan->number, __FUNCTION__, buf);
659 return IRQ_HANDLED;
660 }
661
662 s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK);
663
664 /* free resouces */
665 s3c2410_dma_freebuf(buf);
666 } else {
667 }
668
669 /* only reload if the channel is still running... our buffer done
670 * routine may have altered the state by requesting the dma channel
671 * to stop or shutdown... */
672
673 /* todo: check that when the channel is shut-down from inside this
674 * function, we cope with unsetting reload, etc */
675
676 if (chan->next != NULL && chan->state != S3C2410_DMA_IDLE) {
677 unsigned long flags;
678
679 switch (chan->load_state) {
680 case S3C2410_DMALOAD_1RUNNING:
681 /* don't need to do anything for this state */
682 break;
683
684 case S3C2410_DMALOAD_NONE:
685 /* can load buffer immediately */
686 break;
687
688 case S3C2410_DMALOAD_1LOADED:
689 if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
690 /* flag error? */
691 printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
692 chan->number, __FUNCTION__);
693 return IRQ_HANDLED;
694 }
695
696 break;
697
698 case S3C2410_DMALOAD_1LOADED_1RUNNING:
699 goto no_load;
700
701 default:
702 printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n",
703 chan->number, chan->load_state);
704 return IRQ_HANDLED;
705 }
706
707 local_irq_save(flags);
708 s3c2410_dma_loadbuffer(chan, chan->next);
709 local_irq_restore(flags);
710 } else {
711 s3c2410_dma_lastxfer(chan);
712
713 /* see if we can stop this channel.. */
714 if (chan->load_state == S3C2410_DMALOAD_NONE) {
715 pr_debug("dma%d: end of transfer, stopping channel (%ld)\n",
716 chan->number, jiffies);
717 s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL,
718 S3C2410_DMAOP_STOP);
719 }
720 }
721
722 no_load:
723 return IRQ_HANDLED;
724}
725
726static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel);
727
728/* s3c2410_request_dma
729 *
730 * get control of an dma channel
731*/
732
733int s3c2410_dma_request(unsigned int channel,
734 struct s3c2410_dma_client *client,
735 void *dev)
736{
737 struct s3c2410_dma_chan *chan;
738 unsigned long flags;
739 int err;
740
741 pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n",
742 channel, client->name, dev);
743
744 local_irq_save(flags);
745
746 chan = s3c2410_dma_map_channel(channel);
747 if (chan == NULL) {
748 local_irq_restore(flags);
749 return -EBUSY;
750 }
751
752 dbg_showchan(chan);
753
754 chan->client = client;
755 chan->in_use = 1;
756
757 if (!chan->irq_claimed) {
758 pr_debug("dma%d: %s : requesting irq %d\n",
759 channel, __FUNCTION__, chan->irq);
760
761 chan->irq_claimed = 1;
762 local_irq_restore(flags);
763
764 err = request_irq(chan->irq, s3c2410_dma_irq, IRQF_DISABLED,
765 client->name, (void *)chan);
766
767 local_irq_save(flags);
768
769 if (err) {
770 chan->in_use = 0;
771 chan->irq_claimed = 0;
772 local_irq_restore(flags);
773
774 printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n",
775 client->name, chan->irq, chan->number);
776 return err;
777 }
778
779 chan->irq_enabled = 1;
780 }
781
782 local_irq_restore(flags);
783
784 /* need to setup */
785
786 pr_debug("%s: channel initialised, %p\n", __FUNCTION__, chan);
787
788 return 0;
789}
790
791EXPORT_SYMBOL(s3c2410_dma_request);
792
793/* s3c2410_dma_free
794 *
795 * release the given channel back to the system, will stop and flush
796 * any outstanding transfers, and ensure the channel is ready for the
797 * next claimant.
798 *
799 * Note, although a warning is currently printed if the freeing client
800 * info is not the same as the registrant's client info, the free is still
801 * allowed to go through.
802*/
803 129
804int s3c2410_dma_free(dmach_t channel, struct s3c2410_dma_client *client) 130static int s3c2410_dma_add(struct sys_device *sysdev)
805{ 131{
806 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel); 132 return s3c24xx_dma_init_map(&s3c2410_dma_sel);
807 unsigned long flags;
808
809 if (chan == NULL)
810 return -EINVAL;
811
812 local_irq_save(flags);
813
814 if (chan->client != client) {
815 printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n",
816 channel, chan->client, client);
817 }
818
819 /* sort out stopping and freeing the channel */
820
821 if (chan->state != S3C2410_DMA_IDLE) {
822 pr_debug("%s: need to stop dma channel %p\n",
823 __FUNCTION__, chan);
824
825 /* possibly flush the channel */
826 s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STOP);
827 }
828
829 chan->client = NULL;
830 chan->in_use = 0;
831
832 if (chan->irq_claimed)
833 free_irq(chan->irq, (void *)chan);
834
835 chan->irq_claimed = 0;
836
837 if (!(channel & DMACH_LOW_LEVEL))
838 dma_chan_map[channel] = NULL;
839
840 local_irq_restore(flags);
841
842 return 0;
843} 133}
844 134
845EXPORT_SYMBOL(s3c2410_dma_free); 135#if defined(CONFIG_CPU_S3C2410)
846 136static struct sysdev_driver s3c2410_dma_driver = {
847static int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan) 137 .add = s3c2410_dma_add,
848{ 138};
849 unsigned long flags;
850 unsigned long tmp;
851
852 pr_debug("%s:\n", __FUNCTION__);
853
854 dbg_showchan(chan);
855
856 local_irq_save(flags);
857
858 s3c2410_dma_call_op(chan, S3C2410_DMAOP_STOP);
859
860 tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
861 tmp |= S3C2410_DMASKTRIG_STOP;
862 //tmp &= ~S3C2410_DMASKTRIG_ON;
863 dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
864
865#if 0
866 /* should also clear interrupts, according to WinCE BSP */
867 tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
868 tmp |= S3C2410_DCON_NORELOAD;
869 dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
870#endif
871
872 /* should stop do this, or should we wait for flush? */
873 chan->state = S3C2410_DMA_IDLE;
874 chan->load_state = S3C2410_DMALOAD_NONE;
875
876 local_irq_restore(flags);
877
878 return 0;
879}
880 139
881void s3c2410_dma_waitforstop(struct s3c2410_dma_chan *chan) 140static int __init s3c2410_dma_init(void)
882{ 141{
883 unsigned long tmp; 142 return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_dma_driver);
884 unsigned int timeout = 0x10000;
885
886 while (timeout-- > 0) {
887 tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
888
889 if (!(tmp & S3C2410_DMASKTRIG_ON))
890 return;
891 }
892
893 pr_debug("dma%d: failed to stop?\n", chan->number);
894} 143}
895 144
896 145arch_initcall(s3c2410_dma_init);
897/* s3c2410_dma_flush
898 *
899 * stop the channel, and remove all current and pending transfers
900*/
901
902static int s3c2410_dma_flush(struct s3c2410_dma_chan *chan)
903{
904 struct s3c2410_dma_buf *buf, *next;
905 unsigned long flags;
906
907 pr_debug("%s: chan %p (%d)\n", __FUNCTION__, chan, chan->number);
908
909 dbg_showchan(chan);
910
911 local_irq_save(flags);
912
913 if (chan->state != S3C2410_DMA_IDLE) {
914 pr_debug("%s: stopping channel...\n", __FUNCTION__ );
915 s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP);
916 }
917
918 buf = chan->curr;
919 if (buf == NULL)
920 buf = chan->next;
921
922 chan->curr = chan->next = chan->end = NULL;
923
924 if (buf != NULL) {
925 for ( ; buf != NULL; buf = next) {
926 next = buf->next;
927
928 pr_debug("%s: free buffer %p, next %p\n",
929 __FUNCTION__, buf, buf->next);
930
931 s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT);
932 s3c2410_dma_freebuf(buf);
933 }
934 }
935
936 dbg_showregs(chan);
937
938 s3c2410_dma_waitforstop(chan);
939
940#if 0
941 /* should also clear interrupts, according to WinCE BSP */
942 {
943 unsigned long tmp;
944
945 tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
946 tmp |= S3C2410_DCON_NORELOAD;
947 dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
948 }
949#endif 146#endif
950 147
951 dbg_showregs(chan); 148#if defined(CONFIG_CPU_S3C2442)
952 149/* S3C2442 DMA contains the same selection table as the S3C2410 */
953 local_irq_restore(flags); 150static struct sysdev_driver s3c2442_dma_driver = {
954 151 .add = s3c2410_dma_add,
955 return 0;
956}
957
958int
959s3c2410_dma_started(struct s3c2410_dma_chan *chan)
960{
961 unsigned long flags;
962
963 local_irq_save(flags);
964
965 dbg_showchan(chan);
966
967 /* if we've only loaded one buffer onto the channel, then chec
968 * to see if we have another, and if so, try and load it so when
969 * the first buffer is finished, the new one will be loaded onto
970 * the channel */
971
972 if (chan->next != NULL) {
973 if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
974
975 if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
976 pr_debug("%s: buff not yet loaded, no more todo\n",
977 __FUNCTION__);
978 } else {
979 chan->load_state = S3C2410_DMALOAD_1RUNNING;
980 s3c2410_dma_loadbuffer(chan, chan->next);
981 }
982
983 } else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) {
984 s3c2410_dma_loadbuffer(chan, chan->next);
985 }
986 }
987
988
989 local_irq_restore(flags);
990
991 return 0;
992
993}
994
995int
996s3c2410_dma_ctrl(dmach_t channel, enum s3c2410_chan_op op)
997{
998 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
999
1000 if (chan == NULL)
1001 return -EINVAL;
1002
1003 switch (op) {
1004 case S3C2410_DMAOP_START:
1005 return s3c2410_dma_start(chan);
1006
1007 case S3C2410_DMAOP_STOP:
1008 return s3c2410_dma_dostop(chan);
1009
1010 case S3C2410_DMAOP_PAUSE:
1011 case S3C2410_DMAOP_RESUME:
1012 return -ENOENT;
1013
1014 case S3C2410_DMAOP_FLUSH:
1015 return s3c2410_dma_flush(chan);
1016
1017 case S3C2410_DMAOP_STARTED:
1018 return s3c2410_dma_started(chan);
1019
1020 case S3C2410_DMAOP_TIMEOUT:
1021 return 0;
1022
1023 }
1024
1025 return -ENOENT; /* unknown, don't bother */
1026}
1027
1028EXPORT_SYMBOL(s3c2410_dma_ctrl);
1029
1030/* DMA configuration for each channel
1031 *
1032 * DISRCC -> source of the DMA (AHB,APB)
1033 * DISRC -> source address of the DMA
1034 * DIDSTC -> destination of the DMA (AHB,APD)
1035 * DIDST -> destination address of the DMA
1036*/
1037
1038/* s3c2410_dma_config
1039 *
1040 * xfersize: size of unit in bytes (1,2,4)
1041 * dcon: base value of the DCONx register
1042*/
1043
1044int s3c2410_dma_config(dmach_t channel,
1045 int xferunit,
1046 int dcon)
1047{
1048 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
1049
1050 pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n",
1051 __FUNCTION__, channel, xferunit, dcon);
1052
1053 if (chan == NULL)
1054 return -EINVAL;
1055
1056 pr_debug("%s: Initial dcon is %08x\n", __FUNCTION__, dcon);
1057
1058 dcon |= chan->dcon & dma_sel.dcon_mask;
1059
1060 pr_debug("%s: New dcon is %08x\n", __FUNCTION__, dcon);
1061
1062 switch (xferunit) {
1063 case 1:
1064 dcon |= S3C2410_DCON_BYTE;
1065 break;
1066
1067 case 2:
1068 dcon |= S3C2410_DCON_HALFWORD;
1069 break;
1070
1071 case 4:
1072 dcon |= S3C2410_DCON_WORD;
1073 break;
1074
1075 default:
1076 pr_debug("%s: bad transfer size %d\n", __FUNCTION__, xferunit);
1077 return -EINVAL;
1078 }
1079
1080 dcon |= S3C2410_DCON_HWTRIG;
1081 dcon |= S3C2410_DCON_INTREQ;
1082
1083 pr_debug("%s: dcon now %08x\n", __FUNCTION__, dcon);
1084
1085 chan->dcon = dcon;
1086 chan->xfer_unit = xferunit;
1087
1088 return 0;
1089}
1090
1091EXPORT_SYMBOL(s3c2410_dma_config);
1092
1093int s3c2410_dma_setflags(dmach_t channel, unsigned int flags)
1094{
1095 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
1096
1097 if (chan == NULL)
1098 return -EINVAL;
1099
1100 pr_debug("%s: chan=%p, flags=%08x\n", __FUNCTION__, chan, flags);
1101
1102 chan->flags = flags;
1103
1104 return 0;
1105}
1106
1107EXPORT_SYMBOL(s3c2410_dma_setflags);
1108
1109
1110/* do we need to protect the settings of the fields from
1111 * irq?
1112*/
1113
1114int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn)
1115{
1116 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
1117
1118 if (chan == NULL)
1119 return -EINVAL;
1120
1121 pr_debug("%s: chan=%p, op rtn=%p\n", __FUNCTION__, chan, rtn);
1122
1123 chan->op_fn = rtn;
1124
1125 return 0;
1126}
1127
1128EXPORT_SYMBOL(s3c2410_dma_set_opfn);
1129
1130int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn)
1131{
1132 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
1133
1134 if (chan == NULL)
1135 return -EINVAL;
1136
1137 pr_debug("%s: chan=%p, callback rtn=%p\n", __FUNCTION__, chan, rtn);
1138
1139 chan->callback_fn = rtn;
1140
1141 return 0;
1142}
1143
1144EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);
1145
1146/* s3c2410_dma_devconfig
1147 *
1148 * configure the dma source/destination hardware type and address
1149 *
1150 * source: S3C2410_DMASRC_HW: source is hardware
1151 * S3C2410_DMASRC_MEM: source is memory
1152 *
1153 * hwcfg: the value for xxxSTCn register,
1154 * bit 0: 0=increment pointer, 1=leave pointer
1155 * bit 1: 0=soucre is AHB, 1=soucre is APB
1156 *
1157 * devaddr: physical address of the source
1158*/
1159
1160int s3c2410_dma_devconfig(int channel,
1161 enum s3c2410_dmasrc source,
1162 int hwcfg,
1163 unsigned long devaddr)
1164{
1165 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
1166
1167 if (chan == NULL)
1168 return -EINVAL;
1169
1170 pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n",
1171 __FUNCTION__, (int)source, hwcfg, devaddr);
1172
1173 chan->source = source;
1174 chan->dev_addr = devaddr;
1175
1176 switch (source) {
1177 case S3C2410_DMASRC_HW:
1178 /* source is hardware */
1179 pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n",
1180 __FUNCTION__, devaddr, hwcfg);
1181 dma_wrreg(chan, S3C2410_DMA_DISRCC, hwcfg & 3);
1182 dma_wrreg(chan, S3C2410_DMA_DISRC, devaddr);
1183 dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0));
1184
1185 chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST);
1186 return 0;
1187
1188 case S3C2410_DMASRC_MEM:
1189 /* source is memory */
1190 pr_debug( "%s: mem source, devaddr=%08lx, hwcfg=%d\n",
1191 __FUNCTION__, devaddr, hwcfg);
1192 dma_wrreg(chan, S3C2410_DMA_DISRCC, (0<<1) | (0<<0));
1193 dma_wrreg(chan, S3C2410_DMA_DIDST, devaddr);
1194 dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3);
1195
1196 chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC);
1197 return 0;
1198 }
1199
1200 printk(KERN_ERR "dma%d: invalid source type (%d)\n", channel, source);
1201 return -EINVAL;
1202}
1203
1204EXPORT_SYMBOL(s3c2410_dma_devconfig);
1205
1206/* s3c2410_dma_getposition
1207 *
1208 * returns the current transfer points for the dma source and destination
1209*/
1210
1211int s3c2410_dma_getposition(dmach_t channel, dma_addr_t *src, dma_addr_t *dst)
1212{
1213 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
1214
1215 if (chan == NULL)
1216 return -EINVAL;
1217
1218 if (src != NULL)
1219 *src = dma_rdreg(chan, S3C2410_DMA_DCSRC);
1220
1221 if (dst != NULL)
1222 *dst = dma_rdreg(chan, S3C2410_DMA_DCDST);
1223
1224 return 0;
1225}
1226
1227EXPORT_SYMBOL(s3c2410_dma_getposition);
1228
1229
1230/* system device class */
1231
1232#ifdef CONFIG_PM
1233
1234static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state)
1235{
1236 struct s3c2410_dma_chan *cp = container_of(dev, struct s3c2410_dma_chan, dev);
1237
1238 printk(KERN_DEBUG "suspending dma channel %d\n", cp->number);
1239
1240 if (dma_rdreg(cp, S3C2410_DMA_DMASKTRIG) & S3C2410_DMASKTRIG_ON) {
1241 /* the dma channel is still working, which is probably
1242 * a bad thing to do over suspend/resume. We stop the
1243 * channel and assume that the client is either going to
1244 * retry after resume, or that it is broken.
1245 */
1246
1247 printk(KERN_INFO "dma: stopping channel %d due to suspend\n",
1248 cp->number);
1249
1250 s3c2410_dma_dostop(cp);
1251 }
1252
1253 return 0;
1254}
1255
1256static int s3c2410_dma_resume(struct sys_device *dev)
1257{
1258 return 0;
1259}
1260
1261#else
1262#define s3c2410_dma_suspend NULL
1263#define s3c2410_dma_resume NULL
1264#endif /* CONFIG_PM */
1265
1266struct sysdev_class dma_sysclass = {
1267 set_kset_name("s3c24xx-dma"),
1268 .suspend = s3c2410_dma_suspend,
1269 .resume = s3c2410_dma_resume,
1270}; 152};
1271 153
1272/* kmem cache implementation */ 154static int __init s3c2442_dma_init(void)
1273
1274static void s3c2410_dma_cache_ctor(void *p, struct kmem_cache *c, unsigned long f)
1275{
1276 memset(p, 0, sizeof(struct s3c2410_dma_buf));
1277}
1278
1279/* initialisation code */
1280
1281static int __init s3c2410_init_dma(void)
1282{
1283 struct s3c2410_dma_chan *cp;
1284 int channel;
1285 int ret;
1286
1287 printk("S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics\n");
1288
1289 dma_base = ioremap(S3C24XX_PA_DMA, 0x200);
1290 if (dma_base == NULL) {
1291 printk(KERN_ERR "dma failed to remap register block\n");
1292 return -ENOMEM;
1293 }
1294
1295 printk("Registering sysclass\n");
1296
1297 ret = sysdev_class_register(&dma_sysclass);
1298 if (ret != 0) {
1299 printk(KERN_ERR "dma sysclass registration failed\n");
1300 goto err;
1301 }
1302
1303 dma_kmem = kmem_cache_create("dma_desc", sizeof(struct s3c2410_dma_buf), 0,
1304 SLAB_HWCACHE_ALIGN,
1305 s3c2410_dma_cache_ctor, NULL);
1306
1307 if (dma_kmem == NULL) {
1308 printk(KERN_ERR "dma failed to make kmem cache\n");
1309 ret = -ENOMEM;
1310 goto err;
1311 }
1312
1313 for (channel = 0; channel < S3C2410_DMA_CHANNELS; channel++) {
1314 cp = &s3c2410_chans[channel];
1315
1316 memset(cp, 0, sizeof(struct s3c2410_dma_chan));
1317
1318 /* dma channel irqs are in order.. */
1319 cp->number = channel;
1320 cp->irq = channel + IRQ_DMA0;
1321 cp->regs = dma_base + (channel*0x40);
1322
1323 /* point current stats somewhere */
1324 cp->stats = &cp->stats_store;
1325 cp->stats_store.timeout_shortest = LONG_MAX;
1326
1327 /* basic channel configuration */
1328
1329 cp->load_timeout = 1<<18;
1330
1331 /* register system device */
1332
1333 cp->dev.cls = &dma_sysclass;
1334 cp->dev.id = channel;
1335 ret = sysdev_register(&cp->dev);
1336
1337 printk("DMA channel %d at %p, irq %d\n",
1338 cp->number, cp->regs, cp->irq);
1339 }
1340
1341 return 0;
1342
1343 err:
1344 kmem_cache_destroy(dma_kmem);
1345 iounmap(dma_base);
1346 dma_base = NULL;
1347 return ret;
1348}
1349
1350core_initcall(s3c2410_init_dma);
1351
1352static inline int is_channel_valid(unsigned int channel)
1353{ 155{
1354 return (channel & DMA_CH_VALID); 156 return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_dma_driver);
1355} 157}
1356 158
1357/* s3c2410_dma_map_channel() 159arch_initcall(s3c2442_dma_init);
1358 * 160#endif
1359 * turn the virtual channel number into a real, and un-used hardware
1360 * channel.
1361 *
1362 * currently this code uses first-free channel from the specified harware
1363 * map, not taking into account anything that the board setup code may
1364 * have to say about the likely peripheral set to be in use.
1365*/
1366
1367struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
1368{
1369 struct s3c24xx_dma_map *ch_map;
1370 struct s3c2410_dma_chan *dmach;
1371 int ch;
1372
1373 if (dma_sel.map == NULL || channel > dma_sel.map_size)
1374 return NULL;
1375
1376 ch_map = dma_sel.map + channel;
1377
1378 for (ch = 0; ch < S3C2410_DMA_CHANNELS; ch++) {
1379 if (!is_channel_valid(ch_map->channels[ch]))
1380 continue;
1381
1382 if (s3c2410_chans[ch].in_use == 0) {
1383 printk("mapped channel %d to %d\n", channel, ch);
1384 break;
1385 }
1386 }
1387
1388 if (ch >= S3C2410_DMA_CHANNELS)
1389 return NULL;
1390
1391 /* update our channel mapping */
1392
1393 dmach = &s3c2410_chans[ch];
1394 dma_chan_map[channel] = dmach;
1395
1396 /* select the channel */
1397
1398 (dma_sel.select)(dmach, ch_map);
1399
1400 return dmach;
1401}
1402
1403static void s3c24xx_dma_show_ch(struct s3c24xx_dma_map *map, int ch)
1404{
1405 /* show the channel configuration */
1406
1407 printk("%2d: %20s, channels %c%c%c%c\n", ch, map->name,
1408 (is_channel_valid(map->channels[0]) ? '0' : '-'),
1409 (is_channel_valid(map->channels[1]) ? '1' : '-'),
1410 (is_channel_valid(map->channels[2]) ? '2' : '-'),
1411 (is_channel_valid(map->channels[3]) ? '3' : '-'));
1412}
1413
1414static int s3c24xx_dma_check_entry(struct s3c24xx_dma_map *map, int ch)
1415{
1416 if (1)
1417 s3c24xx_dma_show_ch(map, ch);
1418
1419 return 0;
1420}
1421
1422int __init s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel)
1423{
1424 struct s3c24xx_dma_map *nmap;
1425 size_t map_sz = sizeof(*nmap) * sel->map_size;
1426 int ptr;
1427
1428 nmap = kmalloc(map_sz, GFP_KERNEL);
1429 if (nmap == NULL)
1430 return -ENOMEM;
1431
1432 memcpy(nmap, sel->map, map_sz);
1433 memcpy(&dma_sel, sel, sizeof(*sel));
1434
1435 dma_sel.map = nmap;
1436
1437 for (ptr = 0; ptr < sel->map_size; ptr++)
1438 s3c24xx_dma_check_entry(nmap+ptr, ptr);
1439 161
1440 return 0;
1441}
diff --git a/arch/arm/mach-s3c2410/gpio.c b/arch/arm/mach-s3c2410/gpio.c
index f6fb215bb48c..01e795d1146e 100644
--- a/arch/arm/mach-s3c2410/gpio.c
+++ b/arch/arm/mach-s3c2410/gpio.c
@@ -1,9 +1,9 @@
1/* linux/arch/arm/mach-s3c2410/gpio.c 1/* linux/arch/arm/mach-s3c2410/gpio.c
2 * 2 *
3 * Copyright (c) 2004-2005 Simtec Electronics 3 * Copyright (c) 2004-2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
5 * 5 *
6 * S3C24XX GPIO support 6 * S3C2410 GPIO support
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -18,8 +18,7 @@
18 * You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software 19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21*/ 21 */
22
23 22
24#include <linux/kernel.h> 23#include <linux/kernel.h>
25#include <linux/init.h> 24#include <linux/init.h>
@@ -33,156 +32,40 @@
33 32
34#include <asm/arch/regs-gpio.h> 33#include <asm/arch/regs-gpio.h>
35 34
36void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function) 35int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
37{ 36 unsigned int config)
38 void __iomem *base = S3C24XX_GPIO_BASE(pin);
39 unsigned long mask;
40 unsigned long con;
41 unsigned long flags;
42
43 if (pin < S3C2410_GPIO_BANKB) {
44 mask = 1 << S3C2410_GPIO_OFFSET(pin);
45 } else {
46 mask = 3 << S3C2410_GPIO_OFFSET(pin)*2;
47 }
48
49 switch (function) {
50 case S3C2410_GPIO_LEAVE:
51 mask = 0;
52 function = 0;
53 break;
54
55 case S3C2410_GPIO_INPUT:
56 case S3C2410_GPIO_OUTPUT:
57 case S3C2410_GPIO_SFN2:
58 case S3C2410_GPIO_SFN3:
59 if (pin < S3C2410_GPIO_BANKB) {
60 function -= 1;
61 function &= 1;
62 function <<= S3C2410_GPIO_OFFSET(pin);
63 } else {
64 function &= 3;
65 function <<= S3C2410_GPIO_OFFSET(pin)*2;
66 }
67 }
68
69 /* modify the specified register wwith IRQs off */
70
71 local_irq_save(flags);
72
73 con = __raw_readl(base + 0x00);
74 con &= ~mask;
75 con |= function;
76
77 __raw_writel(con, base + 0x00);
78
79 local_irq_restore(flags);
80}
81
82EXPORT_SYMBOL(s3c2410_gpio_cfgpin);
83
84unsigned int s3c2410_gpio_getcfg(unsigned int pin)
85{
86 void __iomem *base = S3C24XX_GPIO_BASE(pin);
87 unsigned long val = __raw_readl(base);
88
89 if (pin < S3C2410_GPIO_BANKB) {
90 val >>= S3C2410_GPIO_OFFSET(pin);
91 val &= 1;
92 val += 1;
93 } else {
94 val >>= S3C2410_GPIO_OFFSET(pin)*2;
95 val &= 3;
96 }
97
98 return val | S3C2410_GPIO_INPUT;
99}
100
101EXPORT_SYMBOL(s3c2410_gpio_getcfg);
102
103void s3c2410_gpio_pullup(unsigned int pin, unsigned int to)
104{ 37{
105 void __iomem *base = S3C24XX_GPIO_BASE(pin); 38 void __iomem *reg = S3C24XX_EINFLT0;
106 unsigned long offs = S3C2410_GPIO_OFFSET(pin);
107 unsigned long flags; 39 unsigned long flags;
108 unsigned long up; 40 unsigned long val;
109
110 if (pin < S3C2410_GPIO_BANKB)
111 return;
112
113 local_irq_save(flags);
114
115 up = __raw_readl(base + 0x08);
116 up &= ~(1L << offs);
117 up |= to << offs;
118 __raw_writel(up, base + 0x08);
119 41
120 local_irq_restore(flags); 42 if (pin < S3C2410_GPG8 || pin > S3C2410_GPG15)
121} 43 return -1;
122 44
123EXPORT_SYMBOL(s3c2410_gpio_pullup); 45 config &= 0xff;
124 46
125void s3c2410_gpio_setpin(unsigned int pin, unsigned int to) 47 pin -= S3C2410_GPG8;
126{ 48 reg += pin & ~3;
127 void __iomem *base = S3C24XX_GPIO_BASE(pin);
128 unsigned long offs = S3C2410_GPIO_OFFSET(pin);
129 unsigned long flags;
130 unsigned long dat;
131 49
132 local_irq_save(flags); 50 local_irq_save(flags);
133 51
134 dat = __raw_readl(base + 0x04); 52 /* update filter width and clock source */
135 dat &= ~(1 << offs);
136 dat |= to << offs;
137 __raw_writel(dat, base + 0x04);
138
139 local_irq_restore(flags);
140}
141
142EXPORT_SYMBOL(s3c2410_gpio_setpin);
143
144unsigned int s3c2410_gpio_getpin(unsigned int pin)
145{
146 void __iomem *base = S3C24XX_GPIO_BASE(pin);
147 unsigned long offs = S3C2410_GPIO_OFFSET(pin);
148 53
149 return __raw_readl(base + 0x04) & (1<< offs); 54 val = __raw_readl(reg);
150} 55 val &= ~(0xff << ((pin & 3) * 8));
56 val |= config << ((pin & 3) * 8);
57 __raw_writel(val, reg);
151 58
152EXPORT_SYMBOL(s3c2410_gpio_getpin); 59 /* update filter enable */
153 60
154unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change) 61 val = __raw_readl(S3C24XX_EXTINT2);
155{ 62 val &= ~(1 << ((pin * 4) + 3));
156 unsigned long flags; 63 val |= on << ((pin * 4) + 3);
157 unsigned long misccr; 64 __raw_writel(val, S3C24XX_EXTINT2);
158 65
159 local_irq_save(flags);
160 misccr = __raw_readl(S3C24XX_MISCCR);
161 misccr &= ~clear;
162 misccr ^= change;
163 __raw_writel(misccr, S3C24XX_MISCCR);
164 local_irq_restore(flags); 66 local_irq_restore(flags);
165 67
166 return misccr; 68 return 0;
167}
168
169EXPORT_SYMBOL(s3c2410_modify_misccr);
170
171int s3c2410_gpio_getirq(unsigned int pin)
172{
173 if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15)
174 return -1; /* not valid interrupts */
175
176 if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7)
177 return -1; /* not valid pin */
178
179 if (pin < S3C2410_GPF4)
180 return (pin - S3C2410_GPF0) + IRQ_EINT0;
181
182 if (pin < S3C2410_GPG0)
183 return (pin - S3C2410_GPF4) + IRQ_EINT4;
184
185 return (pin - S3C2410_GPG0) + IRQ_EINT8;
186} 69}
187 70
188EXPORT_SYMBOL(s3c2410_gpio_getirq); 71EXPORT_SYMBOL(s3c2410_gpio_irqfilter);
diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c
index 3c0ed7871c55..53cbdaa43ac6 100644
--- a/arch/arm/mach-s3c2410/irq.c
+++ b/arch/arm/mach-s3c2410/irq.c
@@ -1,6 +1,6 @@
1/* linux/arch/arm/mach-s3c2410/irq.c 1/* linux/arch/arm/mach-s3c2410/irq.c
2 * 2 *
3 * Copyright (c) 2003,2004 Simtec Electronics 3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
@@ -17,37 +17,6 @@
17 * along with this program; if not, write to the Free Software 17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * 19 *
20 * Changelog:
21 *
22 * 22-Jul-2004 Ben Dooks <ben@simtec.co.uk>
23 * Fixed compile warnings
24 *
25 * 22-Jul-2004 Roc Wu <cooloney@yahoo.com.cn>
26 * Fixed s3c_extirq_type
27 *
28 * 21-Jul-2004 Arnaud Patard (Rtp) <arnaud.patard@rtp-net.org>
29 * Addition of ADC/TC demux
30 *
31 * 04-Oct-2004 Klaus Fetscher <k.fetscher@fetron.de>
32 * Fix for set_irq_type() on low EINT numbers
33 *
34 * 05-Oct-2004 Ben Dooks <ben@simtec.co.uk>
35 * Tidy up KF's patch and sort out new release
36 *
37 * 05-Oct-2004 Ben Dooks <ben@simtec.co.uk>
38 * Add support for power management controls
39 *
40 * 04-Nov-2004 Ben Dooks
41 * Fix standard IRQ wake for EINT0..4 and RTC
42 *
43 * 22-Feb-2005 Ben Dooks
44 * Fixed edge-triggering on ADC IRQ
45 *
46 * 28-Jun-2005 Ben Dooks
47 * Mark IRQ_LCD valid
48 *
49 * 25-Jul-2005 Ben Dooks
50 * Split the S3C2440 IRQ code to seperate file
51*/ 20*/
52 21
53#include <linux/init.h> 22#include <linux/init.h>
@@ -57,745 +26,23 @@
57#include <linux/ptrace.h> 26#include <linux/ptrace.h>
58#include <linux/sysdev.h> 27#include <linux/sysdev.h>
59 28
60#include <asm/hardware.h> 29#include <asm/plat-s3c24xx/cpu.h>
61#include <asm/irq.h> 30#include <asm/plat-s3c24xx/pm.h>
62#include <asm/io.h>
63
64#include <asm/mach/irq.h>
65
66#include <asm/arch/regs-irq.h>
67#include <asm/arch/regs-gpio.h>
68
69#include "cpu.h"
70#include "pm.h"
71#include "irq.h"
72
73/* wakeup irq control */
74
75#ifdef CONFIG_PM
76
77/* state for IRQs over sleep */
78
79/* default is to allow for EINT0..EINT15, and IRQ_RTC as wakeup sources
80 *
81 * set bit to 1 in allow bitfield to enable the wakeup settings on it
82*/
83
84unsigned long s3c_irqwake_intallow = 1L << (IRQ_RTC - IRQ_EINT0) | 0xfL;
85unsigned long s3c_irqwake_intmask = 0xffffffffL;
86unsigned long s3c_irqwake_eintallow = 0x0000fff0L;
87unsigned long s3c_irqwake_eintmask = 0xffffffffL;
88
89int
90s3c_irq_wake(unsigned int irqno, unsigned int state)
91{
92 unsigned long irqbit = 1 << (irqno - IRQ_EINT0);
93
94 if (!(s3c_irqwake_intallow & irqbit))
95 return -ENOENT;
96
97 printk(KERN_INFO "wake %s for irq %d\n",
98 state ? "enabled" : "disabled", irqno);
99
100 if (!state)
101 s3c_irqwake_intmask |= irqbit;
102 else
103 s3c_irqwake_intmask &= ~irqbit;
104
105 return 0;
106}
107
108static int
109s3c_irqext_wake(unsigned int irqno, unsigned int state)
110{
111 unsigned long bit = 1L << (irqno - EXTINT_OFF);
112
113 if (!(s3c_irqwake_eintallow & bit))
114 return -ENOENT;
115
116 printk(KERN_INFO "wake %s for irq %d\n",
117 state ? "enabled" : "disabled", irqno);
118
119 if (!state)
120 s3c_irqwake_eintmask |= bit;
121 else
122 s3c_irqwake_eintmask &= ~bit;
123
124 return 0;
125}
126
127#else
128#define s3c_irqext_wake NULL
129#define s3c_irq_wake NULL
130#endif
131
132
133static void
134s3c_irq_mask(unsigned int irqno)
135{
136 unsigned long mask;
137
138 irqno -= IRQ_EINT0;
139
140 mask = __raw_readl(S3C2410_INTMSK);
141 mask |= 1UL << irqno;
142 __raw_writel(mask, S3C2410_INTMSK);
143}
144
145static inline void
146s3c_irq_ack(unsigned int irqno)
147{
148 unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
149
150 __raw_writel(bitval, S3C2410_SRCPND);
151 __raw_writel(bitval, S3C2410_INTPND);
152}
153
154static inline void
155s3c_irq_maskack(unsigned int irqno)
156{
157 unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
158 unsigned long mask;
159
160 mask = __raw_readl(S3C2410_INTMSK);
161 __raw_writel(mask|bitval, S3C2410_INTMSK);
162
163 __raw_writel(bitval, S3C2410_SRCPND);
164 __raw_writel(bitval, S3C2410_INTPND);
165}
166
167
168static void
169s3c_irq_unmask(unsigned int irqno)
170{
171 unsigned long mask;
172
173 if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23)
174 irqdbf2("s3c_irq_unmask %d\n", irqno);
175
176 irqno -= IRQ_EINT0;
177
178 mask = __raw_readl(S3C2410_INTMSK);
179 mask &= ~(1UL << irqno);
180 __raw_writel(mask, S3C2410_INTMSK);
181}
182
183struct irq_chip s3c_irq_level_chip = {
184 .name = "s3c-level",
185 .ack = s3c_irq_maskack,
186 .mask = s3c_irq_mask,
187 .unmask = s3c_irq_unmask,
188 .set_wake = s3c_irq_wake
189};
190
191static struct irq_chip s3c_irq_chip = {
192 .name = "s3c",
193 .ack = s3c_irq_ack,
194 .mask = s3c_irq_mask,
195 .unmask = s3c_irq_unmask,
196 .set_wake = s3c_irq_wake
197};
198
199static void
200s3c_irqext_mask(unsigned int irqno)
201{
202 unsigned long mask;
203
204 irqno -= EXTINT_OFF;
205
206 mask = __raw_readl(S3C24XX_EINTMASK);
207 mask |= ( 1UL << irqno);
208 __raw_writel(mask, S3C24XX_EINTMASK);
209}
210
211static void
212s3c_irqext_ack(unsigned int irqno)
213{
214 unsigned long req;
215 unsigned long bit;
216 unsigned long mask;
217 31
218 bit = 1UL << (irqno - EXTINT_OFF); 32static int s3c2410_irq_add(struct sys_device *sysdev)
219
220 mask = __raw_readl(S3C24XX_EINTMASK);
221
222 __raw_writel(bit, S3C24XX_EINTPEND);
223
224 req = __raw_readl(S3C24XX_EINTPEND);
225 req &= ~mask;
226
227 /* not sure if we should be acking the parent irq... */
228
229 if (irqno <= IRQ_EINT7 ) {
230 if ((req & 0xf0) == 0)
231 s3c_irq_ack(IRQ_EINT4t7);
232 } else {
233 if ((req >> 8) == 0)
234 s3c_irq_ack(IRQ_EINT8t23);
235 }
236}
237
238static void
239s3c_irqext_unmask(unsigned int irqno)
240{ 33{
241 unsigned long mask;
242
243 irqno -= EXTINT_OFF;
244
245 mask = __raw_readl(S3C24XX_EINTMASK);
246 mask &= ~( 1UL << irqno);
247 __raw_writel(mask, S3C24XX_EINTMASK);
248}
249
250int
251s3c_irqext_type(unsigned int irq, unsigned int type)
252{
253 void __iomem *extint_reg;
254 void __iomem *gpcon_reg;
255 unsigned long gpcon_offset, extint_offset;
256 unsigned long newvalue = 0, value;
257
258 if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3))
259 {
260 gpcon_reg = S3C2410_GPFCON;
261 extint_reg = S3C24XX_EXTINT0;
262 gpcon_offset = (irq - IRQ_EINT0) * 2;
263 extint_offset = (irq - IRQ_EINT0) * 4;
264 }
265 else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7))
266 {
267 gpcon_reg = S3C2410_GPFCON;
268 extint_reg = S3C24XX_EXTINT0;
269 gpcon_offset = (irq - (EXTINT_OFF)) * 2;
270 extint_offset = (irq - (EXTINT_OFF)) * 4;
271 }
272 else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15))
273 {
274 gpcon_reg = S3C2410_GPGCON;
275 extint_reg = S3C24XX_EXTINT1;
276 gpcon_offset = (irq - IRQ_EINT8) * 2;
277 extint_offset = (irq - IRQ_EINT8) * 4;
278 }
279 else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23))
280 {
281 gpcon_reg = S3C2410_GPGCON;
282 extint_reg = S3C24XX_EXTINT2;
283 gpcon_offset = (irq - IRQ_EINT8) * 2;
284 extint_offset = (irq - IRQ_EINT16) * 4;
285 } else
286 return -1;
287
288 /* Set the GPIO to external interrupt mode */
289 value = __raw_readl(gpcon_reg);
290 value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset);
291 __raw_writel(value, gpcon_reg);
292
293 /* Set the external interrupt to pointed trigger type */
294 switch (type)
295 {
296 case IRQT_NOEDGE:
297 printk(KERN_WARNING "No edge setting!\n");
298 break;
299
300 case IRQT_RISING:
301 newvalue = S3C2410_EXTINT_RISEEDGE;
302 break;
303
304 case IRQT_FALLING:
305 newvalue = S3C2410_EXTINT_FALLEDGE;
306 break;
307
308 case IRQT_BOTHEDGE:
309 newvalue = S3C2410_EXTINT_BOTHEDGE;
310 break;
311
312 case IRQT_LOW:
313 newvalue = S3C2410_EXTINT_LOWLEV;
314 break;
315
316 case IRQT_HIGH:
317 newvalue = S3C2410_EXTINT_HILEV;
318 break;
319
320 default:
321 printk(KERN_ERR "No such irq type %d", type);
322 return -1;
323 }
324
325 value = __raw_readl(extint_reg);
326 value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset);
327 __raw_writel(value, extint_reg);
328
329 return 0; 34 return 0;
330} 35}
331 36
332static struct irq_chip s3c_irqext_chip = { 37static struct sysdev_driver s3c2410_irq_driver = {
333 .name = "s3c-ext", 38 .add = s3c2410_irq_add,
334 .mask = s3c_irqext_mask, 39 .suspend = s3c24xx_irq_suspend,
335 .unmask = s3c_irqext_unmask, 40 .resume = s3c24xx_irq_resume,
336 .ack = s3c_irqext_ack,
337 .set_type = s3c_irqext_type,
338 .set_wake = s3c_irqext_wake
339};
340
341static struct irq_chip s3c_irq_eint0t4 = {
342 .name = "s3c-ext0",
343 .ack = s3c_irq_ack,
344 .mask = s3c_irq_mask,
345 .unmask = s3c_irq_unmask,
346 .set_wake = s3c_irq_wake,
347 .set_type = s3c_irqext_type,
348};
349
350/* mask values for the parent registers for each of the interrupt types */
351
352#define INTMSK_UART0 (1UL << (IRQ_UART0 - IRQ_EINT0))
353#define INTMSK_UART1 (1UL << (IRQ_UART1 - IRQ_EINT0))
354#define INTMSK_UART2 (1UL << (IRQ_UART2 - IRQ_EINT0))
355#define INTMSK_ADCPARENT (1UL << (IRQ_ADCPARENT - IRQ_EINT0))
356
357
358/* UART0 */
359
360static void
361s3c_irq_uart0_mask(unsigned int irqno)
362{
363 s3c_irqsub_mask(irqno, INTMSK_UART0, 7);
364}
365
366static void
367s3c_irq_uart0_unmask(unsigned int irqno)
368{
369 s3c_irqsub_unmask(irqno, INTMSK_UART0);
370}
371
372static void
373s3c_irq_uart0_ack(unsigned int irqno)
374{
375 s3c_irqsub_maskack(irqno, INTMSK_UART0, 7);
376}
377
378static struct irq_chip s3c_irq_uart0 = {
379 .name = "s3c-uart0",
380 .mask = s3c_irq_uart0_mask,
381 .unmask = s3c_irq_uart0_unmask,
382 .ack = s3c_irq_uart0_ack,
383};
384
385/* UART1 */
386
387static void
388s3c_irq_uart1_mask(unsigned int irqno)
389{
390 s3c_irqsub_mask(irqno, INTMSK_UART1, 7 << 3);
391}
392
393static void
394s3c_irq_uart1_unmask(unsigned int irqno)
395{
396 s3c_irqsub_unmask(irqno, INTMSK_UART1);
397}
398
399static void
400s3c_irq_uart1_ack(unsigned int irqno)
401{
402 s3c_irqsub_maskack(irqno, INTMSK_UART1, 7 << 3);
403}
404
405static struct irq_chip s3c_irq_uart1 = {
406 .name = "s3c-uart1",
407 .mask = s3c_irq_uart1_mask,
408 .unmask = s3c_irq_uart1_unmask,
409 .ack = s3c_irq_uart1_ack,
410};
411
412/* UART2 */
413
414static void
415s3c_irq_uart2_mask(unsigned int irqno)
416{
417 s3c_irqsub_mask(irqno, INTMSK_UART2, 7 << 6);
418}
419
420static void
421s3c_irq_uart2_unmask(unsigned int irqno)
422{
423 s3c_irqsub_unmask(irqno, INTMSK_UART2);
424}
425
426static void
427s3c_irq_uart2_ack(unsigned int irqno)
428{
429 s3c_irqsub_maskack(irqno, INTMSK_UART2, 7 << 6);
430}
431
432static struct irq_chip s3c_irq_uart2 = {
433 .name = "s3c-uart2",
434 .mask = s3c_irq_uart2_mask,
435 .unmask = s3c_irq_uart2_unmask,
436 .ack = s3c_irq_uart2_ack,
437};
438
439/* ADC and Touchscreen */
440
441static void
442s3c_irq_adc_mask(unsigned int irqno)
443{
444 s3c_irqsub_mask(irqno, INTMSK_ADCPARENT, 3 << 9);
445}
446
447static void
448s3c_irq_adc_unmask(unsigned int irqno)
449{
450 s3c_irqsub_unmask(irqno, INTMSK_ADCPARENT);
451}
452
453static void
454s3c_irq_adc_ack(unsigned int irqno)
455{
456 s3c_irqsub_ack(irqno, INTMSK_ADCPARENT, 3 << 9);
457}
458
459static struct irq_chip s3c_irq_adc = {
460 .name = "s3c-adc",
461 .mask = s3c_irq_adc_mask,
462 .unmask = s3c_irq_adc_unmask,
463 .ack = s3c_irq_adc_ack,
464};
465
466/* irq demux for adc */
467static void s3c_irq_demux_adc(unsigned int irq,
468 struct irq_desc *desc)
469{
470 unsigned int subsrc, submsk;
471 unsigned int offset = 9;
472 struct irq_desc *mydesc;
473
474 /* read the current pending interrupts, and the mask
475 * for what it is available */
476
477 subsrc = __raw_readl(S3C2410_SUBSRCPND);
478 submsk = __raw_readl(S3C2410_INTSUBMSK);
479
480 subsrc &= ~submsk;
481 subsrc >>= offset;
482 subsrc &= 3;
483
484 if (subsrc != 0) {
485 if (subsrc & 1) {
486 mydesc = irq_desc + IRQ_TC;
487 desc_handle_irq(IRQ_TC, mydesc);
488 }
489 if (subsrc & 2) {
490 mydesc = irq_desc + IRQ_ADC;
491 desc_handle_irq(IRQ_ADC, mydesc);
492 }
493 }
494}
495
496static void s3c_irq_demux_uart(unsigned int start)
497{
498 unsigned int subsrc, submsk;
499 unsigned int offset = start - IRQ_S3CUART_RX0;
500 struct irq_desc *desc;
501
502 /* read the current pending interrupts, and the mask
503 * for what it is available */
504
505 subsrc = __raw_readl(S3C2410_SUBSRCPND);
506 submsk = __raw_readl(S3C2410_INTSUBMSK);
507
508 irqdbf2("s3c_irq_demux_uart: start=%d (%d), subsrc=0x%08x,0x%08x\n",
509 start, offset, subsrc, submsk);
510
511 subsrc &= ~submsk;
512 subsrc >>= offset;
513 subsrc &= 7;
514
515 if (subsrc != 0) {
516 desc = irq_desc + start;
517
518 if (subsrc & 1)
519 desc_handle_irq(start, desc);
520
521 desc++;
522
523 if (subsrc & 2)
524 desc_handle_irq(start+1, desc);
525
526 desc++;
527
528 if (subsrc & 4)
529 desc_handle_irq(start+2, desc);
530 }
531}
532
533/* uart demux entry points */
534
535static void
536s3c_irq_demux_uart0(unsigned int irq,
537 struct irq_desc *desc)
538{
539 irq = irq;
540 s3c_irq_demux_uart(IRQ_S3CUART_RX0);
541}
542
543static void
544s3c_irq_demux_uart1(unsigned int irq,
545 struct irq_desc *desc)
546{
547 irq = irq;
548 s3c_irq_demux_uart(IRQ_S3CUART_RX1);
549}
550
551static void
552s3c_irq_demux_uart2(unsigned int irq,
553 struct irq_desc *desc)
554{
555 irq = irq;
556 s3c_irq_demux_uart(IRQ_S3CUART_RX2);
557}
558
559static void
560s3c_irq_demux_extint8(unsigned int irq,
561 struct irq_desc *desc)
562{
563 unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
564 unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
565
566 eintpnd &= ~eintmsk;
567 eintpnd &= ~0xff; /* ignore lower irqs */
568
569 /* we may as well handle all the pending IRQs here */
570
571 while (eintpnd) {
572 irq = __ffs(eintpnd);
573 eintpnd &= ~(1<<irq);
574
575 irq += (IRQ_EINT4 - 4);
576 desc_handle_irq(irq, irq_desc + irq);
577 }
578
579}
580
581static void
582s3c_irq_demux_extint4t7(unsigned int irq,
583 struct irq_desc *desc)
584{
585 unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
586 unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
587
588 eintpnd &= ~eintmsk;
589 eintpnd &= 0xff; /* only lower irqs */
590
591 /* we may as well handle all the pending IRQs here */
592
593 while (eintpnd) {
594 irq = __ffs(eintpnd);
595 eintpnd &= ~(1<<irq);
596
597 irq += (IRQ_EINT4 - 4);
598
599 desc_handle_irq(irq, irq_desc + irq);
600 }
601}
602
603#ifdef CONFIG_PM
604
605static struct sleep_save irq_save[] = {
606 SAVE_ITEM(S3C2410_INTMSK),
607 SAVE_ITEM(S3C2410_INTSUBMSK),
608}; 41};
609 42
610/* the extint values move between the s3c2410/s3c2440 and the s3c2412 43static int s3c2410_irq_init(void)
611 * so we use an array to hold them, and to calculate the address of
612 * the register at run-time
613*/
614
615static unsigned long save_extint[3];
616static unsigned long save_eintflt[4];
617static unsigned long save_eintmask;
618
619int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state)
620{ 44{
621 unsigned int i; 45 return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_irq_driver);
622
623 for (i = 0; i < ARRAY_SIZE(save_extint); i++)
624 save_extint[i] = __raw_readl(S3C24XX_EXTINT0 + (i*4));
625
626 for (i = 0; i < ARRAY_SIZE(save_eintflt); i++)
627 save_eintflt[i] = __raw_readl(S3C24XX_EINFLT0 + (i*4));
628
629 s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save));
630 save_eintmask = __raw_readl(S3C24XX_EINTMASK);
631
632 return 0;
633} 46}
634 47
635int s3c24xx_irq_resume(struct sys_device *dev) 48arch_initcall(s3c2410_irq_init);
636{
637 unsigned int i;
638
639 for (i = 0; i < ARRAY_SIZE(save_extint); i++)
640 __raw_writel(save_extint[i], S3C24XX_EXTINT0 + (i*4));
641
642 for (i = 0; i < ARRAY_SIZE(save_eintflt); i++)
643 __raw_writel(save_eintflt[i], S3C24XX_EINFLT0 + (i*4));
644
645 s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
646 __raw_writel(save_eintmask, S3C24XX_EINTMASK);
647
648 return 0;
649}
650
651#else
652#define s3c24xx_irq_suspend NULL
653#define s3c24xx_irq_resume NULL
654#endif
655
656/* s3c24xx_init_irq
657 *
658 * Initialise S3C2410 IRQ system
659*/
660
661void __init s3c24xx_init_irq(void)
662{
663 unsigned long pend;
664 unsigned long last;
665 int irqno;
666 int i;
667
668 irqdbf("s3c2410_init_irq: clearing interrupt status flags\n");
669
670 /* first, clear all interrupts pending... */
671
672 last = 0;
673 for (i = 0; i < 4; i++) {
674 pend = __raw_readl(S3C24XX_EINTPEND);
675
676 if (pend == 0 || pend == last)
677 break;
678
679 __raw_writel(pend, S3C24XX_EINTPEND);
680 printk("irq: clearing pending ext status %08x\n", (int)pend);
681 last = pend;
682 }
683
684 last = 0;
685 for (i = 0; i < 4; i++) {
686 pend = __raw_readl(S3C2410_INTPND);
687
688 if (pend == 0 || pend == last)
689 break;
690
691 __raw_writel(pend, S3C2410_SRCPND);
692 __raw_writel(pend, S3C2410_INTPND);
693 printk("irq: clearing pending status %08x\n", (int)pend);
694 last = pend;
695 }
696
697 last = 0;
698 for (i = 0; i < 4; i++) {
699 pend = __raw_readl(S3C2410_SUBSRCPND);
700
701 if (pend == 0 || pend == last)
702 break;
703
704 printk("irq: clearing subpending status %08x\n", (int)pend);
705 __raw_writel(pend, S3C2410_SUBSRCPND);
706 last = pend;
707 }
708
709 /* register the main interrupts */
710
711 irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n");
712
713 for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) {
714 /* set all the s3c2410 internal irqs */
715
716 switch (irqno) {
717 /* deal with the special IRQs (cascaded) */
718
719 case IRQ_EINT4t7:
720 case IRQ_EINT8t23:
721 case IRQ_UART0:
722 case IRQ_UART1:
723 case IRQ_UART2:
724 case IRQ_ADCPARENT:
725 set_irq_chip(irqno, &s3c_irq_level_chip);
726 set_irq_handler(irqno, handle_level_irq);
727 break;
728
729 case IRQ_RESERVED6:
730 case IRQ_RESERVED24:
731 /* no IRQ here */
732 break;
733
734 default:
735 //irqdbf("registering irq %d (s3c irq)\n", irqno);
736 set_irq_chip(irqno, &s3c_irq_chip);
737 set_irq_handler(irqno, handle_edge_irq);
738 set_irq_flags(irqno, IRQF_VALID);
739 }
740 }
741
742 /* setup the cascade irq handlers */
743
744 set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7);
745 set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8);
746
747 set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
748 set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);
749 set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2);
750 set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc);
751
752 /* external interrupts */
753
754 for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
755 irqdbf("registering irq %d (ext int)\n", irqno);
756 set_irq_chip(irqno, &s3c_irq_eint0t4);
757 set_irq_handler(irqno, handle_edge_irq);
758 set_irq_flags(irqno, IRQF_VALID);
759 }
760
761 for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {
762 irqdbf("registering irq %d (extended s3c irq)\n", irqno);
763 set_irq_chip(irqno, &s3c_irqext_chip);
764 set_irq_handler(irqno, handle_edge_irq);
765 set_irq_flags(irqno, IRQF_VALID);
766 }
767
768 /* register the uart interrupts */
769
770 irqdbf("s3c2410: registering external interrupts\n");
771
772 for (irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) {
773 irqdbf("registering irq %d (s3c uart0 irq)\n", irqno);
774 set_irq_chip(irqno, &s3c_irq_uart0);
775 set_irq_handler(irqno, handle_level_irq);
776 set_irq_flags(irqno, IRQF_VALID);
777 }
778
779 for (irqno = IRQ_S3CUART_RX1; irqno <= IRQ_S3CUART_ERR1; irqno++) {
780 irqdbf("registering irq %d (s3c uart1 irq)\n", irqno);
781 set_irq_chip(irqno, &s3c_irq_uart1);
782 set_irq_handler(irqno, handle_level_irq);
783 set_irq_flags(irqno, IRQF_VALID);
784 }
785
786 for (irqno = IRQ_S3CUART_RX2; irqno <= IRQ_S3CUART_ERR2; irqno++) {
787 irqdbf("registering irq %d (s3c uart2 irq)\n", irqno);
788 set_irq_chip(irqno, &s3c_irq_uart2);
789 set_irq_handler(irqno, handle_level_irq);
790 set_irq_flags(irqno, IRQF_VALID);
791 }
792
793 for (irqno = IRQ_TC; irqno <= IRQ_ADC; irqno++) {
794 irqdbf("registering irq %d (s3c adc irq)\n", irqno);
795 set_irq_chip(irqno, &s3c_irq_adc);
796 set_irq_handler(irqno, handle_edge_irq);
797 set_irq_flags(irqno, IRQF_VALID);
798 }
799
800 irqdbf("s3c2410: registered interrupt handlers\n");
801}
diff --git a/arch/arm/mach-s3c2410/mach-amlm5900.c b/arch/arm/mach-s3c2410/mach-amlm5900.c
index 817e2c684410..d54cda1b3006 100644
--- a/arch/arm/mach-s3c2410/mach-amlm5900.c
+++ b/arch/arm/mach-s3c2410/mach-amlm5900.c
@@ -1,4 +1,4 @@
1/*********************************************************************** 1/* linux/arch/arm/mach-s3c2410/mach-amlm5900.c
2 * 2 *
3 * linux/arch/arm/mach-s3c2410/mach-amlm5900.c 3 * linux/arch/arm/mach-s3c2410/mach-amlm5900.c
4 * 4 *
@@ -52,8 +52,8 @@
52#include <asm/arch/regs-lcd.h> 52#include <asm/arch/regs-lcd.h>
53#include <asm/arch/regs-gpio.h> 53#include <asm/arch/regs-gpio.h>
54 54
55#include "devs.h" 55#include <asm/plat-s3c24xx/devs.h>
56#include "cpu.h" 56#include <asm/plat-s3c24xx/cpu.h>
57 57
58#ifdef CONFIG_MTD_PARTITIONS 58#ifdef CONFIG_MTD_PARTITIONS
59 59
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c
index b8b76757ec54..7b81296427eb 100644
--- a/arch/arm/mach-s3c2410/mach-bast.c
+++ b/arch/arm/mach-s3c2410/mach-bast.c
@@ -50,9 +50,9 @@
50 50
51#include <linux/serial_8250.h> 51#include <linux/serial_8250.h>
52 52
53#include "clock.h" 53#include <asm/plat-s3c24xx/clock.h>
54#include "devs.h" 54#include <asm/plat-s3c24xx/devs.h>
55#include "cpu.h" 55#include <asm/plat-s3c24xx/cpu.h>
56#include "usb-simtec.h" 56#include "usb-simtec.h"
57 57
58#define COPYRIGHT ", (c) 2004-2005 Simtec Electronics" 58#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 15b625eae499..5af26e177966 100644
--- a/arch/arm/mach-s3c2410/mach-h1940.c
+++ b/arch/arm/mach-s3c2410/mach-h1940.c
@@ -38,10 +38,10 @@
38#include <asm/arch/h1940-latch.h> 38#include <asm/arch/h1940-latch.h>
39#include <asm/arch/fb.h> 39#include <asm/arch/fb.h>
40 40
41#include "clock.h" 41#include <asm/plat-s3c24xx/clock.h>
42#include "devs.h" 42#include <asm/plat-s3c24xx/devs.h>
43#include "cpu.h" 43#include <asm/plat-s3c24xx/cpu.h>
44#include "pm.h" 44#include <asm/plat-s3c24xx/pm.h>
45 45
46static struct map_desc h1940_iodesc[] __initdata = { 46static struct map_desc h1940_iodesc[] __initdata = {
47 [0] = { 47 [0] = {
diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c2410/mach-n30.c
index 0411e9adb54d..dbac7311f98f 100644
--- a/arch/arm/mach-s3c2410/mach-n30.c
+++ b/arch/arm/mach-s3c2410/mach-n30.c
@@ -38,10 +38,10 @@
38#include <asm/arch/regs-gpio.h> 38#include <asm/arch/regs-gpio.h>
39#include <asm/arch/iic.h> 39#include <asm/arch/iic.h>
40 40
41#include "s3c2410.h" 41#include <asm/plat-s3c24xx/s3c2410.h>
42#include "clock.h" 42#include <asm/plat-s3c24xx/clock.h>
43#include "devs.h" 43#include <asm/plat-s3c24xx/devs.h>
44#include "cpu.h" 44#include <asm/plat-s3c24xx/cpu.h>
45 45
46static struct map_desc n30_iodesc[] __initdata = { 46static struct map_desc n30_iodesc[] __initdata = {
47 /* nothing here yet */ 47 /* nothing here yet */
diff --git a/arch/arm/mach-s3c2410/mach-otom.c b/arch/arm/mach-s3c2410/mach-otom.c
index 2c738b375e4d..c78ab75b44f3 100644
--- a/arch/arm/mach-s3c2410/mach-otom.c
+++ b/arch/arm/mach-s3c2410/mach-otom.c
@@ -32,10 +32,10 @@
32#include <asm/arch/regs-serial.h> 32#include <asm/arch/regs-serial.h>
33#include <asm/arch/regs-gpio.h> 33#include <asm/arch/regs-gpio.h>
34 34
35#include "s3c2410.h" 35#include <asm/plat-s3c24xx/s3c2410.h>
36#include "clock.h" 36#include <asm/plat-s3c24xx/clock.h>
37#include "devs.h" 37#include <asm/plat-s3c24xx/devs.h>
38#include "cpu.h" 38#include <asm/plat-s3c24xx/cpu.h>
39 39
40static struct map_desc otom11_iodesc[] __initdata = { 40static struct map_desc otom11_iodesc[] __initdata = {
41 /* Device area */ 41 /* Device area */
diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c
index 01c0c986d827..57b8a80f33d0 100644
--- a/arch/arm/mach-s3c2410/mach-smdk2410.c
+++ b/arch/arm/mach-s3c2410/mach-smdk2410.c
@@ -1,4 +1,4 @@
1/*********************************************************************** 1/* linux/arch/arm/mach-s3c2410/mach-smdk2410.c
2 * 2 *
3 * linux/arch/arm/mach-s3c2410/mach-smdk2410.c 3 * linux/arch/arm/mach-s3c2410/mach-smdk2410.c
4 * 4 *
@@ -49,10 +49,10 @@
49 49
50#include <asm/arch/regs-serial.h> 50#include <asm/arch/regs-serial.h>
51 51
52#include "devs.h" 52#include <asm/plat-s3c24xx/devs.h>
53#include "cpu.h" 53#include <asm/plat-s3c24xx/cpu.h>
54 54
55#include "common-smdk.h" 55#include <asm/plat-s3c24xx/common-smdk.h>
56 56
57static struct map_desc smdk2410_iodesc[] __initdata = { 57static struct map_desc smdk2410_iodesc[] __initdata = {
58 /* nothing here yet */ 58 /* nothing here yet */
diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c
index a382fc095110..c947c75bcbf0 100644
--- a/arch/arm/mach-s3c2410/mach-vr1000.c
+++ b/arch/arm/mach-s3c2410/mach-vr1000.c
@@ -43,9 +43,9 @@
43#include <asm/arch/regs-gpio.h> 43#include <asm/arch/regs-gpio.h>
44#include <asm/arch/leds-gpio.h> 44#include <asm/arch/leds-gpio.h>
45 45
46#include "clock.h" 46#include <asm/plat-s3c24xx/clock.h>
47#include "devs.h" 47#include <asm/plat-s3c24xx/devs.h>
48#include "cpu.h" 48#include <asm/plat-s3c24xx/cpu.h>
49#include "usb-simtec.h" 49#include "usb-simtec.h"
50 50
51/* macros for virtual address mods for the io space entries */ 51/* 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 ebf294dd31da..3b3a7db4e0dd 100644
--- a/arch/arm/mach-s3c2410/pm.c
+++ b/arch/arm/mach-s3c2410/pm.c
@@ -1,11 +1,9 @@
1/* linux/arch/arm/mach-s3c2410/pm.c 1/* linux/arch/arm/mach-s3c2410/pm.c
2 * 2 *
3 * Copyright (c) 2004,2006 Simtec Electronics 3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
5 * 5 *
6 * S3C24XX Power Manager (Suspend-To-RAM) support 6 * S3C2410 (and compatible) Power Manager (Suspend-To-RAM) support
7 *
8 * See Documentation/arm/Samsung-S3C24XX/Suspend.txt for more information
9 * 7 *
10 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -20,640 +18,139 @@
20 * You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software 19 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 * Parts based on arch/arm/mach-pxa/pm.c
25 *
26 * Thanks to Dimitry Andric for debugging
27*/ 21*/
28 22
29#include <linux/init.h> 23#include <linux/init.h>
30#include <linux/suspend.h> 24#include <linux/suspend.h>
31#include <linux/errno.h> 25#include <linux/errno.h>
32#include <linux/time.h> 26#include <linux/time.h>
33#include <linux/interrupt.h> 27#include <linux/sysdev.h>
34#include <linux/crc32.h>
35#include <linux/ioport.h>
36#include <linux/delay.h>
37#include <linux/serial_core.h>
38 28
39#include <asm/cacheflush.h>
40#include <asm/hardware.h> 29#include <asm/hardware.h>
41#include <asm/io.h> 30#include <asm/io.h>
42 31
43#include <asm/arch/regs-serial.h> 32#include <asm/mach-types.h>
44#include <asm/arch/regs-clock.h>
45#include <asm/arch/regs-gpio.h>
46#include <asm/arch/regs-mem.h>
47#include <asm/arch/regs-irq.h>
48
49#include <asm/mach/time.h>
50
51#include "pm.h"
52
53/* for external use */
54
55unsigned long s3c_pm_flags;
56
57#define PFX "s3c24xx-pm: "
58
59static struct sleep_save core_save[] = {
60 SAVE_ITEM(S3C2410_LOCKTIME),
61 SAVE_ITEM(S3C2410_CLKCON),
62
63 /* we restore the timings here, with the proviso that the board
64 * brings the system up in an slower, or equal frequency setting
65 * to the original system.
66 *
67 * if we cannot guarantee this, then things are going to go very
68 * wrong here, as we modify the refresh and both pll settings.
69 */
70
71 SAVE_ITEM(S3C2410_BWSCON),
72 SAVE_ITEM(S3C2410_BANKCON0),
73 SAVE_ITEM(S3C2410_BANKCON1),
74 SAVE_ITEM(S3C2410_BANKCON2),
75 SAVE_ITEM(S3C2410_BANKCON3),
76 SAVE_ITEM(S3C2410_BANKCON4),
77 SAVE_ITEM(S3C2410_BANKCON5),
78
79 SAVE_ITEM(S3C2410_CLKDIVN),
80 SAVE_ITEM(S3C2410_MPLLCON),
81 SAVE_ITEM(S3C2410_UPLLCON),
82 SAVE_ITEM(S3C2410_CLKSLOW),
83 SAVE_ITEM(S3C2410_REFRESH),
84};
85
86static struct sleep_save gpio_save[] = {
87 SAVE_ITEM(S3C2410_GPACON),
88 SAVE_ITEM(S3C2410_GPADAT),
89
90 SAVE_ITEM(S3C2410_GPBCON),
91 SAVE_ITEM(S3C2410_GPBDAT),
92 SAVE_ITEM(S3C2410_GPBUP),
93
94 SAVE_ITEM(S3C2410_GPCCON),
95 SAVE_ITEM(S3C2410_GPCDAT),
96 SAVE_ITEM(S3C2410_GPCUP),
97
98 SAVE_ITEM(S3C2410_GPDCON),
99 SAVE_ITEM(S3C2410_GPDDAT),
100 SAVE_ITEM(S3C2410_GPDUP),
101
102 SAVE_ITEM(S3C2410_GPECON),
103 SAVE_ITEM(S3C2410_GPEDAT),
104 SAVE_ITEM(S3C2410_GPEUP),
105
106 SAVE_ITEM(S3C2410_GPFCON),
107 SAVE_ITEM(S3C2410_GPFDAT),
108 SAVE_ITEM(S3C2410_GPFUP),
109 33
110 SAVE_ITEM(S3C2410_GPGCON), 34#include <asm/arch/regs-gpio.h>
111 SAVE_ITEM(S3C2410_GPGDAT), 35#include <asm/arch/h1940.h>
112 SAVE_ITEM(S3C2410_GPGUP),
113
114 SAVE_ITEM(S3C2410_GPHCON),
115 SAVE_ITEM(S3C2410_GPHDAT),
116 SAVE_ITEM(S3C2410_GPHUP),
117 36
118 SAVE_ITEM(S3C2410_DCLKCON), 37#include <asm/plat-s3c24xx/cpu.h>
119}; 38#include <asm/plat-s3c24xx/pm.h>
120 39
121#ifdef CONFIG_S3C2410_PM_DEBUG 40#ifdef CONFIG_S3C2410_PM_DEBUG
122 41extern void pm_dbg(const char *fmt, ...);
123#define SAVE_UART(va) \
124 SAVE_ITEM((va) + S3C2410_ULCON), \
125 SAVE_ITEM((va) + S3C2410_UCON), \
126 SAVE_ITEM((va) + S3C2410_UFCON), \
127 SAVE_ITEM((va) + S3C2410_UMCON), \
128 SAVE_ITEM((va) + S3C2410_UBRDIV)
129
130static struct sleep_save uart_save[] = {
131 SAVE_UART(S3C24XX_VA_UART0),
132 SAVE_UART(S3C24XX_VA_UART1),
133#ifndef CONFIG_CPU_S3C2400
134 SAVE_UART(S3C24XX_VA_UART2),
135#endif
136};
137
138/* debug
139 *
140 * we send the debug to printascii() to allow it to be seen if the
141 * system never wakes up from the sleep
142*/
143
144extern void printascii(const char *);
145
146void pm_dbg(const char *fmt, ...)
147{
148 va_list va;
149 char buff[256];
150
151 va_start(va, fmt);
152 vsprintf(buff, fmt, va);
153 va_end(va);
154
155 printascii(buff);
156}
157
158static void s3c2410_pm_debug_init(void)
159{
160 unsigned long tmp = __raw_readl(S3C2410_CLKCON);
161
162 /* re-start uart clocks */
163 tmp |= S3C2410_CLKCON_UART0;
164 tmp |= S3C2410_CLKCON_UART1;
165 tmp |= S3C2410_CLKCON_UART2;
166
167 __raw_writel(tmp, S3C2410_CLKCON);
168 udelay(10);
169}
170
171#define DBG(fmt...) pm_dbg(fmt) 42#define DBG(fmt...) pm_dbg(fmt)
172#else 43#else
173#define DBG(fmt...) printk(KERN_DEBUG fmt) 44#define DBG(fmt...) printk(KERN_DEBUG fmt)
174
175#define s3c2410_pm_debug_init() do { } while(0)
176
177static struct sleep_save uart_save[] = {};
178#endif 45#endif
179 46
180#if defined(CONFIG_S3C2410_PM_CHECK) && CONFIG_S3C2410_PM_CHECK_CHUNKSIZE != 0 47static void s3c2410_pm_prepare(void)
181
182/* suspend checking code...
183 *
184 * this next area does a set of crc checks over all the installed
185 * memory, so the system can verify if the resume was ok.
186 *
187 * CONFIG_S3C2410_PM_CHECK_CHUNKSIZE defines the block-size for the CRC,
188 * increasing it will mean that the area corrupted will be less easy to spot,
189 * and reducing the size will cause the CRC save area to grow
190*/
191
192#define CHECK_CHUNKSIZE (CONFIG_S3C2410_PM_CHECK_CHUNKSIZE * 1024)
193
194static u32 crc_size; /* size needed for the crc block */
195static u32 *crcs; /* allocated over suspend/resume */
196
197typedef u32 *(run_fn_t)(struct resource *ptr, u32 *arg);
198
199/* s3c2410_pm_run_res
200 *
201 * go thorugh the given resource list, and look for system ram
202*/
203
204static void s3c2410_pm_run_res(struct resource *ptr, run_fn_t fn, u32 *arg)
205{
206 while (ptr != NULL) {
207 if (ptr->child != NULL)
208 s3c2410_pm_run_res(ptr->child, fn, arg);
209
210 if ((ptr->flags & IORESOURCE_MEM) &&
211 strcmp(ptr->name, "System RAM") == 0) {
212 DBG("Found system RAM at %08lx..%08lx\n",
213 ptr->start, ptr->end);
214 arg = (fn)(ptr, arg);
215 }
216
217 ptr = ptr->sibling;
218 }
219}
220
221static void s3c2410_pm_run_sysram(run_fn_t fn, u32 *arg)
222{
223 s3c2410_pm_run_res(&iomem_resource, fn, arg);
224}
225
226static u32 *s3c2410_pm_countram(struct resource *res, u32 *val)
227{
228 u32 size = (u32)(res->end - res->start)+1;
229
230 size += CHECK_CHUNKSIZE-1;
231 size /= CHECK_CHUNKSIZE;
232
233 DBG("Area %08lx..%08lx, %d blocks\n", res->start, res->end, size);
234
235 *val += size * sizeof(u32);
236 return val;
237}
238
239/* s3c2410_pm_prepare_check
240 *
241 * prepare the necessary information for creating the CRCs. This
242 * must be done before the final save, as it will require memory
243 * allocating, and thus touching bits of the kernel we do not
244 * know about.
245*/
246
247static void s3c2410_pm_check_prepare(void)
248{ 48{
249 crc_size = 0; 49 /* ensure at least GSTATUS3 has the resume address */
250 50
251 s3c2410_pm_run_sysram(s3c2410_pm_countram, &crc_size); 51 __raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C2410_GSTATUS3);
252 52
253 DBG("s3c2410_pm_prepare_check: %u checks needed\n", crc_size); 53 DBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3));
54 DBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4));
254 55
255 crcs = kmalloc(crc_size+4, GFP_KERNEL); 56 if (machine_is_h1940()) {
256 if (crcs == NULL) 57 void *base = phys_to_virt(H1940_SUSPEND_CHECK);
257 printk(KERN_ERR "Cannot allocated CRC save area\n"); 58 unsigned long ptr;
258} 59 unsigned long calc = 0;
259 60
260static u32 *s3c2410_pm_makecheck(struct resource *res, u32 *val) 61 /* generate check for the bootloader to check on resume */
261{
262 unsigned long addr, left;
263 62
264 for (addr = res->start; addr < res->end; 63 for (ptr = 0; ptr < 0x40000; ptr += 0x400)
265 addr += CHECK_CHUNKSIZE) { 64 calc += __raw_readl(base+ptr);
266 left = res->end - addr;
267 65
268 if (left > CHECK_CHUNKSIZE) 66 __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM));
269 left = CHECK_CHUNKSIZE;
270
271 *val = crc32_le(~0, phys_to_virt(addr), left);
272 val++;
273 } 67 }
274 68
275 return val; 69 /* the RX3715 uses similar code and the same H1940 and the
276} 70 * same offsets for resume and checksum pointers */
277
278/* s3c2410_pm_check_store
279 *
280 * compute the CRC values for the memory blocks before the final
281 * sleep.
282*/
283
284static void s3c2410_pm_check_store(void)
285{
286 if (crcs != NULL)
287 s3c2410_pm_run_sysram(s3c2410_pm_makecheck, crcs);
288}
289
290/* in_region
291 *
292 * return TRUE if the area defined by ptr..ptr+size contatins the
293 * what..what+whatsz
294*/
295
296static inline int in_region(void *ptr, int size, void *what, size_t whatsz)
297{
298 if ((what+whatsz) < ptr)
299 return 0;
300
301 if (what > (ptr+size))
302 return 0;
303
304 return 1;
305}
306
307static u32 *s3c2410_pm_runcheck(struct resource *res, u32 *val)
308{
309 void *save_at = phys_to_virt(s3c2410_sleep_save_phys);
310 unsigned long addr;
311 unsigned long left;
312 void *ptr;
313 u32 calc;
314
315 for (addr = res->start; addr < res->end;
316 addr += CHECK_CHUNKSIZE) {
317 left = res->end - addr;
318 71
319 if (left > CHECK_CHUNKSIZE) 72 if (machine_is_rx3715()) {
320 left = CHECK_CHUNKSIZE; 73 void *base = phys_to_virt(H1940_SUSPEND_CHECK);
74 unsigned long ptr;
75 unsigned long calc = 0;
321 76
322 ptr = phys_to_virt(addr); 77 /* generate check for the bootloader to check on resume */
323 78
324 if (in_region(ptr, left, crcs, crc_size)) { 79 for (ptr = 0; ptr < 0x40000; ptr += 0x4)
325 DBG("skipping %08lx, has crc block in\n", addr); 80 calc += __raw_readl(base+ptr);
326 goto skip_check;
327 }
328 81
329 if (in_region(ptr, left, save_at, 32*4 )) { 82 __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM));
330 DBG("skipping %08lx, has save block in\n", addr);
331 goto skip_check;
332 }
333
334 /* calculate and check the checksum */
335
336 calc = crc32_le(~0, ptr, left);
337 if (calc != *val) {
338 printk(KERN_ERR PFX "Restore CRC error at "
339 "%08lx (%08x vs %08x)\n", addr, calc, *val);
340
341 DBG("Restore CRC error at %08lx (%08x vs %08x)\n",
342 addr, calc, *val);
343 }
344
345 skip_check:
346 val++;
347 } 83 }
348 84
349 return val; 85 if ( machine_is_aml_m5900() )
350} 86 s3c2410_gpio_setpin(S3C2410_GPF2, 1);
351 87
352/* s3c2410_pm_check_restore
353 *
354 * check the CRCs after the restore event and free the memory used
355 * to hold them
356*/
357
358static void s3c2410_pm_check_restore(void)
359{
360 if (crcs != NULL) {
361 s3c2410_pm_run_sysram(s3c2410_pm_runcheck, crcs);
362 kfree(crcs);
363 crcs = NULL;
364 }
365} 88}
366 89
367#else 90static int s3c2410_pm_resume(struct sys_device *dev)
368
369#define s3c2410_pm_check_prepare() do { } while(0)
370#define s3c2410_pm_check_restore() do { } while(0)
371#define s3c2410_pm_check_store() do { } while(0)
372#endif
373
374/* helper functions to save and restore register state */
375
376void s3c2410_pm_do_save(struct sleep_save *ptr, int count)
377{ 91{
378 for (; count > 0; count--, ptr++) { 92 unsigned long tmp;
379 ptr->val = __raw_readl(ptr->reg);
380 DBG("saved %p value %08lx\n", ptr->reg, ptr->val);
381 }
382}
383 93
384/* s3c2410_pm_do_restore 94 /* unset the return-from-sleep flag, to ensure reset */
385 *
386 * restore the system from the given list of saved registers
387 *
388 * Note, we do not use DBG() in here, as the system may not have
389 * restore the UARTs state yet
390*/
391 95
392void s3c2410_pm_do_restore(struct sleep_save *ptr, int count) 96 tmp = __raw_readl(S3C2410_GSTATUS2);
393{ 97 tmp &= S3C2410_GSTATUS2_OFFRESET;
394 for (; count > 0; count--, ptr++) { 98 __raw_writel(tmp, S3C2410_GSTATUS2);
395 printk(KERN_DEBUG "restore %p (restore %08lx, was %08x)\n",
396 ptr->reg, ptr->val, __raw_readl(ptr->reg));
397
398 __raw_writel(ptr->val, ptr->reg);
399 }
400}
401 99
402/* s3c2410_pm_do_restore_core 100 if ( machine_is_aml_m5900() )
403 * 101 s3c2410_gpio_setpin(S3C2410_GPF2, 0);
404 * similar to s3c2410_pm_do_restore_core
405 *
406 * WARNING: Do not put any debug in here that may effect memory or use
407 * peripherals, as things may be changing!
408*/
409 102
410static void s3c2410_pm_do_restore_core(struct sleep_save *ptr, int count) 103 return 0;
411{
412 for (; count > 0; count--, ptr++) {
413 __raw_writel(ptr->val, ptr->reg);
414 }
415} 104}
416 105
417/* s3c2410_pm_show_resume_irqs 106static int s3c2410_pm_add(struct sys_device *dev)
418 *
419 * print any IRQs asserted at resume time (ie, we woke from)
420*/
421
422static void s3c2410_pm_show_resume_irqs(int start, unsigned long which,
423 unsigned long mask)
424{ 107{
425 int i; 108 pm_cpu_prep = s3c2410_pm_prepare;
109 pm_cpu_sleep = s3c2410_cpu_suspend;
426 110
427 which &= ~mask; 111 return 0;
428
429 for (i = 0; i <= 31; i++) {
430 if ((which) & (1L<<i)) {
431 DBG("IRQ %d asserted at resume\n", start+i);
432 }
433 }
434} 112}
435 113
436/* s3c2410_pm_check_resume_pin 114#if defined(CONFIG_CPU_S3C2410)
437 * 115static struct sysdev_driver s3c2410_pm_driver = {
438 * check to see if the pin is configured correctly for sleep mode, and 116 .add = s3c2410_pm_add,
439 * make any necessary adjustments if it is not 117 .resume = s3c2410_pm_resume,
440*/ 118};
441
442static void s3c2410_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs)
443{
444 unsigned long irqstate;
445 unsigned long pinstate;
446 int irq = s3c2410_gpio_getirq(pin);
447
448 if (irqoffs < 4)
449 irqstate = s3c_irqwake_intmask & (1L<<irqoffs);
450 else
451 irqstate = s3c_irqwake_eintmask & (1L<<irqoffs);
452
453 pinstate = s3c2410_gpio_getcfg(pin);
454
455 if (!irqstate) {
456 if (pinstate == S3C2410_GPIO_IRQ)
457 DBG("Leaving IRQ %d (pin %d) enabled\n", irq, pin);
458 } else {
459 if (pinstate == S3C2410_GPIO_IRQ) {
460 DBG("Disabling IRQ %d (pin %d)\n", irq, pin);
461 s3c2410_gpio_cfgpin(pin, S3C2410_GPIO_INPUT);
462 }
463 }
464}
465 119
466/* s3c2410_pm_configure_extint 120/* register ourselves */
467 *
468 * configure all external interrupt pins
469*/
470 121
471static void s3c2410_pm_configure_extint(void) 122static int __init s3c2410_pm_drvinit(void)
472{ 123{
473 int pin; 124 return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_pm_driver);
474
475 /* for each of the external interrupts (EINT0..EINT15) we
476 * need to check wether it is an external interrupt source,
477 * and then configure it as an input if it is not
478 */
479
480 for (pin = S3C2410_GPF0; pin <= S3C2410_GPF7; pin++) {
481 s3c2410_pm_check_resume_pin(pin, pin - S3C2410_GPF0);
482 }
483
484 for (pin = S3C2410_GPG0; pin <= S3C2410_GPG7; pin++) {
485 s3c2410_pm_check_resume_pin(pin, (pin - S3C2410_GPG0)+8);
486 }
487} 125}
488 126
489void (*pm_cpu_prep)(void); 127arch_initcall(s3c2410_pm_drvinit);
490void (*pm_cpu_sleep)(void); 128#endif
491
492#define any_allowed(mask, allow) (((mask) & (allow)) != (allow))
493
494/* s3c2410_pm_enter
495 *
496 * central control for sleep/resume process
497*/
498
499static int s3c2410_pm_enter(suspend_state_t state)
500{
501 unsigned long regs_save[16];
502
503 /* ensure the debug is initialised (if enabled) */
504
505 s3c2410_pm_debug_init();
506
507 DBG("s3c2410_pm_enter(%d)\n", state);
508
509 if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) {
510 printk(KERN_ERR PFX "error: no cpu sleep functions set\n");
511 return -EINVAL;
512 }
513
514 if (state != PM_SUSPEND_MEM) {
515 printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n");
516 return -EINVAL;
517 }
518
519 /* check if we have anything to wake-up with... bad things seem
520 * to happen if you suspend with no wakeup (system will often
521 * require a full power-cycle)
522 */
523
524 if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) &&
525 !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) {
526 printk(KERN_ERR PFX "No sources enabled for wake-up!\n");
527 printk(KERN_ERR PFX "Aborting sleep\n");
528 return -EINVAL;
529 }
530
531 /* prepare check area if configured */
532
533 s3c2410_pm_check_prepare();
534
535 /* store the physical address of the register recovery block */
536
537 s3c2410_sleep_save_phys = virt_to_phys(regs_save);
538
539 DBG("s3c2410_sleep_save_phys=0x%08lx\n", s3c2410_sleep_save_phys);
540
541 /* save all necessary core registers not covered by the drivers */
542
543 s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save));
544 s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save));
545 s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save));
546
547 /* set the irq configuration for wake */
548
549 s3c2410_pm_configure_extint();
550
551 DBG("sleep: irq wakeup masks: %08lx,%08lx\n",
552 s3c_irqwake_intmask, s3c_irqwake_eintmask);
553
554 __raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK);
555 __raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK);
556
557 /* ack any outstanding external interrupts before we go to sleep */
558
559 __raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND);
560 __raw_writel(__raw_readl(S3C2410_INTPND), S3C2410_INTPND);
561 __raw_writel(__raw_readl(S3C2410_SRCPND), S3C2410_SRCPND);
562
563 /* call cpu specific preperation */
564
565 pm_cpu_prep();
566
567 /* flush cache back to ram */
568
569 flush_cache_all();
570
571 s3c2410_pm_check_store();
572
573 /* send the cpu to sleep... */
574
575 __raw_writel(0x00, S3C2410_CLKCON); /* turn off clocks over sleep */
576
577 /* s3c2410_cpu_save will also act as our return point from when
578 * we resume as it saves its own register state, so use the return
579 * code to differentiate return from save and return from sleep */
580
581 if (s3c2410_cpu_save(regs_save) == 0) {
582 flush_cache_all();
583 pm_cpu_sleep();
584 }
585
586 /* restore the cpu state */
587
588 cpu_init();
589
590 /* restore the system state */
591
592 s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save));
593 s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save));
594 s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save));
595
596 s3c2410_pm_debug_init();
597
598 /* check what irq (if any) restored the system */
599
600 DBG("post sleep: IRQs 0x%08x, 0x%08x\n",
601 __raw_readl(S3C2410_SRCPND),
602 __raw_readl(S3C2410_EINTPEND));
603
604 s3c2410_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND),
605 s3c_irqwake_intmask);
606
607 s3c2410_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND),
608 s3c_irqwake_eintmask);
609
610 DBG("post sleep, preparing to return\n");
611
612 s3c2410_pm_check_restore();
613
614 /* ok, let's return from sleep */
615 129
616 DBG("S3C2410 PM Resume (post-restore)\n"); 130#if defined(CONFIG_CPU_S3C2440)
617 return 0; 131static struct sysdev_driver s3c2440_pm_driver = {
618} 132 .add = s3c2410_pm_add,
133 .resume = s3c2410_pm_resume,
134};
619 135
620/* 136static int __init s3c2440_pm_drvinit(void)
621 * Called after processes are frozen, but before we shut down devices.
622 */
623static int s3c2410_pm_prepare(suspend_state_t state)
624{ 137{
625 return 0; 138 return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_pm_driver);
626} 139}
627 140
628/* 141arch_initcall(s3c2440_pm_drvinit);
629 * Called after devices are re-setup, but before processes are thawed. 142#endif
630 */
631static int s3c2410_pm_finish(suspend_state_t state)
632{
633 return 0;
634}
635 143
636/* 144#if defined(CONFIG_CPU_S3C2442)
637 * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk. 145static struct sysdev_driver s3c2442_pm_driver = {
638 */ 146 .add = s3c2410_pm_add,
639static struct pm_ops s3c2410_pm_ops = { 147 .resume = s3c2410_pm_resume,
640 .pm_disk_mode = PM_DISK_FIRMWARE,
641 .prepare = s3c2410_pm_prepare,
642 .enter = s3c2410_pm_enter,
643 .finish = s3c2410_pm_finish,
644}; 148};
645 149
646/* s3c2410_pm_init 150static int __init s3c2442_pm_drvinit(void)
647 *
648 * Attach the power management functions. This should be called
649 * from the board specific initialisation if the board supports
650 * it.
651*/
652
653int __init s3c2410_pm_init(void)
654{ 151{
655 printk("S3C2410 Power Management, (c) 2004 Simtec Electronics\n"); 152 return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_pm_driver);
656
657 pm_set_ops(&s3c2410_pm_ops);
658 return 0;
659} 153}
154
155arch_initcall(s3c2442_pm_drvinit);
156#endif
diff --git a/arch/arm/mach-s3c2410/s3c2410-clock.c b/arch/arm/mach-s3c2410/s3c2410-clock.c
deleted file mode 100644
index 992cc6af230e..000000000000
--- a/arch/arm/mach-s3c2410/s3c2410-clock.c
+++ /dev/null
@@ -1,276 +0,0 @@
1/* linux/arch/arm/mach-s3c2410/s3c2410-clock.c
2 *
3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * S3C2410,S3C2440,S3C2442 Clock control support
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21*/
22
23#include <linux/init.h>
24#include <linux/module.h>
25#include <linux/kernel.h>
26#include <linux/list.h>
27#include <linux/errno.h>
28#include <linux/err.h>
29#include <linux/sysdev.h>
30#include <linux/clk.h>
31#include <linux/mutex.h>
32#include <linux/delay.h>
33#include <linux/serial_core.h>
34
35#include <asm/mach/map.h>
36
37#include <asm/hardware.h>
38#include <asm/io.h>
39
40#include <asm/arch/regs-serial.h>
41#include <asm/arch/regs-clock.h>
42#include <asm/arch/regs-gpio.h>
43
44#include "s3c2410.h"
45#include "clock.h"
46#include "cpu.h"
47
48int s3c2410_clkcon_enable(struct clk *clk, int enable)
49{
50 unsigned int clocks = clk->ctrlbit;
51 unsigned long clkcon;
52
53 clkcon = __raw_readl(S3C2410_CLKCON);
54
55 if (enable)
56 clkcon |= clocks;
57 else
58 clkcon &= ~clocks;
59
60 /* ensure none of the special function bits set */
61 clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER);
62
63 __raw_writel(clkcon, S3C2410_CLKCON);
64
65 return 0;
66}
67
68static int s3c2410_upll_enable(struct clk *clk, int enable)
69{
70 unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
71 unsigned long orig = clkslow;
72
73 if (enable)
74 clkslow &= ~S3C2410_CLKSLOW_UCLK_OFF;
75 else
76 clkslow |= S3C2410_CLKSLOW_UCLK_OFF;
77
78 __raw_writel(clkslow, S3C2410_CLKSLOW);
79
80 /* if we started the UPLL, then allow to settle */
81
82 if (enable && (orig & S3C2410_CLKSLOW_UCLK_OFF))
83 udelay(200);
84
85 return 0;
86}
87
88/* standard clock definitions */
89
90static struct clk init_clocks_disable[] = {
91 {
92 .name = "nand",
93 .id = -1,
94 .parent = &clk_h,
95 .enable = s3c2410_clkcon_enable,
96 .ctrlbit = S3C2410_CLKCON_NAND,
97 }, {
98 .name = "sdi",
99 .id = -1,
100 .parent = &clk_p,
101 .enable = s3c2410_clkcon_enable,
102 .ctrlbit = S3C2410_CLKCON_SDI,
103 }, {
104 .name = "adc",
105 .id = -1,
106 .parent = &clk_p,
107 .enable = s3c2410_clkcon_enable,
108 .ctrlbit = S3C2410_CLKCON_ADC,
109 }, {
110 .name = "i2c",
111 .id = -1,
112 .parent = &clk_p,
113 .enable = s3c2410_clkcon_enable,
114 .ctrlbit = S3C2410_CLKCON_IIC,
115 }, {
116 .name = "iis",
117 .id = -1,
118 .parent = &clk_p,
119 .enable = s3c2410_clkcon_enable,
120 .ctrlbit = S3C2410_CLKCON_IIS,
121 }, {
122 .name = "spi",
123 .id = -1,
124 .parent = &clk_p,
125 .enable = s3c2410_clkcon_enable,
126 .ctrlbit = S3C2410_CLKCON_SPI,
127 }
128};
129
130static struct clk init_clocks[] = {
131 {
132 .name = "lcd",
133 .id = -1,
134 .parent = &clk_h,
135 .enable = s3c2410_clkcon_enable,
136 .ctrlbit = S3C2410_CLKCON_LCDC,
137 }, {
138 .name = "gpio",
139 .id = -1,
140 .parent = &clk_p,
141 .enable = s3c2410_clkcon_enable,
142 .ctrlbit = S3C2410_CLKCON_GPIO,
143 }, {
144 .name = "usb-host",
145 .id = -1,
146 .parent = &clk_h,
147 .enable = s3c2410_clkcon_enable,
148 .ctrlbit = S3C2410_CLKCON_USBH,
149 }, {
150 .name = "usb-device",
151 .id = -1,
152 .parent = &clk_h,
153 .enable = s3c2410_clkcon_enable,
154 .ctrlbit = S3C2410_CLKCON_USBD,
155 }, {
156 .name = "timers",
157 .id = -1,
158 .parent = &clk_p,
159 .enable = s3c2410_clkcon_enable,
160 .ctrlbit = S3C2410_CLKCON_PWMT,
161 }, {
162 .name = "uart",
163 .id = 0,
164 .parent = &clk_p,
165 .enable = s3c2410_clkcon_enable,
166 .ctrlbit = S3C2410_CLKCON_UART0,
167 }, {
168 .name = "uart",
169 .id = 1,
170 .parent = &clk_p,
171 .enable = s3c2410_clkcon_enable,
172 .ctrlbit = S3C2410_CLKCON_UART1,
173 }, {
174 .name = "uart",
175 .id = 2,
176 .parent = &clk_p,
177 .enable = s3c2410_clkcon_enable,
178 .ctrlbit = S3C2410_CLKCON_UART2,
179 }, {
180 .name = "rtc",
181 .id = -1,
182 .parent = &clk_p,
183 .enable = s3c2410_clkcon_enable,
184 .ctrlbit = S3C2410_CLKCON_RTC,
185 }, {
186 .name = "watchdog",
187 .id = -1,
188 .parent = &clk_p,
189 .ctrlbit = 0,
190 }, {
191 .name = "usb-bus-host",
192 .id = -1,
193 .parent = &clk_usb_bus,
194 }, {
195 .name = "usb-bus-gadget",
196 .id = -1,
197 .parent = &clk_usb_bus,
198 },
199};
200
201/* s3c2410_baseclk_add()
202 *
203 * Add all the clocks used by the s3c2410 or compatible CPUs
204 * such as the S3C2440 and S3C2442.
205 *
206 * We cannot use a system device as we are needed before any
207 * of the init-calls that initialise the devices are actually
208 * done.
209*/
210
211int __init s3c2410_baseclk_add(void)
212{
213 unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
214 unsigned long clkcon = __raw_readl(S3C2410_CLKCON);
215 struct clk *clkp;
216 struct clk *xtal;
217 int ret;
218 int ptr;
219
220 clk_upll.enable = s3c2410_upll_enable;
221
222 if (s3c24xx_register_clock(&clk_usb_bus) < 0)
223 printk(KERN_ERR "failed to register usb bus clock\n");
224
225 /* register clocks from clock array */
226
227 clkp = init_clocks;
228 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
229 /* ensure that we note the clock state */
230
231 clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0;
232
233 ret = s3c24xx_register_clock(clkp);
234 if (ret < 0) {
235 printk(KERN_ERR "Failed to register clock %s (%d)\n",
236 clkp->name, ret);
237 }
238 }
239
240 /* We must be careful disabling the clocks we are not intending to
241 * be using at boot time, as subsytems such as the LCD which do
242 * their own DMA requests to the bus can cause the system to lockup
243 * if they where in the middle of requesting bus access.
244 *
245 * Disabling the LCD clock if the LCD is active is very dangerous,
246 * and therefore the bootloader should be careful to not enable
247 * the LCD clock if it is not needed.
248 */
249
250 /* install (and disable) the clocks we do not need immediately */
251
252 clkp = init_clocks_disable;
253 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
254
255 ret = s3c24xx_register_clock(clkp);
256 if (ret < 0) {
257 printk(KERN_ERR "Failed to register clock %s (%d)\n",
258 clkp->name, ret);
259 }
260
261 s3c2410_clkcon_enable(clkp, 0);
262 }
263
264 /* show the clock-slow value */
265
266 xtal = clk_get(NULL, "xtal");
267
268 printk("CLOCK: Slow mode (%ld.%ld MHz), %s, MPLL %s, UPLL %s\n",
269 print_mhz(clk_get_rate(xtal) /
270 ( 2 * S3C2410_CLKSLOW_GET_SLOWVAL(clkslow))),
271 (clkslow & S3C2410_CLKSLOW_SLOW) ? "slow" : "fast",
272 (clkslow & S3C2410_CLKSLOW_MPLL_OFF) ? "off" : "on",
273 (clkslow & S3C2410_CLKSLOW_UCLK_OFF) ? "off" : "on");
274
275 return 0;
276}
diff --git a/arch/arm/mach-s3c2410/s3c2410-dma.c b/arch/arm/mach-s3c2410/s3c2410-dma.c
deleted file mode 100644
index e67ba3911f11..000000000000
--- a/arch/arm/mach-s3c2410/s3c2410-dma.c
+++ /dev/null
@@ -1,161 +0,0 @@
1/* linux/arch/arm/mach-s3c2410/s3c2410-dma.c
2 *
3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * S3C2410 DMA selection
7 *
8 * http://armlinux.simtec.co.uk/
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13*/
14
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/sysdev.h>
18#include <linux/serial_core.h>
19
20#include <asm/dma.h>
21#include <asm/arch/dma.h>
22#include "dma.h"
23
24#include "cpu.h"
25
26#include <asm/arch/regs-serial.h>
27#include <asm/arch/regs-gpio.h>
28#include <asm/arch/regs-ac97.h>
29#include <asm/arch/regs-mem.h>
30#include <asm/arch/regs-lcd.h>
31#include <asm/arch/regs-sdi.h>
32#include <asm/arch/regs-iis.h>
33#include <asm/arch/regs-spi.h>
34
35static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = {
36 [DMACH_XD0] = {
37 .name = "xdreq0",
38 .channels[0] = S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID,
39 },
40 [DMACH_XD1] = {
41 .name = "xdreq1",
42 .channels[1] = S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID,
43 },
44 [DMACH_SDI] = {
45 .name = "sdi",
46 .channels[0] = S3C2410_DCON_CH0_SDI | DMA_CH_VALID,
47 .channels[2] = S3C2410_DCON_CH2_SDI | DMA_CH_VALID,
48 .channels[3] = S3C2410_DCON_CH3_SDI | DMA_CH_VALID,
49 .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
50 .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
51 },
52 [DMACH_SPI0] = {
53 .name = "spi0",
54 .channels[1] = S3C2410_DCON_CH1_SPI | DMA_CH_VALID,
55 .hw_addr.to = S3C2410_PA_SPI + S3C2410_SPTDAT,
56 .hw_addr.from = S3C2410_PA_SPI + S3C2410_SPRDAT,
57 },
58 [DMACH_SPI1] = {
59 .name = "spi1",
60 .channels[3] = S3C2410_DCON_CH3_SPI | DMA_CH_VALID,
61 .hw_addr.to = S3C2410_PA_SPI + 0x20 + S3C2410_SPTDAT,
62 .hw_addr.from = S3C2410_PA_SPI + 0x20 + S3C2410_SPRDAT,
63 },
64 [DMACH_UART0] = {
65 .name = "uart0",
66 .channels[0] = S3C2410_DCON_CH0_UART0 | DMA_CH_VALID,
67 .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH,
68 .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH,
69 },
70 [DMACH_UART1] = {
71 .name = "uart1",
72 .channels[1] = S3C2410_DCON_CH1_UART1 | DMA_CH_VALID,
73 .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH,
74 .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH,
75 },
76 [DMACH_UART2] = {
77 .name = "uart2",
78 .channels[3] = S3C2410_DCON_CH3_UART2 | DMA_CH_VALID,
79 .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH,
80 .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH,
81 },
82 [DMACH_TIMER] = {
83 .name = "timer",
84 .channels[0] = S3C2410_DCON_CH0_TIMER | DMA_CH_VALID,
85 .channels[2] = S3C2410_DCON_CH2_TIMER | DMA_CH_VALID,
86 .channels[3] = S3C2410_DCON_CH3_TIMER | DMA_CH_VALID,
87 },
88 [DMACH_I2S_IN] = {
89 .name = "i2s-sdi",
90 .channels[1] = S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID,
91 .channels[2] = S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID,
92 .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
93 },
94 [DMACH_I2S_OUT] = {
95 .name = "i2s-sdo",
96 .channels[2] = S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID,
97 .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
98 },
99 [DMACH_USB_EP1] = {
100 .name = "usb-ep1",
101 .channels[0] = S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID,
102 },
103 [DMACH_USB_EP2] = {
104 .name = "usb-ep2",
105 .channels[1] = S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID,
106 },
107 [DMACH_USB_EP3] = {
108 .name = "usb-ep3",
109 .channels[2] = S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID,
110 },
111 [DMACH_USB_EP4] = {
112 .name = "usb-ep4",
113 .channels[3] =S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID,
114 },
115};
116
117static void s3c2410_dma_select(struct s3c2410_dma_chan *chan,
118 struct s3c24xx_dma_map *map)
119{
120 chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID;
121}
122
123static struct s3c24xx_dma_selection __initdata s3c2410_dma_sel = {
124 .select = s3c2410_dma_select,
125 .dcon_mask = 7 << 24,
126 .map = s3c2410_dma_mappings,
127 .map_size = ARRAY_SIZE(s3c2410_dma_mappings),
128};
129
130static int s3c2410_dma_add(struct sys_device *sysdev)
131{
132 return s3c24xx_dma_init_map(&s3c2410_dma_sel);
133}
134
135#if defined(CONFIG_CPU_S3C2410)
136static struct sysdev_driver s3c2410_dma_driver = {
137 .add = s3c2410_dma_add,
138};
139
140static int __init s3c2410_dma_init(void)
141{
142 return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_dma_driver);
143}
144
145arch_initcall(s3c2410_dma_init);
146#endif
147
148#if defined(CONFIG_CPU_S3C2442)
149/* S3C2442 DMA contains the same selection table as the S3C2410 */
150static struct sysdev_driver s3c2442_dma_driver = {
151 .add = s3c2410_dma_add,
152};
153
154static int __init s3c2442_dma_init(void)
155{
156 return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_dma_driver);
157}
158
159arch_initcall(s3c2442_dma_init);
160#endif
161
diff --git a/arch/arm/mach-s3c2410/s3c2410-gpio.c b/arch/arm/mach-s3c2410/s3c2410-gpio.c
deleted file mode 100644
index ec3a276cc3cf..000000000000
--- a/arch/arm/mach-s3c2410/s3c2410-gpio.c
+++ /dev/null
@@ -1,71 +0,0 @@
1/* linux/arch/arm/mach-s3c2410/s3c2410-gpio.c
2 *
3 * Copyright (c) 2004-2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * S3C2410 GPIO support
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include <linux/kernel.h>
24#include <linux/init.h>
25#include <linux/module.h>
26#include <linux/interrupt.h>
27#include <linux/ioport.h>
28
29#include <asm/hardware.h>
30#include <asm/irq.h>
31#include <asm/io.h>
32
33#include <asm/arch/regs-gpio.h>
34
35int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
36 unsigned int config)
37{
38 void __iomem *reg = S3C24XX_EINFLT0;
39 unsigned long flags;
40 unsigned long val;
41
42 if (pin < S3C2410_GPG8 || pin > S3C2410_GPG15)
43 return -1;
44
45 config &= 0xff;
46
47 pin -= S3C2410_GPG8;
48 reg += pin & ~3;
49
50 local_irq_save(flags);
51
52 /* update filter width and clock source */
53
54 val = __raw_readl(reg);
55 val &= ~(0xff << ((pin & 3) * 8));
56 val |= config << ((pin & 3) * 8);
57 __raw_writel(val, reg);
58
59 /* update filter enable */
60
61 val = __raw_readl(S3C24XX_EXTINT2);
62 val &= ~(1 << ((pin * 4) + 3));
63 val |= on << ((pin * 4) + 3);
64 __raw_writel(val, S3C24XX_EXTINT2);
65
66 local_irq_restore(flags);
67
68 return 0;
69}
70
71EXPORT_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 c796c9c76e78..000000000000
--- a/arch/arm/mach-s3c2410/s3c2410-irq.c
+++ /dev/null
@@ -1,48 +0,0 @@
1/* linux/arch/arm/mach-s3c2410/s3c2410-irq.c
2 *
3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20*/
21
22#include <linux/init.h>
23#include <linux/module.h>
24#include <linux/interrupt.h>
25#include <linux/ioport.h>
26#include <linux/ptrace.h>
27#include <linux/sysdev.h>
28
29#include "cpu.h"
30#include "pm.h"
31
32static int s3c2410_irq_add(struct sys_device *sysdev)
33{
34 return 0;
35}
36
37static struct sysdev_driver s3c2410_irq_driver = {
38 .add = s3c2410_irq_add,
39 .suspend = s3c24xx_irq_suspend,
40 .resume = s3c24xx_irq_resume,
41};
42
43static int s3c2410_irq_init(void)
44{
45 return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_irq_driver);
46}
47
48arch_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 8bb6e5e21f59..000000000000
--- a/arch/arm/mach-s3c2410/s3c2410-pm.c
+++ /dev/null
@@ -1,156 +0,0 @@
1/* linux/arch/arm/mach-s3c2410/s3c2410-pm.c
2 *
3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * S3C2410 (and compatible) Power Manager (Suspend-To-RAM) support
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21*/
22
23#include <linux/init.h>
24#include <linux/suspend.h>
25#include <linux/errno.h>
26#include <linux/time.h>
27#include <linux/sysdev.h>
28
29#include <asm/hardware.h>
30#include <asm/io.h>
31
32#include <asm/mach-types.h>
33
34#include <asm/arch/regs-gpio.h>
35#include <asm/arch/h1940.h>
36
37#include "cpu.h"
38#include "pm.h"
39
40#ifdef CONFIG_S3C2410_PM_DEBUG
41extern void pm_dbg(const char *fmt, ...);
42#define DBG(fmt...) pm_dbg(fmt)
43#else
44#define DBG(fmt...) printk(KERN_DEBUG fmt)
45#endif
46
47static void s3c2410_pm_prepare(void)
48{
49 /* ensure at least GSTATUS3 has the resume address */
50
51 __raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C2410_GSTATUS3);
52
53 DBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3));
54 DBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4));
55
56 if (machine_is_h1940()) {
57 void *base = phys_to_virt(H1940_SUSPEND_CHECK);
58 unsigned long ptr;
59 unsigned long calc = 0;
60
61 /* generate check for the bootloader to check on resume */
62
63 for (ptr = 0; ptr < 0x40000; ptr += 0x400)
64 calc += __raw_readl(base+ptr);
65
66 __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM));
67 }
68
69 /* the RX3715 uses similar code and the same H1940 and the
70 * same offsets for resume and checksum pointers */
71
72 if (machine_is_rx3715()) {
73 void *base = phys_to_virt(H1940_SUSPEND_CHECK);
74 unsigned long ptr;
75 unsigned long calc = 0;
76
77 /* generate check for the bootloader to check on resume */
78
79 for (ptr = 0; ptr < 0x40000; ptr += 0x4)
80 calc += __raw_readl(base+ptr);
81
82 __raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM));
83 }
84
85 if ( machine_is_aml_m5900() )
86 s3c2410_gpio_setpin(S3C2410_GPF2, 1);
87
88}
89
90static int s3c2410_pm_resume(struct sys_device *dev)
91{
92 unsigned long tmp;
93
94 /* unset the return-from-sleep flag, to ensure reset */
95
96 tmp = __raw_readl(S3C2410_GSTATUS2);
97 tmp &= S3C2410_GSTATUS2_OFFRESET;
98 __raw_writel(tmp, S3C2410_GSTATUS2);
99
100 if ( machine_is_aml_m5900() )
101 s3c2410_gpio_setpin(S3C2410_GPF2, 0);
102
103 return 0;
104}
105
106static int s3c2410_pm_add(struct sys_device *dev)
107{
108 pm_cpu_prep = s3c2410_pm_prepare;
109 pm_cpu_sleep = s3c2410_cpu_suspend;
110
111 return 0;
112}
113
114#if defined(CONFIG_CPU_S3C2410)
115static struct sysdev_driver s3c2410_pm_driver = {
116 .add = s3c2410_pm_add,
117 .resume = s3c2410_pm_resume,
118};
119
120/* register ourselves */
121
122static int __init s3c2410_pm_drvinit(void)
123{
124 return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_pm_driver);
125}
126
127arch_initcall(s3c2410_pm_drvinit);
128#endif
129
130#if defined(CONFIG_CPU_S3C2440)
131static struct sysdev_driver s3c2440_pm_driver = {
132 .add = s3c2410_pm_add,
133 .resume = s3c2410_pm_resume,
134};
135
136static int __init s3c2440_pm_drvinit(void)
137{
138 return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_pm_driver);
139}
140
141arch_initcall(s3c2440_pm_drvinit);
142#endif
143
144#if defined(CONFIG_CPU_S3C2442)
145static struct sysdev_driver s3c2442_pm_driver = {
146 .add = s3c2410_pm_add,
147 .resume = s3c2410_pm_resume,
148};
149
150static int __init s3c2442_pm_drvinit(void)
151{
152 return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_pm_driver);
153}
154
155arch_initcall(s3c2442_pm_drvinit);
156#endif
diff --git a/arch/arm/mach-s3c2410/s3c2410-sleep.S b/arch/arm/mach-s3c2410/s3c2410-sleep.S
deleted file mode 100644
index 9179a1024588..000000000000
--- a/arch/arm/mach-s3c2410/s3c2410-sleep.S
+++ /dev/null
@@ -1,68 +0,0 @@
1/* linux/arch/arm/mach-s3c2410/s3c2410-sleep.S
2 *
3 * Copyright (c) 2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * S3C2410 Power Manager (Suspend-To-RAM) support
7 *
8 * Based on PXA/SA1100 sleep code by:
9 * Nicolas Pitre, (c) 2002 Monta Vista Software Inc
10 * Cliff Brake, (c) 2001
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25*/
26
27#include <linux/linkage.h>
28#include <asm/assembler.h>
29#include <asm/hardware.h>
30#include <asm/arch/map.h>
31
32#include <asm/arch/regs-gpio.h>
33#include <asm/arch/regs-clock.h>
34#include <asm/arch/regs-mem.h>
35#include <asm/arch/regs-serial.h>
36
37 /* s3c2410_cpu_suspend
38 *
39 * put the cpu into sleep mode
40 */
41
42ENTRY(s3c2410_cpu_suspend)
43 @@ prepare cpu to sleep
44
45 ldr r4, =S3C2410_REFRESH
46 ldr r5, =S3C24XX_MISCCR
47 ldr r6, =S3C2410_CLKCON
48 ldr r7, [ r4 ] @ get REFRESH (and ensure in TLB)
49 ldr r8, [ r5 ] @ get MISCCR (and ensure in TLB)
50 ldr r9, [ r6 ] @ get CLKCON (and ensure in TLB)
51
52 orr r7, r7, #S3C2410_REFRESH_SELF @ SDRAM sleep command
53 orr r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals
54 orr r9, r9, #S3C2410_CLKCON_POWER @ power down command
55
56 teq pc, #0 @ first as a trial-run to load cache
57 bl s3c2410_do_sleep
58 teq r0, r0 @ now do it for real
59 b s3c2410_do_sleep @
60
61 @@ align next bit of code to cache line
62 .align 8
63s3c2410_do_sleep:
64 streq r7, [ r4 ] @ SDRAM sleep command
65 streq r8, [ r5 ] @ SDRAM power-down config
66 streq r9, [ r6 ] @ CPU sleep
671: beq 1b
68 mov pc, r14
diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c
index 4cdc0d70c19f..d96fdcf2d2e3 100644
--- a/arch/arm/mach-s3c2410/s3c2410.c
+++ b/arch/arm/mach-s3c2410/s3c2410.c
@@ -31,10 +31,10 @@
31#include <asm/arch/regs-clock.h> 31#include <asm/arch/regs-clock.h>
32#include <asm/arch/regs-serial.h> 32#include <asm/arch/regs-serial.h>
33 33
34#include "s3c2410.h" 34#include <asm/plat-s3c24xx/s3c2410.h>
35#include "cpu.h" 35#include <asm/plat-s3c24xx/cpu.h>
36#include "devs.h" 36#include <asm/plat-s3c24xx/devs.h>
37#include "clock.h" 37#include <asm/plat-s3c24xx/clock.h>
38 38
39/* Initial IO mappings */ 39/* Initial IO mappings */
40 40
diff --git a/arch/arm/mach-s3c2410/sleep.S b/arch/arm/mach-s3c2410/sleep.S
index 2018c2e1dcc5..9179a1024588 100644
--- a/arch/arm/mach-s3c2410/sleep.S
+++ b/arch/arm/mach-s3c2410/sleep.S
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/sleep.S 1/* linux/arch/arm/mach-s3c2410/s3c2410-sleep.S
2 * 2 *
3 * Copyright (c) 2004 Simtec Electronics 3 * Copyright (c) 2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
@@ -34,126 +34,35 @@
34#include <asm/arch/regs-mem.h> 34#include <asm/arch/regs-mem.h>
35#include <asm/arch/regs-serial.h> 35#include <asm/arch/regs-serial.h>
36 36
37/* CONFIG_DEBUG_RESUME is dangerous if your bootloader does not 37 /* s3c2410_cpu_suspend
38 * reset the UART configuration, only enable if you really need this!
39*/
40//#define CONFIG_DEBUG_RESUME
41
42 .text
43
44 /* s3c2410_cpu_save
45 *
46 * save enough of the CPU state to allow us to re-start
47 * pm.c code. as we store items like the sp/lr, we will
48 * end up returning from this function when the cpu resumes
49 * so the return value is set to mark this.
50 *
51 * This arangement means we avoid having to flush the cache
52 * from this code.
53 *
54 * entry:
55 * r0 = pointer to save block
56 *
57 * exit:
58 * r0 = 0 => we stored everything
59 * 1 => resumed from sleep
60 */
61
62ENTRY(s3c2410_cpu_save)
63 stmfd sp!, { r4 - r12, lr }
64
65 @@ store co-processor registers
66
67 mrc p15, 0, r4, c15, c1, 0 @ CP access register
68 mrc p15, 0, r5, c13, c0, 0 @ PID
69 mrc p15, 0, r6, c3, c0, 0 @ Domain ID
70 mrc p15, 0, r7, c2, c0, 0 @ translation table base address
71 mrc p15, 0, r8, c1, c0, 0 @ control register
72
73 stmia r0, { r4 - r13 }
74
75 mov r0, #0
76 ldmfd sp, { r4 - r12, pc }
77
78 @@ return to the caller, after having the MMU
79 @@ turned on, this restores the last bits from the
80 @@ stack
81resume_with_mmu:
82 mov r0, #1
83 ldmfd sp!, { r4 - r12, pc }
84
85 .ltorg
86
87 @@ the next bits sit in the .data segment, even though they
88 @@ happen to be code... the s3c2410_sleep_save_phys needs to be
89 @@ accessed by the resume code before it can restore the MMU.
90 @@ This means that the variable has to be close enough for the
91 @@ code to read it... since the .text segment needs to be RO,
92 @@ the data segment can be the only place to put this code.
93
94 .data
95
96 .global s3c2410_sleep_save_phys
97s3c2410_sleep_save_phys:
98 .word 0
99
100 /* s3c2410_cpu_resume
101 * 38 *
102 * resume code entry for bootloader to call 39 * put the cpu into sleep mode
103 *
104 * we must put this code here in the data segment as we have no
105 * other way of restoring the stack pointer after sleep, and we
106 * must not write to the code segment (code is read-only)
107 */ 40 */
108 41
109ENTRY(s3c2410_cpu_resume) 42ENTRY(s3c2410_cpu_suspend)
110 mov r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE 43 @@ prepare cpu to sleep
111 msr cpsr_c, r0 44
112 45 ldr r4, =S3C2410_REFRESH
113 @@ load UART to allow us to print the two characters for 46 ldr r5, =S3C24XX_MISCCR
114 @@ resume debug 47 ldr r6, =S3C2410_CLKCON
115 48 ldr r7, [ r4 ] @ get REFRESH (and ensure in TLB)
116 mov r2, #S3C24XX_PA_UART & 0xff000000 49 ldr r8, [ r5 ] @ get MISCCR (and ensure in TLB)
117 orr r2, r2, #S3C24XX_PA_UART & 0xff000 50 ldr r9, [ r6 ] @ get CLKCON (and ensure in TLB)
118 51
119#if 0 52 orr r7, r7, #S3C2410_REFRESH_SELF @ SDRAM sleep command
120 /* SMDK2440 LED set */ 53 orr r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals
121 mov r14, #S3C24XX_PA_GPIO 54 orr r9, r9, #S3C2410_CLKCON_POWER @ power down command
122 ldr r12, [ r14, #0x54 ] 55
123 bic r12, r12, #3<<4 56 teq pc, #0 @ first as a trial-run to load cache
124 orr r12, r12, #1<<7 57 bl s3c2410_do_sleep
125 str r12, [ r14, #0x54 ] 58 teq r0, r0 @ now do it for real
126#endif 59 b s3c2410_do_sleep @
127 60
128#ifdef CONFIG_DEBUG_RESUME 61 @@ align next bit of code to cache line
129 mov r3, #'L' 62 .align 8
130 strb r3, [ r2, #S3C2410_UTXH ] 63s3c2410_do_sleep:
1311001: 64 streq r7, [ r4 ] @ SDRAM sleep command
132 ldrb r14, [ r3, #S3C2410_UTRSTAT ] 65 streq r8, [ r5 ] @ SDRAM power-down config
133 tst r14, #S3C2410_UTRSTAT_TXE 66 streq r9, [ r6 ] @ CPU sleep
134 beq 1001b 671: beq 1b
135#endif /* CONFIG_DEBUG_RESUME */ 68 mov pc, r14
136
137 mov r1, #0
138 mcr p15, 0, r1, c8, c7, 0 @@ invalidate I & D TLBs
139 mcr p15, 0, r1, c7, c7, 0 @@ invalidate I & D caches
140
141 ldr r0, s3c2410_sleep_save_phys @ address of restore block
142 ldmia r0, { r4 - r13 }
143
144 mcr p15, 0, r4, c15, c1, 0 @ CP access register
145 mcr p15, 0, r5, c13, c0, 0 @ PID
146 mcr p15, 0, r6, c3, c0, 0 @ Domain ID
147 mcr p15, 0, r7, c2, c0, 0 @ translation table base
148
149#ifdef CONFIG_DEBUG_RESUME
150 mov r3, #'R'
151 strb r3, [ r2, #S3C2410_UTXH ]
152#endif
153
154 ldr r2, =resume_with_mmu
155 mcr p15, 0, r8, c1, c0, 0 @ turn on MMU, etc
156 nop @ second-to-last before mmu
157 mov pc, r2 @ go back to virtual address
158
159 .ltorg
diff --git a/arch/arm/mach-s3c2410/usb-simtec.c b/arch/arm/mach-s3c2410/usb-simtec.c
index 22b0e1cdd4bf..bcd562ac1d3d 100644
--- a/arch/arm/mach-s3c2410/usb-simtec.c
+++ b/arch/arm/mach-s3c2410/usb-simtec.c
@@ -35,7 +35,7 @@
35#include <asm/io.h> 35#include <asm/io.h>
36#include <asm/irq.h> 36#include <asm/irq.h>
37 37
38#include "devs.h" 38#include <asm/plat-s3c24xx/devs.h>
39#include "usb-simtec.h" 39#include "usb-simtec.h"
40 40
41/* control power and monitor over-current events on various Simtec 41/* 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 000000000000..6d629de84cdb
--- /dev/null
+++ b/arch/arm/mach-s3c2412/Kconfig
@@ -0,0 +1,58 @@
1# arch/arm/mach-s3c2412/Kconfig
2#
3# Copyright 2007 Simtec Electronics
4#
5# Licensed under GPLv2
6
7config CPU_S3C2412
8 bool
9 depends on ARCH_S3C2410
10 select S3C2412_PM if PM
11 select S3C2412_DMA if S3C2410_DMA
12 help
13 Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line
14
15config CPU_S3C2412_ONLY
16 bool
17 depends on ARCH_S3C2410 && !CPU_S3C2400 && !CPU_S3C2410 && \
18 !CPU_S3C2440 && !CPU_S3C2442 && CPU_S3C2412
19 default y if CPU_S3C2412
20
21config S3C2412_DMA
22 bool
23 depends on CPU_S3C2412
24 help
25 Internal config node for S3C2412 DMA support
26
27config S3C2412_PM
28 bool
29 help
30 Internal config node to apply S3C2412 power management
31
32
33menu "S3C2412 Machines"
34
35config MACH_SMDK2413
36 bool "SMDK2413"
37 select CPU_S3C2412
38 select MACH_S3C2413
39 select MACH_SMDK
40 help
41 Say Y here if you are using an SMDK2413
42
43config MACH_S3C2413
44 bool
45 help
46 Internal node for S3C2413 version of SMDK2413, so that
47 machine_is_s3c2413() will work when MACH_SMDK2413 is
48 selected
49
50config MACH_VSTMS
51 bool "VMSTMS"
52 select CPU_S3C2412
53 help
54 Say Y here if you are using an VSTMS board
55
56
57endmenu
58
diff --git a/arch/arm/mach-s3c2412/Makefile b/arch/arm/mach-s3c2412/Makefile
new file mode 100644
index 000000000000..f8e011691b31
--- /dev/null
+++ b/arch/arm/mach-s3c2412/Makefile
@@ -0,0 +1,21 @@
1# arch/arm/mach-s3c2412/Makefile
2#
3# Copyright 2007 Simtec Electronics
4#
5# Licensed under GPLv2
6
7obj-y :=
8obj-m :=
9obj-n :=
10obj- :=
11
12obj-$(CONFIG_CPU_S3C2412) += s3c2412.o
13obj-$(CONFIG_CPU_S3C2412) += irq.o
14obj-$(CONFIG_CPU_S3C2412) += clock.o
15obj-$(CONFIG_S3C2412_DMA) += dma.o
16obj-$(CONFIG_S3C2412_PM) += pm.o
17
18# Machine support
19
20obj-$(CONFIG_MACH_SMDK2413) += mach-smdk2413.o
21obj-$(CONFIG_MACH_VSTMS) += mach-vstms.o
diff --git a/arch/arm/mach-s3c2410/s3c2412-clock.c b/arch/arm/mach-s3c2412/clock.c
index 8f94ad83901d..6a8e4448770b 100644
--- a/arch/arm/mach-s3c2410/s3c2412-clock.c
+++ b/arch/arm/mach-s3c2412/clock.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/s3c2412-clock.c 1/* linux/arch/arm/mach-s3c2412/clock.c
2 * 2 *
3 * Copyright (c) 2006 Simtec Electronics 3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
@@ -41,9 +41,9 @@
41#include <asm/arch/regs-clock.h> 41#include <asm/arch/regs-clock.h>
42#include <asm/arch/regs-gpio.h> 42#include <asm/arch/regs-gpio.h>
43 43
44#include "s3c2412.h" 44#include <asm/plat-s3c24xx/s3c2412.h>
45#include "clock.h" 45#include <asm/plat-s3c24xx/clock.h>
46#include "cpu.h" 46#include <asm/plat-s3c24xx/cpu.h>
47 47
48/* We currently have to assume that the system is running 48/* We currently have to assume that the system is running
49 * from the XTPll input, and that all ***REFCLKs are being 49 * 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 138f726ac6bf..28b598287fae 100644
--- a/arch/arm/mach-s3c2410/s3c2412-dma.c
+++ b/arch/arm/mach-s3c2412/dma.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/s3c2412-dma.c 1/* linux/arch/arm/mach-s3c2412/dma.c
2 * 2 *
3 * Copyright (c) 2006 Simtec Electronics 3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
@@ -21,8 +21,8 @@
21#include <asm/arch/dma.h> 21#include <asm/arch/dma.h>
22#include <asm/io.h> 22#include <asm/io.h>
23 23
24#include "dma.h" 24#include <asm/plat-s3c24xx/dma.h>
25#include "cpu.h" 25#include <asm/plat-s3c24xx/cpu.h>
26 26
27#include <asm/arch/regs-serial.h> 27#include <asm/arch/regs-serial.h>
28#include <asm/arch/regs-gpio.h> 28#include <asm/arch/regs-gpio.h>
diff --git a/arch/arm/mach-s3c2410/s3c2412-irq.c b/arch/arm/mach-s3c2412/irq.c
index ffcc30b23a80..e89dbdcb1b7b 100644
--- a/arch/arm/mach-s3c2410/s3c2412-irq.c
+++ b/arch/arm/mach-s3c2412/irq.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2412/s3c2412-irq.c 1/* linux/arch/arm/mach-s3c2412/irq.c
2 * 2 *
3 * Copyright (c) 2006 Simtec Electronics 3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
@@ -35,9 +35,9 @@
35#include <asm/arch/regs-irq.h> 35#include <asm/arch/regs-irq.h>
36#include <asm/arch/regs-gpio.h> 36#include <asm/arch/regs-gpio.h>
37 37
38#include "cpu.h" 38#include <asm/plat-s3c24xx/cpu.h>
39#include "irq.h" 39#include <asm/plat-s3c24xx/irq.h>
40#include "pm.h" 40#include <asm/plat-s3c24xx/pm.h>
41 41
42/* the s3c2412 changes the behaviour of IRQ_EINT0 through IRQ_EINT3 by 42/* the s3c2412 changes the behaviour of IRQ_EINT0 through IRQ_EINT3 by
43 * having them turn up in both the INT* and the EINT* registers. Whilst 43 * 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 4f89abd7a6df..32b15617ef2a 100644
--- a/arch/arm/mach-s3c2410/mach-smdk2413.c
+++ b/arch/arm/mach-s3c2412/mach-smdk2413.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/mach-smdk2413.c 1/* linux/arch/arm/mach-s3c2412/mach-smdk2413.c
2 * 2 *
3 * Copyright (c) 2006 Simtec Electronics 3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
@@ -39,13 +39,13 @@
39#include <asm/arch/idle.h> 39#include <asm/arch/idle.h>
40#include <asm/arch/fb.h> 40#include <asm/arch/fb.h>
41 41
42#include "s3c2410.h" 42#include <asm/plat-s3c24xx/s3c2410.h>
43#include "s3c2412.h" 43#include <asm/plat-s3c24xx/s3c2412.h>
44#include "clock.h" 44#include <asm/plat-s3c24xx/clock.h>
45#include "devs.h" 45#include <asm/plat-s3c24xx/devs.h>
46#include "cpu.h" 46#include <asm/plat-s3c24xx/cpu.h>
47 47
48#include "common-smdk.h" 48#include <asm/plat-s3c24xx/common-smdk.h>
49 49
50static struct map_desc smdk2413_iodesc[] __initdata = { 50static struct map_desc smdk2413_iodesc[] __initdata = {
51}; 51};
diff --git a/arch/arm/mach-s3c2410/mach-vstms.c b/arch/arm/mach-s3c2412/mach-vstms.c
index 0360e1055bcd..f1afb707ff16 100644
--- a/arch/arm/mach-s3c2410/mach-vstms.c
+++ b/arch/arm/mach-s3c2412/mach-vstms.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/mach-vstms.c 1/* linux/arch/arm/mach-s3c2412/mach-vstms.c
2 * 2 *
3 * (C) 2006 Thomas Gleixner <tglx@linutronix.de> 3 * (C) 2006 Thomas Gleixner <tglx@linutronix.de>
4 * 4 *
@@ -43,11 +43,11 @@
43 43
44#include <asm/arch/nand.h> 44#include <asm/arch/nand.h>
45 45
46#include "s3c2410.h" 46#include <asm/plat-s3c24xx/s3c2410.h>
47#include "s3c2412.h" 47#include <asm/plat-s3c24xx/s3c2412.h>
48#include "clock.h" 48#include <asm/plat-s3c24xx/clock.h>
49#include "devs.h" 49#include <asm/plat-s3c24xx/devs.h>
50#include "cpu.h" 50#include <asm/plat-s3c24xx/cpu.h>
51 51
52 52
53static struct map_desc vstms_iodesc[] __initdata = { 53static struct map_desc vstms_iodesc[] __initdata = {
diff --git a/arch/arm/mach-s3c2410/s3c2412-pm.c b/arch/arm/mach-s3c2412/pm.c
index 19b63322d259..8988dac388a9 100644
--- a/arch/arm/mach-s3c2410/s3c2412-pm.c
+++ b/arch/arm/mach-s3c2412/pm.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/s3c2412-pm.c 1/* linux/arch/arm/mach-s3c2412/pm.c
2 * 2 *
3 * Copyright (c) 2006 Simtec Electronics 3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
@@ -28,10 +28,10 @@
28#include <asm/arch/regs-gpio.h> 28#include <asm/arch/regs-gpio.h>
29#include <asm/arch/regs-dsc.h> 29#include <asm/arch/regs-dsc.h>
30 30
31#include "cpu.h" 31#include <asm/plat-s3c24xx/cpu.h>
32#include "pm.h" 32#include <asm/plat-s3c24xx/pm.h>
33 33
34#include "s3c2412.h" 34#include <asm/plat-s3c24xx/s3c2412.h>
35 35
36static void s3c2412_cpu_suspend(void) 36static void s3c2412_cpu_suspend(void)
37{ 37{
diff --git a/arch/arm/mach-s3c2410/s3c2412.c b/arch/arm/mach-s3c2412/s3c2412.c
index 2f651a811ecd..aafe0bc593f1 100644
--- a/arch/arm/mach-s3c2410/s3c2412.c
+++ b/arch/arm/mach-s3c2412/s3c2412.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/s3c2412.c 1/* linux/arch/arm/mach-s3c2412/s3c2412.c
2 * 2 *
3 * Copyright (c) 2006 Simtec Electronics 3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
@@ -38,11 +38,11 @@
38#include <asm/arch/regs-gpioj.h> 38#include <asm/arch/regs-gpioj.h>
39#include <asm/arch/regs-dsc.h> 39#include <asm/arch/regs-dsc.h>
40 40
41#include "s3c2412.h" 41#include <asm/plat-s3c24xx/s3c2412.h>
42#include "cpu.h" 42#include <asm/plat-s3c24xx/cpu.h>
43#include "devs.h" 43#include <asm/plat-s3c24xx/devs.h>
44#include "clock.h" 44#include <asm/plat-s3c24xx/clock.h>
45#include "pm.h" 45#include <asm/plat-s3c24xx/pm.h>
46 46
47#ifndef CONFIG_CPU_S3C2412_ONLY 47#ifndef CONFIG_CPU_S3C2412_ONLY
48void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO; 48void __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 000000000000..e3bfda098c0f
--- /dev/null
+++ b/arch/arm/mach-s3c2440/Kconfig
@@ -0,0 +1,71 @@
1# arch/arm/mach-s3c2440/Kconfig
2#
3# Copyright 2007 Simtec Electronics
4#
5# Licensed under GPLv2
6
7config CPU_S3C2440
8 bool
9 depends on ARCH_S3C2410
10 select S3C2410_CLOCK
11 select S3C2410_PM if PM
12 select S3C2410_GPIO
13 select S3C2440_DMA if S3C2410_DMA
14 select CPU_S3C244X
15 help
16 Support for S3C2440 Samsung Mobile CPU based systems.
17
18config S3C2440_DMA
19 bool
20 depends on ARCH_S3C2410 && CPU_S3C24405B
21 help
22 Support for S3C2440 specific DMA code5A
23
24
25menu "S3C2440 Machines"
26
27config MACH_ANUBIS
28 bool "Simtec Electronics ANUBIS"
29 select CPU_S3C2440
30 select PM_SIMTEC if PM
31 help
32 Say Y here if you are using the Simtec Electronics ANUBIS
33 development system
34
35config MACH_OSIRIS
36 bool "Simtec IM2440D20 (OSIRIS) module"
37 select CPU_S3C2440
38 select PM_SIMTEC if PM
39 help
40 Say Y here if you are using the Simtec IM2440D20 module, also
41 known as the Osiris.
42
43config MACH_RX3715
44 bool "HP iPAQ rx3715"
45 select CPU_S3C2440
46 select PM_H1940 if PM
47 help
48 Say Y here if you are using the HP iPAQ rx3715.
49
50config ARCH_S3C2440
51 bool "SMDK2440"
52 select CPU_S3C2440
53 select MACH_SMDK
54 help
55 Say Y here if you are using the SMDK2440.
56
57config MACH_NEXCODER_2440
58 bool "NexVision NEXCODER 2440 Light Board"
59 select CPU_S3C2440
60 help
61 Say Y here if you are using the Nex Vision NEXCODER 2440 Light Board
62
63config SMDK2440_CPU2440
64 bool "SMDK2440 with S3C2440 CPU module"
65 depends on ARCH_S3C2440
66 default y if ARCH_S3C2440
67 select CPU_S3C2440
68
69
70endmenu
71
diff --git a/arch/arm/mach-s3c2440/Makefile b/arch/arm/mach-s3c2440/Makefile
new file mode 100644
index 000000000000..c81ed6248dcb
--- /dev/null
+++ b/arch/arm/mach-s3c2440/Makefile
@@ -0,0 +1,23 @@
1# arch/arm/mach-s3c2440/Makefile
2#
3# Copyright 2007 Simtec Electronics
4#
5# Licensed under GPLv2
6
7obj-y :=
8obj-m :=
9obj-n :=
10obj- :=
11
12obj-$(CONFIG_CPU_S3C2440) += s3c2440.o dsc.o
13obj-$(CONFIG_CPU_S3C2440) += irq.o
14obj-$(CONFIG_CPU_S3C2440) += clock.o
15obj-$(CONFIG_S3C2440_DMA) += dma.o
16
17# Machine support
18
19obj-$(CONFIG_MACH_ANUBIS) += mach-anubis.o
20obj-$(CONFIG_MACH_OSIRIS) += mach-osiris.o
21obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o
22obj-$(CONFIG_ARCH_S3C2440) += mach-smdk2440.o
23obj-$(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 ba13c1d079d1..79e2ea4adaf3 100644
--- a/arch/arm/mach-s3c2410/s3c2440-clock.c
+++ b/arch/arm/mach-s3c2440/clock.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/s3c2440-clock.c 1/* linux/arch/arm/mach-s3c2440/clock.c
2 * 2 *
3 * Copyright (c) 2004-2005 Simtec Electronics 3 * Copyright (c) 2004-2005 Simtec Electronics
4 * http://armlinux.simtec.co.uk/ 4 * http://armlinux.simtec.co.uk/
@@ -41,8 +41,8 @@
41 41
42#include <asm/arch/regs-clock.h> 42#include <asm/arch/regs-clock.h>
43 43
44#include "clock.h" 44#include <asm/plat-s3c24xx/clock.h>
45#include "cpu.h" 45#include <asm/plat-s3c24xx/cpu.h>
46 46
47/* S3C2440 extended clock support */ 47/* S3C2440 extended clock support */
48 48
diff --git a/arch/arm/mach-s3c2410/s3c2440-dma.c b/arch/arm/mach-s3c2440/dma.c
index 47b861b9443d..8e51137620f2 100644
--- a/arch/arm/mach-s3c2410/s3c2440-dma.c
+++ b/arch/arm/mach-s3c2440/dma.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/s3c2440-dma.c 1/* linux/arch/arm/mach-s3c2440/dma.c
2 * 2 *
3 * Copyright (c) 2006 Simtec Electronics 3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
@@ -19,9 +19,9 @@
19 19
20#include <asm/dma.h> 20#include <asm/dma.h>
21#include <asm/arch/dma.h> 21#include <asm/arch/dma.h>
22#include "dma.h" 22#include <asm/plat-s3c24xx/dma.h>
23 23
24#include "cpu.h" 24#include <asm/plat-s3c24xx/cpu.h>
25 25
26#include <asm/arch/regs-serial.h> 26#include <asm/arch/regs-serial.h>
27#include <asm/arch/regs-gpio.h> 27#include <asm/arch/regs-gpio.h>
diff --git a/arch/arm/mach-s3c2410/s3c2440-dsc.c b/arch/arm/mach-s3c2440/dsc.c
index c92ea66ba45e..2995ff5681bb 100644
--- a/arch/arm/mach-s3c2410/s3c2440-dsc.c
+++ b/arch/arm/mach-s3c2440/dsc.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/s3c2440-dsc.c 1/* linux/arch/arm/mach-s3c2440/dsc.c
2 * 2 *
3 * Copyright (c) 2004-2005 Simtec Electronics 3 * Copyright (c) 2004-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
@@ -27,8 +27,8 @@
27#include <asm/arch/regs-gpio.h> 27#include <asm/arch/regs-gpio.h>
28#include <asm/arch/regs-dsc.h> 28#include <asm/arch/regs-dsc.h>
29 29
30#include "cpu.h" 30#include <asm/plat-s3c24xx/cpu.h>
31#include "s3c2440.h" 31#include <asm/plat-s3c24xx/s3c2440.h>
32 32
33int s3c2440_set_dsc(unsigned int pin, unsigned int value) 33int s3c2440_set_dsc(unsigned int pin, unsigned int value)
34{ 34{
diff --git a/arch/arm/mach-s3c2410/s3c2440-irq.c b/arch/arm/mach-s3c2440/irq.c
index 1ba19b27ab05..1069d13d8c57 100644
--- a/arch/arm/mach-s3c2410/s3c2440-irq.c
+++ b/arch/arm/mach-s3c2440/irq.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/s3c2440-irq.c 1/* linux/arch/arm/mach-s3c2440/irq.c
2 * 2 *
3 * Copyright (c) 2003,2004 Simtec Electronics 3 * Copyright (c) 2003,2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
@@ -35,9 +35,9 @@
35#include <asm/arch/regs-irq.h> 35#include <asm/arch/regs-irq.h>
36#include <asm/arch/regs-gpio.h> 36#include <asm/arch/regs-gpio.h>
37 37
38#include "cpu.h" 38#include <asm/plat-s3c24xx/cpu.h>
39#include "pm.h" 39#include <asm/plat-s3c24xx/pm.h>
40#include "irq.h" 40#include <asm/plat-s3c24xx/irq.h>
41 41
42/* WDT/AC97 */ 42/* WDT/AC97 */
43 43
diff --git a/arch/arm/mach-s3c2410/mach-anubis.c b/arch/arm/mach-s3c2440/mach-anubis.c
index 0fad0c2fe07b..3f0288eb1ed5 100644
--- a/arch/arm/mach-s3c2410/mach-anubis.c
+++ b/arch/arm/mach-s3c2440/mach-anubis.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/mach-anubis.c 1/* linux/arch/arm/mach-s3c2440/mach-anubis.c
2 * 2 *
3 * Copyright (c) 2003-2005 Simtec Electronics 3 * Copyright (c) 2003-2005 Simtec Electronics
4 * http://armlinux.simtec.co.uk/ 4 * http://armlinux.simtec.co.uk/
@@ -42,9 +42,9 @@
42#include <linux/mtd/nand_ecc.h> 42#include <linux/mtd/nand_ecc.h>
43#include <linux/mtd/partitions.h> 43#include <linux/mtd/partitions.h>
44 44
45#include "clock.h" 45#include <asm/plat-s3c24xx/clock.h>
46#include "devs.h" 46#include <asm/plat-s3c24xx/devs.h>
47#include "cpu.h" 47#include <asm/plat-s3c24xx/cpu.h>
48 48
49#define COPYRIGHT ", (c) 2005 Simtec Electronics" 49#define COPYRIGHT ", (c) 2005 Simtec Electronics"
50 50
diff --git a/arch/arm/mach-s3c2410/mach-nexcoder.c b/arch/arm/mach-s3c2440/mach-nexcoder.c
index d6dfdad8c90b..6d551d88330b 100644
--- a/arch/arm/mach-s3c2410/mach-nexcoder.c
+++ b/arch/arm/mach-s3c2440/mach-nexcoder.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/mach-nexcoder.c 1/* linux/arch/arm/mach-s3c2440/mach-nexcoder.c
2 * 2 *
3 * Copyright (c) 2004 Nex Vision 3 * Copyright (c) 2004 Nex Vision
4 * Guillaume GOURAT <guillaume.gourat@nexvision.tv> 4 * Guillaume GOURAT <guillaume.gourat@nexvision.tv>
@@ -38,11 +38,11 @@
38#include <asm/arch/regs-gpio.h> 38#include <asm/arch/regs-gpio.h>
39#include <asm/arch/regs-serial.h> 39#include <asm/arch/regs-serial.h>
40 40
41#include "s3c2410.h" 41#include <asm/plat-s3c24xx/s3c2410.h>
42#include "s3c2440.h" 42#include <asm/plat-s3c24xx/s3c2440.h>
43#include "clock.h" 43#include <asm/plat-s3c24xx/clock.h>
44#include "devs.h" 44#include <asm/plat-s3c24xx/devs.h>
45#include "cpu.h" 45#include <asm/plat-s3c24xx/cpu.h>
46 46
47static struct map_desc nexcoder_iodesc[] __initdata = { 47static struct map_desc nexcoder_iodesc[] __initdata = {
48 /* nothing here yet */ 48 /* nothing here yet */
diff --git a/arch/arm/mach-s3c2410/mach-osiris.c b/arch/arm/mach-s3c2440/mach-osiris.c
index 37b40850c9b9..2ed8e51f20c8 100644
--- a/arch/arm/mach-s3c2410/mach-osiris.c
+++ b/arch/arm/mach-s3c2440/mach-osiris.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/mach-osiris.c 1/* linux/arch/arm/mach-s3c2440/mach-osiris.c
2 * 2 *
3 * Copyright (c) 2005 Simtec Electronics 3 * Copyright (c) 2005 Simtec Electronics
4 * http://armlinux.simtec.co.uk/ 4 * http://armlinux.simtec.co.uk/
@@ -41,9 +41,9 @@
41#include <linux/mtd/nand_ecc.h> 41#include <linux/mtd/nand_ecc.h>
42#include <linux/mtd/partitions.h> 42#include <linux/mtd/partitions.h>
43 43
44#include "clock.h" 44#include <asm/plat-s3c24xx/clock.h>
45#include "devs.h" 45#include <asm/plat-s3c24xx/devs.h>
46#include "cpu.h" 46#include <asm/plat-s3c24xx/cpu.h>
47 47
48/* onboard perihpheral map */ 48/* onboard perihpheral map */
49 49
diff --git a/arch/arm/mach-s3c2410/mach-rx3715.c b/arch/arm/mach-s3c2440/mach-rx3715.c
index ecbcdf79d739..1d4e19bd9206 100644
--- a/arch/arm/mach-s3c2410/mach-rx3715.c
+++ b/arch/arm/mach-s3c2440/mach-rx3715.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/mach-rx3715.c 1/* linux/arch/arm/mach-s3c2440/mach-rx3715.c
2 * 2 *
3 * Copyright (c) 2003,2004 Simtec Electronics 3 * Copyright (c) 2003,2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
@@ -46,10 +46,10 @@
46#include <asm/arch/nand.h> 46#include <asm/arch/nand.h>
47#include <asm/arch/fb.h> 47#include <asm/arch/fb.h>
48 48
49#include "clock.h" 49#include <asm/plat-s3c24xx/clock.h>
50#include "devs.h" 50#include <asm/plat-s3c24xx/devs.h>
51#include "cpu.h" 51#include <asm/plat-s3c24xx/cpu.h>
52#include "pm.h" 52#include <asm/plat-s3c24xx/pm.h>
53 53
54static struct map_desc rx3715_iodesc[] __initdata = { 54static struct map_desc rx3715_iodesc[] __initdata = {
55 /* dump ISA space somewhere unused */ 55 /* dump ISA space somewhere unused */
diff --git a/arch/arm/mach-s3c2410/mach-smdk2440.c b/arch/arm/mach-s3c2440/mach-smdk2440.c
index 2b61f4ed1da4..270e42b9b5c1 100644
--- a/arch/arm/mach-s3c2410/mach-smdk2440.c
+++ b/arch/arm/mach-s3c2440/mach-smdk2440.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/mach-smdk2440.c 1/* linux/arch/arm/mach-s3c2440/mach-smdk2440.c
2 * 2 *
3 * Copyright (c) 2004,2005 Simtec Electronics 3 * Copyright (c) 2004,2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
@@ -40,13 +40,13 @@
40#include <asm/arch/idle.h> 40#include <asm/arch/idle.h>
41#include <asm/arch/fb.h> 41#include <asm/arch/fb.h>
42 42
43#include "s3c2410.h" 43#include <asm/plat-s3c24xx/s3c2410.h>
44#include "s3c2440.h" 44#include <asm/plat-s3c24xx/s3c2440.h>
45#include "clock.h" 45#include <asm/plat-s3c24xx/clock.h>
46#include "devs.h" 46#include <asm/plat-s3c24xx/devs.h>
47#include "cpu.h" 47#include <asm/plat-s3c24xx/cpu.h>
48 48
49#include "common-smdk.h" 49#include <asm/plat-s3c24xx/common-smdk.h>
50 50
51static struct map_desc smdk2440_iodesc[] __initdata = { 51static struct map_desc smdk2440_iodesc[] __initdata = {
52 /* ISA IO Space map (memory space selected by A24) */ 52 /* ISA IO Space map (memory space selected by A24) */
diff --git a/arch/arm/mach-s3c2410/s3c2440.c b/arch/arm/mach-s3c2440/s3c2440.c
index 344eb27cca48..90e1da61fbc3 100644
--- a/arch/arm/mach-s3c2410/s3c2440.c
+++ b/arch/arm/mach-s3c2440/s3c2440.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/s3c2440.c 1/* linux/arch/arm/mach-s3c2440/s3c2440.c
2 * 2 *
3 * Copyright (c) 2004-2006 Simtec Electronics 3 * Copyright (c) 2004-2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
@@ -29,9 +29,9 @@
29#include <asm/io.h> 29#include <asm/io.h>
30#include <asm/irq.h> 30#include <asm/irq.h>
31 31
32#include "s3c2440.h" 32#include <asm/plat-s3c24xx/s3c2440.h>
33#include "devs.h" 33#include <asm/plat-s3c24xx/devs.h>
34#include "cpu.h" 34#include <asm/plat-s3c24xx/cpu.h>
35 35
36static struct sys_device s3c2440_sysdev = { 36static struct sys_device s3c2440_sysdev = {
37 .cls = &s3c2440_sysclass, 37 .cls = &s3c2440_sysclass,
diff --git a/arch/arm/mach-s3c2442/Kconfig b/arch/arm/mach-s3c2442/Kconfig
new file mode 100644
index 000000000000..bf8d87abfab3
--- /dev/null
+++ b/arch/arm/mach-s3c2442/Kconfig
@@ -0,0 +1,27 @@
1# arch/arm/mach-s3c2442/Kconfig
2#
3# Copyright 2007 Simtec Electronics
4#
5# Licensed under GPLv2
6
7config CPU_S3C2442
8 bool
9 depends on ARCH_S3C2420
10 select S3C2410_CLOCK
11 select S3C2410_GPIO
12 select S3C2410_PM if PM
13 select CPU_S3C244X
14 help
15 Support for S3C2442 Samsung Mobile CPU based systems.
16
17
18menu "S3C2442 Machines"
19
20config SMDK2440_CPU2442
21 bool "SMDM2440 with S3C2442 CPU module"
22 depends on ARCH_S3C2440
23 select CPU_S3C2442
24
25
26endmenu
27
diff --git a/arch/arm/mach-s3c2442/Makefile b/arch/arm/mach-s3c2442/Makefile
new file mode 100644
index 000000000000..2a909c6c5798
--- /dev/null
+++ b/arch/arm/mach-s3c2442/Makefile
@@ -0,0 +1,16 @@
1# arch/arm/mach-s3c2442/Makefile
2#
3# Copyright 2007 Simtec Electronics
4#
5# Licensed under GPLv2
6
7obj-y :=
8obj-m :=
9obj-n :=
10obj- :=
11
12obj-$(CONFIG_CPU_S3C2442) += s3c2442.o
13obj-$(CONFIG_CPU_S3C2442) += clock.o
14
15# Machine support
16
diff --git a/arch/arm/mach-s3c2410/s3c2442-clock.c b/arch/arm/mach-s3c2442/clock.c
index 4e292ca7c9be..5b9e830ac4d3 100644
--- a/arch/arm/mach-s3c2410/s3c2442-clock.c
+++ b/arch/arm/mach-s3c2442/clock.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/s3c2442-clock.c 1/* linux/arch/arm/mach-s3c2442/clock.c
2 * 2 *
3 * Copyright (c) 2004-2005 Simtec Electronics 3 * Copyright (c) 2004-2005 Simtec Electronics
4 * http://armlinux.simtec.co.uk/ 4 * http://armlinux.simtec.co.uk/
@@ -41,8 +41,8 @@
41 41
42#include <asm/arch/regs-clock.h> 42#include <asm/arch/regs-clock.h>
43 43
44#include "clock.h" 44#include <asm/plat-s3c24xx/clock.h>
45#include "cpu.h" 45#include <asm/plat-s3c24xx/cpu.h>
46 46
47/* S3C2442 extended clock support */ 47/* S3C2442 extended clock support */
48 48
diff --git a/arch/arm/mach-s3c2410/s3c2442.c b/arch/arm/mach-s3c2442/s3c2442.c
index 428732ee68c4..fbf8264249da 100644
--- a/arch/arm/mach-s3c2410/s3c2442.c
+++ b/arch/arm/mach-s3c2442/s3c2442.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/s3c2442.c 1/* linux/arch/arm/mach-s3c2442/s3c2442.c
2 * 2 *
3 * Copyright (c) 2006 Simtec Electronics 3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
@@ -19,8 +19,8 @@
19#include <linux/serial_core.h> 19#include <linux/serial_core.h>
20#include <linux/sysdev.h> 20#include <linux/sysdev.h>
21 21
22#include "s3c2442.h" 22#include <asm/plat-s3c24xx/s3c2442.h>
23#include "cpu.h" 23#include <asm/plat-s3c24xx/cpu.h>
24 24
25static struct sys_device s3c2442_sysdev = { 25static struct sys_device s3c2442_sysdev = {
26 .cls = &s3c2442_sysclass, 26 .cls = &s3c2442_sysclass,
diff --git a/arch/arm/plat-s3c24xx/Kconfig b/arch/arm/plat-s3c24xx/Kconfig
new file mode 100644
index 000000000000..97813645b5ee
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/Kconfig
@@ -0,0 +1,96 @@
1# arch/arm/plat-s3c24xx/Kconfig
2#
3# Copyright 2007 Simtec Electronics
4#
5# Licensed under GPLv2
6
7config PLAT_S3C24XX
8 bool
9 depends on ARCH_S3C2410
10 default y
11 help
12 Base platform code for any Samsung S3C device
13
14config CPU_S3C244X
15 bool
16 depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442)
17 help
18 Support for S3C2440 and S3C2442 Samsung Mobile CPU based systems.
19
20config PM_SIMTEC
21 bool
22 help
23 Common power management code for systems that are
24 compatible with the Simtec style of power management
25
26config S3C2410_BOOT_WATCHDOG
27 bool "S3C2410 Initialisation watchdog"
28 depends on ARCH_S3C2410 && S3C2410_WATCHDOG
29 help
30 Say y to enable the watchdog during the kernel decompression
31 stage. If the kernel fails to uncompress, then the watchdog
32 will trigger a reset and the system should restart.
33
34config S3C2410_BOOT_ERROR_RESET
35 bool "S3C2410 Reboot on decompression error"
36 depends on ARCH_S3C2410
37 help
38 Say y here to use the watchdog to reset the system if the
39 kernel decompressor detects an error during decompression.
40
41config S3C2410_PM_DEBUG
42 bool "S3C2410 PM Suspend debug"
43 depends on ARCH_S3C2410 && PM
44 help
45 Say Y here if you want verbose debugging from the PM Suspend and
46 Resume code. See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
47 for more information.
48
49config S3C2410_PM_CHECK
50 bool "S3C2410 PM Suspend Memory CRC"
51 depends on ARCH_S3C2410 && PM && CRC32
52 help
53 Enable the PM code's memory area checksum over sleep. This option
54 will generate CRCs of all blocks of memory, and store them before
55 going to sleep. The blocks are then checked on resume for any
56 errors.
57
58config S3C2410_PM_CHECK_CHUNKSIZE
59 int "S3C2410 PM Suspend CRC Chunksize (KiB)"
60 depends on ARCH_S3C2410 && PM && S3C2410_PM_CHECK
61 default 64
62 help
63 Set the chunksize in Kilobytes of the CRC for checking memory
64 corruption over suspend and resume. A smaller value will mean that
65 the CRC data block will take more memory, but wil identify any
66 faults with better precision.
67
68config S3C2410_LOWLEVEL_UART_PORT
69 int "S3C2410 UART to use for low-level messages"
70 default 0
71 help
72 Choice of which UART port to use for the low-level messages,
73 such as the `Uncompressing...` at start time. The value of
74 this configuration should be between zero and two. The port
75 must have been initialised by the boot-loader before use.
76
77config S3C2410_DMA
78 bool "S3C2410 DMA support"
79 depends on ARCH_S3C2410
80 help
81 S3C2410 DMA support. This is needed for drivers like sound which
82 use the S3C2410's DMA system to move data to and from the
83 peripheral blocks.
84
85config S3C2410_DMA_DEBUG
86 bool "S3C2410 DMA support debug"
87 depends on ARCH_S3C2410 && S3C2410_DMA
88 help
89 Enable debugging output for the DMA code. This option sends info
90 to the kernel log, at priority KERN_DEBUG.
91
92config MACH_SMDK
93 bool
94 help
95 Common machine code for SMDK2410 and SMDK2440
96
diff --git a/arch/arm/plat-s3c24xx/Makefile b/arch/arm/plat-s3c24xx/Makefile
new file mode 100644
index 000000000000..8e5ccaa1f03c
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/Makefile
@@ -0,0 +1,30 @@
1# arch/arm/plat-s3c24xx/Makefile
2#
3# Copyright 2007 Simtec Electronics
4#
5# Licensed under GPLv2
6
7obj-y :=
8obj-m :=
9obj-n :=
10obj- :=
11
12
13# Core files
14
15obj-y += cpu.o
16obj-y += irq.o
17obj-y += devs.o
18obj-y += gpio.o
19obj-y += time.o
20obj-y += clock.o
21
22# Architecture dependant builds
23
24obj-$(CONFIG_CPU_S3C244X) += s3c244x.o
25obj-$(CONFIG_CPU_S3C244X) += s3c244x-irq.o
26obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o
27obj-$(CONFIG_PM) += pm.o
28obj-$(CONFIG_PM) += sleep.o
29obj-$(CONFIG_S3C2410_DMA) += dma.o
30obj-$(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 000000000000..d3dc03a7383a
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/clock.c
@@ -0,0 +1,449 @@
1/* linux/arch/arm/plat-s3c24xx/clock.c
2 *
3 * Copyright (c) 2004-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * S3C24XX Core clock control support
7 *
8 * Based on, and code from linux/arch/arm/mach-versatile/clock.c
9 **
10 ** Copyright (C) 2004 ARM Limited.
11 ** Written by Deep Blue Solutions Limited.
12 *
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27*/
28
29#include <linux/init.h>
30#include <linux/module.h>
31#include <linux/kernel.h>
32#include <linux/list.h>
33#include <linux/errno.h>
34#include <linux/err.h>
35#include <linux/platform_device.h>
36#include <linux/sysdev.h>
37#include <linux/interrupt.h>
38#include <linux/ioport.h>
39#include <linux/clk.h>
40#include <linux/mutex.h>
41#include <linux/delay.h>
42
43#include <asm/hardware.h>
44#include <asm/irq.h>
45#include <asm/io.h>
46
47#include <asm/arch/regs-clock.h>
48#include <asm/arch/regs-gpio.h>
49
50#include <asm/plat-s3c24xx/clock.h>
51#include <asm/plat-s3c24xx/cpu.h>
52
53/* clock information */
54
55static LIST_HEAD(clocks);
56
57DEFINE_MUTEX(clocks_mutex);
58
59/* enable and disable calls for use with the clk struct */
60
61static int clk_null_enable(struct clk *clk, int enable)
62{
63 return 0;
64}
65
66/* Clock API calls */
67
68struct clk *clk_get(struct device *dev, const char *id)
69{
70 struct clk *p;
71 struct clk *clk = ERR_PTR(-ENOENT);
72 int idno;
73
74 if (dev == NULL || dev->bus != &platform_bus_type)
75 idno = -1;
76 else
77 idno = to_platform_device(dev)->id;
78
79 mutex_lock(&clocks_mutex);
80
81 list_for_each_entry(p, &clocks, list) {
82 if (p->id == idno &&
83 strcmp(id, p->name) == 0 &&
84 try_module_get(p->owner)) {
85 clk = p;
86 break;
87 }
88 }
89
90 /* check for the case where a device was supplied, but the
91 * clock that was being searched for is not device specific */
92
93 if (IS_ERR(clk)) {
94 list_for_each_entry(p, &clocks, list) {
95 if (p->id == -1 && strcmp(id, p->name) == 0 &&
96 try_module_get(p->owner)) {
97 clk = p;
98 break;
99 }
100 }
101 }
102
103 mutex_unlock(&clocks_mutex);
104 return clk;
105}
106
107void clk_put(struct clk *clk)
108{
109 module_put(clk->owner);
110}
111
112int clk_enable(struct clk *clk)
113{
114 if (IS_ERR(clk) || clk == NULL)
115 return -EINVAL;
116
117 clk_enable(clk->parent);
118
119 mutex_lock(&clocks_mutex);
120
121 if ((clk->usage++) == 0)
122 (clk->enable)(clk, 1);
123
124 mutex_unlock(&clocks_mutex);
125 return 0;
126}
127
128void clk_disable(struct clk *clk)
129{
130 if (IS_ERR(clk) || clk == NULL)
131 return;
132
133 mutex_lock(&clocks_mutex);
134
135 if ((--clk->usage) == 0)
136 (clk->enable)(clk, 0);
137
138 mutex_unlock(&clocks_mutex);
139 clk_disable(clk->parent);
140}
141
142
143unsigned long clk_get_rate(struct clk *clk)
144{
145 if (IS_ERR(clk))
146 return 0;
147
148 if (clk->rate != 0)
149 return clk->rate;
150
151 if (clk->get_rate != NULL)
152 return (clk->get_rate)(clk);
153
154 if (clk->parent != NULL)
155 return clk_get_rate(clk->parent);
156
157 return clk->rate;
158}
159
160long clk_round_rate(struct clk *clk, unsigned long rate)
161{
162 if (!IS_ERR(clk) && clk->round_rate)
163 return (clk->round_rate)(clk, rate);
164
165 return rate;
166}
167
168int clk_set_rate(struct clk *clk, unsigned long rate)
169{
170 int ret;
171
172 if (IS_ERR(clk))
173 return -EINVAL;
174
175 mutex_lock(&clocks_mutex);
176 ret = (clk->set_rate)(clk, rate);
177 mutex_unlock(&clocks_mutex);
178
179 return ret;
180}
181
182struct clk *clk_get_parent(struct clk *clk)
183{
184 return clk->parent;
185}
186
187int clk_set_parent(struct clk *clk, struct clk *parent)
188{
189 int ret = 0;
190
191 if (IS_ERR(clk))
192 return -EINVAL;
193
194 mutex_lock(&clocks_mutex);
195
196 if (clk->set_parent)
197 ret = (clk->set_parent)(clk, parent);
198
199 mutex_unlock(&clocks_mutex);
200
201 return ret;
202}
203
204EXPORT_SYMBOL(clk_get);
205EXPORT_SYMBOL(clk_put);
206EXPORT_SYMBOL(clk_enable);
207EXPORT_SYMBOL(clk_disable);
208EXPORT_SYMBOL(clk_get_rate);
209EXPORT_SYMBOL(clk_round_rate);
210EXPORT_SYMBOL(clk_set_rate);
211EXPORT_SYMBOL(clk_get_parent);
212EXPORT_SYMBOL(clk_set_parent);
213
214/* base clocks */
215
216struct clk clk_xtal = {
217 .name = "xtal",
218 .id = -1,
219 .rate = 0,
220 .parent = NULL,
221 .ctrlbit = 0,
222};
223
224struct clk clk_mpll = {
225 .name = "mpll",
226 .id = -1,
227};
228
229struct clk clk_upll = {
230 .name = "upll",
231 .id = -1,
232 .parent = NULL,
233 .ctrlbit = 0,
234};
235
236struct clk clk_f = {
237 .name = "fclk",
238 .id = -1,
239 .rate = 0,
240 .parent = &clk_mpll,
241 .ctrlbit = 0,
242};
243
244struct clk clk_h = {
245 .name = "hclk",
246 .id = -1,
247 .rate = 0,
248 .parent = NULL,
249 .ctrlbit = 0,
250};
251
252struct clk clk_p = {
253 .name = "pclk",
254 .id = -1,
255 .rate = 0,
256 .parent = NULL,
257 .ctrlbit = 0,
258};
259
260struct clk clk_usb_bus = {
261 .name = "usb-bus",
262 .id = -1,
263 .rate = 0,
264 .parent = &clk_upll,
265};
266
267/* clocks that could be registered by external code */
268
269static int s3c24xx_dclk_enable(struct clk *clk, int enable)
270{
271 unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON);
272
273 if (enable)
274 dclkcon |= clk->ctrlbit;
275 else
276 dclkcon &= ~clk->ctrlbit;
277
278 __raw_writel(dclkcon, S3C24XX_DCLKCON);
279
280 return 0;
281}
282
283static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
284{
285 unsigned long dclkcon;
286 unsigned int uclk;
287
288 if (parent == &clk_upll)
289 uclk = 1;
290 else if (parent == &clk_p)
291 uclk = 0;
292 else
293 return -EINVAL;
294
295 clk->parent = parent;
296
297 dclkcon = __raw_readl(S3C24XX_DCLKCON);
298
299 if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) {
300 if (uclk)
301 dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK;
302 else
303 dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK;
304 } else {
305 if (uclk)
306 dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK;
307 else
308 dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK;
309 }
310
311 __raw_writel(dclkcon, S3C24XX_DCLKCON);
312
313 return 0;
314}
315
316
317static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent)
318{
319 unsigned long mask;
320 unsigned long source;
321
322 /* calculate the MISCCR setting for the clock */
323
324 if (parent == &clk_xtal)
325 source = S3C2410_MISCCR_CLK0_MPLL;
326 else if (parent == &clk_upll)
327 source = S3C2410_MISCCR_CLK0_UPLL;
328 else if (parent == &clk_f)
329 source = S3C2410_MISCCR_CLK0_FCLK;
330 else if (parent == &clk_h)
331 source = S3C2410_MISCCR_CLK0_HCLK;
332 else if (parent == &clk_p)
333 source = S3C2410_MISCCR_CLK0_PCLK;
334 else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0)
335 source = S3C2410_MISCCR_CLK0_DCLK0;
336 else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1)
337 source = S3C2410_MISCCR_CLK0_DCLK0;
338 else
339 return -EINVAL;
340
341 clk->parent = parent;
342
343 if (clk == &s3c24xx_dclk0)
344 mask = S3C2410_MISCCR_CLK0_MASK;
345 else {
346 source <<= 4;
347 mask = S3C2410_MISCCR_CLK1_MASK;
348 }
349
350 s3c2410_modify_misccr(mask, source);
351 return 0;
352}
353
354/* external clock definitions */
355
356struct clk s3c24xx_dclk0 = {
357 .name = "dclk0",
358 .id = -1,
359 .ctrlbit = S3C2410_DCLKCON_DCLK0EN,
360 .enable = s3c24xx_dclk_enable,
361 .set_parent = s3c24xx_dclk_setparent,
362};
363
364struct clk s3c24xx_dclk1 = {
365 .name = "dclk1",
366 .id = -1,
367 .ctrlbit = S3C2410_DCLKCON_DCLK0EN,
368 .enable = s3c24xx_dclk_enable,
369 .set_parent = s3c24xx_dclk_setparent,
370};
371
372struct clk s3c24xx_clkout0 = {
373 .name = "clkout0",
374 .id = -1,
375 .set_parent = s3c24xx_clkout_setparent,
376};
377
378struct clk s3c24xx_clkout1 = {
379 .name = "clkout1",
380 .id = -1,
381 .set_parent = s3c24xx_clkout_setparent,
382};
383
384struct clk s3c24xx_uclk = {
385 .name = "uclk",
386 .id = -1,
387};
388
389/* initialise the clock system */
390
391int s3c24xx_register_clock(struct clk *clk)
392{
393 clk->owner = THIS_MODULE;
394
395 if (clk->enable == NULL)
396 clk->enable = clk_null_enable;
397
398 /* add to the list of available clocks */
399
400 mutex_lock(&clocks_mutex);
401 list_add(&clk->list, &clocks);
402 mutex_unlock(&clocks_mutex);
403
404 return 0;
405}
406
407/* initalise all the clocks */
408
409int __init s3c24xx_setup_clocks(unsigned long xtal,
410 unsigned long fclk,
411 unsigned long hclk,
412 unsigned long pclk)
413{
414 printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n");
415
416 /* initialise the main system clocks */
417
418 clk_xtal.rate = xtal;
419 clk_upll.rate = s3c2410_get_pll(__raw_readl(S3C2410_UPLLCON), xtal);
420
421 clk_mpll.rate = fclk;
422 clk_h.rate = hclk;
423 clk_p.rate = pclk;
424 clk_f.rate = fclk;
425
426 /* assume uart clocks are correctly setup */
427
428 /* register our clocks */
429
430 if (s3c24xx_register_clock(&clk_xtal) < 0)
431 printk(KERN_ERR "failed to register master xtal\n");
432
433 if (s3c24xx_register_clock(&clk_mpll) < 0)
434 printk(KERN_ERR "failed to register mpll clock\n");
435
436 if (s3c24xx_register_clock(&clk_upll) < 0)
437 printk(KERN_ERR "failed to register upll clock\n");
438
439 if (s3c24xx_register_clock(&clk_f) < 0)
440 printk(KERN_ERR "failed to register cpu fclk\n");
441
442 if (s3c24xx_register_clock(&clk_h) < 0)
443 printk(KERN_ERR "failed to register cpu hclk\n");
444
445 if (s3c24xx_register_clock(&clk_p) < 0)
446 printk(KERN_ERR "failed to register cpu pclk\n");
447
448 return 0;
449}
diff --git a/arch/arm/mach-s3c2410/common-smdk.c b/arch/arm/plat-s3c24xx/common-smdk.c
index a40eaa656177..908efa7d745f 100644
--- a/arch/arm/mach-s3c2410/common-smdk.c
+++ b/arch/arm/plat-s3c24xx/common-smdk.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/common-smdk.c 1/* linux/arch/arm/plat-s3c24xx/common-smdk.c
2 * 2 *
3 * Copyright (c) 2006 Simtec Electronics 3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
@@ -38,9 +38,9 @@
38 38
39#include <asm/arch/nand.h> 39#include <asm/arch/nand.h>
40 40
41#include "common-smdk.h" 41#include <asm/plat-s3c24xx/common-smdk.h>
42#include "devs.h" 42#include <asm/plat-s3c24xx/devs.h>
43#include "pm.h" 43#include <asm/plat-s3c24xx/pm.h>
44 44
45/* LED devices */ 45/* LED devices */
46 46
diff --git a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/plat-s3c24xx/cpu.c
index ae1f5bb63f7a..2fbb74969379 100644
--- a/arch/arm/mach-s3c2410/cpu.c
+++ b/arch/arm/plat-s3c24xx/cpu.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/cpu.c 1/* linux/arch/arm/plat-s3c24xx/cpu.c
2 * 2 *
3 * Copyright (c) 2004-2005 Simtec Electronics 3 * Copyright (c) 2004-2005 Simtec Electronics
4 * http://www.simtec.co.uk/products/SWLINUX/ 4 * http://www.simtec.co.uk/products/SWLINUX/
@@ -40,15 +40,15 @@
40#include <asm/arch/regs-gpio.h> 40#include <asm/arch/regs-gpio.h>
41#include <asm/arch/regs-serial.h> 41#include <asm/arch/regs-serial.h>
42 42
43#include "cpu.h" 43#include <asm/plat-s3c24xx/cpu.h>
44#include "devs.h" 44#include <asm/plat-s3c24xx/devs.h>
45#include "clock.h" 45#include <asm/plat-s3c24xx/clock.h>
46#include "s3c2400.h" 46#include <asm/plat-s3c24xx/s3c2400.h>
47#include "s3c2410.h" 47#include <asm/plat-s3c24xx/s3c2410.h>
48#include "s3c2412.h" 48#include <asm/plat-s3c24xx/s3c2412.h>
49#include "s3c244x.h" 49#include "s3c244x.h"
50#include "s3c2440.h" 50#include <asm/plat-s3c24xx/s3c2440.h>
51#include "s3c2442.h" 51#include <asm/plat-s3c24xx/s3c2442.h>
52 52
53struct cpu_table { 53struct cpu_table {
54 unsigned long idcode; 54 unsigned long idcode;
diff --git a/arch/arm/mach-s3c2410/devs.c b/arch/arm/plat-s3c24xx/devs.c
index faccde2092d2..6d46c4e2a4f7 100644
--- a/arch/arm/mach-s3c2410/devs.c
+++ b/arch/arm/plat-s3c24xx/devs.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/devs.c 1/* linux/arch/arm/plat-s3c24xx/devs.c
2 * 2 *
3 * Copyright (c) 2004 Simtec Electronics 3 * Copyright (c) 2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
@@ -30,8 +30,8 @@
30 30
31#include <asm/arch/regs-serial.h> 31#include <asm/arch/regs-serial.h>
32 32
33#include "devs.h" 33#include <asm/plat-s3c24xx/devs.h>
34#include "cpu.h" 34#include <asm/plat-s3c24xx/cpu.h>
35 35
36/* Serial port registrations */ 36/* Serial port registrations */
37 37
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
new file mode 100644
index 000000000000..c784e1f816bb
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/dma.c
@@ -0,0 +1,1441 @@
1/* linux/arch/arm/plat-s3c24xx/dma.c
2 *
3 * Copyright (c) 2003-2005,2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * S3C2410 DMA core
7 *
8 * http://armlinux.simtec.co.uk/
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13*/
14
15
16#ifdef CONFIG_S3C2410_DMA_DEBUG
17#define DEBUG
18#endif
19
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/sched.h>
23#include <linux/spinlock.h>
24#include <linux/interrupt.h>
25#include <linux/sysdev.h>
26#include <linux/slab.h>
27#include <linux/errno.h>
28#include <linux/delay.h>
29
30#include <asm/system.h>
31#include <asm/irq.h>
32#include <asm/hardware.h>
33#include <asm/io.h>
34#include <asm/dma.h>
35
36#include <asm/mach/dma.h>
37#include <asm/arch/map.h>
38
39#include <asm/plat-s3c24xx/dma.h>
40
41/* io map for dma */
42static void __iomem *dma_base;
43static struct kmem_cache *dma_kmem;
44
45struct s3c24xx_dma_selection dma_sel;
46
47/* dma channel state information */
48struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
49
50/* debugging functions */
51
52#define BUF_MAGIC (0xcafebabe)
53
54#define dmawarn(fmt...) printk(KERN_DEBUG fmt)
55
56#define dma_regaddr(chan, reg) ((chan)->regs + (reg))
57
58#if 1
59#define dma_wrreg(chan, reg, val) writel((val), (chan)->regs + (reg))
60#else
61static inline void
62dma_wrreg(struct s3c2410_dma_chan *chan, int reg, unsigned long val)
63{
64 pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg);
65 writel(val, dma_regaddr(chan, reg));
66}
67#endif
68
69#define dma_rdreg(chan, reg) readl((chan)->regs + (reg))
70
71/* captured register state for debug */
72
73struct s3c2410_dma_regstate {
74 unsigned long dcsrc;
75 unsigned long disrc;
76 unsigned long dstat;
77 unsigned long dcon;
78 unsigned long dmsktrig;
79};
80
81#ifdef CONFIG_S3C2410_DMA_DEBUG
82
83/* dmadbg_showregs
84 *
85 * simple debug routine to print the current state of the dma registers
86*/
87
88static void
89dmadbg_capture(struct s3c2410_dma_chan *chan, struct s3c2410_dma_regstate *regs)
90{
91 regs->dcsrc = dma_rdreg(chan, S3C2410_DMA_DCSRC);
92 regs->disrc = dma_rdreg(chan, S3C2410_DMA_DISRC);
93 regs->dstat = dma_rdreg(chan, S3C2410_DMA_DSTAT);
94 regs->dcon = dma_rdreg(chan, S3C2410_DMA_DCON);
95 regs->dmsktrig = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
96}
97
98static void
99dmadbg_dumpregs(const char *fname, int line, struct s3c2410_dma_chan *chan,
100 struct s3c2410_dma_regstate *regs)
101{
102 printk(KERN_DEBUG "dma%d: %s:%d: DCSRC=%08lx, DISRC=%08lx, DSTAT=%08lx DMT=%02lx, DCON=%08lx\n",
103 chan->number, fname, line,
104 regs->dcsrc, regs->disrc, regs->dstat, regs->dmsktrig,
105 regs->dcon);
106}
107
108static void
109dmadbg_showchan(const char *fname, int line, struct s3c2410_dma_chan *chan)
110{
111 struct s3c2410_dma_regstate state;
112
113 dmadbg_capture(chan, &state);
114
115 printk(KERN_DEBUG "dma%d: %s:%d: ls=%d, cur=%p, %p %p\n",
116 chan->number, fname, line, chan->load_state,
117 chan->curr, chan->next, chan->end);
118
119 dmadbg_dumpregs(fname, line, chan, &state);
120}
121
122static void
123dmadbg_showregs(const char *fname, int line, struct s3c2410_dma_chan *chan)
124{
125 struct s3c2410_dma_regstate state;
126
127 dmadbg_capture(chan, &state);
128 dmadbg_dumpregs(fname, line, chan, &state);
129}
130
131#define dbg_showregs(chan) dmadbg_showregs(__FUNCTION__, __LINE__, (chan))
132#define dbg_showchan(chan) dmadbg_showchan(__FUNCTION__, __LINE__, (chan))
133#else
134#define dbg_showregs(chan) do { } while(0)
135#define dbg_showchan(chan) do { } while(0)
136#endif /* CONFIG_S3C2410_DMA_DEBUG */
137
138static struct s3c2410_dma_chan *dma_chan_map[DMACH_MAX];
139
140/* lookup_dma_channel
141 *
142 * change the dma channel number given into a real dma channel id
143*/
144
145static struct s3c2410_dma_chan *lookup_dma_channel(unsigned int channel)
146{
147 if (channel & DMACH_LOW_LEVEL)
148 return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL];
149 else
150 return dma_chan_map[channel];
151}
152
153/* s3c2410_dma_stats_timeout
154 *
155 * Update DMA stats from timeout info
156*/
157
158static void
159s3c2410_dma_stats_timeout(struct s3c2410_dma_stats *stats, int val)
160{
161 if (stats == NULL)
162 return;
163
164 if (val > stats->timeout_longest)
165 stats->timeout_longest = val;
166 if (val < stats->timeout_shortest)
167 stats->timeout_shortest = val;
168
169 stats->timeout_avg += val;
170}
171
172/* s3c2410_dma_waitforload
173 *
174 * wait for the DMA engine to load a buffer, and update the state accordingly
175*/
176
177static int
178s3c2410_dma_waitforload(struct s3c2410_dma_chan *chan, int line)
179{
180 int timeout = chan->load_timeout;
181 int took;
182
183 if (chan->load_state != S3C2410_DMALOAD_1LOADED) {
184 printk(KERN_ERR "dma%d: s3c2410_dma_waitforload() called in loadstate %d from line %d\n", chan->number, chan->load_state, line);
185 return 0;
186 }
187
188 if (chan->stats != NULL)
189 chan->stats->loads++;
190
191 while (--timeout > 0) {
192 if ((dma_rdreg(chan, S3C2410_DMA_DSTAT) << (32-20)) != 0) {
193 took = chan->load_timeout - timeout;
194
195 s3c2410_dma_stats_timeout(chan->stats, took);
196
197 switch (chan->load_state) {
198 case S3C2410_DMALOAD_1LOADED:
199 chan->load_state = S3C2410_DMALOAD_1RUNNING;
200 break;
201
202 default:
203 printk(KERN_ERR "dma%d: unknown load_state in s3c2410_dma_waitforload() %d\n", chan->number, chan->load_state);
204 }
205
206 return 1;
207 }
208 }
209
210 if (chan->stats != NULL) {
211 chan->stats->timeout_failed++;
212 }
213
214 return 0;
215}
216
217
218
219/* s3c2410_dma_loadbuffer
220 *
221 * load a buffer, and update the channel state
222*/
223
224static inline int
225s3c2410_dma_loadbuffer(struct s3c2410_dma_chan *chan,
226 struct s3c2410_dma_buf *buf)
227{
228 unsigned long reload;
229
230 pr_debug("s3c2410_chan_loadbuffer: loading buff %p (0x%08lx,0x%06x)\n",
231 buf, (unsigned long)buf->data, buf->size);
232
233 if (buf == NULL) {
234 dmawarn("buffer is NULL\n");
235 return -EINVAL;
236 }
237
238 /* check the state of the channel before we do anything */
239
240 if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
241 dmawarn("load_state is S3C2410_DMALOAD_1LOADED\n");
242 }
243
244 if (chan->load_state == S3C2410_DMALOAD_1LOADED_1RUNNING) {
245 dmawarn("state is S3C2410_DMALOAD_1LOADED_1RUNNING\n");
246 }
247
248 /* it would seem sensible if we are the last buffer to not bother
249 * with the auto-reload bit, so that the DMA engine will not try
250 * and load another transfer after this one has finished...
251 */
252 if (chan->load_state == S3C2410_DMALOAD_NONE) {
253 pr_debug("load_state is none, checking for noreload (next=%p)\n",
254 buf->next);
255 reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0;
256 } else {
257 //pr_debug("load_state is %d => autoreload\n", chan->load_state);
258 reload = S3C2410_DCON_AUTORELOAD;
259 }
260
261 if ((buf->data & 0xf0000000) != 0x30000000) {
262 dmawarn("dmaload: buffer is %p\n", (void *)buf->data);
263 }
264
265 writel(buf->data, chan->addr_reg);
266
267 dma_wrreg(chan, S3C2410_DMA_DCON,
268 chan->dcon | reload | (buf->size/chan->xfer_unit));
269
270 chan->next = buf->next;
271
272 /* update the state of the channel */
273
274 switch (chan->load_state) {
275 case S3C2410_DMALOAD_NONE:
276 chan->load_state = S3C2410_DMALOAD_1LOADED;
277 break;
278
279 case S3C2410_DMALOAD_1RUNNING:
280 chan->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING;
281 break;
282
283 default:
284 dmawarn("dmaload: unknown state %d in loadbuffer\n",
285 chan->load_state);
286 break;
287 }
288
289 return 0;
290}
291
292/* s3c2410_dma_call_op
293 *
294 * small routine to call the op routine with the given op if it has been
295 * registered
296*/
297
298static void
299s3c2410_dma_call_op(struct s3c2410_dma_chan *chan, enum s3c2410_chan_op op)
300{
301 if (chan->op_fn != NULL) {
302 (chan->op_fn)(chan, op);
303 }
304}
305
306/* s3c2410_dma_buffdone
307 *
308 * small wrapper to check if callback routine needs to be called, and
309 * if so, call it
310*/
311
312static inline void
313s3c2410_dma_buffdone(struct s3c2410_dma_chan *chan, struct s3c2410_dma_buf *buf,
314 enum s3c2410_dma_buffresult result)
315{
316#if 0
317 pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n",
318 chan->callback_fn, buf, buf->id, buf->size, result);
319#endif
320
321 if (chan->callback_fn != NULL) {
322 (chan->callback_fn)(chan, buf->id, buf->size, result);
323 }
324}
325
326/* s3c2410_dma_start
327 *
328 * start a dma channel going
329*/
330
331static int s3c2410_dma_start(struct s3c2410_dma_chan *chan)
332{
333 unsigned long tmp;
334 unsigned long flags;
335
336 pr_debug("s3c2410_start_dma: channel=%d\n", chan->number);
337
338 local_irq_save(flags);
339
340 if (chan->state == S3C2410_DMA_RUNNING) {
341 pr_debug("s3c2410_start_dma: already running (%d)\n", chan->state);
342 local_irq_restore(flags);
343 return 0;
344 }
345
346 chan->state = S3C2410_DMA_RUNNING;
347
348 /* check wether there is anything to load, and if not, see
349 * if we can find anything to load
350 */
351
352 if (chan->load_state == S3C2410_DMALOAD_NONE) {
353 if (chan->next == NULL) {
354 printk(KERN_ERR "dma%d: channel has nothing loaded\n",
355 chan->number);
356 chan->state = S3C2410_DMA_IDLE;
357 local_irq_restore(flags);
358 return -EINVAL;
359 }
360
361 s3c2410_dma_loadbuffer(chan, chan->next);
362 }
363
364 dbg_showchan(chan);
365
366 /* enable the channel */
367
368 if (!chan->irq_enabled) {
369 enable_irq(chan->irq);
370 chan->irq_enabled = 1;
371 }
372
373 /* start the channel going */
374
375 tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
376 tmp &= ~S3C2410_DMASKTRIG_STOP;
377 tmp |= S3C2410_DMASKTRIG_ON;
378 dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
379
380 pr_debug("dma%d: %08lx to DMASKTRIG\n", chan->number, tmp);
381
382#if 0
383 /* the dma buffer loads should take care of clearing the AUTO
384 * reloading feature */
385 tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
386 tmp &= ~S3C2410_DCON_NORELOAD;
387 dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
388#endif
389
390 s3c2410_dma_call_op(chan, S3C2410_DMAOP_START);
391
392 dbg_showchan(chan);
393
394 /* if we've only loaded one buffer onto the channel, then chec
395 * to see if we have another, and if so, try and load it so when
396 * the first buffer is finished, the new one will be loaded onto
397 * the channel */
398
399 if (chan->next != NULL) {
400 if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
401
402 if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
403 pr_debug("%s: buff not yet loaded, no more todo\n",
404 __FUNCTION__);
405 } else {
406 chan->load_state = S3C2410_DMALOAD_1RUNNING;
407 s3c2410_dma_loadbuffer(chan, chan->next);
408 }
409
410 } else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) {
411 s3c2410_dma_loadbuffer(chan, chan->next);
412 }
413 }
414
415
416 local_irq_restore(flags);
417
418 return 0;
419}
420
421/* s3c2410_dma_canload
422 *
423 * work out if we can queue another buffer into the DMA engine
424*/
425
426static int
427s3c2410_dma_canload(struct s3c2410_dma_chan *chan)
428{
429 if (chan->load_state == S3C2410_DMALOAD_NONE ||
430 chan->load_state == S3C2410_DMALOAD_1RUNNING)
431 return 1;
432
433 return 0;
434}
435
436/* s3c2410_dma_enqueue
437 *
438 * queue an given buffer for dma transfer.
439 *
440 * id the device driver's id information for this buffer
441 * data the physical address of the buffer data
442 * size the size of the buffer in bytes
443 *
444 * If the channel is not running, then the flag S3C2410_DMAF_AUTOSTART
445 * is checked, and if set, the channel is started. If this flag isn't set,
446 * then an error will be returned.
447 *
448 * It is possible to queue more than one DMA buffer onto a channel at
449 * once, and the code will deal with the re-loading of the next buffer
450 * when necessary.
451*/
452
453int s3c2410_dma_enqueue(unsigned int channel, void *id,
454 dma_addr_t data, int size)
455{
456 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
457 struct s3c2410_dma_buf *buf;
458 unsigned long flags;
459
460 if (chan == NULL)
461 return -EINVAL;
462
463 pr_debug("%s: id=%p, data=%08x, size=%d\n",
464 __FUNCTION__, id, (unsigned int)data, size);
465
466 buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC);
467 if (buf == NULL) {
468 pr_debug("%s: out of memory (%ld alloc)\n",
469 __FUNCTION__, (long)sizeof(*buf));
470 return -ENOMEM;
471 }
472
473 //pr_debug("%s: new buffer %p\n", __FUNCTION__, buf);
474 //dbg_showchan(chan);
475
476 buf->next = NULL;
477 buf->data = buf->ptr = data;
478 buf->size = size;
479 buf->id = id;
480 buf->magic = BUF_MAGIC;
481
482 local_irq_save(flags);
483
484 if (chan->curr == NULL) {
485 /* we've got nothing loaded... */
486 pr_debug("%s: buffer %p queued onto empty channel\n",
487 __FUNCTION__, buf);
488
489 chan->curr = buf;
490 chan->end = buf;
491 chan->next = NULL;
492 } else {
493 pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n",
494 chan->number, __FUNCTION__, buf);
495
496 if (chan->end == NULL)
497 pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n",
498 chan->number, __FUNCTION__, chan);
499
500 chan->end->next = buf;
501 chan->end = buf;
502 }
503
504 /* if necessary, update the next buffer field */
505 if (chan->next == NULL)
506 chan->next = buf;
507
508 /* check to see if we can load a buffer */
509 if (chan->state == S3C2410_DMA_RUNNING) {
510 if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) {
511 if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
512 printk(KERN_ERR "dma%d: loadbuffer:"
513 "timeout loading buffer\n",
514 chan->number);
515 dbg_showchan(chan);
516 local_irq_restore(flags);
517 return -EINVAL;
518 }
519 }
520
521 while (s3c2410_dma_canload(chan) && chan->next != NULL) {
522 s3c2410_dma_loadbuffer(chan, chan->next);
523 }
524 } else if (chan->state == S3C2410_DMA_IDLE) {
525 if (chan->flags & S3C2410_DMAF_AUTOSTART) {
526 s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_START);
527 }
528 }
529
530 local_irq_restore(flags);
531 return 0;
532}
533
534EXPORT_SYMBOL(s3c2410_dma_enqueue);
535
536static inline void
537s3c2410_dma_freebuf(struct s3c2410_dma_buf *buf)
538{
539 int magicok = (buf->magic == BUF_MAGIC);
540
541 buf->magic = -1;
542
543 if (magicok) {
544 kmem_cache_free(dma_kmem, buf);
545 } else {
546 printk("s3c2410_dma_freebuf: buff %p with bad magic\n", buf);
547 }
548}
549
550/* s3c2410_dma_lastxfer
551 *
552 * called when the system is out of buffers, to ensure that the channel
553 * is prepared for shutdown.
554*/
555
556static inline void
557s3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan)
558{
559#if 0
560 pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n",
561 chan->number, chan->load_state);
562#endif
563
564 switch (chan->load_state) {
565 case S3C2410_DMALOAD_NONE:
566 break;
567
568 case S3C2410_DMALOAD_1LOADED:
569 if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
570 /* flag error? */
571 printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
572 chan->number, __FUNCTION__);
573 return;
574 }
575 break;
576
577 case S3C2410_DMALOAD_1LOADED_1RUNNING:
578 /* I belive in this case we do not have anything to do
579 * until the next buffer comes along, and we turn off the
580 * reload */
581 return;
582
583 default:
584 pr_debug("dma%d: lastxfer: unhandled load_state %d with no next\n",
585 chan->number, chan->load_state);
586 return;
587
588 }
589
590 /* hopefully this'll shut the damned thing up after the transfer... */
591 dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD);
592}
593
594
595#define dmadbg2(x...)
596
597static irqreturn_t
598s3c2410_dma_irq(int irq, void *devpw)
599{
600 struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw;
601 struct s3c2410_dma_buf *buf;
602
603 buf = chan->curr;
604
605 dbg_showchan(chan);
606
607 /* modify the channel state */
608
609 switch (chan->load_state) {
610 case S3C2410_DMALOAD_1RUNNING:
611 /* TODO - if we are running only one buffer, we probably
612 * want to reload here, and then worry about the buffer
613 * callback */
614
615 chan->load_state = S3C2410_DMALOAD_NONE;
616 break;
617
618 case S3C2410_DMALOAD_1LOADED:
619 /* iirc, we should go back to NONE loaded here, we
620 * had a buffer, and it was never verified as being
621 * loaded.
622 */
623
624 chan->load_state = S3C2410_DMALOAD_NONE;
625 break;
626
627 case S3C2410_DMALOAD_1LOADED_1RUNNING:
628 /* we'll worry about checking to see if another buffer is
629 * ready after we've called back the owner. This should
630 * ensure we do not wait around too long for the DMA
631 * engine to start the next transfer
632 */
633
634 chan->load_state = S3C2410_DMALOAD_1LOADED;
635 break;
636
637 case S3C2410_DMALOAD_NONE:
638 printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n",
639 chan->number);
640 break;
641
642 default:
643 printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n",
644 chan->number, chan->load_state);
645 break;
646 }
647
648 if (buf != NULL) {
649 /* update the chain to make sure that if we load any more
650 * buffers when we call the callback function, things should
651 * work properly */
652
653 chan->curr = buf->next;
654 buf->next = NULL;
655
656 if (buf->magic != BUF_MAGIC) {
657 printk(KERN_ERR "dma%d: %s: buf %p incorrect magic\n",
658 chan->number, __FUNCTION__, buf);
659 return IRQ_HANDLED;
660 }
661
662 s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK);
663
664 /* free resouces */
665 s3c2410_dma_freebuf(buf);
666 } else {
667 }
668
669 /* only reload if the channel is still running... our buffer done
670 * routine may have altered the state by requesting the dma channel
671 * to stop or shutdown... */
672
673 /* todo: check that when the channel is shut-down from inside this
674 * function, we cope with unsetting reload, etc */
675
676 if (chan->next != NULL && chan->state != S3C2410_DMA_IDLE) {
677 unsigned long flags;
678
679 switch (chan->load_state) {
680 case S3C2410_DMALOAD_1RUNNING:
681 /* don't need to do anything for this state */
682 break;
683
684 case S3C2410_DMALOAD_NONE:
685 /* can load buffer immediately */
686 break;
687
688 case S3C2410_DMALOAD_1LOADED:
689 if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
690 /* flag error? */
691 printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
692 chan->number, __FUNCTION__);
693 return IRQ_HANDLED;
694 }
695
696 break;
697
698 case S3C2410_DMALOAD_1LOADED_1RUNNING:
699 goto no_load;
700
701 default:
702 printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n",
703 chan->number, chan->load_state);
704 return IRQ_HANDLED;
705 }
706
707 local_irq_save(flags);
708 s3c2410_dma_loadbuffer(chan, chan->next);
709 local_irq_restore(flags);
710 } else {
711 s3c2410_dma_lastxfer(chan);
712
713 /* see if we can stop this channel.. */
714 if (chan->load_state == S3C2410_DMALOAD_NONE) {
715 pr_debug("dma%d: end of transfer, stopping channel (%ld)\n",
716 chan->number, jiffies);
717 s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL,
718 S3C2410_DMAOP_STOP);
719 }
720 }
721
722 no_load:
723 return IRQ_HANDLED;
724}
725
726static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel);
727
728/* s3c2410_request_dma
729 *
730 * get control of an dma channel
731*/
732
733int s3c2410_dma_request(unsigned int channel,
734 struct s3c2410_dma_client *client,
735 void *dev)
736{
737 struct s3c2410_dma_chan *chan;
738 unsigned long flags;
739 int err;
740
741 pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n",
742 channel, client->name, dev);
743
744 local_irq_save(flags);
745
746 chan = s3c2410_dma_map_channel(channel);
747 if (chan == NULL) {
748 local_irq_restore(flags);
749 return -EBUSY;
750 }
751
752 dbg_showchan(chan);
753
754 chan->client = client;
755 chan->in_use = 1;
756
757 if (!chan->irq_claimed) {
758 pr_debug("dma%d: %s : requesting irq %d\n",
759 channel, __FUNCTION__, chan->irq);
760
761 chan->irq_claimed = 1;
762 local_irq_restore(flags);
763
764 err = request_irq(chan->irq, s3c2410_dma_irq, IRQF_DISABLED,
765 client->name, (void *)chan);
766
767 local_irq_save(flags);
768
769 if (err) {
770 chan->in_use = 0;
771 chan->irq_claimed = 0;
772 local_irq_restore(flags);
773
774 printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n",
775 client->name, chan->irq, chan->number);
776 return err;
777 }
778
779 chan->irq_enabled = 1;
780 }
781
782 local_irq_restore(flags);
783
784 /* need to setup */
785
786 pr_debug("%s: channel initialised, %p\n", __FUNCTION__, chan);
787
788 return 0;
789}
790
791EXPORT_SYMBOL(s3c2410_dma_request);
792
793/* s3c2410_dma_free
794 *
795 * release the given channel back to the system, will stop and flush
796 * any outstanding transfers, and ensure the channel is ready for the
797 * next claimant.
798 *
799 * Note, although a warning is currently printed if the freeing client
800 * info is not the same as the registrant's client info, the free is still
801 * allowed to go through.
802*/
803
804int s3c2410_dma_free(dmach_t channel, struct s3c2410_dma_client *client)
805{
806 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
807 unsigned long flags;
808
809 if (chan == NULL)
810 return -EINVAL;
811
812 local_irq_save(flags);
813
814 if (chan->client != client) {
815 printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n",
816 channel, chan->client, client);
817 }
818
819 /* sort out stopping and freeing the channel */
820
821 if (chan->state != S3C2410_DMA_IDLE) {
822 pr_debug("%s: need to stop dma channel %p\n",
823 __FUNCTION__, chan);
824
825 /* possibly flush the channel */
826 s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STOP);
827 }
828
829 chan->client = NULL;
830 chan->in_use = 0;
831
832 if (chan->irq_claimed)
833 free_irq(chan->irq, (void *)chan);
834
835 chan->irq_claimed = 0;
836
837 if (!(channel & DMACH_LOW_LEVEL))
838 dma_chan_map[channel] = NULL;
839
840 local_irq_restore(flags);
841
842 return 0;
843}
844
845EXPORT_SYMBOL(s3c2410_dma_free);
846
847static int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan)
848{
849 unsigned long flags;
850 unsigned long tmp;
851
852 pr_debug("%s:\n", __FUNCTION__);
853
854 dbg_showchan(chan);
855
856 local_irq_save(flags);
857
858 s3c2410_dma_call_op(chan, S3C2410_DMAOP_STOP);
859
860 tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
861 tmp |= S3C2410_DMASKTRIG_STOP;
862 //tmp &= ~S3C2410_DMASKTRIG_ON;
863 dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
864
865#if 0
866 /* should also clear interrupts, according to WinCE BSP */
867 tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
868 tmp |= S3C2410_DCON_NORELOAD;
869 dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
870#endif
871
872 /* should stop do this, or should we wait for flush? */
873 chan->state = S3C2410_DMA_IDLE;
874 chan->load_state = S3C2410_DMALOAD_NONE;
875
876 local_irq_restore(flags);
877
878 return 0;
879}
880
881void s3c2410_dma_waitforstop(struct s3c2410_dma_chan *chan)
882{
883 unsigned long tmp;
884 unsigned int timeout = 0x10000;
885
886 while (timeout-- > 0) {
887 tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
888
889 if (!(tmp & S3C2410_DMASKTRIG_ON))
890 return;
891 }
892
893 pr_debug("dma%d: failed to stop?\n", chan->number);
894}
895
896
897/* s3c2410_dma_flush
898 *
899 * stop the channel, and remove all current and pending transfers
900*/
901
902static int s3c2410_dma_flush(struct s3c2410_dma_chan *chan)
903{
904 struct s3c2410_dma_buf *buf, *next;
905 unsigned long flags;
906
907 pr_debug("%s: chan %p (%d)\n", __FUNCTION__, chan, chan->number);
908
909 dbg_showchan(chan);
910
911 local_irq_save(flags);
912
913 if (chan->state != S3C2410_DMA_IDLE) {
914 pr_debug("%s: stopping channel...\n", __FUNCTION__ );
915 s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP);
916 }
917
918 buf = chan->curr;
919 if (buf == NULL)
920 buf = chan->next;
921
922 chan->curr = chan->next = chan->end = NULL;
923
924 if (buf != NULL) {
925 for ( ; buf != NULL; buf = next) {
926 next = buf->next;
927
928 pr_debug("%s: free buffer %p, next %p\n",
929 __FUNCTION__, buf, buf->next);
930
931 s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT);
932 s3c2410_dma_freebuf(buf);
933 }
934 }
935
936 dbg_showregs(chan);
937
938 s3c2410_dma_waitforstop(chan);
939
940#if 0
941 /* should also clear interrupts, according to WinCE BSP */
942 {
943 unsigned long tmp;
944
945 tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
946 tmp |= S3C2410_DCON_NORELOAD;
947 dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
948 }
949#endif
950
951 dbg_showregs(chan);
952
953 local_irq_restore(flags);
954
955 return 0;
956}
957
958int
959s3c2410_dma_started(struct s3c2410_dma_chan *chan)
960{
961 unsigned long flags;
962
963 local_irq_save(flags);
964
965 dbg_showchan(chan);
966
967 /* if we've only loaded one buffer onto the channel, then chec
968 * to see if we have another, and if so, try and load it so when
969 * the first buffer is finished, the new one will be loaded onto
970 * the channel */
971
972 if (chan->next != NULL) {
973 if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
974
975 if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
976 pr_debug("%s: buff not yet loaded, no more todo\n",
977 __FUNCTION__);
978 } else {
979 chan->load_state = S3C2410_DMALOAD_1RUNNING;
980 s3c2410_dma_loadbuffer(chan, chan->next);
981 }
982
983 } else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) {
984 s3c2410_dma_loadbuffer(chan, chan->next);
985 }
986 }
987
988
989 local_irq_restore(flags);
990
991 return 0;
992
993}
994
995int
996s3c2410_dma_ctrl(dmach_t channel, enum s3c2410_chan_op op)
997{
998 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
999
1000 if (chan == NULL)
1001 return -EINVAL;
1002
1003 switch (op) {
1004 case S3C2410_DMAOP_START:
1005 return s3c2410_dma_start(chan);
1006
1007 case S3C2410_DMAOP_STOP:
1008 return s3c2410_dma_dostop(chan);
1009
1010 case S3C2410_DMAOP_PAUSE:
1011 case S3C2410_DMAOP_RESUME:
1012 return -ENOENT;
1013
1014 case S3C2410_DMAOP_FLUSH:
1015 return s3c2410_dma_flush(chan);
1016
1017 case S3C2410_DMAOP_STARTED:
1018 return s3c2410_dma_started(chan);
1019
1020 case S3C2410_DMAOP_TIMEOUT:
1021 return 0;
1022
1023 }
1024
1025 return -ENOENT; /* unknown, don't bother */
1026}
1027
1028EXPORT_SYMBOL(s3c2410_dma_ctrl);
1029
1030/* DMA configuration for each channel
1031 *
1032 * DISRCC -> source of the DMA (AHB,APB)
1033 * DISRC -> source address of the DMA
1034 * DIDSTC -> destination of the DMA (AHB,APD)
1035 * DIDST -> destination address of the DMA
1036*/
1037
1038/* s3c2410_dma_config
1039 *
1040 * xfersize: size of unit in bytes (1,2,4)
1041 * dcon: base value of the DCONx register
1042*/
1043
1044int s3c2410_dma_config(dmach_t channel,
1045 int xferunit,
1046 int dcon)
1047{
1048 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
1049
1050 pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n",
1051 __FUNCTION__, channel, xferunit, dcon);
1052
1053 if (chan == NULL)
1054 return -EINVAL;
1055
1056 pr_debug("%s: Initial dcon is %08x\n", __FUNCTION__, dcon);
1057
1058 dcon |= chan->dcon & dma_sel.dcon_mask;
1059
1060 pr_debug("%s: New dcon is %08x\n", __FUNCTION__, dcon);
1061
1062 switch (xferunit) {
1063 case 1:
1064 dcon |= S3C2410_DCON_BYTE;
1065 break;
1066
1067 case 2:
1068 dcon |= S3C2410_DCON_HALFWORD;
1069 break;
1070
1071 case 4:
1072 dcon |= S3C2410_DCON_WORD;
1073 break;
1074
1075 default:
1076 pr_debug("%s: bad transfer size %d\n", __FUNCTION__, xferunit);
1077 return -EINVAL;
1078 }
1079
1080 dcon |= S3C2410_DCON_HWTRIG;
1081 dcon |= S3C2410_DCON_INTREQ;
1082
1083 pr_debug("%s: dcon now %08x\n", __FUNCTION__, dcon);
1084
1085 chan->dcon = dcon;
1086 chan->xfer_unit = xferunit;
1087
1088 return 0;
1089}
1090
1091EXPORT_SYMBOL(s3c2410_dma_config);
1092
1093int s3c2410_dma_setflags(dmach_t channel, unsigned int flags)
1094{
1095 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
1096
1097 if (chan == NULL)
1098 return -EINVAL;
1099
1100 pr_debug("%s: chan=%p, flags=%08x\n", __FUNCTION__, chan, flags);
1101
1102 chan->flags = flags;
1103
1104 return 0;
1105}
1106
1107EXPORT_SYMBOL(s3c2410_dma_setflags);
1108
1109
1110/* do we need to protect the settings of the fields from
1111 * irq?
1112*/
1113
1114int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn)
1115{
1116 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
1117
1118 if (chan == NULL)
1119 return -EINVAL;
1120
1121 pr_debug("%s: chan=%p, op rtn=%p\n", __FUNCTION__, chan, rtn);
1122
1123 chan->op_fn = rtn;
1124
1125 return 0;
1126}
1127
1128EXPORT_SYMBOL(s3c2410_dma_set_opfn);
1129
1130int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn)
1131{
1132 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
1133
1134 if (chan == NULL)
1135 return -EINVAL;
1136
1137 pr_debug("%s: chan=%p, callback rtn=%p\n", __FUNCTION__, chan, rtn);
1138
1139 chan->callback_fn = rtn;
1140
1141 return 0;
1142}
1143
1144EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);
1145
1146/* s3c2410_dma_devconfig
1147 *
1148 * configure the dma source/destination hardware type and address
1149 *
1150 * source: S3C2410_DMASRC_HW: source is hardware
1151 * S3C2410_DMASRC_MEM: source is memory
1152 *
1153 * hwcfg: the value for xxxSTCn register,
1154 * bit 0: 0=increment pointer, 1=leave pointer
1155 * bit 1: 0=soucre is AHB, 1=soucre is APB
1156 *
1157 * devaddr: physical address of the source
1158*/
1159
1160int s3c2410_dma_devconfig(int channel,
1161 enum s3c2410_dmasrc source,
1162 int hwcfg,
1163 unsigned long devaddr)
1164{
1165 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
1166
1167 if (chan == NULL)
1168 return -EINVAL;
1169
1170 pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n",
1171 __FUNCTION__, (int)source, hwcfg, devaddr);
1172
1173 chan->source = source;
1174 chan->dev_addr = devaddr;
1175
1176 switch (source) {
1177 case S3C2410_DMASRC_HW:
1178 /* source is hardware */
1179 pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n",
1180 __FUNCTION__, devaddr, hwcfg);
1181 dma_wrreg(chan, S3C2410_DMA_DISRCC, hwcfg & 3);
1182 dma_wrreg(chan, S3C2410_DMA_DISRC, devaddr);
1183 dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0));
1184
1185 chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST);
1186 return 0;
1187
1188 case S3C2410_DMASRC_MEM:
1189 /* source is memory */
1190 pr_debug( "%s: mem source, devaddr=%08lx, hwcfg=%d\n",
1191 __FUNCTION__, devaddr, hwcfg);
1192 dma_wrreg(chan, S3C2410_DMA_DISRCC, (0<<1) | (0<<0));
1193 dma_wrreg(chan, S3C2410_DMA_DIDST, devaddr);
1194 dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3);
1195
1196 chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC);
1197 return 0;
1198 }
1199
1200 printk(KERN_ERR "dma%d: invalid source type (%d)\n", channel, source);
1201 return -EINVAL;
1202}
1203
1204EXPORT_SYMBOL(s3c2410_dma_devconfig);
1205
1206/* s3c2410_dma_getposition
1207 *
1208 * returns the current transfer points for the dma source and destination
1209*/
1210
1211int s3c2410_dma_getposition(dmach_t channel, dma_addr_t *src, dma_addr_t *dst)
1212{
1213 struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
1214
1215 if (chan == NULL)
1216 return -EINVAL;
1217
1218 if (src != NULL)
1219 *src = dma_rdreg(chan, S3C2410_DMA_DCSRC);
1220
1221 if (dst != NULL)
1222 *dst = dma_rdreg(chan, S3C2410_DMA_DCDST);
1223
1224 return 0;
1225}
1226
1227EXPORT_SYMBOL(s3c2410_dma_getposition);
1228
1229
1230/* system device class */
1231
1232#ifdef CONFIG_PM
1233
1234static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state)
1235{
1236 struct s3c2410_dma_chan *cp = container_of(dev, struct s3c2410_dma_chan, dev);
1237
1238 printk(KERN_DEBUG "suspending dma channel %d\n", cp->number);
1239
1240 if (dma_rdreg(cp, S3C2410_DMA_DMASKTRIG) & S3C2410_DMASKTRIG_ON) {
1241 /* the dma channel is still working, which is probably
1242 * a bad thing to do over suspend/resume. We stop the
1243 * channel and assume that the client is either going to
1244 * retry after resume, or that it is broken.
1245 */
1246
1247 printk(KERN_INFO "dma: stopping channel %d due to suspend\n",
1248 cp->number);
1249
1250 s3c2410_dma_dostop(cp);
1251 }
1252
1253 return 0;
1254}
1255
1256static int s3c2410_dma_resume(struct sys_device *dev)
1257{
1258 return 0;
1259}
1260
1261#else
1262#define s3c2410_dma_suspend NULL
1263#define s3c2410_dma_resume NULL
1264#endif /* CONFIG_PM */
1265
1266struct sysdev_class dma_sysclass = {
1267 set_kset_name("s3c24xx-dma"),
1268 .suspend = s3c2410_dma_suspend,
1269 .resume = s3c2410_dma_resume,
1270};
1271
1272/* kmem cache implementation */
1273
1274static void s3c2410_dma_cache_ctor(void *p, struct kmem_cache *c, unsigned long f)
1275{
1276 memset(p, 0, sizeof(struct s3c2410_dma_buf));
1277}
1278
1279/* initialisation code */
1280
1281static int __init s3c2410_init_dma(void)
1282{
1283 struct s3c2410_dma_chan *cp;
1284 int channel;
1285 int ret;
1286
1287 printk("S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics\n");
1288
1289 dma_base = ioremap(S3C24XX_PA_DMA, 0x200);
1290 if (dma_base == NULL) {
1291 printk(KERN_ERR "dma failed to remap register block\n");
1292 return -ENOMEM;
1293 }
1294
1295 printk("Registering sysclass\n");
1296
1297 ret = sysdev_class_register(&dma_sysclass);
1298 if (ret != 0) {
1299 printk(KERN_ERR "dma sysclass registration failed\n");
1300 goto err;
1301 }
1302
1303 dma_kmem = kmem_cache_create("dma_desc", sizeof(struct s3c2410_dma_buf), 0,
1304 SLAB_HWCACHE_ALIGN,
1305 s3c2410_dma_cache_ctor, NULL);
1306
1307 if (dma_kmem == NULL) {
1308 printk(KERN_ERR "dma failed to make kmem cache\n");
1309 ret = -ENOMEM;
1310 goto err;
1311 }
1312
1313 for (channel = 0; channel < S3C2410_DMA_CHANNELS; channel++) {
1314 cp = &s3c2410_chans[channel];
1315
1316 memset(cp, 0, sizeof(struct s3c2410_dma_chan));
1317
1318 /* dma channel irqs are in order.. */
1319 cp->number = channel;
1320 cp->irq = channel + IRQ_DMA0;
1321 cp->regs = dma_base + (channel*0x40);
1322
1323 /* point current stats somewhere */
1324 cp->stats = &cp->stats_store;
1325 cp->stats_store.timeout_shortest = LONG_MAX;
1326
1327 /* basic channel configuration */
1328
1329 cp->load_timeout = 1<<18;
1330
1331 /* register system device */
1332
1333 cp->dev.cls = &dma_sysclass;
1334 cp->dev.id = channel;
1335 ret = sysdev_register(&cp->dev);
1336
1337 printk("DMA channel %d at %p, irq %d\n",
1338 cp->number, cp->regs, cp->irq);
1339 }
1340
1341 return 0;
1342
1343 err:
1344 kmem_cache_destroy(dma_kmem);
1345 iounmap(dma_base);
1346 dma_base = NULL;
1347 return ret;
1348}
1349
1350core_initcall(s3c2410_init_dma);
1351
1352static inline int is_channel_valid(unsigned int channel)
1353{
1354 return (channel & DMA_CH_VALID);
1355}
1356
1357/* s3c2410_dma_map_channel()
1358 *
1359 * turn the virtual channel number into a real, and un-used hardware
1360 * channel.
1361 *
1362 * currently this code uses first-free channel from the specified harware
1363 * map, not taking into account anything that the board setup code may
1364 * have to say about the likely peripheral set to be in use.
1365*/
1366
1367struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
1368{
1369 struct s3c24xx_dma_map *ch_map;
1370 struct s3c2410_dma_chan *dmach;
1371 int ch;
1372
1373 if (dma_sel.map == NULL || channel > dma_sel.map_size)
1374 return NULL;
1375
1376 ch_map = dma_sel.map + channel;
1377
1378 for (ch = 0; ch < S3C2410_DMA_CHANNELS; ch++) {
1379 if (!is_channel_valid(ch_map->channels[ch]))
1380 continue;
1381
1382 if (s3c2410_chans[ch].in_use == 0) {
1383 printk("mapped channel %d to %d\n", channel, ch);
1384 break;
1385 }
1386 }
1387
1388 if (ch >= S3C2410_DMA_CHANNELS)
1389 return NULL;
1390
1391 /* update our channel mapping */
1392
1393 dmach = &s3c2410_chans[ch];
1394 dma_chan_map[channel] = dmach;
1395
1396 /* select the channel */
1397
1398 (dma_sel.select)(dmach, ch_map);
1399
1400 return dmach;
1401}
1402
1403static void s3c24xx_dma_show_ch(struct s3c24xx_dma_map *map, int ch)
1404{
1405 /* show the channel configuration */
1406
1407 printk("%2d: %20s, channels %c%c%c%c\n", ch, map->name,
1408 (is_channel_valid(map->channels[0]) ? '0' : '-'),
1409 (is_channel_valid(map->channels[1]) ? '1' : '-'),
1410 (is_channel_valid(map->channels[2]) ? '2' : '-'),
1411 (is_channel_valid(map->channels[3]) ? '3' : '-'));
1412}
1413
1414static int s3c24xx_dma_check_entry(struct s3c24xx_dma_map *map, int ch)
1415{
1416 if (1)
1417 s3c24xx_dma_show_ch(map, ch);
1418
1419 return 0;
1420}
1421
1422int __init s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel)
1423{
1424 struct s3c24xx_dma_map *nmap;
1425 size_t map_sz = sizeof(*nmap) * sel->map_size;
1426 int ptr;
1427
1428 nmap = kmalloc(map_sz, GFP_KERNEL);
1429 if (nmap == NULL)
1430 return -ENOMEM;
1431
1432 memcpy(nmap, sel->map, map_sz);
1433 memcpy(&dma_sel, sel, sizeof(*sel));
1434
1435 dma_sel.map = nmap;
1436
1437 for (ptr = 0; ptr < sel->map_size; ptr++)
1438 s3c24xx_dma_check_entry(nmap+ptr, ptr);
1439
1440 return 0;
1441}
diff --git a/arch/arm/plat-s3c24xx/gpio.c b/arch/arm/plat-s3c24xx/gpio.c
new file mode 100644
index 000000000000..ec3a09c4d181
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/gpio.c
@@ -0,0 +1,188 @@
1/* linux/arch/arm/plat-s3c24xx/gpio.c
2 *
3 * Copyright (c) 2004-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * S3C24XX GPIO support
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21*/
22
23
24#include <linux/kernel.h>
25#include <linux/init.h>
26#include <linux/module.h>
27#include <linux/interrupt.h>
28#include <linux/ioport.h>
29
30#include <asm/hardware.h>
31#include <asm/irq.h>
32#include <asm/io.h>
33
34#include <asm/arch/regs-gpio.h>
35
36void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
37{
38 void __iomem *base = S3C24XX_GPIO_BASE(pin);
39 unsigned long mask;
40 unsigned long con;
41 unsigned long flags;
42
43 if (pin < S3C2410_GPIO_BANKB) {
44 mask = 1 << S3C2410_GPIO_OFFSET(pin);
45 } else {
46 mask = 3 << S3C2410_GPIO_OFFSET(pin)*2;
47 }
48
49 switch (function) {
50 case S3C2410_GPIO_LEAVE:
51 mask = 0;
52 function = 0;
53 break;
54
55 case S3C2410_GPIO_INPUT:
56 case S3C2410_GPIO_OUTPUT:
57 case S3C2410_GPIO_SFN2:
58 case S3C2410_GPIO_SFN3:
59 if (pin < S3C2410_GPIO_BANKB) {
60 function -= 1;
61 function &= 1;
62 function <<= S3C2410_GPIO_OFFSET(pin);
63 } else {
64 function &= 3;
65 function <<= S3C2410_GPIO_OFFSET(pin)*2;
66 }
67 }
68
69 /* modify the specified register wwith IRQs off */
70
71 local_irq_save(flags);
72
73 con = __raw_readl(base + 0x00);
74 con &= ~mask;
75 con |= function;
76
77 __raw_writel(con, base + 0x00);
78
79 local_irq_restore(flags);
80}
81
82EXPORT_SYMBOL(s3c2410_gpio_cfgpin);
83
84unsigned int s3c2410_gpio_getcfg(unsigned int pin)
85{
86 void __iomem *base = S3C24XX_GPIO_BASE(pin);
87 unsigned long val = __raw_readl(base);
88
89 if (pin < S3C2410_GPIO_BANKB) {
90 val >>= S3C2410_GPIO_OFFSET(pin);
91 val &= 1;
92 val += 1;
93 } else {
94 val >>= S3C2410_GPIO_OFFSET(pin)*2;
95 val &= 3;
96 }
97
98 return val | S3C2410_GPIO_INPUT;
99}
100
101EXPORT_SYMBOL(s3c2410_gpio_getcfg);
102
103void s3c2410_gpio_pullup(unsigned int pin, unsigned int to)
104{
105 void __iomem *base = S3C24XX_GPIO_BASE(pin);
106 unsigned long offs = S3C2410_GPIO_OFFSET(pin);
107 unsigned long flags;
108 unsigned long up;
109
110 if (pin < S3C2410_GPIO_BANKB)
111 return;
112
113 local_irq_save(flags);
114
115 up = __raw_readl(base + 0x08);
116 up &= ~(1L << offs);
117 up |= to << offs;
118 __raw_writel(up, base + 0x08);
119
120 local_irq_restore(flags);
121}
122
123EXPORT_SYMBOL(s3c2410_gpio_pullup);
124
125void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
126{
127 void __iomem *base = S3C24XX_GPIO_BASE(pin);
128 unsigned long offs = S3C2410_GPIO_OFFSET(pin);
129 unsigned long flags;
130 unsigned long dat;
131
132 local_irq_save(flags);
133
134 dat = __raw_readl(base + 0x04);
135 dat &= ~(1 << offs);
136 dat |= to << offs;
137 __raw_writel(dat, base + 0x04);
138
139 local_irq_restore(flags);
140}
141
142EXPORT_SYMBOL(s3c2410_gpio_setpin);
143
144unsigned int s3c2410_gpio_getpin(unsigned int pin)
145{
146 void __iomem *base = S3C24XX_GPIO_BASE(pin);
147 unsigned long offs = S3C2410_GPIO_OFFSET(pin);
148
149 return __raw_readl(base + 0x04) & (1<< offs);
150}
151
152EXPORT_SYMBOL(s3c2410_gpio_getpin);
153
154unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change)
155{
156 unsigned long flags;
157 unsigned long misccr;
158
159 local_irq_save(flags);
160 misccr = __raw_readl(S3C24XX_MISCCR);
161 misccr &= ~clear;
162 misccr ^= change;
163 __raw_writel(misccr, S3C24XX_MISCCR);
164 local_irq_restore(flags);
165
166 return misccr;
167}
168
169EXPORT_SYMBOL(s3c2410_modify_misccr);
170
171int s3c2410_gpio_getirq(unsigned int pin)
172{
173 if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15)
174 return -1; /* not valid interrupts */
175
176 if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7)
177 return -1; /* not valid pin */
178
179 if (pin < S3C2410_GPF4)
180 return (pin - S3C2410_GPF0) + IRQ_EINT0;
181
182 if (pin < S3C2410_GPG0)
183 return (pin - S3C2410_GPF4) + IRQ_EINT4;
184
185 return (pin - S3C2410_GPG0) + IRQ_EINT8;
186}
187
188EXPORT_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 000000000000..ce186398e3fd
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/irq.c
@@ -0,0 +1,801 @@
1/* linux/arch/arm/plat-s3c24xx/irq.c
2 *
3 * Copyright (c) 2003,2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 * Changelog:
21 *
22 * 22-Jul-2004 Ben Dooks <ben@simtec.co.uk>
23 * Fixed compile warnings
24 *
25 * 22-Jul-2004 Roc Wu <cooloney@yahoo.com.cn>
26 * Fixed s3c_extirq_type
27 *
28 * 21-Jul-2004 Arnaud Patard (Rtp) <arnaud.patard@rtp-net.org>
29 * Addition of ADC/TC demux
30 *
31 * 04-Oct-2004 Klaus Fetscher <k.fetscher@fetron.de>
32 * Fix for set_irq_type() on low EINT numbers
33 *
34 * 05-Oct-2004 Ben Dooks <ben@simtec.co.uk>
35 * Tidy up KF's patch and sort out new release
36 *
37 * 05-Oct-2004 Ben Dooks <ben@simtec.co.uk>
38 * Add support for power management controls
39 *
40 * 04-Nov-2004 Ben Dooks
41 * Fix standard IRQ wake for EINT0..4 and RTC
42 *
43 * 22-Feb-2005 Ben Dooks
44 * Fixed edge-triggering on ADC IRQ
45 *
46 * 28-Jun-2005 Ben Dooks
47 * Mark IRQ_LCD valid
48 *
49 * 25-Jul-2005 Ben Dooks
50 * Split the S3C2440 IRQ code to seperate file
51*/
52
53#include <linux/init.h>
54#include <linux/module.h>
55#include <linux/interrupt.h>
56#include <linux/ioport.h>
57#include <linux/ptrace.h>
58#include <linux/sysdev.h>
59
60#include <asm/hardware.h>
61#include <asm/irq.h>
62#include <asm/io.h>
63
64#include <asm/mach/irq.h>
65
66#include <asm/arch/regs-irq.h>
67#include <asm/arch/regs-gpio.h>
68
69#include <asm/plat-s3c24xx/cpu.h>
70#include <asm/plat-s3c24xx/pm.h>
71#include <asm/plat-s3c24xx/irq.h>
72
73/* wakeup irq control */
74
75#ifdef CONFIG_PM
76
77/* state for IRQs over sleep */
78
79/* default is to allow for EINT0..EINT15, and IRQ_RTC as wakeup sources
80 *
81 * set bit to 1 in allow bitfield to enable the wakeup settings on it
82*/
83
84unsigned long s3c_irqwake_intallow = 1L << (IRQ_RTC - IRQ_EINT0) | 0xfL;
85unsigned long s3c_irqwake_intmask = 0xffffffffL;
86unsigned long s3c_irqwake_eintallow = 0x0000fff0L;
87unsigned long s3c_irqwake_eintmask = 0xffffffffL;
88
89int
90s3c_irq_wake(unsigned int irqno, unsigned int state)
91{
92 unsigned long irqbit = 1 << (irqno - IRQ_EINT0);
93
94 if (!(s3c_irqwake_intallow & irqbit))
95 return -ENOENT;
96
97 printk(KERN_INFO "wake %s for irq %d\n",
98 state ? "enabled" : "disabled", irqno);
99
100 if (!state)
101 s3c_irqwake_intmask |= irqbit;
102 else
103 s3c_irqwake_intmask &= ~irqbit;
104
105 return 0;
106}
107
108static int
109s3c_irqext_wake(unsigned int irqno, unsigned int state)
110{
111 unsigned long bit = 1L << (irqno - EXTINT_OFF);
112
113 if (!(s3c_irqwake_eintallow & bit))
114 return -ENOENT;
115
116 printk(KERN_INFO "wake %s for irq %d\n",
117 state ? "enabled" : "disabled", irqno);
118
119 if (!state)
120 s3c_irqwake_eintmask |= bit;
121 else
122 s3c_irqwake_eintmask &= ~bit;
123
124 return 0;
125}
126
127#else
128#define s3c_irqext_wake NULL
129#define s3c_irq_wake NULL
130#endif
131
132
133static void
134s3c_irq_mask(unsigned int irqno)
135{
136 unsigned long mask;
137
138 irqno -= IRQ_EINT0;
139
140 mask = __raw_readl(S3C2410_INTMSK);
141 mask |= 1UL << irqno;
142 __raw_writel(mask, S3C2410_INTMSK);
143}
144
145static inline void
146s3c_irq_ack(unsigned int irqno)
147{
148 unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
149
150 __raw_writel(bitval, S3C2410_SRCPND);
151 __raw_writel(bitval, S3C2410_INTPND);
152}
153
154static inline void
155s3c_irq_maskack(unsigned int irqno)
156{
157 unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
158 unsigned long mask;
159
160 mask = __raw_readl(S3C2410_INTMSK);
161 __raw_writel(mask|bitval, S3C2410_INTMSK);
162
163 __raw_writel(bitval, S3C2410_SRCPND);
164 __raw_writel(bitval, S3C2410_INTPND);
165}
166
167
168static void
169s3c_irq_unmask(unsigned int irqno)
170{
171 unsigned long mask;
172
173 if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23)
174 irqdbf2("s3c_irq_unmask %d\n", irqno);
175
176 irqno -= IRQ_EINT0;
177
178 mask = __raw_readl(S3C2410_INTMSK);
179 mask &= ~(1UL << irqno);
180 __raw_writel(mask, S3C2410_INTMSK);
181}
182
183struct irq_chip s3c_irq_level_chip = {
184 .name = "s3c-level",
185 .ack = s3c_irq_maskack,
186 .mask = s3c_irq_mask,
187 .unmask = s3c_irq_unmask,
188 .set_wake = s3c_irq_wake
189};
190
191static struct irq_chip s3c_irq_chip = {
192 .name = "s3c",
193 .ack = s3c_irq_ack,
194 .mask = s3c_irq_mask,
195 .unmask = s3c_irq_unmask,
196 .set_wake = s3c_irq_wake
197};
198
199static void
200s3c_irqext_mask(unsigned int irqno)
201{
202 unsigned long mask;
203
204 irqno -= EXTINT_OFF;
205
206 mask = __raw_readl(S3C24XX_EINTMASK);
207 mask |= ( 1UL << irqno);
208 __raw_writel(mask, S3C24XX_EINTMASK);
209}
210
211static void
212s3c_irqext_ack(unsigned int irqno)
213{
214 unsigned long req;
215 unsigned long bit;
216 unsigned long mask;
217
218 bit = 1UL << (irqno - EXTINT_OFF);
219
220 mask = __raw_readl(S3C24XX_EINTMASK);
221
222 __raw_writel(bit, S3C24XX_EINTPEND);
223
224 req = __raw_readl(S3C24XX_EINTPEND);
225 req &= ~mask;
226
227 /* not sure if we should be acking the parent irq... */
228
229 if (irqno <= IRQ_EINT7 ) {
230 if ((req & 0xf0) == 0)
231 s3c_irq_ack(IRQ_EINT4t7);
232 } else {
233 if ((req >> 8) == 0)
234 s3c_irq_ack(IRQ_EINT8t23);
235 }
236}
237
238static void
239s3c_irqext_unmask(unsigned int irqno)
240{
241 unsigned long mask;
242
243 irqno -= EXTINT_OFF;
244
245 mask = __raw_readl(S3C24XX_EINTMASK);
246 mask &= ~( 1UL << irqno);
247 __raw_writel(mask, S3C24XX_EINTMASK);
248}
249
250int
251s3c_irqext_type(unsigned int irq, unsigned int type)
252{
253 void __iomem *extint_reg;
254 void __iomem *gpcon_reg;
255 unsigned long gpcon_offset, extint_offset;
256 unsigned long newvalue = 0, value;
257
258 if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3))
259 {
260 gpcon_reg = S3C2410_GPFCON;
261 extint_reg = S3C24XX_EXTINT0;
262 gpcon_offset = (irq - IRQ_EINT0) * 2;
263 extint_offset = (irq - IRQ_EINT0) * 4;
264 }
265 else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7))
266 {
267 gpcon_reg = S3C2410_GPFCON;
268 extint_reg = S3C24XX_EXTINT0;
269 gpcon_offset = (irq - (EXTINT_OFF)) * 2;
270 extint_offset = (irq - (EXTINT_OFF)) * 4;
271 }
272 else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15))
273 {
274 gpcon_reg = S3C2410_GPGCON;
275 extint_reg = S3C24XX_EXTINT1;
276 gpcon_offset = (irq - IRQ_EINT8) * 2;
277 extint_offset = (irq - IRQ_EINT8) * 4;
278 }
279 else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23))
280 {
281 gpcon_reg = S3C2410_GPGCON;
282 extint_reg = S3C24XX_EXTINT2;
283 gpcon_offset = (irq - IRQ_EINT8) * 2;
284 extint_offset = (irq - IRQ_EINT16) * 4;
285 } else
286 return -1;
287
288 /* Set the GPIO to external interrupt mode */
289 value = __raw_readl(gpcon_reg);
290 value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset);
291 __raw_writel(value, gpcon_reg);
292
293 /* Set the external interrupt to pointed trigger type */
294 switch (type)
295 {
296 case IRQT_NOEDGE:
297 printk(KERN_WARNING "No edge setting!\n");
298 break;
299
300 case IRQT_RISING:
301 newvalue = S3C2410_EXTINT_RISEEDGE;
302 break;
303
304 case IRQT_FALLING:
305 newvalue = S3C2410_EXTINT_FALLEDGE;
306 break;
307
308 case IRQT_BOTHEDGE:
309 newvalue = S3C2410_EXTINT_BOTHEDGE;
310 break;
311
312 case IRQT_LOW:
313 newvalue = S3C2410_EXTINT_LOWLEV;
314 break;
315
316 case IRQT_HIGH:
317 newvalue = S3C2410_EXTINT_HILEV;
318 break;
319
320 default:
321 printk(KERN_ERR "No such irq type %d", type);
322 return -1;
323 }
324
325 value = __raw_readl(extint_reg);
326 value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset);
327 __raw_writel(value, extint_reg);
328
329 return 0;
330}
331
332static struct irq_chip s3c_irqext_chip = {
333 .name = "s3c-ext",
334 .mask = s3c_irqext_mask,
335 .unmask = s3c_irqext_unmask,
336 .ack = s3c_irqext_ack,
337 .set_type = s3c_irqext_type,
338 .set_wake = s3c_irqext_wake
339};
340
341static struct irq_chip s3c_irq_eint0t4 = {
342 .name = "s3c-ext0",
343 .ack = s3c_irq_ack,
344 .mask = s3c_irq_mask,
345 .unmask = s3c_irq_unmask,
346 .set_wake = s3c_irq_wake,
347 .set_type = s3c_irqext_type,
348};
349
350/* mask values for the parent registers for each of the interrupt types */
351
352#define INTMSK_UART0 (1UL << (IRQ_UART0 - IRQ_EINT0))
353#define INTMSK_UART1 (1UL << (IRQ_UART1 - IRQ_EINT0))
354#define INTMSK_UART2 (1UL << (IRQ_UART2 - IRQ_EINT0))
355#define INTMSK_ADCPARENT (1UL << (IRQ_ADCPARENT - IRQ_EINT0))
356
357
358/* UART0 */
359
360static void
361s3c_irq_uart0_mask(unsigned int irqno)
362{
363 s3c_irqsub_mask(irqno, INTMSK_UART0, 7);
364}
365
366static void
367s3c_irq_uart0_unmask(unsigned int irqno)
368{
369 s3c_irqsub_unmask(irqno, INTMSK_UART0);
370}
371
372static void
373s3c_irq_uart0_ack(unsigned int irqno)
374{
375 s3c_irqsub_maskack(irqno, INTMSK_UART0, 7);
376}
377
378static struct irq_chip s3c_irq_uart0 = {
379 .name = "s3c-uart0",
380 .mask = s3c_irq_uart0_mask,
381 .unmask = s3c_irq_uart0_unmask,
382 .ack = s3c_irq_uart0_ack,
383};
384
385/* UART1 */
386
387static void
388s3c_irq_uart1_mask(unsigned int irqno)
389{
390 s3c_irqsub_mask(irqno, INTMSK_UART1, 7 << 3);
391}
392
393static void
394s3c_irq_uart1_unmask(unsigned int irqno)
395{
396 s3c_irqsub_unmask(irqno, INTMSK_UART1);
397}
398
399static void
400s3c_irq_uart1_ack(unsigned int irqno)
401{
402 s3c_irqsub_maskack(irqno, INTMSK_UART1, 7 << 3);
403}
404
405static struct irq_chip s3c_irq_uart1 = {
406 .name = "s3c-uart1",
407 .mask = s3c_irq_uart1_mask,
408 .unmask = s3c_irq_uart1_unmask,
409 .ack = s3c_irq_uart1_ack,
410};
411
412/* UART2 */
413
414static void
415s3c_irq_uart2_mask(unsigned int irqno)
416{
417 s3c_irqsub_mask(irqno, INTMSK_UART2, 7 << 6);
418}
419
420static void
421s3c_irq_uart2_unmask(unsigned int irqno)
422{
423 s3c_irqsub_unmask(irqno, INTMSK_UART2);
424}
425
426static void
427s3c_irq_uart2_ack(unsigned int irqno)
428{
429 s3c_irqsub_maskack(irqno, INTMSK_UART2, 7 << 6);
430}
431
432static struct irq_chip s3c_irq_uart2 = {
433 .name = "s3c-uart2",
434 .mask = s3c_irq_uart2_mask,
435 .unmask = s3c_irq_uart2_unmask,
436 .ack = s3c_irq_uart2_ack,
437};
438
439/* ADC and Touchscreen */
440
441static void
442s3c_irq_adc_mask(unsigned int irqno)
443{
444 s3c_irqsub_mask(irqno, INTMSK_ADCPARENT, 3 << 9);
445}
446
447static void
448s3c_irq_adc_unmask(unsigned int irqno)
449{
450 s3c_irqsub_unmask(irqno, INTMSK_ADCPARENT);
451}
452
453static void
454s3c_irq_adc_ack(unsigned int irqno)
455{
456 s3c_irqsub_ack(irqno, INTMSK_ADCPARENT, 3 << 9);
457}
458
459static struct irq_chip s3c_irq_adc = {
460 .name = "s3c-adc",
461 .mask = s3c_irq_adc_mask,
462 .unmask = s3c_irq_adc_unmask,
463 .ack = s3c_irq_adc_ack,
464};
465
466/* irq demux for adc */
467static void s3c_irq_demux_adc(unsigned int irq,
468 struct irq_desc *desc)
469{
470 unsigned int subsrc, submsk;
471 unsigned int offset = 9;
472 struct irq_desc *mydesc;
473
474 /* read the current pending interrupts, and the mask
475 * for what it is available */
476
477 subsrc = __raw_readl(S3C2410_SUBSRCPND);
478 submsk = __raw_readl(S3C2410_INTSUBMSK);
479
480 subsrc &= ~submsk;
481 subsrc >>= offset;
482 subsrc &= 3;
483
484 if (subsrc != 0) {
485 if (subsrc & 1) {
486 mydesc = irq_desc + IRQ_TC;
487 desc_handle_irq(IRQ_TC, mydesc);
488 }
489 if (subsrc & 2) {
490 mydesc = irq_desc + IRQ_ADC;
491 desc_handle_irq(IRQ_ADC, mydesc);
492 }
493 }
494}
495
496static void s3c_irq_demux_uart(unsigned int start)
497{
498 unsigned int subsrc, submsk;
499 unsigned int offset = start - IRQ_S3CUART_RX0;
500 struct irq_desc *desc;
501
502 /* read the current pending interrupts, and the mask
503 * for what it is available */
504
505 subsrc = __raw_readl(S3C2410_SUBSRCPND);
506 submsk = __raw_readl(S3C2410_INTSUBMSK);
507
508 irqdbf2("s3c_irq_demux_uart: start=%d (%d), subsrc=0x%08x,0x%08x\n",
509 start, offset, subsrc, submsk);
510
511 subsrc &= ~submsk;
512 subsrc >>= offset;
513 subsrc &= 7;
514
515 if (subsrc != 0) {
516 desc = irq_desc + start;
517
518 if (subsrc & 1)
519 desc_handle_irq(start, desc);
520
521 desc++;
522
523 if (subsrc & 2)
524 desc_handle_irq(start+1, desc);
525
526 desc++;
527
528 if (subsrc & 4)
529 desc_handle_irq(start+2, desc);
530 }
531}
532
533/* uart demux entry points */
534
535static void
536s3c_irq_demux_uart0(unsigned int irq,
537 struct irq_desc *desc)
538{
539 irq = irq;
540 s3c_irq_demux_uart(IRQ_S3CUART_RX0);
541}
542
543static void
544s3c_irq_demux_uart1(unsigned int irq,
545 struct irq_desc *desc)
546{
547 irq = irq;
548 s3c_irq_demux_uart(IRQ_S3CUART_RX1);
549}
550
551static void
552s3c_irq_demux_uart2(unsigned int irq,
553 struct irq_desc *desc)
554{
555 irq = irq;
556 s3c_irq_demux_uart(IRQ_S3CUART_RX2);
557}
558
559static void
560s3c_irq_demux_extint8(unsigned int irq,
561 struct irq_desc *desc)
562{
563 unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
564 unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
565
566 eintpnd &= ~eintmsk;
567 eintpnd &= ~0xff; /* ignore lower irqs */
568
569 /* we may as well handle all the pending IRQs here */
570
571 while (eintpnd) {
572 irq = __ffs(eintpnd);
573 eintpnd &= ~(1<<irq);
574
575 irq += (IRQ_EINT4 - 4);
576 desc_handle_irq(irq, irq_desc + irq);
577 }
578
579}
580
581static void
582s3c_irq_demux_extint4t7(unsigned int irq,
583 struct irq_desc *desc)
584{
585 unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
586 unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
587
588 eintpnd &= ~eintmsk;
589 eintpnd &= 0xff; /* only lower irqs */
590
591 /* we may as well handle all the pending IRQs here */
592
593 while (eintpnd) {
594 irq = __ffs(eintpnd);
595 eintpnd &= ~(1<<irq);
596
597 irq += (IRQ_EINT4 - 4);
598
599 desc_handle_irq(irq, irq_desc + irq);
600 }
601}
602
603#ifdef CONFIG_PM
604
605static struct sleep_save irq_save[] = {
606 SAVE_ITEM(S3C2410_INTMSK),
607 SAVE_ITEM(S3C2410_INTSUBMSK),
608};
609
610/* the extint values move between the s3c2410/s3c2440 and the s3c2412
611 * so we use an array to hold them, and to calculate the address of
612 * the register at run-time
613*/
614
615static unsigned long save_extint[3];
616static unsigned long save_eintflt[4];
617static unsigned long save_eintmask;
618
619int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state)
620{
621 unsigned int i;
622
623 for (i = 0; i < ARRAY_SIZE(save_extint); i++)
624 save_extint[i] = __raw_readl(S3C24XX_EXTINT0 + (i*4));
625
626 for (i = 0; i < ARRAY_SIZE(save_eintflt); i++)
627 save_eintflt[i] = __raw_readl(S3C24XX_EINFLT0 + (i*4));
628
629 s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save));
630 save_eintmask = __raw_readl(S3C24XX_EINTMASK);
631
632 return 0;
633}
634
635int s3c24xx_irq_resume(struct sys_device *dev)
636{
637 unsigned int i;
638
639 for (i = 0; i < ARRAY_SIZE(save_extint); i++)
640 __raw_writel(save_extint[i], S3C24XX_EXTINT0 + (i*4));
641
642 for (i = 0; i < ARRAY_SIZE(save_eintflt); i++)
643 __raw_writel(save_eintflt[i], S3C24XX_EINFLT0 + (i*4));
644
645 s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
646 __raw_writel(save_eintmask, S3C24XX_EINTMASK);
647
648 return 0;
649}
650
651#else
652#define s3c24xx_irq_suspend NULL
653#define s3c24xx_irq_resume NULL
654#endif
655
656/* s3c24xx_init_irq
657 *
658 * Initialise S3C2410 IRQ system
659*/
660
661void __init s3c24xx_init_irq(void)
662{
663 unsigned long pend;
664 unsigned long last;
665 int irqno;
666 int i;
667
668 irqdbf("s3c2410_init_irq: clearing interrupt status flags\n");
669
670 /* first, clear all interrupts pending... */
671
672 last = 0;
673 for (i = 0; i < 4; i++) {
674 pend = __raw_readl(S3C24XX_EINTPEND);
675
676 if (pend == 0 || pend == last)
677 break;
678
679 __raw_writel(pend, S3C24XX_EINTPEND);
680 printk("irq: clearing pending ext status %08x\n", (int)pend);
681 last = pend;
682 }
683
684 last = 0;
685 for (i = 0; i < 4; i++) {
686 pend = __raw_readl(S3C2410_INTPND);
687
688 if (pend == 0 || pend == last)
689 break;
690
691 __raw_writel(pend, S3C2410_SRCPND);
692 __raw_writel(pend, S3C2410_INTPND);
693 printk("irq: clearing pending status %08x\n", (int)pend);
694 last = pend;
695 }
696
697 last = 0;
698 for (i = 0; i < 4; i++) {
699 pend = __raw_readl(S3C2410_SUBSRCPND);
700
701 if (pend == 0 || pend == last)
702 break;
703
704 printk("irq: clearing subpending status %08x\n", (int)pend);
705 __raw_writel(pend, S3C2410_SUBSRCPND);
706 last = pend;
707 }
708
709 /* register the main interrupts */
710
711 irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n");
712
713 for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) {
714 /* set all the s3c2410 internal irqs */
715
716 switch (irqno) {
717 /* deal with the special IRQs (cascaded) */
718
719 case IRQ_EINT4t7:
720 case IRQ_EINT8t23:
721 case IRQ_UART0:
722 case IRQ_UART1:
723 case IRQ_UART2:
724 case IRQ_ADCPARENT:
725 set_irq_chip(irqno, &s3c_irq_level_chip);
726 set_irq_handler(irqno, handle_level_irq);
727 break;
728
729 case IRQ_RESERVED6:
730 case IRQ_RESERVED24:
731 /* no IRQ here */
732 break;
733
734 default:
735 //irqdbf("registering irq %d (s3c irq)\n", irqno);
736 set_irq_chip(irqno, &s3c_irq_chip);
737 set_irq_handler(irqno, handle_edge_irq);
738 set_irq_flags(irqno, IRQF_VALID);
739 }
740 }
741
742 /* setup the cascade irq handlers */
743
744 set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7);
745 set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8);
746
747 set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
748 set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);
749 set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2);
750 set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc);
751
752 /* external interrupts */
753
754 for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
755 irqdbf("registering irq %d (ext int)\n", irqno);
756 set_irq_chip(irqno, &s3c_irq_eint0t4);
757 set_irq_handler(irqno, handle_edge_irq);
758 set_irq_flags(irqno, IRQF_VALID);
759 }
760
761 for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {
762 irqdbf("registering irq %d (extended s3c irq)\n", irqno);
763 set_irq_chip(irqno, &s3c_irqext_chip);
764 set_irq_handler(irqno, handle_edge_irq);
765 set_irq_flags(irqno, IRQF_VALID);
766 }
767
768 /* register the uart interrupts */
769
770 irqdbf("s3c2410: registering external interrupts\n");
771
772 for (irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) {
773 irqdbf("registering irq %d (s3c uart0 irq)\n", irqno);
774 set_irq_chip(irqno, &s3c_irq_uart0);
775 set_irq_handler(irqno, handle_level_irq);
776 set_irq_flags(irqno, IRQF_VALID);
777 }
778
779 for (irqno = IRQ_S3CUART_RX1; irqno <= IRQ_S3CUART_ERR1; irqno++) {
780 irqdbf("registering irq %d (s3c uart1 irq)\n", irqno);
781 set_irq_chip(irqno, &s3c_irq_uart1);
782 set_irq_handler(irqno, handle_level_irq);
783 set_irq_flags(irqno, IRQF_VALID);
784 }
785
786 for (irqno = IRQ_S3CUART_RX2; irqno <= IRQ_S3CUART_ERR2; irqno++) {
787 irqdbf("registering irq %d (s3c uart2 irq)\n", irqno);
788 set_irq_chip(irqno, &s3c_irq_uart2);
789 set_irq_handler(irqno, handle_level_irq);
790 set_irq_flags(irqno, IRQF_VALID);
791 }
792
793 for (irqno = IRQ_TC; irqno <= IRQ_ADC; irqno++) {
794 irqdbf("registering irq %d (s3c adc irq)\n", irqno);
795 set_irq_chip(irqno, &s3c_irq_adc);
796 set_irq_handler(irqno, handle_edge_irq);
797 set_irq_flags(irqno, IRQF_VALID);
798 }
799
800 irqdbf("s3c2410: registered interrupt handlers\n");
801}
diff --git a/arch/arm/mach-s3c2410/pm-simtec.c b/arch/arm/plat-s3c24xx/pm-simtec.c
index 619133eb7168..bd965f2feeca 100644
--- a/arch/arm/mach-s3c2410/pm-simtec.c
+++ b/arch/arm/plat-s3c24xx/pm-simtec.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/pm-simtec.c 1/* linux/arch/arm/plat-s3c24xx/pm-simtec.c
2 * 2 *
3 * Copyright (c) 2004 Simtec Electronics 3 * Copyright (c) 2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
@@ -32,7 +32,7 @@
32 32
33#include <asm/mach-types.h> 33#include <asm/mach-types.h>
34 34
35#include "pm.h" 35#include <asm/plat-s3c24xx/pm.h>
36 36
37#define COPYRIGHT ", (c) 2005 Simtec Electronics" 37#define COPYRIGHT ", (c) 2005 Simtec Electronics"
38 38
diff --git a/arch/arm/plat-s3c24xx/pm.c b/arch/arm/plat-s3c24xx/pm.c
new file mode 100644
index 000000000000..ecf68d611904
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/pm.c
@@ -0,0 +1,659 @@
1/* linux/arch/arm/plat-s3c24xx/pm.c
2 *
3 * Copyright (c) 2004,2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * S3C24XX Power Manager (Suspend-To-RAM) support
7 *
8 * See Documentation/arm/Samsung-S3C24XX/Suspend.txt for more information
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 * Parts based on arch/arm/mach-pxa/pm.c
25 *
26 * Thanks to Dimitry Andric for debugging
27*/
28
29#include <linux/init.h>
30#include <linux/suspend.h>
31#include <linux/errno.h>
32#include <linux/time.h>
33#include <linux/interrupt.h>
34#include <linux/crc32.h>
35#include <linux/ioport.h>
36#include <linux/delay.h>
37#include <linux/serial_core.h>
38
39#include <asm/cacheflush.h>
40#include <asm/hardware.h>
41#include <asm/io.h>
42
43#include <asm/arch/regs-serial.h>
44#include <asm/arch/regs-clock.h>
45#include <asm/arch/regs-gpio.h>
46#include <asm/arch/regs-mem.h>
47#include <asm/arch/regs-irq.h>
48
49#include <asm/mach/time.h>
50
51#include <asm/plat-s3c24xx/pm.h>
52
53/* for external use */
54
55unsigned long s3c_pm_flags;
56
57#define PFX "s3c24xx-pm: "
58
59static struct sleep_save core_save[] = {
60 SAVE_ITEM(S3C2410_LOCKTIME),
61 SAVE_ITEM(S3C2410_CLKCON),
62
63 /* we restore the timings here, with the proviso that the board
64 * brings the system up in an slower, or equal frequency setting
65 * to the original system.
66 *
67 * if we cannot guarantee this, then things are going to go very
68 * wrong here, as we modify the refresh and both pll settings.
69 */
70
71 SAVE_ITEM(S3C2410_BWSCON),
72 SAVE_ITEM(S3C2410_BANKCON0),
73 SAVE_ITEM(S3C2410_BANKCON1),
74 SAVE_ITEM(S3C2410_BANKCON2),
75 SAVE_ITEM(S3C2410_BANKCON3),
76 SAVE_ITEM(S3C2410_BANKCON4),
77 SAVE_ITEM(S3C2410_BANKCON5),
78
79 SAVE_ITEM(S3C2410_CLKDIVN),
80 SAVE_ITEM(S3C2410_MPLLCON),
81 SAVE_ITEM(S3C2410_UPLLCON),
82 SAVE_ITEM(S3C2410_CLKSLOW),
83 SAVE_ITEM(S3C2410_REFRESH),
84};
85
86static struct sleep_save gpio_save[] = {
87 SAVE_ITEM(S3C2410_GPACON),
88 SAVE_ITEM(S3C2410_GPADAT),
89
90 SAVE_ITEM(S3C2410_GPBCON),
91 SAVE_ITEM(S3C2410_GPBDAT),
92 SAVE_ITEM(S3C2410_GPBUP),
93
94 SAVE_ITEM(S3C2410_GPCCON),
95 SAVE_ITEM(S3C2410_GPCDAT),
96 SAVE_ITEM(S3C2410_GPCUP),
97
98 SAVE_ITEM(S3C2410_GPDCON),
99 SAVE_ITEM(S3C2410_GPDDAT),
100 SAVE_ITEM(S3C2410_GPDUP),
101
102 SAVE_ITEM(S3C2410_GPECON),
103 SAVE_ITEM(S3C2410_GPEDAT),
104 SAVE_ITEM(S3C2410_GPEUP),
105
106 SAVE_ITEM(S3C2410_GPFCON),
107 SAVE_ITEM(S3C2410_GPFDAT),
108 SAVE_ITEM(S3C2410_GPFUP),
109
110 SAVE_ITEM(S3C2410_GPGCON),
111 SAVE_ITEM(S3C2410_GPGDAT),
112 SAVE_ITEM(S3C2410_GPGUP),
113
114 SAVE_ITEM(S3C2410_GPHCON),
115 SAVE_ITEM(S3C2410_GPHDAT),
116 SAVE_ITEM(S3C2410_GPHUP),
117
118 SAVE_ITEM(S3C2410_DCLKCON),
119};
120
121#ifdef CONFIG_S3C2410_PM_DEBUG
122
123#define SAVE_UART(va) \
124 SAVE_ITEM((va) + S3C2410_ULCON), \
125 SAVE_ITEM((va) + S3C2410_UCON), \
126 SAVE_ITEM((va) + S3C2410_UFCON), \
127 SAVE_ITEM((va) + S3C2410_UMCON), \
128 SAVE_ITEM((va) + S3C2410_UBRDIV)
129
130static struct sleep_save uart_save[] = {
131 SAVE_UART(S3C24XX_VA_UART0),
132 SAVE_UART(S3C24XX_VA_UART1),
133#ifndef CONFIG_CPU_S3C2400
134 SAVE_UART(S3C24XX_VA_UART2),
135#endif
136};
137
138/* debug
139 *
140 * we send the debug to printascii() to allow it to be seen if the
141 * system never wakes up from the sleep
142*/
143
144extern void printascii(const char *);
145
146void pm_dbg(const char *fmt, ...)
147{
148 va_list va;
149 char buff[256];
150
151 va_start(va, fmt);
152 vsprintf(buff, fmt, va);
153 va_end(va);
154
155 printascii(buff);
156}
157
158static void s3c2410_pm_debug_init(void)
159{
160 unsigned long tmp = __raw_readl(S3C2410_CLKCON);
161
162 /* re-start uart clocks */
163 tmp |= S3C2410_CLKCON_UART0;
164 tmp |= S3C2410_CLKCON_UART1;
165 tmp |= S3C2410_CLKCON_UART2;
166
167 __raw_writel(tmp, S3C2410_CLKCON);
168 udelay(10);
169}
170
171#define DBG(fmt...) pm_dbg(fmt)
172#else
173#define DBG(fmt...) printk(KERN_DEBUG fmt)
174
175#define s3c2410_pm_debug_init() do { } while(0)
176
177static struct sleep_save uart_save[] = {};
178#endif
179
180#if defined(CONFIG_S3C2410_PM_CHECK) && CONFIG_S3C2410_PM_CHECK_CHUNKSIZE != 0
181
182/* suspend checking code...
183 *
184 * this next area does a set of crc checks over all the installed
185 * memory, so the system can verify if the resume was ok.
186 *
187 * CONFIG_S3C2410_PM_CHECK_CHUNKSIZE defines the block-size for the CRC,
188 * increasing it will mean that the area corrupted will be less easy to spot,
189 * and reducing the size will cause the CRC save area to grow
190*/
191
192#define CHECK_CHUNKSIZE (CONFIG_S3C2410_PM_CHECK_CHUNKSIZE * 1024)
193
194static u32 crc_size; /* size needed for the crc block */
195static u32 *crcs; /* allocated over suspend/resume */
196
197typedef u32 *(run_fn_t)(struct resource *ptr, u32 *arg);
198
199/* s3c2410_pm_run_res
200 *
201 * go thorugh the given resource list, and look for system ram
202*/
203
204static void s3c2410_pm_run_res(struct resource *ptr, run_fn_t fn, u32 *arg)
205{
206 while (ptr != NULL) {
207 if (ptr->child != NULL)
208 s3c2410_pm_run_res(ptr->child, fn, arg);
209
210 if ((ptr->flags & IORESOURCE_MEM) &&
211 strcmp(ptr->name, "System RAM") == 0) {
212 DBG("Found system RAM at %08lx..%08lx\n",
213 ptr->start, ptr->end);
214 arg = (fn)(ptr, arg);
215 }
216
217 ptr = ptr->sibling;
218 }
219}
220
221static void s3c2410_pm_run_sysram(run_fn_t fn, u32 *arg)
222{
223 s3c2410_pm_run_res(&iomem_resource, fn, arg);
224}
225
226static u32 *s3c2410_pm_countram(struct resource *res, u32 *val)
227{
228 u32 size = (u32)(res->end - res->start)+1;
229
230 size += CHECK_CHUNKSIZE-1;
231 size /= CHECK_CHUNKSIZE;
232
233 DBG("Area %08lx..%08lx, %d blocks\n", res->start, res->end, size);
234
235 *val += size * sizeof(u32);
236 return val;
237}
238
239/* s3c2410_pm_prepare_check
240 *
241 * prepare the necessary information for creating the CRCs. This
242 * must be done before the final save, as it will require memory
243 * allocating, and thus touching bits of the kernel we do not
244 * know about.
245*/
246
247static void s3c2410_pm_check_prepare(void)
248{
249 crc_size = 0;
250
251 s3c2410_pm_run_sysram(s3c2410_pm_countram, &crc_size);
252
253 DBG("s3c2410_pm_prepare_check: %u checks needed\n", crc_size);
254
255 crcs = kmalloc(crc_size+4, GFP_KERNEL);
256 if (crcs == NULL)
257 printk(KERN_ERR "Cannot allocated CRC save area\n");
258}
259
260static u32 *s3c2410_pm_makecheck(struct resource *res, u32 *val)
261{
262 unsigned long addr, left;
263
264 for (addr = res->start; addr < res->end;
265 addr += CHECK_CHUNKSIZE) {
266 left = res->end - addr;
267
268 if (left > CHECK_CHUNKSIZE)
269 left = CHECK_CHUNKSIZE;
270
271 *val = crc32_le(~0, phys_to_virt(addr), left);
272 val++;
273 }
274
275 return val;
276}
277
278/* s3c2410_pm_check_store
279 *
280 * compute the CRC values for the memory blocks before the final
281 * sleep.
282*/
283
284static void s3c2410_pm_check_store(void)
285{
286 if (crcs != NULL)
287 s3c2410_pm_run_sysram(s3c2410_pm_makecheck, crcs);
288}
289
290/* in_region
291 *
292 * return TRUE if the area defined by ptr..ptr+size contatins the
293 * what..what+whatsz
294*/
295
296static inline int in_region(void *ptr, int size, void *what, size_t whatsz)
297{
298 if ((what+whatsz) < ptr)
299 return 0;
300
301 if (what > (ptr+size))
302 return 0;
303
304 return 1;
305}
306
307static u32 *s3c2410_pm_runcheck(struct resource *res, u32 *val)
308{
309 void *save_at = phys_to_virt(s3c2410_sleep_save_phys);
310 unsigned long addr;
311 unsigned long left;
312 void *ptr;
313 u32 calc;
314
315 for (addr = res->start; addr < res->end;
316 addr += CHECK_CHUNKSIZE) {
317 left = res->end - addr;
318
319 if (left > CHECK_CHUNKSIZE)
320 left = CHECK_CHUNKSIZE;
321
322 ptr = phys_to_virt(addr);
323
324 if (in_region(ptr, left, crcs, crc_size)) {
325 DBG("skipping %08lx, has crc block in\n", addr);
326 goto skip_check;
327 }
328
329 if (in_region(ptr, left, save_at, 32*4 )) {
330 DBG("skipping %08lx, has save block in\n", addr);
331 goto skip_check;
332 }
333
334 /* calculate and check the checksum */
335
336 calc = crc32_le(~0, ptr, left);
337 if (calc != *val) {
338 printk(KERN_ERR PFX "Restore CRC error at "
339 "%08lx (%08x vs %08x)\n", addr, calc, *val);
340
341 DBG("Restore CRC error at %08lx (%08x vs %08x)\n",
342 addr, calc, *val);
343 }
344
345 skip_check:
346 val++;
347 }
348
349 return val;
350}
351
352/* s3c2410_pm_check_restore
353 *
354 * check the CRCs after the restore event and free the memory used
355 * to hold them
356*/
357
358static void s3c2410_pm_check_restore(void)
359{
360 if (crcs != NULL) {
361 s3c2410_pm_run_sysram(s3c2410_pm_runcheck, crcs);
362 kfree(crcs);
363 crcs = NULL;
364 }
365}
366
367#else
368
369#define s3c2410_pm_check_prepare() do { } while(0)
370#define s3c2410_pm_check_restore() do { } while(0)
371#define s3c2410_pm_check_store() do { } while(0)
372#endif
373
374/* helper functions to save and restore register state */
375
376void s3c2410_pm_do_save(struct sleep_save *ptr, int count)
377{
378 for (; count > 0; count--, ptr++) {
379 ptr->val = __raw_readl(ptr->reg);
380 DBG("saved %p value %08lx\n", ptr->reg, ptr->val);
381 }
382}
383
384/* s3c2410_pm_do_restore
385 *
386 * restore the system from the given list of saved registers
387 *
388 * Note, we do not use DBG() in here, as the system may not have
389 * restore the UARTs state yet
390*/
391
392void s3c2410_pm_do_restore(struct sleep_save *ptr, int count)
393{
394 for (; count > 0; count--, ptr++) {
395 printk(KERN_DEBUG "restore %p (restore %08lx, was %08x)\n",
396 ptr->reg, ptr->val, __raw_readl(ptr->reg));
397
398 __raw_writel(ptr->val, ptr->reg);
399 }
400}
401
402/* s3c2410_pm_do_restore_core
403 *
404 * similar to s3c2410_pm_do_restore_core
405 *
406 * WARNING: Do not put any debug in here that may effect memory or use
407 * peripherals, as things may be changing!
408*/
409
410static void s3c2410_pm_do_restore_core(struct sleep_save *ptr, int count)
411{
412 for (; count > 0; count--, ptr++) {
413 __raw_writel(ptr->val, ptr->reg);
414 }
415}
416
417/* s3c2410_pm_show_resume_irqs
418 *
419 * print any IRQs asserted at resume time (ie, we woke from)
420*/
421
422static void s3c2410_pm_show_resume_irqs(int start, unsigned long which,
423 unsigned long mask)
424{
425 int i;
426
427 which &= ~mask;
428
429 for (i = 0; i <= 31; i++) {
430 if ((which) & (1L<<i)) {
431 DBG("IRQ %d asserted at resume\n", start+i);
432 }
433 }
434}
435
436/* s3c2410_pm_check_resume_pin
437 *
438 * check to see if the pin is configured correctly for sleep mode, and
439 * make any necessary adjustments if it is not
440*/
441
442static void s3c2410_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs)
443{
444 unsigned long irqstate;
445 unsigned long pinstate;
446 int irq = s3c2410_gpio_getirq(pin);
447
448 if (irqoffs < 4)
449 irqstate = s3c_irqwake_intmask & (1L<<irqoffs);
450 else
451 irqstate = s3c_irqwake_eintmask & (1L<<irqoffs);
452
453 pinstate = s3c2410_gpio_getcfg(pin);
454
455 if (!irqstate) {
456 if (pinstate == S3C2410_GPIO_IRQ)
457 DBG("Leaving IRQ %d (pin %d) enabled\n", irq, pin);
458 } else {
459 if (pinstate == S3C2410_GPIO_IRQ) {
460 DBG("Disabling IRQ %d (pin %d)\n", irq, pin);
461 s3c2410_gpio_cfgpin(pin, S3C2410_GPIO_INPUT);
462 }
463 }
464}
465
466/* s3c2410_pm_configure_extint
467 *
468 * configure all external interrupt pins
469*/
470
471static void s3c2410_pm_configure_extint(void)
472{
473 int pin;
474
475 /* for each of the external interrupts (EINT0..EINT15) we
476 * need to check wether it is an external interrupt source,
477 * and then configure it as an input if it is not
478 */
479
480 for (pin = S3C2410_GPF0; pin <= S3C2410_GPF7; pin++) {
481 s3c2410_pm_check_resume_pin(pin, pin - S3C2410_GPF0);
482 }
483
484 for (pin = S3C2410_GPG0; pin <= S3C2410_GPG7; pin++) {
485 s3c2410_pm_check_resume_pin(pin, (pin - S3C2410_GPG0)+8);
486 }
487}
488
489void (*pm_cpu_prep)(void);
490void (*pm_cpu_sleep)(void);
491
492#define any_allowed(mask, allow) (((mask) & (allow)) != (allow))
493
494/* s3c2410_pm_enter
495 *
496 * central control for sleep/resume process
497*/
498
499static int s3c2410_pm_enter(suspend_state_t state)
500{
501 unsigned long regs_save[16];
502
503 /* ensure the debug is initialised (if enabled) */
504
505 s3c2410_pm_debug_init();
506
507 DBG("s3c2410_pm_enter(%d)\n", state);
508
509 if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) {
510 printk(KERN_ERR PFX "error: no cpu sleep functions set\n");
511 return -EINVAL;
512 }
513
514 if (state != PM_SUSPEND_MEM) {
515 printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n");
516 return -EINVAL;
517 }
518
519 /* check if we have anything to wake-up with... bad things seem
520 * to happen if you suspend with no wakeup (system will often
521 * require a full power-cycle)
522 */
523
524 if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) &&
525 !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) {
526 printk(KERN_ERR PFX "No sources enabled for wake-up!\n");
527 printk(KERN_ERR PFX "Aborting sleep\n");
528 return -EINVAL;
529 }
530
531 /* prepare check area if configured */
532
533 s3c2410_pm_check_prepare();
534
535 /* store the physical address of the register recovery block */
536
537 s3c2410_sleep_save_phys = virt_to_phys(regs_save);
538
539 DBG("s3c2410_sleep_save_phys=0x%08lx\n", s3c2410_sleep_save_phys);
540
541 /* save all necessary core registers not covered by the drivers */
542
543 s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save));
544 s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save));
545 s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save));
546
547 /* set the irq configuration for wake */
548
549 s3c2410_pm_configure_extint();
550
551 DBG("sleep: irq wakeup masks: %08lx,%08lx\n",
552 s3c_irqwake_intmask, s3c_irqwake_eintmask);
553
554 __raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK);
555 __raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK);
556
557 /* ack any outstanding external interrupts before we go to sleep */
558
559 __raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND);
560 __raw_writel(__raw_readl(S3C2410_INTPND), S3C2410_INTPND);
561 __raw_writel(__raw_readl(S3C2410_SRCPND), S3C2410_SRCPND);
562
563 /* call cpu specific preperation */
564
565 pm_cpu_prep();
566
567 /* flush cache back to ram */
568
569 flush_cache_all();
570
571 s3c2410_pm_check_store();
572
573 /* send the cpu to sleep... */
574
575 __raw_writel(0x00, S3C2410_CLKCON); /* turn off clocks over sleep */
576
577 /* s3c2410_cpu_save will also act as our return point from when
578 * we resume as it saves its own register state, so use the return
579 * code to differentiate return from save and return from sleep */
580
581 if (s3c2410_cpu_save(regs_save) == 0) {
582 flush_cache_all();
583 pm_cpu_sleep();
584 }
585
586 /* restore the cpu state */
587
588 cpu_init();
589
590 /* restore the system state */
591
592 s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save));
593 s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save));
594 s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save));
595
596 s3c2410_pm_debug_init();
597
598 /* check what irq (if any) restored the system */
599
600 DBG("post sleep: IRQs 0x%08x, 0x%08x\n",
601 __raw_readl(S3C2410_SRCPND),
602 __raw_readl(S3C2410_EINTPEND));
603
604 s3c2410_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND),
605 s3c_irqwake_intmask);
606
607 s3c2410_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND),
608 s3c_irqwake_eintmask);
609
610 DBG("post sleep, preparing to return\n");
611
612 s3c2410_pm_check_restore();
613
614 /* ok, let's return from sleep */
615
616 DBG("S3C2410 PM Resume (post-restore)\n");
617 return 0;
618}
619
620/*
621 * Called after processes are frozen, but before we shut down devices.
622 */
623static int s3c2410_pm_prepare(suspend_state_t state)
624{
625 return 0;
626}
627
628/*
629 * Called after devices are re-setup, but before processes are thawed.
630 */
631static int s3c2410_pm_finish(suspend_state_t state)
632{
633 return 0;
634}
635
636/*
637 * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
638 */
639static struct pm_ops s3c2410_pm_ops = {
640 .pm_disk_mode = PM_DISK_FIRMWARE,
641 .prepare = s3c2410_pm_prepare,
642 .enter = s3c2410_pm_enter,
643 .finish = s3c2410_pm_finish,
644};
645
646/* s3c2410_pm_init
647 *
648 * Attach the power management functions. This should be called
649 * from the board specific initialisation if the board supports
650 * it.
651*/
652
653int __init s3c2410_pm_init(void)
654{
655 printk("S3C2410 Power Management, (c) 2004 Simtec Electronics\n");
656
657 pm_set_ops(&s3c2410_pm_ops);
658 return 0;
659}
diff --git a/arch/arm/mach-s3c2410/s3c244x-irq.c b/arch/arm/plat-s3c24xx/s3c244x-irq.c
index ede94636a72a..a0e39d894014 100644
--- a/arch/arm/mach-s3c2410/s3c244x-irq.c
+++ b/arch/arm/plat-s3c24xx/s3c244x-irq.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/s3c244x-irq.c 1/* linux/arch/arm/plat-s3c24xx/s3c244x-irq.c
2 * 2 *
3 * Copyright (c) 2003,2004 Simtec Electronics 3 * Copyright (c) 2003,2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
@@ -35,9 +35,9 @@
35#include <asm/arch/regs-irq.h> 35#include <asm/arch/regs-irq.h>
36#include <asm/arch/regs-gpio.h> 36#include <asm/arch/regs-gpio.h>
37 37
38#include "cpu.h" 38#include <asm/plat-s3c24xx/cpu.h>
39#include "pm.h" 39#include <asm/plat-s3c24xx/pm.h>
40#include "irq.h" 40#include <asm/plat-s3c24xx/irq.h>
41 41
42/* camera irq */ 42/* camera irq */
43 43
diff --git a/arch/arm/mach-s3c2410/s3c244x.c b/arch/arm/plat-s3c24xx/s3c244x.c
index 23c7494ad10d..87aace4c8f8c 100644
--- a/arch/arm/mach-s3c2410/s3c244x.c
+++ b/arch/arm/plat-s3c24xx/s3c244x.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/s3c244x.c 1/* linux/arch/arm/plat-s3c24xx/s3c244x.c
2 * 2 *
3 * Copyright (c) 2004-2006 Simtec Electronics 3 * Copyright (c) 2004-2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
@@ -35,13 +35,13 @@
35#include <asm/arch/regs-gpioj.h> 35#include <asm/arch/regs-gpioj.h>
36#include <asm/arch/regs-dsc.h> 36#include <asm/arch/regs-dsc.h>
37 37
38#include "s3c2410.h" 38#include <asm/plat-s3c24xx/s3c2410.h>
39#include "s3c2440.h" 39#include <asm/plat-s3c24xx/s3c2440.h>
40#include "s3c244x.h" 40#include "s3c244x.h"
41#include "clock.h" 41#include <asm/plat-s3c24xx/clock.h>
42#include "devs.h" 42#include <asm/plat-s3c24xx/devs.h>
43#include "cpu.h" 43#include <asm/plat-s3c24xx/cpu.h>
44#include "pm.h" 44#include <asm/plat-s3c24xx/pm.h>
45 45
46static struct map_desc s3c244x_iodesc[] __initdata = { 46static struct map_desc s3c244x_iodesc[] __initdata = {
47 IODESC_ENT(CLKPWR), 47 IODESC_ENT(CLKPWR),
diff --git a/arch/arm/mach-s3c2410/s3c244x.h b/arch/arm/plat-s3c24xx/s3c244x.h
index 1488c1eb37e6..f8ed17676a35 100644
--- a/arch/arm/mach-s3c2410/s3c244x.h
+++ b/arch/arm/plat-s3c24xx/s3c244x.h
@@ -1,4 +1,4 @@
1/* arch/arm/mach-s3c2410/s3c244x.h 1/* linux/arch/arm/plat-s3c24xx/s3c244x.h
2 * 2 *
3 * Copyright (c) 2004-2005 Simtec Electronics 3 * Copyright (c) 2004-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * 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 000000000000..2018c2e1dcc5
--- /dev/null
+++ b/arch/arm/plat-s3c24xx/sleep.S
@@ -0,0 +1,159 @@
1/* linux/arch/arm/mach-s3c2410/sleep.S
2 *
3 * Copyright (c) 2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * S3C2410 Power Manager (Suspend-To-RAM) support
7 *
8 * Based on PXA/SA1100 sleep code by:
9 * Nicolas Pitre, (c) 2002 Monta Vista Software Inc
10 * Cliff Brake, (c) 2001
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25*/
26
27#include <linux/linkage.h>
28#include <asm/assembler.h>
29#include <asm/hardware.h>
30#include <asm/arch/map.h>
31
32#include <asm/arch/regs-gpio.h>
33#include <asm/arch/regs-clock.h>
34#include <asm/arch/regs-mem.h>
35#include <asm/arch/regs-serial.h>
36
37/* CONFIG_DEBUG_RESUME is dangerous if your bootloader does not
38 * reset the UART configuration, only enable if you really need this!
39*/
40//#define CONFIG_DEBUG_RESUME
41
42 .text
43
44 /* s3c2410_cpu_save
45 *
46 * save enough of the CPU state to allow us to re-start
47 * pm.c code. as we store items like the sp/lr, we will
48 * end up returning from this function when the cpu resumes
49 * so the return value is set to mark this.
50 *
51 * This arangement means we avoid having to flush the cache
52 * from this code.
53 *
54 * entry:
55 * r0 = pointer to save block
56 *
57 * exit:
58 * r0 = 0 => we stored everything
59 * 1 => resumed from sleep
60 */
61
62ENTRY(s3c2410_cpu_save)
63 stmfd sp!, { r4 - r12, lr }
64
65 @@ store co-processor registers
66
67 mrc p15, 0, r4, c15, c1, 0 @ CP access register
68 mrc p15, 0, r5, c13, c0, 0 @ PID
69 mrc p15, 0, r6, c3, c0, 0 @ Domain ID
70 mrc p15, 0, r7, c2, c0, 0 @ translation table base address
71 mrc p15, 0, r8, c1, c0, 0 @ control register
72
73 stmia r0, { r4 - r13 }
74
75 mov r0, #0
76 ldmfd sp, { r4 - r12, pc }
77
78 @@ return to the caller, after having the MMU
79 @@ turned on, this restores the last bits from the
80 @@ stack
81resume_with_mmu:
82 mov r0, #1
83 ldmfd sp!, { r4 - r12, pc }
84
85 .ltorg
86
87 @@ the next bits sit in the .data segment, even though they
88 @@ happen to be code... the s3c2410_sleep_save_phys needs to be
89 @@ accessed by the resume code before it can restore the MMU.
90 @@ This means that the variable has to be close enough for the
91 @@ code to read it... since the .text segment needs to be RO,
92 @@ the data segment can be the only place to put this code.
93
94 .data
95
96 .global s3c2410_sleep_save_phys
97s3c2410_sleep_save_phys:
98 .word 0
99
100 /* s3c2410_cpu_resume
101 *
102 * resume code entry for bootloader to call
103 *
104 * we must put this code here in the data segment as we have no
105 * other way of restoring the stack pointer after sleep, and we
106 * must not write to the code segment (code is read-only)
107 */
108
109ENTRY(s3c2410_cpu_resume)
110 mov r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE
111 msr cpsr_c, r0
112
113 @@ load UART to allow us to print the two characters for
114 @@ resume debug
115
116 mov r2, #S3C24XX_PA_UART & 0xff000000
117 orr r2, r2, #S3C24XX_PA_UART & 0xff000
118
119#if 0
120 /* SMDK2440 LED set */
121 mov r14, #S3C24XX_PA_GPIO
122 ldr r12, [ r14, #0x54 ]
123 bic r12, r12, #3<<4
124 orr r12, r12, #1<<7
125 str r12, [ r14, #0x54 ]
126#endif
127
128#ifdef CONFIG_DEBUG_RESUME
129 mov r3, #'L'
130 strb r3, [ r2, #S3C2410_UTXH ]
1311001:
132 ldrb r14, [ r3, #S3C2410_UTRSTAT ]
133 tst r14, #S3C2410_UTRSTAT_TXE
134 beq 1001b
135#endif /* CONFIG_DEBUG_RESUME */
136
137 mov r1, #0
138 mcr p15, 0, r1, c8, c7, 0 @@ invalidate I & D TLBs
139 mcr p15, 0, r1, c7, c7, 0 @@ invalidate I & D caches
140
141 ldr r0, s3c2410_sleep_save_phys @ address of restore block
142 ldmia r0, { r4 - r13 }
143
144 mcr p15, 0, r4, c15, c1, 0 @ CP access register
145 mcr p15, 0, r5, c13, c0, 0 @ PID
146 mcr p15, 0, r6, c3, c0, 0 @ Domain ID
147 mcr p15, 0, r7, c2, c0, 0 @ translation table base
148
149#ifdef CONFIG_DEBUG_RESUME
150 mov r3, #'R'
151 strb r3, [ r2, #S3C2410_UTXH ]
152#endif
153
154 ldr r2, =resume_with_mmu
155 mcr p15, 0, r8, c1, c0, 0 @ turn on MMU, etc
156 nop @ second-to-last before mmu
157 mov pc, r2 @ go back to virtual address
158
159 .ltorg
diff --git a/arch/arm/mach-s3c2410/time.c b/arch/arm/plat-s3c24xx/time.c
index 9910bf0f2cea..c523d1c9cce5 100644
--- a/arch/arm/mach-s3c2410/time.c
+++ b/arch/arm/plat-s3c24xx/time.c
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/time.c 1/* linux/arch/arm/plat-s3c24xx/time.c
2 * 2 *
3 * Copyright (C) 2003-2005 Simtec Electronics 3 * Copyright (C) 2003-2005 Simtec Electronics
4 * Ben Dooks, <ben@simtec.co.uk> 4 * Ben Dooks, <ben@simtec.co.uk>
@@ -37,8 +37,8 @@
37#include <asm/arch/regs-irq.h> 37#include <asm/arch/regs-irq.h>
38#include <asm/mach/time.h> 38#include <asm/mach/time.h>
39 39
40#include "clock.h" 40#include <asm/plat-s3c24xx/clock.h>
41#include "cpu.h" 41#include <asm/plat-s3c24xx/cpu.h>
42 42
43static unsigned long timer_startval; 43static unsigned long timer_startval;
44static unsigned long timer_usec_ticks; 44static unsigned long timer_usec_ticks;
diff --git a/arch/arm/mach-s3c2410/clock.h b/include/asm-arm/plat-s3c24xx/clock.h
index 7f0ea03e1d49..f6135dbb9fa9 100644
--- a/arch/arm/mach-s3c2410/clock.h
+++ b/include/asm-arm/plat-s3c24xx/clock.h
@@ -1,4 +1,4 @@
1/* 1/* linux/include/asm-arm/plat-s3c24xx/clock.h
2 * linux/arch/arm/mach-s3c2410/clock.h 2 * linux/arch/arm/mach-s3c2410/clock.h
3 * 3 *
4 * Copyright (c) 2004-2005 Simtec Electronics 4 * 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 0e3a3be330a3..58d9094c935c 100644
--- a/arch/arm/mach-s3c2410/common-smdk.h
+++ b/include/asm-arm/plat-s3c24xx/common-smdk.h
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/common-smdk.h 1/* linux/include/asm-arm/plat-s3c24xx/common-smdk.h
2 * 2 *
3 * Copyright (c) 2006 Simtec Electronics 3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c2410/cpu.h b/include/asm-arm/plat-s3c24xx/cpu.h
index be42e4032a6d..8181b22532bd 100644
--- a/arch/arm/mach-s3c2410/cpu.h
+++ b/include/asm-arm/plat-s3c24xx/cpu.h
@@ -1,4 +1,4 @@
1/* arch/arm/mach-s3c2410/cpu.h 1/* linux/include/asm-arm/plat-s3c24xx/cpu.h
2 * 2 *
3 * Copyright (c) 2004-2005 Simtec Electronics 3 * Copyright (c) 2004-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c2410/devs.h b/include/asm-arm/plat-s3c24xx/devs.h
index 14fb0bade716..dddf485fc067 100644
--- a/arch/arm/mach-s3c2410/devs.h
+++ b/include/asm-arm/plat-s3c24xx/devs.h
@@ -1,4 +1,4 @@
1/* arch/arm/mach-s3c2410/devs.h 1/* linux/include/asm-arm/plat-s3c24xx/devs.h
2 * 2 *
3 * Copyright (c) 2004 Simtec Electronics 3 * Copyright (c) 2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c2410/dma.h b/include/asm-arm/plat-s3c24xx/dma.h
index 0ebfe0aab80b..421b567fa019 100644
--- a/arch/arm/mach-s3c2410/dma.h
+++ b/include/asm-arm/plat-s3c24xx/dma.h
@@ -1,4 +1,4 @@
1/* arch/arm/mach-s3c2410/dma.h 1/* linux/include/asm-arm/plat-s3c24xx/dma.h
2 * 2 *
3 * Copyright (C) 2006 Simtec Electronics 3 * Copyright (C) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c2410/irq.h b/include/asm-arm/plat-s3c24xx/irq.h
index e5913da3b919..8af6d9579b31 100644
--- a/arch/arm/mach-s3c2410/irq.h
+++ b/include/asm-arm/plat-s3c24xx/irq.h
@@ -1,4 +1,4 @@
1/* arch/arm/mach-s3c2410/irq.h 1/* linux/include/asm-arm/plat-s3c24xx/irq.h
2 * 2 *
3 * Copyright (c) 2004-2005 Simtec Electronics 3 * Copyright (c) 2004-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c2410/pm.h b/include/asm-arm/plat-s3c24xx/pm.h
index ffe197a119fb..cc623667e48a 100644
--- a/arch/arm/mach-s3c2410/pm.h
+++ b/include/asm-arm/plat-s3c24xx/pm.h
@@ -1,4 +1,4 @@
1/* linux/arch/arm/mach-s3c2410/pm.h 1/* linux/include/asm-arm/plat-s3c24xx/pm.h
2 * 2 *
3 * Copyright (c) 2004 Simtec Electronics 3 * Copyright (c) 2004 Simtec Electronics
4 * Written by Ben Dooks, <ben@simtec.co.uk> 4 * 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 8b2394e1ed40..3a5a16821af8 100644
--- a/arch/arm/mach-s3c2410/s3c2400.h
+++ b/include/asm-arm/plat-s3c24xx/s3c2400.h
@@ -1,4 +1,4 @@
1/* arch/arm/mach-s3c2410/s3c2400.h 1/* linux/include/asm-arm/plat-s3c24xx/s3c2400.h
2 * 2 *
3 * Copyright (c) 2004 Simtec Electronics 3 * Copyright (c) 2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c2410/s3c2410.h b/include/asm-arm/plat-s3c24xx/s3c2410.h
index fbed084f26d0..36de0b835873 100644
--- a/arch/arm/mach-s3c2410/s3c2410.h
+++ b/include/asm-arm/plat-s3c24xx/s3c2410.h
@@ -1,4 +1,4 @@
1/* arch/arm/mach-s3c2410/s3c2410.h 1/* linux/include/asm-arm/plat-s3c24xx/s3c2410.h
2 * 2 *
3 * Copyright (c) 2004 Simtec Electronics 3 * Copyright (c) 2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c2410/s3c2412.h b/include/asm-arm/plat-s3c24xx/s3c2412.h
index c6e56032a6e7..3ec97685e781 100644
--- a/arch/arm/mach-s3c2410/s3c2412.h
+++ b/include/asm-arm/plat-s3c24xx/s3c2412.h
@@ -1,4 +1,4 @@
1/* arch/arm/mach-s3c2410/s3c2412.h 1/* linux/include/asm-arm/plat-s3c24xx/s3c2412.h
2 * 2 *
3 * Copyright (c) 2006 Simtec Electronics 3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c2410/s3c2440.h b/include/asm-arm/plat-s3c24xx/s3c2440.h
index dcd316076c59..107853bf9481 100644
--- a/arch/arm/mach-s3c2410/s3c2440.h
+++ b/include/asm-arm/plat-s3c24xx/s3c2440.h
@@ -1,4 +1,4 @@
1/* arch/arm/mach-s3c2410/s3c2440.h 1/* linux/include/asm-arm/plat-s3c24xx/s3c2440.h
2 * 2 *
3 * Copyright (c) 2004-2005 Simtec Electronics 3 * Copyright (c) 2004-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c2410/s3c2442.h b/include/asm-arm/plat-s3c24xx/s3c2442.h
index 0ae37d24866c..451a23a2092a 100644
--- a/arch/arm/mach-s3c2410/s3c2442.h
+++ b/include/asm-arm/plat-s3c24xx/s3c2442.h
@@ -1,4 +1,4 @@
1/* arch/arm/mach-s3c2410/s3c2442.h 1/* linux/include/asm-arm/plat-s3c24xx/s3c2442.h
2 * 2 *
3 * Copyright (c) 2006 Simtec Electronics 3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>