aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s3c2410
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-s3c2410')
-rw-r--r--arch/arm/mach-s3c2410/Kconfig169
-rw-r--r--arch/arm/mach-s3c2410/Makefile36
-rw-r--r--arch/arm/mach-s3c2410/Makefile.boot3
-rw-r--r--arch/arm/mach-s3c2410/bast-irq.c132
-rw-r--r--arch/arm/mach-s3c2410/bast.h2
-rw-r--r--arch/arm/mach-s3c2410/clock.c507
-rw-r--r--arch/arm/mach-s3c2410/clock.h44
-rw-r--r--arch/arm/mach-s3c2410/cpu.c241
-rw-r--r--arch/arm/mach-s3c2410/cpu.h69
-rw-r--r--arch/arm/mach-s3c2410/devs.c485
-rw-r--r--arch/arm/mach-s3c2410/devs.h48
-rw-r--r--arch/arm/mach-s3c2410/dma.c1210
-rw-r--r--arch/arm/mach-s3c2410/gpio.c213
-rw-r--r--arch/arm/mach-s3c2410/irq.c966
-rw-r--r--arch/arm/mach-s3c2410/mach-bast.c409
-rw-r--r--arch/arm/mach-s3c2410/mach-h1940.c126
-rw-r--r--arch/arm/mach-s3c2410/mach-n30.c155
-rw-r--r--arch/arm/mach-s3c2410/mach-nexcoder.c156
-rw-r--r--arch/arm/mach-s3c2410/mach-otom.c124
-rw-r--r--arch/arm/mach-s3c2410/mach-rx3715.c141
-rw-r--r--arch/arm/mach-s3c2410/mach-smdk2410.c123
-rw-r--r--arch/arm/mach-s3c2410/mach-smdk2440.c135
-rw-r--r--arch/arm/mach-s3c2410/mach-vr1000.c317
-rw-r--r--arch/arm/mach-s3c2410/pm.c672
-rw-r--r--arch/arm/mach-s3c2410/pm.h59
-rw-r--r--arch/arm/mach-s3c2410/s3c2410.c200
-rw-r--r--arch/arm/mach-s3c2410/s3c2410.h37
-rw-r--r--arch/arm/mach-s3c2410/s3c2440-dsc.c59
-rw-r--r--arch/arm/mach-s3c2410/s3c2440.c281
-rw-r--r--arch/arm/mach-s3c2410/s3c2440.h35
-rw-r--r--arch/arm/mach-s3c2410/sleep.S180
-rw-r--r--arch/arm/mach-s3c2410/time.c256
-rw-r--r--arch/arm/mach-s3c2410/usb-simtec.c113
-rw-r--r--arch/arm/mach-s3c2410/usb-simtec.h19
34 files changed, 7722 insertions, 0 deletions
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
new file mode 100644
index 000000000000..534df0c6c770
--- /dev/null
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -0,0 +1,169 @@
1if ARCH_S3C2410
2
3menu "S3C24XX Implementations"
4
5config ARCH_BAST
6 bool "Simtec Electronics BAST (EB2410ITX)"
7 select CPU_S3C2410
8 help
9 Say Y here if you are using the Simtec Electronics EB2410ITX
10 development board (also known as BAST)
11
12 Product page: <http://www.simtec.co.uk/products/EB2410ITX/>.
13
14config ARCH_H1940
15 bool "IPAQ H1940"
16 select CPU_S3C2410
17 help
18 Say Y here if you are using the HP IPAQ H1940
19
20 <http://www.handhelds.org/projects/h1940.html>.
21
22config MACH_N30
23 bool "Acer N30"
24 select CPU_S3C2410
25 help
26 Say Y here if you are using the Acer N30
27
28 <http://zoo.weinigel.se/n30>.
29
30config ARCH_SMDK2410
31 bool "SMDK2410/A9M2410"
32 select CPU_S3C2410
33 help
34 Say Y here if you are using the SMDK2410 or the derived module A9M2410
35 <http://www.fsforth.de>
36
37config ARCH_S3C2440
38 bool "SMDK2440"
39 select CPU_S3C2440
40 help
41 Say Y here if you are using the SMDK2440.
42
43config MACH_VR1000
44 bool "Thorcom VR1000"
45 select CPU_S3C2410
46 help
47 Say Y here if you are using the Thorcom VR1000 board.
48
49 This linux port is currently being maintained by Simtec, on behalf
50 of Thorcom. Any queries, please contact Thorcom first.
51
52config MACH_RX3715
53 bool "HP iPAQ rx3715"
54 select CPU_S3C2440
55 help
56 Say Y here if you are using the HP iPAQ rx3715.
57
58 See <http://www.handhelds.org/projects/rx3715.html> for more
59 information on this project
60
61config MACH_OTOM
62 bool "NexVision OTOM Board"
63 select CPU_S3C2410
64 help
65 Say Y here if you are using the Nex Vision OTOM board
66
67config MACH_NEXCODER_2440
68 bool "NexVision NEXCODER 2440 Light Board"
69 select CPU_S3C2440
70 help
71 Say Y here if you are using the Nex Vision NEXCODER 2440 Light Board
72
73endmenu
74
75config CPU_S3C2410
76 bool
77 depends on ARCH_S3C2410
78 help
79 Support for S3C2410 and S3C2410A family from the S3C24XX line
80 of Samsung Mobile CPUs.
81
82config CPU_S3C2440
83 bool
84 depends on ARCH_S3C2410
85 help
86 Support for S3C2440 Samsung Mobile CPU based systems.
87
88comment "S3C2410 Boot"
89
90config S3C2410_BOOT_WATCHDOG
91 bool "S3C2410 Initialisation watchdog"
92 depends on ARCH_S3C2410 && S3C2410_WATCHDOG
93 help
94 Say y to enable the watchdog during the kernel decompression
95 stage. If the kernel fails to uncompress, then the watchdog
96 will trigger a reset and the system should restart.
97
98 Although this uses the same hardware unit as the kernel watchdog
99 driver, it is not a replacement for it. If you use this option,
100 you will have to use the watchdg driver to either stop the timeout
101 or restart it. If you do not, then your kernel will reboot after
102 startup.
103
104 The driver uses a fixed timeout value, so the exact time till the
105 system resets depends on the value of PCLK. The timeout on an
106 200MHz s3c2410 should be about 30 seconds.
107
108comment "S3C2410 Setup"
109
110config S3C2410_DMA
111 bool "S3C2410 DMA support"
112 depends on ARCH_S3C2410
113 help
114 S3C2410 DMA support. This is needed for drivers like sound which
115 use the S3C2410's DMA system to move data to and from the
116 peripheral blocks.
117
118config S3C2410_DMA_DEBUG
119 bool "S3C2410 DMA support debug"
120 depends on ARCH_S3C2410 && S3C2410_DMA
121 help
122 Enable debugging output for the DMA code. This option sends info
123 to the kernel log, at priority KERN_DEBUG.
124
125 Note, it is easy to create and fill the log buffer in a small
126 amount of time, as well as using an significant percentage of
127 the CPU time doing so.
128
129
130config S3C2410_PM_DEBUG
131 bool "S3C2410 PM Suspend debug"
132 depends on ARCH_S3C2410 && PM
133 help
134 Say Y here if you want verbose debugging from the PM Suspend and
135 Resume code. See `Documentation/arm/Samsing-S3C24XX/Suspend.txt`
136 for more information.
137
138config S3C2410_PM_CHECK
139 bool "S3C2410 PM Suspend Memory CRC"
140 depends on ARCH_S3C2410 && PM && CRC32
141 help
142 Enable the PM code's memory area checksum over sleep. This option
143 will generate CRCs of all blocks of memory, and store them before
144 going to sleep. The blocks are then checked on resume for any
145 errors.
146
147config S3C2410_PM_CHECK_CHUNKSIZE
148 int "S3C2410 PM Suspend CRC Chunksize (KiB)"
149 depends on ARCH_S3C2410 && PM && S3C2410_PM_CHECK
150 default 64
151 help
152 Set the chunksize in Kilobytes of the CRC for checking memory
153 corruption over suspend and resume. A smaller value will mean that
154 the CRC data block will take more memory, but wil identify any
155 faults with better precision.
156
157config S3C2410_LOWLEVEL_UART_PORT
158 int "S3C2410 UART to use for low-level messages"
159 default 0
160 help
161 Choice of which UART port to use for the low-level messages,
162 such as the `Uncompressing...` at start time. The value of
163 this configuration should be between zero and two. The port
164 must have been initialised by the boot-loader before use.
165
166 Note, this does not affect the port used by the debug messages,
167 which is a separate configuration.
168
169endif
diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
new file mode 100644
index 000000000000..7c379aad5d62
--- /dev/null
+++ b/arch/arm/mach-s3c2410/Makefile
@@ -0,0 +1,36 @@
1
2#
3# Makefile for the linux kernel.
4#
5
6# Object file lists.
7
8obj-y := cpu.o irq.o time.o gpio.o clock.o devs.o
9obj-m :=
10obj-n :=
11obj- :=
12
13# S3C2410 support files
14
15obj-$(CONFIG_CPU_S3C2410) += s3c2410.o
16obj-$(CONFIG_S3C2410_DMA) += dma.o
17
18# Power Management support
19
20obj-$(CONFIG_PM) += pm.o sleep.o
21
22# S3C2440 support
23
24obj-$(CONFIG_CPU_S3C2440) += s3c2440.o s3c2440-dsc.o
25
26# machine specific support
27
28obj-$(CONFIG_ARCH_BAST) += mach-bast.o usb-simtec.o
29obj-$(CONFIG_ARCH_H1940) += mach-h1940.o
30obj-$(CONFIG_MACH_N30) += mach-n30.o
31obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o
32obj-$(CONFIG_ARCH_S3C2440) += mach-smdk2440.o
33obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o
34obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o
35obj-$(CONFIG_MACH_OTOM) += mach-otom.o
36obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o
diff --git a/arch/arm/mach-s3c2410/Makefile.boot b/arch/arm/mach-s3c2410/Makefile.boot
new file mode 100644
index 000000000000..7dab2a0325b5
--- /dev/null
+++ b/arch/arm/mach-s3c2410/Makefile.boot
@@ -0,0 +1,3 @@
1 zreladdr-y := 0x30008000
2params_phys-y := 0x30000100
3
diff --git a/arch/arm/mach-s3c2410/bast-irq.c b/arch/arm/mach-s3c2410/bast-irq.c
new file mode 100644
index 000000000000..5e5bbe893cbb
--- /dev/null
+++ b/arch/arm/mach-s3c2410/bast-irq.c
@@ -0,0 +1,132 @@
1/* linux/arch/arm/mach-s3c2410/bast-irq.c
2 *
3 * Copyright (c) 2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * http://www.simtec.co.uk/products/EB2410ITX/
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 * Modifications:
23 * 08-Jan-2003 BJD Moved from central IRQ code
24 */
25
26
27#include <linux/init.h>
28#include <linux/module.h>
29#include <linux/ioport.h>
30#include <linux/ptrace.h>
31#include <linux/sysdev.h>
32
33#include <asm/hardware.h>
34#include <asm/irq.h>
35#include <asm/io.h>
36
37#include <asm/mach/irq.h>
38#include <asm/hardware/s3c2410/irq.h>
39
40#if 0
41#include <asm/debug-ll.h>
42#endif
43
44#define irqdbf(x...)
45#define irqdbf2(x...)
46
47
48/* handle PC104 ISA interrupts from the system CPLD */
49
50/* table of ISA irq nos to the relevant mask... zero means
51 * the irq is not implemented
52*/
53static unsigned char bast_pc104_irqmasks[] = {
54 0, /* 0 */
55 0, /* 1 */
56 0, /* 2 */
57 1, /* 3 */
58 0, /* 4 */
59 2, /* 5 */
60 0, /* 6 */
61 4, /* 7 */
62 0, /* 8 */
63 0, /* 9 */
64 8, /* 10 */
65 0, /* 11 */
66 0, /* 12 */
67 0, /* 13 */
68 0, /* 14 */
69 0, /* 15 */
70};
71
72static unsigned char bast_pc104_irqs[] = { 3, 5, 7, 10 };
73
74static void
75bast_pc104_mask(unsigned int irqno)
76{
77 unsigned long temp;
78
79 temp = __raw_readb(BAST_VA_PC104_IRQMASK);
80 temp &= ~bast_pc104_irqmasks[irqno];
81 __raw_writeb(temp, BAST_VA_PC104_IRQMASK);
82
83 if (temp == 0)
84 bast_extint_mask(IRQ_ISA);
85}
86
87static void
88bast_pc104_ack(unsigned int irqno)
89{
90 bast_extint_ack(IRQ_ISA);
91}
92
93static void
94bast_pc104_unmask(unsigned int irqno)
95{
96 unsigned long temp;
97
98 temp = __raw_readb(BAST_VA_PC104_IRQMASK);
99 temp |= bast_pc104_irqmasks[irqno];
100 __raw_writeb(temp, BAST_VA_PC104_IRQMASK);
101
102 bast_extint_unmask(IRQ_ISA);
103}
104
105static struct bast_pc104_chip = {
106 .mask = bast_pc104_mask,
107 .unmask = bast_pc104_unmask,
108 .ack = bast_pc104_ack
109};
110
111static void
112bast_irq_pc104_demux(unsigned int irq,
113 struct irqdesc *desc,
114 struct pt_regs *regs)
115{
116 unsigned int stat;
117 unsigned int irqno;
118 int i;
119
120 stat = __raw_readb(BAST_VA_PC104_IRQREQ) & 0xf;
121
122 for (i = 0; i < 4 && stat != 0; i++) {
123 if (stat & 1) {
124 irqno = bast_pc104_irqs[i];
125 desc = irq_desc + irqno;
126
127 desc->handle(irqno, desc, regs);
128 }
129
130 stat >>= 1;
131 }
132}
diff --git a/arch/arm/mach-s3c2410/bast.h b/arch/arm/mach-s3c2410/bast.h
new file mode 100644
index 000000000000..e5d03311752c
--- /dev/null
+++ b/arch/arm/mach-s3c2410/bast.h
@@ -0,0 +1,2 @@
1
2extern void bast_init_irq(void);
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c
new file mode 100644
index 000000000000..e23f534d4e1d
--- /dev/null
+++ b/arch/arm/mach-s3c2410/clock.c
@@ -0,0 +1,507 @@
1/* linux/arch/arm/mach-s3c2410/clock.c
2 *
3 * Copyright (c) 2004-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * S3C2410 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/device.h>
36#include <linux/sysdev.h>
37
38#include <linux/interrupt.h>
39#include <linux/ioport.h>
40
41#include <asm/hardware.h>
42#include <asm/atomic.h>
43#include <asm/irq.h>
44#include <asm/io.h>
45
46#include <asm/hardware/clock.h>
47#include <asm/arch/regs-clock.h>
48
49#include "clock.h"
50#include "cpu.h"
51
52/* clock information */
53
54static LIST_HEAD(clocks);
55static DECLARE_MUTEX(clocks_sem);
56
57/* old functions */
58
59void inline s3c24xx_clk_enable(unsigned int clocks, unsigned int enable)
60{
61 unsigned long clkcon;
62 unsigned long flags;
63
64 local_irq_save(flags);
65
66 clkcon = __raw_readl(S3C2410_CLKCON);
67 clkcon &= ~clocks;
68
69 if (enable)
70 clkcon |= clocks;
71
72 /* ensure none of the special function bits set */
73 clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER);
74
75 __raw_writel(clkcon, S3C2410_CLKCON);
76
77 local_irq_restore(flags);
78}
79
80/* enable and disable calls for use with the clk struct */
81
82static int clk_null_enable(struct clk *clk, int enable)
83{
84 return 0;
85}
86
87int s3c24xx_clkcon_enable(struct clk *clk, int enable)
88{
89 s3c24xx_clk_enable(clk->ctrlbit, enable);
90 return 0;
91}
92
93/* Clock API calls */
94
95struct clk *clk_get(struct device *dev, const char *id)
96{
97 struct clk *p;
98 struct clk *clk = ERR_PTR(-ENOENT);
99 int idno;
100
101 idno = (dev == NULL) ? -1 : to_platform_device(dev)->id;
102
103 down(&clocks_sem);
104
105 list_for_each_entry(p, &clocks, list) {
106 if (p->id == idno &&
107 strcmp(id, p->name) == 0 &&
108 try_module_get(p->owner)) {
109 clk = p;
110 break;
111 }
112 }
113
114 /* check for the case where a device was supplied, but the
115 * clock that was being searched for is not device specific */
116
117 if (IS_ERR(clk)) {
118 list_for_each_entry(p, &clocks, list) {
119 if (p->id == -1 && strcmp(id, p->name) == 0 &&
120 try_module_get(p->owner)) {
121 clk = p;
122 break;
123 }
124 }
125 }
126
127 up(&clocks_sem);
128 return clk;
129}
130
131void clk_put(struct clk *clk)
132{
133 module_put(clk->owner);
134}
135
136int clk_enable(struct clk *clk)
137{
138 if (IS_ERR(clk))
139 return -EINVAL;
140
141 return (clk->enable)(clk, 1);
142}
143
144void clk_disable(struct clk *clk)
145{
146 if (!IS_ERR(clk))
147 (clk->enable)(clk, 0);
148}
149
150
151int clk_use(struct clk *clk)
152{
153 atomic_inc(&clk->used);
154 return 0;
155}
156
157
158void clk_unuse(struct clk *clk)
159{
160 atomic_dec(&clk->used);
161}
162
163unsigned long clk_get_rate(struct clk *clk)
164{
165 if (IS_ERR(clk))
166 return 0;
167
168 if (clk->rate != 0)
169 return clk->rate;
170
171 while (clk->parent != NULL && clk->rate == 0)
172 clk = clk->parent;
173
174 return clk->rate;
175}
176
177long clk_round_rate(struct clk *clk, unsigned long rate)
178{
179 return rate;
180}
181
182int clk_set_rate(struct clk *clk, unsigned long rate)
183{
184 return -EINVAL;
185}
186
187struct clk *clk_get_parent(struct clk *clk)
188{
189 return clk->parent;
190}
191
192EXPORT_SYMBOL(clk_get);
193EXPORT_SYMBOL(clk_put);
194EXPORT_SYMBOL(clk_enable);
195EXPORT_SYMBOL(clk_disable);
196EXPORT_SYMBOL(clk_use);
197EXPORT_SYMBOL(clk_unuse);
198EXPORT_SYMBOL(clk_get_rate);
199EXPORT_SYMBOL(clk_round_rate);
200EXPORT_SYMBOL(clk_set_rate);
201EXPORT_SYMBOL(clk_get_parent);
202
203/* base clocks */
204
205static struct clk clk_xtal = {
206 .name = "xtal",
207 .id = -1,
208 .rate = 0,
209 .parent = NULL,
210 .ctrlbit = 0,
211};
212
213static struct clk clk_f = {
214 .name = "fclk",
215 .id = -1,
216 .rate = 0,
217 .parent = NULL,
218 .ctrlbit = 0,
219};
220
221static struct clk clk_h = {
222 .name = "hclk",
223 .id = -1,
224 .rate = 0,
225 .parent = NULL,
226 .ctrlbit = 0,
227};
228
229static struct clk clk_p = {
230 .name = "pclk",
231 .id = -1,
232 .rate = 0,
233 .parent = NULL,
234 .ctrlbit = 0,
235};
236
237/* clocks that could be registered by external code */
238
239struct clk s3c24xx_dclk0 = {
240 .name = "dclk0",
241 .id = -1,
242};
243
244struct clk s3c24xx_dclk1 = {
245 .name = "dclk1",
246 .id = -1,
247};
248
249struct clk s3c24xx_clkout0 = {
250 .name = "clkout0",
251 .id = -1,
252};
253
254struct clk s3c24xx_clkout1 = {
255 .name = "clkout1",
256 .id = -1,
257};
258
259struct clk s3c24xx_uclk = {
260 .name = "uclk",
261 .id = -1,
262};
263
264
265/* clock definitions */
266
267static struct clk init_clocks[] = {
268 { .name = "nand",
269 .id = -1,
270 .parent = &clk_h,
271 .enable = s3c24xx_clkcon_enable,
272 .ctrlbit = S3C2410_CLKCON_NAND
273 },
274 { .name = "lcd",
275 .id = -1,
276 .parent = &clk_h,
277 .enable = s3c24xx_clkcon_enable,
278 .ctrlbit = S3C2410_CLKCON_LCDC
279 },
280 { .name = "usb-host",
281 .id = -1,
282 .parent = &clk_h,
283 .enable = s3c24xx_clkcon_enable,
284 .ctrlbit = S3C2410_CLKCON_USBH
285 },
286 { .name = "usb-device",
287 .id = -1,
288 .parent = &clk_h,
289 .enable = s3c24xx_clkcon_enable,
290 .ctrlbit = S3C2410_CLKCON_USBD
291 },
292 { .name = "timers",
293 .id = -1,
294 .parent = &clk_p,
295 .enable = s3c24xx_clkcon_enable,
296 .ctrlbit = S3C2410_CLKCON_PWMT
297 },
298 { .name = "sdi",
299 .id = -1,
300 .parent = &clk_p,
301 .enable = s3c24xx_clkcon_enable,
302 .ctrlbit = S3C2410_CLKCON_SDI
303 },
304 { .name = "uart",
305 .id = 0,
306 .parent = &clk_p,
307 .enable = s3c24xx_clkcon_enable,
308 .ctrlbit = S3C2410_CLKCON_UART0
309 },
310 { .name = "uart",
311 .id = 1,
312 .parent = &clk_p,
313 .enable = s3c24xx_clkcon_enable,
314 .ctrlbit = S3C2410_CLKCON_UART1
315 },
316 { .name = "uart",
317 .id = 2,
318 .parent = &clk_p,
319 .enable = s3c24xx_clkcon_enable,
320 .ctrlbit = S3C2410_CLKCON_UART2
321 },
322 { .name = "gpio",
323 .id = -1,
324 .parent = &clk_p,
325 .enable = s3c24xx_clkcon_enable,
326 .ctrlbit = S3C2410_CLKCON_GPIO
327 },
328 { .name = "rtc",
329 .id = -1,
330 .parent = &clk_p,
331 .enable = s3c24xx_clkcon_enable,
332 .ctrlbit = S3C2410_CLKCON_RTC
333 },
334 { .name = "adc",
335 .id = -1,
336 .parent = &clk_p,
337 .enable = s3c24xx_clkcon_enable,
338 .ctrlbit = S3C2410_CLKCON_ADC
339 },
340 { .name = "i2c",
341 .id = -1,
342 .parent = &clk_p,
343 .enable = s3c24xx_clkcon_enable,
344 .ctrlbit = S3C2410_CLKCON_IIC
345 },
346 { .name = "iis",
347 .id = -1,
348 .parent = &clk_p,
349 .enable = s3c24xx_clkcon_enable,
350 .ctrlbit = S3C2410_CLKCON_IIS
351 },
352 { .name = "spi",
353 .id = -1,
354 .parent = &clk_p,
355 .enable = s3c24xx_clkcon_enable,
356 .ctrlbit = S3C2410_CLKCON_SPI
357 },
358 { .name = "watchdog",
359 .id = -1,
360 .parent = &clk_p,
361 .ctrlbit = 0
362 }
363};
364
365/* initialise the clock system */
366
367int s3c24xx_register_clock(struct clk *clk)
368{
369 clk->owner = THIS_MODULE;
370 atomic_set(&clk->used, 0);
371
372 if (clk->enable == NULL)
373 clk->enable = clk_null_enable;
374
375 /* add to the list of available clocks */
376
377 down(&clocks_sem);
378 list_add(&clk->list, &clocks);
379 up(&clocks_sem);
380
381 return 0;
382}
383
384/* initalise all the clocks */
385
386int __init s3c24xx_setup_clocks(unsigned long xtal,
387 unsigned long fclk,
388 unsigned long hclk,
389 unsigned long pclk)
390{
391 struct clk *clkp = init_clocks;
392 int ptr;
393 int ret;
394
395 printk(KERN_INFO "S3C2410 Clocks, (c) 2004 Simtec Electronics\n");
396
397 /* initialise the main system clocks */
398
399 clk_xtal.rate = xtal;
400
401 clk_h.rate = hclk;
402 clk_p.rate = pclk;
403 clk_f.rate = fclk;
404
405 /* it looks like just setting the register here is not good
406 * enough, and causes the odd hang at initial boot time, so
407 * do all of them indivdually.
408 *
409 * I think disabling the LCD clock if the LCD is active is
410 * very dangerous, and therefore the bootloader should be
411 * careful to not enable the LCD clock if it is not needed.
412 *
413 * and of course, this looks neater
414 */
415
416 s3c24xx_clk_enable(S3C2410_CLKCON_NAND, 0);
417 s3c24xx_clk_enable(S3C2410_CLKCON_USBH, 0);
418 s3c24xx_clk_enable(S3C2410_CLKCON_USBD, 0);
419 s3c24xx_clk_enable(S3C2410_CLKCON_ADC, 0);
420 s3c24xx_clk_enable(S3C2410_CLKCON_IIC, 0);
421 s3c24xx_clk_enable(S3C2410_CLKCON_SPI, 0);
422
423 /* assume uart clocks are correctly setup */
424
425 /* register our clocks */
426
427 if (s3c24xx_register_clock(&clk_xtal) < 0)
428 printk(KERN_ERR "failed to register master xtal\n");
429
430 if (s3c24xx_register_clock(&clk_f) < 0)
431 printk(KERN_ERR "failed to register cpu fclk\n");
432
433 if (s3c24xx_register_clock(&clk_h) < 0)
434 printk(KERN_ERR "failed to register cpu hclk\n");
435
436 if (s3c24xx_register_clock(&clk_p) < 0)
437 printk(KERN_ERR "failed to register cpu pclk\n");
438
439 /* register clocks from clock array */
440
441 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
442 ret = s3c24xx_register_clock(clkp);
443 if (ret < 0) {
444 printk(KERN_ERR "Failed to register clock %s (%d)\n",
445 clkp->name, ret);
446 }
447 }
448
449 return 0;
450}
451
452/* S3C2440 extended clock support */
453
454#ifdef CONFIG_CPU_S3C2440
455
456static struct clk s3c2440_clk_upll = {
457 .name = "upll",
458 .id = -1,
459};
460
461static struct clk s3c2440_clk_cam = {
462 .name = "camif",
463 .parent = &clk_h,
464 .id = -1,
465 .enable = s3c24xx_clkcon_enable,
466 .ctrlbit = S3C2440_CLKCON_CAMERA,
467};
468
469static struct clk s3c2440_clk_ac97 = {
470 .name = "ac97",
471 .parent = &clk_p,
472 .id = -1,
473 .enable = s3c24xx_clkcon_enable,
474 .ctrlbit = S3C2440_CLKCON_CAMERA,
475};
476
477static int s3c2440_clk_add(struct sys_device *sysdev)
478{
479 unsigned long upllcon = __raw_readl(S3C2410_UPLLCON);
480
481 s3c2440_clk_upll.rate = s3c2410_get_pll(upllcon, clk_xtal.rate) * 2;
482
483 printk("S3C2440: Clock Support, UPLL %ld.%03ld MHz\n",
484 print_mhz(s3c2440_clk_upll.rate));
485
486 s3c24xx_register_clock(&s3c2440_clk_ac97);
487 s3c24xx_register_clock(&s3c2440_clk_cam);
488 s3c24xx_register_clock(&s3c2440_clk_upll);
489
490 clk_disable(&s3c2440_clk_ac97);
491 clk_disable(&s3c2440_clk_cam);
492
493 return 0;
494}
495
496static struct sysdev_driver s3c2440_clk_driver = {
497 .add = s3c2440_clk_add,
498};
499
500static int s3c24xx_clk_driver(void)
501{
502 return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_clk_driver);
503}
504
505arch_initcall(s3c24xx_clk_driver);
506
507#endif /* CONFIG_CPU_S3C2440 */
diff --git a/arch/arm/mach-s3c2410/clock.h b/arch/arm/mach-s3c2410/clock.h
new file mode 100644
index 000000000000..7953b6f397b9
--- /dev/null
+++ b/arch/arm/mach-s3c2410/clock.h
@@ -0,0 +1,44 @@
1/*
2 * linux/arch/arm/mach-s3c2410/clock.h
3 *
4 * Copyright (c) 2004-2005 Simtec Electronics
5 * http://www.simtec.co.uk/products/SWLINUX/
6 * Written by Ben Dooks, <ben@simtec.co.uk>
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 version 2 as
10 * published by the Free Software Foundation.
11*/
12
13struct clk {
14 struct list_head list;
15 struct module *owner;
16 struct clk *parent;
17 const char *name;
18 int id;
19 atomic_t used;
20 unsigned long rate;
21 unsigned long ctrlbit;
22 int (*enable)(struct clk *, int enable);
23};
24
25/* other clocks which may be registered by board support */
26
27extern struct clk s3c24xx_dclk0;
28extern struct clk s3c24xx_dclk1;
29extern struct clk s3c24xx_clkout0;
30extern struct clk s3c24xx_clkout1;
31extern struct clk s3c24xx_uclk;
32
33/* exports for arch/arm/mach-s3c2410
34 *
35 * Please DO NOT use these outside of arch/arm/mach-s3c2410
36*/
37
38extern int s3c24xx_clkcon_enable(struct clk *clk, int enable);
39extern int s3c24xx_register_clock(struct clk *clk);
40
41extern int s3c24xx_setup_clocks(unsigned long xtal,
42 unsigned long fclk,
43 unsigned long hclk,
44 unsigned long pclk);
diff --git a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/mach-s3c2410/cpu.c
new file mode 100644
index 000000000000..ca366e9e264d
--- /dev/null
+++ b/arch/arm/mach-s3c2410/cpu.c
@@ -0,0 +1,241 @@
1/* linux/arch/arm/mach-s3c2410/cpu.c
2 *
3 * Copyright (c) 2004-2005 Simtec Electronics
4 * http://www.simtec.co.uk/products/SWLINUX/
5 * Ben Dooks <ben@simtec.co.uk>
6 *
7 * S3C24XX CPU Support
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22*/
23
24
25#include <linux/init.h>
26#include <linux/module.h>
27#include <linux/interrupt.h>
28#include <linux/ioport.h>
29#include <linux/device.h>
30
31#include <asm/hardware.h>
32#include <asm/irq.h>
33#include <asm/io.h>
34#include <asm/delay.h>
35
36#include <asm/mach/arch.h>
37#include <asm/mach/map.h>
38
39#include <asm/arch/regs-gpio.h>
40
41#include "cpu.h"
42#include "clock.h"
43#include "s3c2410.h"
44#include "s3c2440.h"
45
46struct cpu_table {
47 unsigned long idcode;
48 unsigned long idmask;
49 void (*map_io)(struct map_desc *mach_desc, int size);
50 void (*init_uarts)(struct s3c2410_uartcfg *cfg, int no);
51 void (*init_clocks)(int xtal);
52 int (*init)(void);
53 const char *name;
54};
55
56/* table of supported CPUs */
57
58static const char name_s3c2410[] = "S3C2410";
59static const char name_s3c2440[] = "S3C2440";
60static const char name_s3c2410a[] = "S3C2410A";
61static const char name_s3c2440a[] = "S3C2440A";
62
63static struct cpu_table cpu_ids[] __initdata = {
64 {
65 .idcode = 0x32410000,
66 .idmask = 0xffffffff,
67 .map_io = s3c2410_map_io,
68 .init_clocks = s3c2410_init_clocks,
69 .init_uarts = s3c2410_init_uarts,
70 .init = s3c2410_init,
71 .name = name_s3c2410
72 },
73 {
74 .idcode = 0x32410002,
75 .idmask = 0xffffffff,
76 .map_io = s3c2410_map_io,
77 .init_clocks = s3c2410_init_clocks,
78 .init_uarts = s3c2410_init_uarts,
79 .init = s3c2410_init,
80 .name = name_s3c2410a
81 },
82 {
83 .idcode = 0x32440000,
84 .idmask = 0xffffffff,
85 .map_io = s3c2440_map_io,
86 .init_clocks = s3c2440_init_clocks,
87 .init_uarts = s3c2440_init_uarts,
88 .init = s3c2440_init,
89 .name = name_s3c2440
90 },
91 {
92 .idcode = 0x32440001,
93 .idmask = 0xffffffff,
94 .map_io = s3c2440_map_io,
95 .init_clocks = s3c2440_init_clocks,
96 .init_uarts = s3c2440_init_uarts,
97 .init = s3c2440_init,
98 .name = name_s3c2440a
99 }
100};
101
102/* minimal IO mapping */
103
104static struct map_desc s3c_iodesc[] __initdata = {
105 IODESC_ENT(GPIO),
106 IODESC_ENT(IRQ),
107 IODESC_ENT(MEMCTRL),
108 IODESC_ENT(UART)
109};
110
111
112static struct cpu_table *
113s3c_lookup_cpu(unsigned long idcode)
114{
115 struct cpu_table *tab;
116 int count;
117
118 tab = cpu_ids;
119 for (count = 0; count < ARRAY_SIZE(cpu_ids); count++, tab++) {
120 if ((idcode & tab->idmask) == tab->idcode)
121 return tab;
122 }
123
124 return NULL;
125}
126
127/* board information */
128
129static struct s3c24xx_board *board;
130
131void s3c24xx_set_board(struct s3c24xx_board *b)
132{
133 int i;
134
135 board = b;
136
137 if (b->clocks_count != 0) {
138 struct clk **ptr = b->clocks;;
139
140 for (i = b->clocks_count; i > 0; i--, ptr++)
141 s3c24xx_register_clock(*ptr);
142 }
143}
144
145/* cpu information */
146
147static struct cpu_table *cpu;
148
149void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
150{
151 unsigned long idcode;
152
153 /* initialise the io descriptors we need for initialisation */
154 iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc));
155
156 idcode = __raw_readl(S3C2410_GSTATUS1);
157 cpu = s3c_lookup_cpu(idcode);
158
159 if (cpu == NULL) {
160 printk(KERN_ERR "Unknown CPU type 0x%08lx\n", idcode);
161 panic("Unknown S3C24XX CPU");
162 }
163
164 if (cpu->map_io == NULL || cpu->init == NULL) {
165 printk(KERN_ERR "CPU %s support not enabled\n", cpu->name);
166 panic("Unsupported S3C24XX CPU");
167 }
168
169 printk("CPU %s (id 0x%08lx)\n", cpu->name, idcode);
170
171 (cpu->map_io)(mach_desc, size);
172}
173
174/* s3c24xx_init_clocks
175 *
176 * Initialise the clock subsystem and associated information from the
177 * given master crystal value.
178 *
179 * xtal = 0 -> use default PLL crystal value (normally 12MHz)
180 * != 0 -> PLL crystal value in Hz
181*/
182
183void __init s3c24xx_init_clocks(int xtal)
184{
185 if (xtal == 0)
186 xtal = 12*1000*1000;
187
188 if (cpu == NULL)
189 panic("s3c24xx_init_clocks: no cpu setup?\n");
190
191 if (cpu->init_clocks == NULL)
192 panic("s3c24xx_init_clocks: cpu has no clock init\n");
193 else
194 (cpu->init_clocks)(xtal);
195}
196
197void __init s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no)
198{
199 if (cpu == NULL)
200 return;
201
202 if (cpu->init_uarts == NULL) {
203 printk(KERN_ERR "s3c24xx_init_uarts: cpu has no uart init\n");
204 } else
205 (cpu->init_uarts)(cfg, no);
206}
207
208static int __init s3c_arch_init(void)
209{
210 int ret;
211
212 // do the correct init for cpu
213
214 if (cpu == NULL)
215 panic("s3c_arch_init: NULL cpu\n");
216
217 ret = (cpu->init)();
218 if (ret != 0)
219 return ret;
220
221 if (board != NULL) {
222 struct platform_device **ptr = board->devices;
223 int i;
224
225 for (i = 0; i < board->devices_count; i++, ptr++) {
226 ret = platform_device_register(*ptr);
227
228 if (ret) {
229 printk(KERN_ERR "s3c24xx: failed to add board device %s (%d) @%p\n", (*ptr)->name, ret, *ptr);
230 }
231 }
232
233 /* mask any error, we may not need all these board
234 * devices */
235 ret = 0;
236 }
237
238 return ret;
239}
240
241arch_initcall(s3c_arch_init);
diff --git a/arch/arm/mach-s3c2410/cpu.h b/arch/arm/mach-s3c2410/cpu.h
new file mode 100644
index 000000000000..478c15c0e36a
--- /dev/null
+++ b/arch/arm/mach-s3c2410/cpu.h
@@ -0,0 +1,69 @@
1/* arch/arm/mach-s3c2410/cpu.h
2 *
3 * Copyright (c) 2004-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * Header file for S3C24XX CPU 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 version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Modifications:
13 * 24-Aug-2004 BJD Start of generic S3C24XX support
14 * 18-Oct-2004 BJD Moved board struct into this file
15 * 04-Jan-2005 BJD New uart initialisation
16 * 10-Jan-2005 BJD Moved generic init here, specific to cpu headers
17 * 14-Jan-2005 BJD Added s3c24xx_init_clocks() call
18 * 10-Mar-2005 LCVR Changed S3C2410_{VA,SZ} to S3C24XX_{VA,SZ} & IODESC_ENT
19 * 14-Mar-2005 BJD Updated for __iomem
20*/
21
22/* todo - fix when rmk changes iodescs to use `void __iomem *` */
23
24#define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, S3C2410_PA_##x, S3C24XX_SZ_##x, MT_DEVICE }
25
26#ifndef MHZ
27#define MHZ (1000*1000)
28#endif
29
30#define print_mhz(m) ((m) / MHZ), ((m / 1000) % 1000)
31
32/* forward declaration */
33struct s3c2410_uartcfg;
34struct map_desc;
35
36/* core initialisation functions */
37
38extern void s3c24xx_init_irq(void);
39
40extern void s3c24xx_init_io(struct map_desc *mach_desc, int size);
41
42extern void s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no);
43
44extern void s3c24xx_init_clocks(int xtal);
45
46/* the board structure is used at first initialsation time
47 * to get info such as the devices to register for this
48 * board. This is done because platfrom_add_devices() cannot
49 * be called from the map_io entry.
50*/
51
52struct s3c24xx_board {
53 struct platform_device **devices;
54 unsigned int devices_count;
55
56 struct clk **clocks;
57 unsigned int clocks_count;
58};
59
60extern void s3c24xx_set_board(struct s3c24xx_board *board);
61
62/* timer for 2410/2440 */
63
64struct sys_timer;
65extern struct sys_timer s3c24xx_timer;
66
67/* system device classes */
68
69extern struct sysdev_class s3c2440_sysclass;
diff --git a/arch/arm/mach-s3c2410/devs.c b/arch/arm/mach-s3c2410/devs.c
new file mode 100644
index 000000000000..64792f678668
--- /dev/null
+++ b/arch/arm/mach-s3c2410/devs.c
@@ -0,0 +1,485 @@
1/* linux/arch/arm/mach-s3c2410/devs.c
2 *
3 * Copyright (c) 2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * Base S3C2410 platform device definitions
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 version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Modifications:
13 * 10-Mar-2005 LCVR Changed S3C2410_{VA,SZ} to S3C24XX_{VA,SZ}
14 * 10-Feb-2005 BJD Added camera from guillaume.gourat@nexvision.tv
15 * 29-Aug-2004 BJD Added timers 0 through 3
16 * 29-Aug-2004 BJD Changed index of devices we only have one of to -1
17 * 21-Aug-2004 BJD Added IRQ_TICK to RTC resources
18 * 18-Aug-2004 BJD Created initial version
19*/
20
21#include <linux/kernel.h>
22#include <linux/types.h>
23#include <linux/interrupt.h>
24#include <linux/list.h>
25#include <linux/timer.h>
26#include <linux/init.h>
27#include <linux/device.h>
28
29#include <asm/mach/arch.h>
30#include <asm/mach/map.h>
31#include <asm/mach/irq.h>
32
33#include <asm/hardware.h>
34#include <asm/io.h>
35#include <asm/irq.h>
36
37#include <asm/arch/regs-serial.h>
38
39#include "devs.h"
40
41/* Serial port registrations */
42
43struct platform_device *s3c24xx_uart_devs[3];
44
45/* USB Host Controller */
46
47static struct resource s3c_usb_resource[] = {
48 [0] = {
49 .start = S3C2410_PA_USBHOST,
50 .end = S3C2410_PA_USBHOST + S3C24XX_SZ_USBHOST,
51 .flags = IORESOURCE_MEM,
52 },
53 [1] = {
54 .start = IRQ_USBH,
55 .end = IRQ_USBH,
56 .flags = IORESOURCE_IRQ,
57 }
58};
59
60static u64 s3c_device_usb_dmamask = 0xffffffffUL;
61
62struct platform_device s3c_device_usb = {
63 .name = "s3c2410-ohci",
64 .id = -1,
65 .num_resources = ARRAY_SIZE(s3c_usb_resource),
66 .resource = s3c_usb_resource,
67 .dev = {
68 .dma_mask = &s3c_device_usb_dmamask,
69 .coherent_dma_mask = 0xffffffffUL
70 }
71};
72
73EXPORT_SYMBOL(s3c_device_usb);
74
75/* LCD Controller */
76
77static struct resource s3c_lcd_resource[] = {
78 [0] = {
79 .start = S3C2410_PA_LCD,
80 .end = S3C2410_PA_LCD + S3C24XX_SZ_LCD,
81 .flags = IORESOURCE_MEM,
82 },
83 [1] = {
84 .start = IRQ_LCD,
85 .end = IRQ_LCD,
86 .flags = IORESOURCE_IRQ,
87 }
88
89};
90
91static u64 s3c_device_lcd_dmamask = 0xffffffffUL;
92
93struct platform_device s3c_device_lcd = {
94 .name = "s3c2410-lcd",
95 .id = -1,
96 .num_resources = ARRAY_SIZE(s3c_lcd_resource),
97 .resource = s3c_lcd_resource,
98 .dev = {
99 .dma_mask = &s3c_device_lcd_dmamask,
100 .coherent_dma_mask = 0xffffffffUL
101 }
102};
103
104EXPORT_SYMBOL(s3c_device_lcd);
105
106/* NAND Controller */
107
108static struct resource s3c_nand_resource[] = {
109 [0] = {
110 .start = S3C2410_PA_NAND,
111 .end = S3C2410_PA_NAND + S3C24XX_SZ_NAND,
112 .flags = IORESOURCE_MEM,
113 }
114};
115
116struct platform_device s3c_device_nand = {
117 .name = "s3c2410-nand",
118 .id = -1,
119 .num_resources = ARRAY_SIZE(s3c_nand_resource),
120 .resource = s3c_nand_resource,
121};
122
123EXPORT_SYMBOL(s3c_device_nand);
124
125/* USB Device (Gadget)*/
126
127static struct resource s3c_usbgadget_resource[] = {
128 [0] = {
129 .start = S3C2410_PA_USBDEV,
130 .end = S3C2410_PA_USBDEV + S3C24XX_SZ_USBDEV,
131 .flags = IORESOURCE_MEM,
132 },
133 [1] = {
134 .start = IRQ_USBD,
135 .end = IRQ_USBD,
136 .flags = IORESOURCE_IRQ,
137 }
138
139};
140
141struct platform_device s3c_device_usbgadget = {
142 .name = "s3c2410-usbgadget",
143 .id = -1,
144 .num_resources = ARRAY_SIZE(s3c_usbgadget_resource),
145 .resource = s3c_usbgadget_resource,
146};
147
148EXPORT_SYMBOL(s3c_device_usbgadget);
149
150/* Watchdog */
151
152static struct resource s3c_wdt_resource[] = {
153 [0] = {
154 .start = S3C2410_PA_WATCHDOG,
155 .end = S3C2410_PA_WATCHDOG + S3C24XX_SZ_WATCHDOG,
156 .flags = IORESOURCE_MEM,
157 },
158 [1] = {
159 .start = IRQ_WDT,
160 .end = IRQ_WDT,
161 .flags = IORESOURCE_IRQ,
162 }
163
164};
165
166struct platform_device s3c_device_wdt = {
167 .name = "s3c2410-wdt",
168 .id = -1,
169 .num_resources = ARRAY_SIZE(s3c_wdt_resource),
170 .resource = s3c_wdt_resource,
171};
172
173EXPORT_SYMBOL(s3c_device_wdt);
174
175/* I2C */
176
177static struct resource s3c_i2c_resource[] = {
178 [0] = {
179 .start = S3C2410_PA_IIC,
180 .end = S3C2410_PA_IIC + S3C24XX_SZ_IIC,
181 .flags = IORESOURCE_MEM,
182 },
183 [1] = {
184 .start = IRQ_IIC,
185 .end = IRQ_IIC,
186 .flags = IORESOURCE_IRQ,
187 }
188
189};
190
191struct platform_device s3c_device_i2c = {
192 .name = "s3c2410-i2c",
193 .id = -1,
194 .num_resources = ARRAY_SIZE(s3c_i2c_resource),
195 .resource = s3c_i2c_resource,
196};
197
198EXPORT_SYMBOL(s3c_device_i2c);
199
200/* IIS */
201
202static struct resource s3c_iis_resource[] = {
203 [0] = {
204 .start = S3C2410_PA_IIS,
205 .end = S3C2410_PA_IIS + S3C24XX_SZ_IIS,
206 .flags = IORESOURCE_MEM,
207 }
208};
209
210static u64 s3c_device_iis_dmamask = 0xffffffffUL;
211
212struct platform_device s3c_device_iis = {
213 .name = "s3c2410-iis",
214 .id = -1,
215 .num_resources = ARRAY_SIZE(s3c_iis_resource),
216 .resource = s3c_iis_resource,
217 .dev = {
218 .dma_mask = &s3c_device_iis_dmamask,
219 .coherent_dma_mask = 0xffffffffUL
220 }
221};
222
223EXPORT_SYMBOL(s3c_device_iis);
224
225/* RTC */
226
227static struct resource s3c_rtc_resource[] = {
228 [0] = {
229 .start = S3C2410_PA_RTC,
230 .end = S3C2410_PA_RTC + 0xff,
231 .flags = IORESOURCE_MEM,
232 },
233 [1] = {
234 .start = IRQ_RTC,
235 .end = IRQ_RTC,
236 .flags = IORESOURCE_IRQ,
237 },
238 [2] = {
239 .start = IRQ_TICK,
240 .end = IRQ_TICK,
241 .flags = IORESOURCE_IRQ
242 }
243};
244
245struct platform_device s3c_device_rtc = {
246 .name = "s3c2410-rtc",
247 .id = -1,
248 .num_resources = ARRAY_SIZE(s3c_rtc_resource),
249 .resource = s3c_rtc_resource,
250};
251
252EXPORT_SYMBOL(s3c_device_rtc);
253
254/* ADC */
255
256static struct resource s3c_adc_resource[] = {
257 [0] = {
258 .start = S3C2410_PA_ADC,
259 .end = S3C2410_PA_ADC + S3C24XX_SZ_ADC,
260 .flags = IORESOURCE_MEM,
261 },
262 [1] = {
263 .start = IRQ_TC,
264 .end = IRQ_ADC,
265 .flags = IORESOURCE_IRQ,
266 }
267
268};
269
270struct platform_device s3c_device_adc = {
271 .name = "s3c2410-adc",
272 .id = -1,
273 .num_resources = ARRAY_SIZE(s3c_adc_resource),
274 .resource = s3c_adc_resource,
275};
276
277/* SDI */
278
279static struct resource s3c_sdi_resource[] = {
280 [0] = {
281 .start = S3C2410_PA_SDI,
282 .end = S3C2410_PA_SDI + S3C24XX_SZ_SDI,
283 .flags = IORESOURCE_MEM,
284 },
285 [1] = {
286 .start = IRQ_SDI,
287 .end = IRQ_SDI,
288 .flags = IORESOURCE_IRQ,
289 }
290
291};
292
293struct platform_device s3c_device_sdi = {
294 .name = "s3c2410-sdi",
295 .id = -1,
296 .num_resources = ARRAY_SIZE(s3c_sdi_resource),
297 .resource = s3c_sdi_resource,
298};
299
300EXPORT_SYMBOL(s3c_device_sdi);
301
302/* SPI (0) */
303
304static struct resource s3c_spi0_resource[] = {
305 [0] = {
306 .start = S3C2410_PA_SPI,
307 .end = S3C2410_PA_SPI + 0x1f,
308 .flags = IORESOURCE_MEM,
309 },
310 [1] = {
311 .start = IRQ_SPI0,
312 .end = IRQ_SPI0,
313 .flags = IORESOURCE_IRQ,
314 }
315
316};
317
318struct platform_device s3c_device_spi0 = {
319 .name = "s3c2410-spi",
320 .id = 0,
321 .num_resources = ARRAY_SIZE(s3c_spi0_resource),
322 .resource = s3c_spi0_resource,
323};
324
325EXPORT_SYMBOL(s3c_device_spi0);
326
327/* SPI (1) */
328
329static struct resource s3c_spi1_resource[] = {
330 [0] = {
331 .start = S3C2410_PA_SPI + 0x20,
332 .end = S3C2410_PA_SPI + 0x20 + 0x1f,
333 .flags = IORESOURCE_MEM,
334 },
335 [1] = {
336 .start = IRQ_SPI1,
337 .end = IRQ_SPI1,
338 .flags = IORESOURCE_IRQ,
339 }
340
341};
342
343struct platform_device s3c_device_spi1 = {
344 .name = "s3c2410-spi",
345 .id = 1,
346 .num_resources = ARRAY_SIZE(s3c_spi1_resource),
347 .resource = s3c_spi1_resource,
348};
349
350EXPORT_SYMBOL(s3c_device_spi1);
351
352/* pwm timer blocks */
353
354static struct resource s3c_timer0_resource[] = {
355 [0] = {
356 .start = S3C2410_PA_TIMER + 0x0C,
357 .end = S3C2410_PA_TIMER + 0x0C + 0xB,
358 .flags = IORESOURCE_MEM,
359 },
360 [1] = {
361 .start = IRQ_TIMER0,
362 .end = IRQ_TIMER0,
363 .flags = IORESOURCE_IRQ,
364 }
365
366};
367
368struct platform_device s3c_device_timer0 = {
369 .name = "s3c2410-timer",
370 .id = 0,
371 .num_resources = ARRAY_SIZE(s3c_timer0_resource),
372 .resource = s3c_timer0_resource,
373};
374
375EXPORT_SYMBOL(s3c_device_timer0);
376
377/* timer 1 */
378
379static struct resource s3c_timer1_resource[] = {
380 [0] = {
381 .start = S3C2410_PA_TIMER + 0x18,
382 .end = S3C2410_PA_TIMER + 0x23,
383 .flags = IORESOURCE_MEM,
384 },
385 [1] = {
386 .start = IRQ_TIMER1,
387 .end = IRQ_TIMER1,
388 .flags = IORESOURCE_IRQ,
389 }
390
391};
392
393struct platform_device s3c_device_timer1 = {
394 .name = "s3c2410-timer",
395 .id = 1,
396 .num_resources = ARRAY_SIZE(s3c_timer1_resource),
397 .resource = s3c_timer1_resource,
398};
399
400EXPORT_SYMBOL(s3c_device_timer1);
401
402/* timer 2 */
403
404static struct resource s3c_timer2_resource[] = {
405 [0] = {
406 .start = S3C2410_PA_TIMER + 0x24,
407 .end = S3C2410_PA_TIMER + 0x2F,
408 .flags = IORESOURCE_MEM,
409 },
410 [1] = {
411 .start = IRQ_TIMER2,
412 .end = IRQ_TIMER2,
413 .flags = IORESOURCE_IRQ,
414 }
415
416};
417
418struct platform_device s3c_device_timer2 = {
419 .name = "s3c2410-timer",
420 .id = 2,
421 .num_resources = ARRAY_SIZE(s3c_timer2_resource),
422 .resource = s3c_timer2_resource,
423};
424
425EXPORT_SYMBOL(s3c_device_timer2);
426
427/* timer 3 */
428
429static struct resource s3c_timer3_resource[] = {
430 [0] = {
431 .start = S3C2410_PA_TIMER + 0x30,
432 .end = S3C2410_PA_TIMER + 0x3B,
433 .flags = IORESOURCE_MEM,
434 },
435 [1] = {
436 .start = IRQ_TIMER3,
437 .end = IRQ_TIMER3,
438 .flags = IORESOURCE_IRQ,
439 }
440
441};
442
443struct platform_device s3c_device_timer3 = {
444 .name = "s3c2410-timer",
445 .id = 3,
446 .num_resources = ARRAY_SIZE(s3c_timer3_resource),
447 .resource = s3c_timer3_resource,
448};
449
450EXPORT_SYMBOL(s3c_device_timer3);
451
452#ifdef CONFIG_CPU_S3C2440
453
454/* Camif Controller */
455
456static struct resource s3c_camif_resource[] = {
457 [0] = {
458 .start = S3C2440_PA_CAMIF,
459 .end = S3C2440_PA_CAMIF + S3C2440_SZ_CAMIF,
460 .flags = IORESOURCE_MEM,
461 },
462 [1] = {
463 .start = IRQ_CAM,
464 .end = IRQ_CAM,
465 .flags = IORESOURCE_IRQ,
466 }
467
468};
469
470static u64 s3c_device_camif_dmamask = 0xffffffffUL;
471
472struct platform_device s3c_device_camif = {
473 .name = "s3c2440-camif",
474 .id = -1,
475 .num_resources = ARRAY_SIZE(s3c_camif_resource),
476 .resource = s3c_camif_resource,
477 .dev = {
478 .dma_mask = &s3c_device_camif_dmamask,
479 .coherent_dma_mask = 0xffffffffUL
480 }
481};
482
483EXPORT_SYMBOL(s3c_device_camif);
484
485#endif // CONFIG_CPU_S32440
diff --git a/arch/arm/mach-s3c2410/devs.h b/arch/arm/mach-s3c2410/devs.h
new file mode 100644
index 000000000000..d6328f96728b
--- /dev/null
+++ b/arch/arm/mach-s3c2410/devs.h
@@ -0,0 +1,48 @@
1/* arch/arm/mach-s3c2410/devs.h
2 *
3 * Copyright (c) 2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * Header file for s3c2410 standard platform devices
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 version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Modifications:
13 * 18-Aug-2004 BJD Created initial version
14 * 27-Aug-2004 BJD Added timers 0 through 3
15 * 10-Feb-2005 BJD Added camera from guillaume.gourat@nexvision.tv
16*/
17#include <linux/config.h>
18
19extern struct platform_device *s3c24xx_uart_devs[];
20
21extern struct platform_device s3c_device_usb;
22extern struct platform_device s3c_device_lcd;
23extern struct platform_device s3c_device_wdt;
24extern struct platform_device s3c_device_i2c;
25extern struct platform_device s3c_device_iis;
26extern struct platform_device s3c_device_rtc;
27extern struct platform_device s3c_device_adc;
28extern struct platform_device s3c_device_sdi;
29
30extern struct platform_device s3c_device_spi0;
31extern struct platform_device s3c_device_spi1;
32
33extern struct platform_device s3c_device_nand;
34
35extern struct platform_device s3c_device_timer0;
36extern struct platform_device s3c_device_timer1;
37extern struct platform_device s3c_device_timer2;
38extern struct platform_device s3c_device_timer3;
39
40extern struct platform_device s3c_device_usbgadget;
41
42/* s3c2440 specific devices */
43
44#ifdef CONFIG_CPU_S3C2440
45
46extern struct platform_device s3c_device_camif;
47
48#endif
diff --git a/arch/arm/mach-s3c2410/dma.c b/arch/arm/mach-s3c2410/dma.c
new file mode 100644
index 000000000000..bc229fab86d4
--- /dev/null
+++ b/arch/arm/mach-s3c2410/dma.c
@@ -0,0 +1,1210 @@
1/* linux/arch/arm/mach-bast/dma.c
2 *
3 * (c) 2003-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * S3C2410 DMA core
7 *
8 * http://www.simtec.co.uk/products/EB2410ITX/
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 * Changelog:
15 * 27-Feb-2005 BJD Added kmem cache for dma descriptors
16 * 18-Nov-2004 BJD Removed error for loading onto stopped channel
17 * 10-Nov-2004 BJD Ensure all external symbols exported for modules
18 * 10-Nov-2004 BJD Use sys_device and sysdev_class for power management
19 * 08-Aug-2004 BJD Apply rmk's suggestions
20 * 21-Jul-2004 BJD Ported to linux 2.6
21 * 12-Jul-2004 BJD Finished re-write and change of API
22 * 06-Jul-2004 BJD Rewrote dma code to try and cope with various problems
23 * 23-May-2003 BJD Created file
24 * 19-Aug-2003 BJD Cleanup, header fix, added URL
25 *
26 * This file is based on the Sangwook Lee/Samsung patches, re-written due
27 * to various ommisions from the code (such as flexible dma configuration)
28 * for use with the BAST system board.
29 *
30 * The re-write is pretty much complete, and should be good enough for any
31 * possible DMA function
32 */
33
34#include <linux/config.h>
35
36#ifdef CONFIG_S3C2410_DMA_DEBUG
37#define DEBUG
38#endif
39
40#include <linux/module.h>
41#include <linux/init.h>
42#include <linux/sched.h>
43#include <linux/spinlock.h>
44#include <linux/interrupt.h>
45#include <linux/sysdev.h>
46#include <linux/slab.h>
47#include <linux/errno.h>
48#include <linux/delay.h>
49
50#include <asm/system.h>
51#include <asm/irq.h>
52#include <asm/hardware.h>
53#include <asm/io.h>
54#include <asm/dma.h>
55
56#include <asm/mach/dma.h>
57#include <asm/arch/map.h>
58
59/* io map for dma */
60static void __iomem *dma_base;
61static kmem_cache_t *dma_kmem;
62
63/* dma channel state information */
64s3c2410_dma_chan_t s3c2410_chans[S3C2410_DMA_CHANNELS];
65
66/* debugging functions */
67
68#define BUF_MAGIC (0xcafebabe)
69
70#define dmawarn(fmt...) printk(KERN_DEBUG fmt)
71
72#define dma_regaddr(chan, reg) ((chan)->regs + (reg))
73
74#if 1
75#define dma_wrreg(chan, reg, val) writel((val), (chan)->regs + (reg))
76#else
77static inline void
78dma_wrreg(s3c2410_dma_chan_t *chan, int reg, unsigned long val)
79{
80 pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg);
81 writel(val, dma_regaddr(chan, reg));
82}
83
84#endif
85
86#define dma_rdreg(chan, reg) readl((chan)->regs + (reg))
87
88/* captured register state for debug */
89
90struct s3c2410_dma_regstate {
91 unsigned long dcsrc;
92 unsigned long disrc;
93 unsigned long dstat;
94 unsigned long dcon;
95 unsigned long dmsktrig;
96};
97
98#ifdef CONFIG_S3C2410_DMA_DEBUG
99
100/* dmadbg_showregs
101 *
102 * simple debug routine to print the current state of the dma registers
103*/
104
105static void
106dmadbg_capture(s3c2410_dma_chan_t *chan, struct s3c2410_dma_regstate *regs)
107{
108 regs->dcsrc = dma_rdreg(chan, S3C2410_DMA_DCSRC);
109 regs->disrc = dma_rdreg(chan, S3C2410_DMA_DISRC);
110 regs->dstat = dma_rdreg(chan, S3C2410_DMA_DSTAT);
111 regs->dcon = dma_rdreg(chan, S3C2410_DMA_DCON);
112 regs->dmsktrig = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
113}
114
115static void
116dmadbg_showregs(const char *fname, int line, s3c2410_dma_chan_t *chan,
117 struct s3c2410_dma_regstate *regs)
118{
119 printk(KERN_DEBUG "dma%d: %s:%d: DCSRC=%08lx, DISRC=%08lx, DSTAT=%08lx DMT=%02lx, DCON=%08lx\n",
120 chan->number, fname, line,
121 regs->dcsrc, regs->disrc, regs->dstat, regs->dmsktrig,
122 regs->dcon);
123}
124
125static void
126dmadbg_showchan(const char *fname, int line, s3c2410_dma_chan_t *chan)
127{
128 struct s3c2410_dma_regstate state;
129
130 dmadbg_capture(chan, &state);
131
132 printk(KERN_DEBUG "dma%d: %s:%d: ls=%d, cur=%p, %p %p\n",
133 chan->number, fname, line, chan->load_state,
134 chan->curr, chan->next, chan->end);
135
136 dmadbg_showregs(fname, line, chan, &state);
137}
138
139#define dbg_showregs(chan) dmadbg_showregs(__FUNCTION__, __LINE__, (chan))
140#define dbg_showchan(chan) dmadbg_showchan(__FUNCTION__, __LINE__, (chan))
141#else
142#define dbg_showregs(chan) do { } while(0)
143#define dbg_showchan(chan) do { } while(0)
144#endif /* CONFIG_S3C2410_DMA_DEBUG */
145
146#define check_channel(chan) \
147 do { if ((chan) >= S3C2410_DMA_CHANNELS) { \
148 printk(KERN_ERR "%s: invalid channel %d\n", __FUNCTION__, (chan)); \
149 return -EINVAL; \
150 } } while(0)
151
152
153/* s3c2410_dma_stats_timeout
154 *
155 * Update DMA stats from timeout info
156*/
157
158static void
159s3c2410_dma_stats_timeout(s3c2410_dma_stats_t *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(s3c2410_dma_chan_t *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(s3c2410_dma_chan_t *chan,
226 s3c2410_dma_buf_t *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 writel(buf->data, chan->addr_reg);
262
263 dma_wrreg(chan, S3C2410_DMA_DCON,
264 chan->dcon | reload | (buf->size/chan->xfer_unit));
265
266 chan->next = buf->next;
267
268 /* update the state of the channel */
269
270 switch (chan->load_state) {
271 case S3C2410_DMALOAD_NONE:
272 chan->load_state = S3C2410_DMALOAD_1LOADED;
273 break;
274
275 case S3C2410_DMALOAD_1RUNNING:
276 chan->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING;
277 break;
278
279 default:
280 dmawarn("dmaload: unknown state %d in loadbuffer\n",
281 chan->load_state);
282 break;
283 }
284
285 return 0;
286}
287
288/* s3c2410_dma_call_op
289 *
290 * small routine to call the op routine with the given op if it has been
291 * registered
292*/
293
294static void
295s3c2410_dma_call_op(s3c2410_dma_chan_t *chan, s3c2410_chan_op_t op)
296{
297 if (chan->op_fn != NULL) {
298 (chan->op_fn)(chan, op);
299 }
300}
301
302/* s3c2410_dma_buffdone
303 *
304 * small wrapper to check if callback routine needs to be called, and
305 * if so, call it
306*/
307
308static inline void
309s3c2410_dma_buffdone(s3c2410_dma_chan_t *chan, s3c2410_dma_buf_t *buf,
310 s3c2410_dma_buffresult_t result)
311{
312 pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n",
313 chan->callback_fn, buf, buf->id, buf->size, result);
314
315 if (chan->callback_fn != NULL) {
316 (chan->callback_fn)(chan, buf->id, buf->size, result);
317 }
318}
319
320/* s3c2410_dma_start
321 *
322 * start a dma channel going
323*/
324
325static int s3c2410_dma_start(s3c2410_dma_chan_t *chan)
326{
327 unsigned long tmp;
328 unsigned long flags;
329
330 pr_debug("s3c2410_start_dma: channel=%d\n", chan->number);
331
332 local_irq_save(flags);
333
334 if (chan->state == S3C2410_DMA_RUNNING) {
335 pr_debug("s3c2410_start_dma: already running (%d)\n", chan->state);
336 local_irq_restore(flags);
337 return 0;
338 }
339
340 chan->state = S3C2410_DMA_RUNNING;
341
342 /* check wether there is anything to load, and if not, see
343 * if we can find anything to load
344 */
345
346 if (chan->load_state == S3C2410_DMALOAD_NONE) {
347 if (chan->next == NULL) {
348 printk(KERN_ERR "dma%d: channel has nothing loaded\n",
349 chan->number);
350 chan->state = S3C2410_DMA_IDLE;
351 local_irq_restore(flags);
352 return -EINVAL;
353 }
354
355 s3c2410_dma_loadbuffer(chan, chan->next);
356 }
357
358 dbg_showchan(chan);
359
360 /* enable the channel */
361
362 if (!chan->irq_enabled) {
363 enable_irq(chan->irq);
364 chan->irq_enabled = 1;
365 }
366
367 /* start the channel going */
368
369 tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
370 tmp &= ~S3C2410_DMASKTRIG_STOP;
371 tmp |= S3C2410_DMASKTRIG_ON;
372 dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
373
374 pr_debug("wrote %08lx to DMASKTRIG\n", tmp);
375
376#if 0
377 /* the dma buffer loads should take care of clearing the AUTO
378 * reloading feature */
379 tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
380 tmp &= ~S3C2410_DCON_NORELOAD;
381 dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
382#endif
383
384 s3c2410_dma_call_op(chan, S3C2410_DMAOP_START);
385
386 dbg_showchan(chan);
387
388 local_irq_restore(flags);
389 return 0;
390}
391
392/* s3c2410_dma_canload
393 *
394 * work out if we can queue another buffer into the DMA engine
395*/
396
397static int
398s3c2410_dma_canload(s3c2410_dma_chan_t *chan)
399{
400 if (chan->load_state == S3C2410_DMALOAD_NONE ||
401 chan->load_state == S3C2410_DMALOAD_1RUNNING)
402 return 1;
403
404 return 0;
405}
406
407
408/* s3c2410_dma_enqueue
409 *
410 * queue an given buffer for dma transfer.
411 *
412 * id the device driver's id information for this buffer
413 * data the physical address of the buffer data
414 * size the size of the buffer in bytes
415 *
416 * If the channel is not running, then the flag S3C2410_DMAF_AUTOSTART
417 * is checked, and if set, the channel is started. If this flag isn't set,
418 * then an error will be returned.
419 *
420 * It is possible to queue more than one DMA buffer onto a channel at
421 * once, and the code will deal with the re-loading of the next buffer
422 * when necessary.
423*/
424
425int s3c2410_dma_enqueue(unsigned int channel, void *id,
426 dma_addr_t data, int size)
427{
428 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
429 s3c2410_dma_buf_t *buf;
430 unsigned long flags;
431
432 check_channel(channel);
433
434 pr_debug("%s: id=%p, data=%08x, size=%d\n",
435 __FUNCTION__, id, (unsigned int)data, size);
436
437 buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC);
438 if (buf == NULL) {
439 pr_debug("%s: out of memory (%d alloc)\n",
440 __FUNCTION__, sizeof(*buf));
441 return -ENOMEM;
442 }
443
444 pr_debug("%s: new buffer %p\n", __FUNCTION__, buf);
445
446 //dbg_showchan(chan);
447
448 buf->next = NULL;
449 buf->data = buf->ptr = data;
450 buf->size = size;
451 buf->id = id;
452 buf->magic = BUF_MAGIC;
453
454 local_irq_save(flags);
455
456 if (chan->curr == NULL) {
457 /* we've got nothing loaded... */
458 pr_debug("%s: buffer %p queued onto empty channel\n",
459 __FUNCTION__, buf);
460
461 chan->curr = buf;
462 chan->end = buf;
463 chan->next = NULL;
464 } else {
465 pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n",
466 chan->number, __FUNCTION__, buf);
467
468 if (chan->end == NULL)
469 pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n",
470 chan->number, __FUNCTION__, chan);
471
472 chan->end->next = buf;
473 chan->end = buf;
474 }
475
476 /* if necessary, update the next buffer field */
477 if (chan->next == NULL)
478 chan->next = buf;
479
480 /* check to see if we can load a buffer */
481 if (chan->state == S3C2410_DMA_RUNNING) {
482 if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) {
483 if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
484 printk(KERN_ERR "dma%d: loadbuffer:"
485 "timeout loading buffer\n",
486 chan->number);
487 dbg_showchan(chan);
488 local_irq_restore(flags);
489 return -EINVAL;
490 }
491 }
492
493 while (s3c2410_dma_canload(chan) && chan->next != NULL) {
494 s3c2410_dma_loadbuffer(chan, chan->next);
495 }
496 } else if (chan->state == S3C2410_DMA_IDLE) {
497 if (chan->flags & S3C2410_DMAF_AUTOSTART) {
498 s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_START);
499 }
500 }
501
502 local_irq_restore(flags);
503 return 0;
504}
505
506EXPORT_SYMBOL(s3c2410_dma_enqueue);
507
508static inline void
509s3c2410_dma_freebuf(s3c2410_dma_buf_t *buf)
510{
511 int magicok = (buf->magic == BUF_MAGIC);
512
513 buf->magic = -1;
514
515 if (magicok) {
516 kmem_cache_free(dma_kmem, buf);
517 } else {
518 printk("s3c2410_dma_freebuf: buff %p with bad magic\n", buf);
519 }
520}
521
522/* s3c2410_dma_lastxfer
523 *
524 * called when the system is out of buffers, to ensure that the channel
525 * is prepared for shutdown.
526*/
527
528static inline void
529s3c2410_dma_lastxfer(s3c2410_dma_chan_t *chan)
530{
531 pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n",
532 chan->number, chan->load_state);
533
534 switch (chan->load_state) {
535 case S3C2410_DMALOAD_NONE:
536 break;
537
538 case S3C2410_DMALOAD_1LOADED:
539 if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
540 /* flag error? */
541 printk(KERN_ERR "dma%d: timeout waiting for load\n",
542 chan->number);
543 return;
544 }
545 break;
546
547 default:
548 pr_debug("dma%d: lastxfer: unhandled load_state %d with no next",
549 chan->number, chan->load_state);
550 return;
551
552 }
553
554 /* hopefully this'll shut the damned thing up after the transfer... */
555 dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD);
556}
557
558
559#define dmadbg2(x...)
560
561static irqreturn_t
562s3c2410_dma_irq(int irq, void *devpw, struct pt_regs *regs)
563{
564 s3c2410_dma_chan_t *chan = (s3c2410_dma_chan_t *)devpw;
565 s3c2410_dma_buf_t *buf;
566
567 buf = chan->curr;
568
569 dbg_showchan(chan);
570
571 /* modify the channel state */
572
573 switch (chan->load_state) {
574 case S3C2410_DMALOAD_1RUNNING:
575 /* TODO - if we are running only one buffer, we probably
576 * want to reload here, and then worry about the buffer
577 * callback */
578
579 chan->load_state = S3C2410_DMALOAD_NONE;
580 break;
581
582 case S3C2410_DMALOAD_1LOADED:
583 /* iirc, we should go back to NONE loaded here, we
584 * had a buffer, and it was never verified as being
585 * loaded.
586 */
587
588 chan->load_state = S3C2410_DMALOAD_NONE;
589 break;
590
591 case S3C2410_DMALOAD_1LOADED_1RUNNING:
592 /* we'll worry about checking to see if another buffer is
593 * ready after we've called back the owner. This should
594 * ensure we do not wait around too long for the DMA
595 * engine to start the next transfer
596 */
597
598 chan->load_state = S3C2410_DMALOAD_1LOADED;
599 break;
600
601 case S3C2410_DMALOAD_NONE:
602 printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n",
603 chan->number);
604 break;
605
606 default:
607 printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n",
608 chan->number, chan->load_state);
609 break;
610 }
611
612 if (buf != NULL) {
613 /* update the chain to make sure that if we load any more
614 * buffers when we call the callback function, things should
615 * work properly */
616
617 chan->curr = buf->next;
618 buf->next = NULL;
619
620 if (buf->magic != BUF_MAGIC) {
621 printk(KERN_ERR "dma%d: %s: buf %p incorrect magic\n",
622 chan->number, __FUNCTION__, buf);
623 return IRQ_HANDLED;
624 }
625
626 s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK);
627
628 /* free resouces */
629 s3c2410_dma_freebuf(buf);
630 } else {
631 }
632
633 if (chan->next != NULL) {
634 unsigned long flags;
635
636 switch (chan->load_state) {
637 case S3C2410_DMALOAD_1RUNNING:
638 /* don't need to do anything for this state */
639 break;
640
641 case S3C2410_DMALOAD_NONE:
642 /* can load buffer immediately */
643 break;
644
645 case S3C2410_DMALOAD_1LOADED:
646 if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
647 /* flag error? */
648 printk(KERN_ERR "dma%d: timeout waiting for load\n",
649 chan->number);
650 return IRQ_HANDLED;
651 }
652
653 break;
654
655 case S3C2410_DMALOAD_1LOADED_1RUNNING:
656 goto no_load;
657
658 default:
659 printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n",
660 chan->number, chan->load_state);
661 return IRQ_HANDLED;
662 }
663
664 local_irq_save(flags);
665 s3c2410_dma_loadbuffer(chan, chan->next);
666 local_irq_restore(flags);
667 } else {
668 s3c2410_dma_lastxfer(chan);
669
670 /* see if we can stop this channel.. */
671 if (chan->load_state == S3C2410_DMALOAD_NONE) {
672 pr_debug("dma%d: end of transfer, stopping channel (%ld)\n",
673 chan->number, jiffies);
674 s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP);
675 }
676 }
677
678 no_load:
679 return IRQ_HANDLED;
680}
681
682
683
684/* s3c2410_request_dma
685 *
686 * get control of an dma channel
687*/
688
689int s3c2410_dma_request(unsigned int channel, s3c2410_dma_client_t *client,
690 void *dev)
691{
692 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
693 unsigned long flags;
694 int err;
695
696 pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n",
697 channel, client->name, dev);
698
699 check_channel(channel);
700
701 local_irq_save(flags);
702
703 dbg_showchan(chan);
704
705 if (chan->in_use) {
706 if (client != chan->client) {
707 printk(KERN_ERR "dma%d: already in use\n", channel);
708 local_irq_restore(flags);
709 return -EBUSY;
710 } else {
711 printk(KERN_ERR "dma%d: client already has channel\n", channel);
712 }
713 }
714
715 chan->client = client;
716 chan->in_use = 1;
717
718 if (!chan->irq_claimed) {
719 pr_debug("dma%d: %s : requesting irq %d\n",
720 channel, __FUNCTION__, chan->irq);
721
722 err = request_irq(chan->irq, s3c2410_dma_irq, SA_INTERRUPT,
723 client->name, (void *)chan);
724
725 if (err) {
726 chan->in_use = 0;
727 local_irq_restore(flags);
728
729 printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n",
730 client->name, chan->irq, chan->number);
731 return err;
732 }
733
734 chan->irq_claimed = 1;
735 chan->irq_enabled = 1;
736 }
737
738 local_irq_restore(flags);
739
740 /* need to setup */
741
742 pr_debug("%s: channel initialised, %p\n", __FUNCTION__, chan);
743
744 return 0;
745}
746
747EXPORT_SYMBOL(s3c2410_dma_request);
748
749/* s3c2410_dma_free
750 *
751 * release the given channel back to the system, will stop and flush
752 * any outstanding transfers, and ensure the channel is ready for the
753 * next claimant.
754 *
755 * Note, although a warning is currently printed if the freeing client
756 * info is not the same as the registrant's client info, the free is still
757 * allowed to go through.
758*/
759
760int s3c2410_dma_free(dmach_t channel, s3c2410_dma_client_t *client)
761{
762 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
763 unsigned long flags;
764
765 check_channel(channel);
766
767 local_irq_save(flags);
768
769
770 if (chan->client != client) {
771 printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n",
772 channel, chan->client, client);
773 }
774
775 /* sort out stopping and freeing the channel */
776
777 if (chan->state != S3C2410_DMA_IDLE) {
778 pr_debug("%s: need to stop dma channel %p\n",
779 __FUNCTION__, chan);
780
781 /* possibly flush the channel */
782 s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STOP);
783 }
784
785 chan->client = NULL;
786 chan->in_use = 0;
787
788 local_irq_restore(flags);
789
790 return 0;
791}
792
793EXPORT_SYMBOL(s3c2410_dma_free);
794
795static int s3c2410_dma_dostop(s3c2410_dma_chan_t *chan)
796{
797 unsigned long tmp;
798 unsigned long flags;
799
800 pr_debug("%s:\n", __FUNCTION__);
801
802 dbg_showchan(chan);
803
804 local_irq_save(flags);
805
806 s3c2410_dma_call_op(chan, S3C2410_DMAOP_STOP);
807
808 tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
809 tmp |= S3C2410_DMASKTRIG_STOP;
810 dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
811
812#if 0
813 /* should also clear interrupts, according to WinCE BSP */
814 tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
815 tmp |= S3C2410_DCON_NORELOAD;
816 dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
817#endif
818
819 chan->state = S3C2410_DMA_IDLE;
820 chan->load_state = S3C2410_DMALOAD_NONE;
821
822 local_irq_restore(flags);
823
824 return 0;
825}
826
827/* s3c2410_dma_flush
828 *
829 * stop the channel, and remove all current and pending transfers
830*/
831
832static int s3c2410_dma_flush(s3c2410_dma_chan_t *chan)
833{
834 s3c2410_dma_buf_t *buf, *next;
835 unsigned long flags;
836
837 pr_debug("%s:\n", __FUNCTION__);
838
839 local_irq_save(flags);
840
841 if (chan->state != S3C2410_DMA_IDLE) {
842 pr_debug("%s: stopping channel...\n", __FUNCTION__ );
843 s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP);
844 }
845
846 buf = chan->curr;
847 if (buf == NULL)
848 buf = chan->next;
849
850 chan->curr = chan->next = chan->end = NULL;
851
852 if (buf != NULL) {
853 for ( ; buf != NULL; buf = next) {
854 next = buf->next;
855
856 pr_debug("%s: free buffer %p, next %p\n",
857 __FUNCTION__, buf, buf->next);
858
859 s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT);
860 s3c2410_dma_freebuf(buf);
861 }
862 }
863
864 local_irq_restore(flags);
865
866 return 0;
867}
868
869
870int
871s3c2410_dma_ctrl(dmach_t channel, s3c2410_chan_op_t op)
872{
873 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
874
875 check_channel(channel);
876
877 switch (op) {
878 case S3C2410_DMAOP_START:
879 return s3c2410_dma_start(chan);
880
881 case S3C2410_DMAOP_STOP:
882 return s3c2410_dma_dostop(chan);
883
884 case S3C2410_DMAOP_PAUSE:
885 return -ENOENT;
886
887 case S3C2410_DMAOP_RESUME:
888 return -ENOENT;
889
890 case S3C2410_DMAOP_FLUSH:
891 return s3c2410_dma_flush(chan);
892
893 case S3C2410_DMAOP_TIMEOUT:
894 return 0;
895
896 }
897
898 return -ENOENT; /* unknown, don't bother */
899}
900
901EXPORT_SYMBOL(s3c2410_dma_ctrl);
902
903/* DMA configuration for each channel
904 *
905 * DISRCC -> source of the DMA (AHB,APB)
906 * DISRC -> source address of the DMA
907 * DIDSTC -> destination of the DMA (AHB,APD)
908 * DIDST -> destination address of the DMA
909*/
910
911/* s3c2410_dma_config
912 *
913 * xfersize: size of unit in bytes (1,2,4)
914 * dcon: base value of the DCONx register
915*/
916
917int s3c2410_dma_config(dmach_t channel,
918 int xferunit,
919 int dcon)
920{
921 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
922
923 pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n",
924 __FUNCTION__, channel, xferunit, dcon);
925
926 check_channel(channel);
927
928 switch (xferunit) {
929 case 1:
930 dcon |= S3C2410_DCON_BYTE;
931 break;
932
933 case 2:
934 dcon |= S3C2410_DCON_HALFWORD;
935 break;
936
937 case 4:
938 dcon |= S3C2410_DCON_WORD;
939 break;
940
941 default:
942 pr_debug("%s: bad transfer size %d\n", __FUNCTION__, xferunit);
943 return -EINVAL;
944 }
945
946 dcon |= S3C2410_DCON_HWTRIG;
947 dcon |= S3C2410_DCON_INTREQ;
948
949 pr_debug("%s: dcon now %08x\n", __FUNCTION__, dcon);
950
951 chan->dcon = dcon;
952 chan->xfer_unit = xferunit;
953
954 return 0;
955}
956
957EXPORT_SYMBOL(s3c2410_dma_config);
958
959int s3c2410_dma_setflags(dmach_t channel, unsigned int flags)
960{
961 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
962
963 check_channel(channel);
964
965 pr_debug("%s: chan=%p, flags=%08x\n", __FUNCTION__, chan, flags);
966
967 chan->flags = flags;
968
969 return 0;
970}
971
972EXPORT_SYMBOL(s3c2410_dma_setflags);
973
974
975/* do we need to protect the settings of the fields from
976 * irq?
977*/
978
979int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn)
980{
981 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
982
983 check_channel(channel);
984
985 pr_debug("%s: chan=%p, op rtn=%p\n", __FUNCTION__, chan, rtn);
986
987 chan->op_fn = rtn;
988
989 return 0;
990}
991
992EXPORT_SYMBOL(s3c2410_dma_set_opfn);
993
994int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn)
995{
996 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
997
998 check_channel(channel);
999
1000 pr_debug("%s: chan=%p, callback rtn=%p\n", __FUNCTION__, chan, rtn);
1001
1002 chan->callback_fn = rtn;
1003
1004 return 0;
1005}
1006
1007EXPORT_SYMBOL(s3c2410_dma_set_buffdone_fn);
1008
1009/* s3c2410_dma_devconfig
1010 *
1011 * configure the dma source/destination hardware type and address
1012 *
1013 * source: S3C2410_DMASRC_HW: source is hardware
1014 * S3C2410_DMASRC_MEM: source is memory
1015 *
1016 * hwcfg: the value for xxxSTCn register,
1017 * bit 0: 0=increment pointer, 1=leave pointer
1018 * bit 1: 0=soucre is AHB, 1=soucre is APB
1019 *
1020 * devaddr: physical address of the source
1021*/
1022
1023int s3c2410_dma_devconfig(int channel,
1024 s3c2410_dmasrc_t source,
1025 int hwcfg,
1026 unsigned long devaddr)
1027{
1028 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
1029
1030 check_channel(channel);
1031
1032 pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n",
1033 __FUNCTION__, (int)source, hwcfg, devaddr);
1034
1035 chan->source = source;
1036 chan->dev_addr = devaddr;
1037
1038 switch (source) {
1039 case S3C2410_DMASRC_HW:
1040 /* source is hardware */
1041 pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n",
1042 __FUNCTION__, devaddr, hwcfg);
1043 dma_wrreg(chan, S3C2410_DMA_DISRCC, hwcfg & 3);
1044 dma_wrreg(chan, S3C2410_DMA_DISRC, devaddr);
1045 dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0));
1046
1047 chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST);
1048 return 0;
1049
1050 case S3C2410_DMASRC_MEM:
1051 /* source is memory */
1052 pr_debug( "%s: mem source, devaddr=%08lx, hwcfg=%d\n",
1053 __FUNCTION__, devaddr, hwcfg);
1054 dma_wrreg(chan, S3C2410_DMA_DISRCC, (0<<1) | (0<<0));
1055 dma_wrreg(chan, S3C2410_DMA_DIDST, devaddr);
1056 dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3);
1057
1058 chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC);
1059 return 0;
1060 }
1061
1062 printk(KERN_ERR "dma%d: invalid source type (%d)\n", channel, source);
1063 return -EINVAL;
1064}
1065
1066EXPORT_SYMBOL(s3c2410_dma_devconfig);
1067
1068/* s3c2410_dma_getposition
1069 *
1070 * returns the current transfer points for the dma source and destination
1071*/
1072
1073int s3c2410_dma_getposition(dmach_t channel, dma_addr_t *src, dma_addr_t *dst)
1074{
1075 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
1076
1077 check_channel(channel);
1078
1079 if (src != NULL)
1080 *src = dma_rdreg(chan, S3C2410_DMA_DCSRC);
1081
1082 if (dst != NULL)
1083 *dst = dma_rdreg(chan, S3C2410_DMA_DCDST);
1084
1085 return 0;
1086}
1087
1088EXPORT_SYMBOL(s3c2410_dma_getposition);
1089
1090
1091/* system device class */
1092
1093#ifdef CONFIG_PM
1094
1095static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state)
1096{
1097 s3c2410_dma_chan_t *cp = container_of(dev, s3c2410_dma_chan_t, dev);
1098
1099 printk(KERN_DEBUG "suspending dma channel %d\n", cp->number);
1100
1101 if (dma_rdreg(cp, S3C2410_DMA_DMASKTRIG) & S3C2410_DMASKTRIG_ON) {
1102 /* the dma channel is still working, which is probably
1103 * a bad thing to do over suspend/resume. We stop the
1104 * channel and assume that the client is either going to
1105 * retry after resume, or that it is broken.
1106 */
1107
1108 printk(KERN_INFO "dma: stopping channel %d due to suspend\n",
1109 cp->number);
1110
1111 s3c2410_dma_dostop(cp);
1112 }
1113
1114 return 0;
1115}
1116
1117static int s3c2410_dma_resume(struct sys_device *dev)
1118{
1119 return 0;
1120}
1121
1122#else
1123#define s3c2410_dma_suspend NULL
1124#define s3c2410_dma_resume NULL
1125#endif /* CONFIG_PM */
1126
1127static struct sysdev_class dma_sysclass = {
1128 set_kset_name("s3c24xx-dma"),
1129 .suspend = s3c2410_dma_suspend,
1130 .resume = s3c2410_dma_resume,
1131};
1132
1133/* kmem cache implementation */
1134
1135static void s3c2410_dma_cache_ctor(void *p, kmem_cache_t *c, unsigned long f)
1136{
1137 memset(p, 0, sizeof(s3c2410_dma_buf_t));
1138}
1139
1140
1141/* initialisation code */
1142
1143static int __init s3c2410_init_dma(void)
1144{
1145 s3c2410_dma_chan_t *cp;
1146 int channel;
1147 int ret;
1148
1149 printk("S3C2410 DMA Driver, (c) 2003-2004 Simtec Electronics\n");
1150
1151 dma_base = ioremap(S3C2410_PA_DMA, 0x200);
1152 if (dma_base == NULL) {
1153 printk(KERN_ERR "dma failed to remap register block\n");
1154 return -ENOMEM;
1155 }
1156
1157 ret = sysdev_class_register(&dma_sysclass);
1158 if (ret != 0) {
1159 printk(KERN_ERR "dma sysclass registration failed\n");
1160 goto err;
1161 }
1162
1163 dma_kmem = kmem_cache_create("dma_desc", sizeof(s3c2410_dma_buf_t), 0,
1164 SLAB_HWCACHE_ALIGN,
1165 s3c2410_dma_cache_ctor, NULL);
1166
1167 if (dma_kmem == NULL) {
1168 printk(KERN_ERR "dma failed to make kmem cache\n");
1169 ret = -ENOMEM;
1170 goto err;
1171 }
1172
1173 for (channel = 0; channel < S3C2410_DMA_CHANNELS; channel++) {
1174 cp = &s3c2410_chans[channel];
1175
1176 memset(cp, 0, sizeof(s3c2410_dma_chan_t));
1177
1178 /* dma channel irqs are in order.. */
1179 cp->number = channel;
1180 cp->irq = channel + IRQ_DMA0;
1181 cp->regs = dma_base + (channel*0x40);
1182
1183 /* point current stats somewhere */
1184 cp->stats = &cp->stats_store;
1185 cp->stats_store.timeout_shortest = LONG_MAX;
1186
1187 /* basic channel configuration */
1188
1189 cp->load_timeout = 1<<18;
1190
1191 /* register system device */
1192
1193 cp->dev.cls = &dma_sysclass;
1194 cp->dev.id = channel;
1195 ret = sysdev_register(&cp->dev);
1196
1197 printk("DMA channel %d at %p, irq %d\n",
1198 cp->number, cp->regs, cp->irq);
1199 }
1200
1201 return 0;
1202
1203 err:
1204 kmem_cache_destroy(dma_kmem);
1205 iounmap(dma_base);
1206 dma_base = NULL;
1207 return ret;
1208}
1209
1210__initcall(s3c2410_init_dma);
diff --git a/arch/arm/mach-s3c2410/gpio.c b/arch/arm/mach-s3c2410/gpio.c
new file mode 100644
index 000000000000..94f1776cf312
--- /dev/null
+++ b/arch/arm/mach-s3c2410/gpio.c
@@ -0,0 +1,213 @@
1/* linux/arch/arm/mach-s3c2410/gpio.c
2 *
3 * Copyright (c) 2004-2005 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 * Changelog
23 * 13-Sep-2004 BJD Implemented change of MISCCR
24 * 14-Sep-2004 BJD Added getpin call
25 * 14-Sep-2004 BJD Fixed bug in setpin() call
26 * 30-Sep-2004 BJD Fixed cfgpin() mask bug
27 * 01-Oct-2004 BJD Added getcfg() to get pin configuration
28 * 01-Oct-2004 BJD Fixed mask bug in pullup() call
29 * 01-Oct-2004 BJD Added getirq() to turn pin into irqno
30 * 04-Oct-2004 BJD Added irq filter controls for GPIO
31 * 05-Nov-2004 BJD EXPORT_SYMBOL() added for all code
32 * 13-Mar-2005 BJD Updates for __iomem
33 */
34
35
36#include <linux/kernel.h>
37#include <linux/init.h>
38#include <linux/module.h>
39#include <linux/interrupt.h>
40#include <linux/ioport.h>
41
42#include <asm/hardware.h>
43#include <asm/irq.h>
44#include <asm/io.h>
45
46#include <asm/arch/regs-gpio.h>
47
48void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
49{
50 void __iomem *base = S3C2410_GPIO_BASE(pin);
51 unsigned long mask;
52 unsigned long con;
53 unsigned long flags;
54
55 if (pin < S3C2410_GPIO_BANKB) {
56 mask = 1 << S3C2410_GPIO_OFFSET(pin);
57 } else {
58 mask = 3 << S3C2410_GPIO_OFFSET(pin)*2;
59 }
60
61 local_irq_save(flags);
62
63 con = __raw_readl(base + 0x00);
64 con &= ~mask;
65 con |= function;
66
67 __raw_writel(con, base + 0x00);
68
69 local_irq_restore(flags);
70}
71
72EXPORT_SYMBOL(s3c2410_gpio_cfgpin);
73
74unsigned int s3c2410_gpio_getcfg(unsigned int pin)
75{
76 void __iomem *base = S3C2410_GPIO_BASE(pin);
77 unsigned long mask;
78
79 if (pin < S3C2410_GPIO_BANKB) {
80 mask = 1 << S3C2410_GPIO_OFFSET(pin);
81 } else {
82 mask = 3 << S3C2410_GPIO_OFFSET(pin)*2;
83 }
84
85 return __raw_readl(base) & mask;
86}
87
88EXPORT_SYMBOL(s3c2410_gpio_getcfg);
89
90void s3c2410_gpio_pullup(unsigned int pin, unsigned int to)
91{
92 void __iomem *base = S3C2410_GPIO_BASE(pin);
93 unsigned long offs = S3C2410_GPIO_OFFSET(pin);
94 unsigned long flags;
95 unsigned long up;
96
97 if (pin < S3C2410_GPIO_BANKB)
98 return;
99
100 local_irq_save(flags);
101
102 up = __raw_readl(base + 0x08);
103 up &= ~(1L << offs);
104 up |= to << offs;
105 __raw_writel(up, base + 0x08);
106
107 local_irq_restore(flags);
108}
109
110EXPORT_SYMBOL(s3c2410_gpio_pullup);
111
112void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
113{
114 void __iomem *base = S3C2410_GPIO_BASE(pin);
115 unsigned long offs = S3C2410_GPIO_OFFSET(pin);
116 unsigned long flags;
117 unsigned long dat;
118
119 local_irq_save(flags);
120
121 dat = __raw_readl(base + 0x04);
122 dat &= ~(1 << offs);
123 dat |= to << offs;
124 __raw_writel(dat, base + 0x04);
125
126 local_irq_restore(flags);
127}
128
129EXPORT_SYMBOL(s3c2410_gpio_setpin);
130
131unsigned int s3c2410_gpio_getpin(unsigned int pin)
132{
133 void __iomem *base = S3C2410_GPIO_BASE(pin);
134 unsigned long offs = S3C2410_GPIO_OFFSET(pin);
135
136 return __raw_readl(base + 0x04) & (1<< offs);
137}
138
139EXPORT_SYMBOL(s3c2410_gpio_getpin);
140
141unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change)
142{
143 unsigned long flags;
144 unsigned long misccr;
145
146 local_irq_save(flags);
147 misccr = __raw_readl(S3C2410_MISCCR);
148 misccr &= ~clear;
149 misccr ^= change;
150 __raw_writel(misccr, S3C2410_MISCCR);
151 local_irq_restore(flags);
152
153 return misccr;
154}
155
156EXPORT_SYMBOL(s3c2410_modify_misccr);
157
158int s3c2410_gpio_getirq(unsigned int pin)
159{
160 if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15_EINT23)
161 return -1; /* not valid interrupts */
162
163 if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7)
164 return -1; /* not valid pin */
165
166 if (pin < S3C2410_GPF4)
167 return (pin - S3C2410_GPF0) + IRQ_EINT0;
168
169 if (pin < S3C2410_GPG0)
170 return (pin - S3C2410_GPF4) + IRQ_EINT4;
171
172 return (pin - S3C2410_GPG0) + IRQ_EINT8;
173}
174
175EXPORT_SYMBOL(s3c2410_gpio_getirq);
176
177int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
178 unsigned int config)
179{
180 void __iomem *reg = S3C2410_EINFLT0;
181 unsigned long flags;
182 unsigned long val;
183
184 if (pin < S3C2410_GPG8 || pin > S3C2410_GPG15)
185 return -1;
186
187 config &= 0xff;
188
189 pin -= S3C2410_GPG8_EINT16;
190 reg += pin & ~3;
191
192 local_irq_save(flags);
193
194 /* update filter width and clock source */
195
196 val = __raw_readl(reg);
197 val &= ~(0xff << ((pin & 3) * 8));
198 val |= config << ((pin & 3) * 8);
199 __raw_writel(val, reg);
200
201 /* update filter enable */
202
203 val = __raw_readl(S3C2410_EXTINT2);
204 val &= ~(1 << ((pin * 4) + 3));
205 val |= on << ((pin * 4) + 3);
206 __raw_writel(val, S3C2410_EXTINT2);
207
208 local_irq_restore(flags);
209
210 return 0;
211}
212
213EXPORT_SYMBOL(s3c2410_gpio_irqfilter);
diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c
new file mode 100644
index 000000000000..b668c48f4399
--- /dev/null
+++ b/arch/arm/mach-s3c2410/irq.c
@@ -0,0 +1,966 @@
1/* linux/arch/arm/mach-s3c2410/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-2004 Ben Dooks
44 * Fixed edge-triggering on ADC IRQ
45*/
46
47#include <linux/init.h>
48#include <linux/module.h>
49#include <linux/interrupt.h>
50#include <linux/ioport.h>
51#include <linux/ptrace.h>
52#include <linux/sysdev.h>
53
54#include <asm/hardware.h>
55#include <asm/irq.h>
56#include <asm/io.h>
57
58#include <asm/mach/irq.h>
59
60#include <asm/arch/regs-irq.h>
61#include <asm/arch/regs-gpio.h>
62
63#include "cpu.h"
64#include "pm.h"
65
66#define irqdbf(x...)
67#define irqdbf2(x...)
68
69#define EXTINT_OFF (IRQ_EINT4 - 4)
70
71/* wakeup irq control */
72
73#ifdef CONFIG_PM
74
75/* state for IRQs over sleep */
76
77/* default is to allow for EINT0..EINT15, and IRQ_RTC as wakeup sources
78 *
79 * set bit to 1 in allow bitfield to enable the wakeup settings on it
80*/
81
82unsigned long s3c_irqwake_intallow = 1L << (IRQ_RTC - IRQ_EINT0) | 0xfL;
83unsigned long s3c_irqwake_intmask = 0xffffffffL;
84unsigned long s3c_irqwake_eintallow = 0x0000fff0L;
85unsigned long s3c_irqwake_eintmask = 0xffffffffL;
86
87static int
88s3c_irq_wake(unsigned int irqno, unsigned int state)
89{
90 unsigned long irqbit = 1 << (irqno - IRQ_EINT0);
91
92 if (!(s3c_irqwake_intallow & irqbit))
93 return -ENOENT;
94
95 printk(KERN_INFO "wake %s for irq %d\n",
96 state ? "enabled" : "disabled", irqno);
97
98 if (!state)
99 s3c_irqwake_intmask |= irqbit;
100 else
101 s3c_irqwake_intmask &= ~irqbit;
102
103 return 0;
104}
105
106static int
107s3c_irqext_wake(unsigned int irqno, unsigned int state)
108{
109 unsigned long bit = 1L << (irqno - EXTINT_OFF);
110
111 if (!(s3c_irqwake_eintallow & bit))
112 return -ENOENT;
113
114 printk(KERN_INFO "wake %s for irq %d\n",
115 state ? "enabled" : "disabled", irqno);
116
117 if (!state)
118 s3c_irqwake_eintmask |= bit;
119 else
120 s3c_irqwake_eintmask &= ~bit;
121
122 return 0;
123}
124
125#else
126#define s3c_irqext_wake NULL
127#define s3c_irq_wake NULL
128#endif
129
130
131static void
132s3c_irq_mask(unsigned int irqno)
133{
134 unsigned long mask;
135
136 irqno -= IRQ_EINT0;
137
138 mask = __raw_readl(S3C2410_INTMSK);
139 mask |= 1UL << irqno;
140 __raw_writel(mask, S3C2410_INTMSK);
141}
142
143static inline void
144s3c_irq_ack(unsigned int irqno)
145{
146 unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
147
148 __raw_writel(bitval, S3C2410_SRCPND);
149 __raw_writel(bitval, S3C2410_INTPND);
150}
151
152static inline void
153s3c_irq_maskack(unsigned int irqno)
154{
155 unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
156 unsigned long mask;
157
158 mask = __raw_readl(S3C2410_INTMSK);
159 __raw_writel(mask|bitval, S3C2410_INTMSK);
160
161 __raw_writel(bitval, S3C2410_SRCPND);
162 __raw_writel(bitval, S3C2410_INTPND);
163}
164
165
166static void
167s3c_irq_unmask(unsigned int irqno)
168{
169 unsigned long mask;
170
171 if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23)
172 irqdbf2("s3c_irq_unmask %d\n", irqno);
173
174 irqno -= IRQ_EINT0;
175
176 mask = __raw_readl(S3C2410_INTMSK);
177 mask &= ~(1UL << irqno);
178 __raw_writel(mask, S3C2410_INTMSK);
179}
180
181static struct irqchip s3c_irq_level_chip = {
182 .ack = s3c_irq_maskack,
183 .mask = s3c_irq_mask,
184 .unmask = s3c_irq_unmask,
185 .wake = s3c_irq_wake
186};
187
188static struct irqchip s3c_irq_chip = {
189 .ack = s3c_irq_ack,
190 .mask = s3c_irq_mask,
191 .unmask = s3c_irq_unmask,
192 .wake = s3c_irq_wake
193};
194
195/* S3C2410_EINTMASK
196 * S3C2410_EINTPEND
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(S3C2410_EINTMASK);
207 mask |= ( 1UL << irqno);
208 __raw_writel(mask, S3C2410_EINTMASK);
209
210 if (irqno <= (IRQ_EINT7 - EXTINT_OFF)) {
211 /* check to see if all need masking */
212
213 if ((mask & (0xf << 4)) == (0xf << 4)) {
214 /* all masked, mask the parent */
215 s3c_irq_mask(IRQ_EINT4t7);
216 }
217 } else {
218 /* todo: the same check as above for the rest of the irq regs...*/
219
220 }
221}
222
223static void
224s3c_irqext_ack(unsigned int irqno)
225{
226 unsigned long req;
227 unsigned long bit;
228 unsigned long mask;
229
230 bit = 1UL << (irqno - EXTINT_OFF);
231
232
233 mask = __raw_readl(S3C2410_EINTMASK);
234
235 __raw_writel(bit, S3C2410_EINTPEND);
236
237 req = __raw_readl(S3C2410_EINTPEND);
238 req &= ~mask;
239
240 /* not sure if we should be acking the parent irq... */
241
242 if (irqno <= IRQ_EINT7 ) {
243 if ((req & 0xf0) == 0)
244 s3c_irq_ack(IRQ_EINT4t7);
245 } else {
246 if ((req >> 8) == 0)
247 s3c_irq_ack(IRQ_EINT8t23);
248 }
249}
250
251static void
252s3c_irqext_unmask(unsigned int irqno)
253{
254 unsigned long mask;
255
256 irqno -= EXTINT_OFF;
257
258 mask = __raw_readl(S3C2410_EINTMASK);
259 mask &= ~( 1UL << irqno);
260 __raw_writel(mask, S3C2410_EINTMASK);
261
262 s3c_irq_unmask((irqno <= (IRQ_EINT7 - EXTINT_OFF)) ? IRQ_EINT4t7 : IRQ_EINT8t23);
263}
264
265static int
266s3c_irqext_type(unsigned int irq, unsigned int type)
267{
268 void __iomem *extint_reg;
269 void __iomem *gpcon_reg;
270 unsigned long gpcon_offset, extint_offset;
271 unsigned long newvalue = 0, value;
272
273 if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3))
274 {
275 gpcon_reg = S3C2410_GPFCON;
276 extint_reg = S3C2410_EXTINT0;
277 gpcon_offset = (irq - IRQ_EINT0) * 2;
278 extint_offset = (irq - IRQ_EINT0) * 4;
279 }
280 else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7))
281 {
282 gpcon_reg = S3C2410_GPFCON;
283 extint_reg = S3C2410_EXTINT0;
284 gpcon_offset = (irq - (EXTINT_OFF)) * 2;
285 extint_offset = (irq - (EXTINT_OFF)) * 4;
286 }
287 else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15))
288 {
289 gpcon_reg = S3C2410_GPGCON;
290 extint_reg = S3C2410_EXTINT1;
291 gpcon_offset = (irq - IRQ_EINT8) * 2;
292 extint_offset = (irq - IRQ_EINT8) * 4;
293 }
294 else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23))
295 {
296 gpcon_reg = S3C2410_GPGCON;
297 extint_reg = S3C2410_EXTINT2;
298 gpcon_offset = (irq - IRQ_EINT8) * 2;
299 extint_offset = (irq - IRQ_EINT16) * 4;
300 } else
301 return -1;
302
303 /* Set the GPIO to external interrupt mode */
304 value = __raw_readl(gpcon_reg);
305 value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset);
306 __raw_writel(value, gpcon_reg);
307
308 /* Set the external interrupt to pointed trigger type */
309 switch (type)
310 {
311 case IRQT_NOEDGE:
312 printk(KERN_WARNING "No edge setting!\n");
313 break;
314
315 case IRQT_RISING:
316 newvalue = S3C2410_EXTINT_RISEEDGE;
317 break;
318
319 case IRQT_FALLING:
320 newvalue = S3C2410_EXTINT_FALLEDGE;
321 break;
322
323 case IRQT_BOTHEDGE:
324 newvalue = S3C2410_EXTINT_BOTHEDGE;
325 break;
326
327 case IRQT_LOW:
328 newvalue = S3C2410_EXTINT_LOWLEV;
329 break;
330
331 case IRQT_HIGH:
332 newvalue = S3C2410_EXTINT_HILEV;
333 break;
334
335 default:
336 printk(KERN_ERR "No such irq type %d", type);
337 return -1;
338 }
339
340 value = __raw_readl(extint_reg);
341 value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset);
342 __raw_writel(value, extint_reg);
343
344 return 0;
345}
346
347static struct irqchip s3c_irqext_chip = {
348 .mask = s3c_irqext_mask,
349 .unmask = s3c_irqext_unmask,
350 .ack = s3c_irqext_ack,
351 .type = s3c_irqext_type,
352 .wake = s3c_irqext_wake
353};
354
355static struct irqchip s3c_irq_eint0t4 = {
356 .ack = s3c_irq_ack,
357 .mask = s3c_irq_mask,
358 .unmask = s3c_irq_unmask,
359 .wake = s3c_irq_wake,
360 .type = s3c_irqext_type,
361};
362
363/* mask values for the parent registers for each of the interrupt types */
364
365#define INTMSK_UART0 (1UL << (IRQ_UART0 - IRQ_EINT0))
366#define INTMSK_UART1 (1UL << (IRQ_UART1 - IRQ_EINT0))
367#define INTMSK_UART2 (1UL << (IRQ_UART2 - IRQ_EINT0))
368#define INTMSK_ADCPARENT (1UL << (IRQ_ADCPARENT - IRQ_EINT0))
369#define INTMSK_LCD (1UL << (IRQ_LCD - IRQ_EINT0))
370
371static inline void
372s3c_irqsub_mask(unsigned int irqno, unsigned int parentbit,
373 int subcheck)
374{
375 unsigned long mask;
376 unsigned long submask;
377
378 submask = __raw_readl(S3C2410_INTSUBMSK);
379 mask = __raw_readl(S3C2410_INTMSK);
380
381 submask |= (1UL << (irqno - IRQ_S3CUART_RX0));
382
383 /* check to see if we need to mask the parent IRQ */
384
385 if ((submask & subcheck) == subcheck) {
386 __raw_writel(mask | parentbit, S3C2410_INTMSK);
387 }
388
389 /* write back masks */
390 __raw_writel(submask, S3C2410_INTSUBMSK);
391
392}
393
394static inline void
395s3c_irqsub_unmask(unsigned int irqno, unsigned int parentbit)
396{
397 unsigned long mask;
398 unsigned long submask;
399
400 submask = __raw_readl(S3C2410_INTSUBMSK);
401 mask = __raw_readl(S3C2410_INTMSK);
402
403 submask &= ~(1UL << (irqno - IRQ_S3CUART_RX0));
404 mask &= ~parentbit;
405
406 /* write back masks */
407 __raw_writel(submask, S3C2410_INTSUBMSK);
408 __raw_writel(mask, S3C2410_INTMSK);
409}
410
411
412static inline void
413s3c_irqsub_maskack(unsigned int irqno, unsigned int parentmask, unsigned int group)
414{
415 unsigned int bit = 1UL << (irqno - IRQ_S3CUART_RX0);
416
417 s3c_irqsub_mask(irqno, parentmask, group);
418
419 __raw_writel(bit, S3C2410_SUBSRCPND);
420
421 /* only ack parent if we've got all the irqs (seems we must
422 * ack, all and hope that the irq system retriggers ok when
423 * the interrupt goes off again)
424 */
425
426 if (1) {
427 __raw_writel(parentmask, S3C2410_SRCPND);
428 __raw_writel(parentmask, S3C2410_INTPND);
429 }
430}
431
432static inline void
433s3c_irqsub_ack(unsigned int irqno, unsigned int parentmask, unsigned int group)
434{
435 unsigned int bit = 1UL << (irqno - IRQ_S3CUART_RX0);
436
437 __raw_writel(bit, S3C2410_SUBSRCPND);
438
439 /* only ack parent if we've got all the irqs (seems we must
440 * ack, all and hope that the irq system retriggers ok when
441 * the interrupt goes off again)
442 */
443
444 if (1) {
445 __raw_writel(parentmask, S3C2410_SRCPND);
446 __raw_writel(parentmask, S3C2410_INTPND);
447 }
448}
449
450/* UART0 */
451
452static void
453s3c_irq_uart0_mask(unsigned int irqno)
454{
455 s3c_irqsub_mask(irqno, INTMSK_UART0, 7);
456}
457
458static void
459s3c_irq_uart0_unmask(unsigned int irqno)
460{
461 s3c_irqsub_unmask(irqno, INTMSK_UART0);
462}
463
464static void
465s3c_irq_uart0_ack(unsigned int irqno)
466{
467 s3c_irqsub_maskack(irqno, INTMSK_UART0, 7);
468}
469
470static struct irqchip s3c_irq_uart0 = {
471 .mask = s3c_irq_uart0_mask,
472 .unmask = s3c_irq_uart0_unmask,
473 .ack = s3c_irq_uart0_ack,
474};
475
476/* UART1 */
477
478static void
479s3c_irq_uart1_mask(unsigned int irqno)
480{
481 s3c_irqsub_mask(irqno, INTMSK_UART1, 7 << 3);
482}
483
484static void
485s3c_irq_uart1_unmask(unsigned int irqno)
486{
487 s3c_irqsub_unmask(irqno, INTMSK_UART1);
488}
489
490static void
491s3c_irq_uart1_ack(unsigned int irqno)
492{
493 s3c_irqsub_maskack(irqno, INTMSK_UART1, 7 << 3);
494}
495
496static struct irqchip s3c_irq_uart1 = {
497 .mask = s3c_irq_uart1_mask,
498 .unmask = s3c_irq_uart1_unmask,
499 .ack = s3c_irq_uart1_ack,
500};
501
502/* UART2 */
503
504static void
505s3c_irq_uart2_mask(unsigned int irqno)
506{
507 s3c_irqsub_mask(irqno, INTMSK_UART2, 7 << 6);
508}
509
510static void
511s3c_irq_uart2_unmask(unsigned int irqno)
512{
513 s3c_irqsub_unmask(irqno, INTMSK_UART2);
514}
515
516static void
517s3c_irq_uart2_ack(unsigned int irqno)
518{
519 s3c_irqsub_maskack(irqno, INTMSK_UART2, 7 << 6);
520}
521
522static struct irqchip s3c_irq_uart2 = {
523 .mask = s3c_irq_uart2_mask,
524 .unmask = s3c_irq_uart2_unmask,
525 .ack = s3c_irq_uart2_ack,
526};
527
528/* ADC and Touchscreen */
529
530static void
531s3c_irq_adc_mask(unsigned int irqno)
532{
533 s3c_irqsub_mask(irqno, INTMSK_ADCPARENT, 3 << 9);
534}
535
536static void
537s3c_irq_adc_unmask(unsigned int irqno)
538{
539 s3c_irqsub_unmask(irqno, INTMSK_ADCPARENT);
540}
541
542static void
543s3c_irq_adc_ack(unsigned int irqno)
544{
545 s3c_irqsub_ack(irqno, INTMSK_ADCPARENT, 3 << 9);
546}
547
548static struct irqchip s3c_irq_adc = {
549 .mask = s3c_irq_adc_mask,
550 .unmask = s3c_irq_adc_unmask,
551 .ack = s3c_irq_adc_ack,
552};
553
554/* irq demux for adc */
555static void s3c_irq_demux_adc(unsigned int irq,
556 struct irqdesc *desc,
557 struct pt_regs *regs)
558{
559 unsigned int subsrc, submsk;
560 unsigned int offset = 9;
561 struct irqdesc *mydesc;
562
563 /* read the current pending interrupts, and the mask
564 * for what it is available */
565
566 subsrc = __raw_readl(S3C2410_SUBSRCPND);
567 submsk = __raw_readl(S3C2410_INTSUBMSK);
568
569 subsrc &= ~submsk;
570 subsrc >>= offset;
571 subsrc &= 3;
572
573 if (subsrc != 0) {
574 if (subsrc & 1) {
575 mydesc = irq_desc + IRQ_TC;
576 mydesc->handle( IRQ_TC, mydesc, regs);
577 }
578 if (subsrc & 2) {
579 mydesc = irq_desc + IRQ_ADC;
580 mydesc->handle(IRQ_ADC, mydesc, regs);
581 }
582 }
583}
584
585static void s3c_irq_demux_uart(unsigned int start,
586 struct pt_regs *regs)
587{
588 unsigned int subsrc, submsk;
589 unsigned int offset = start - IRQ_S3CUART_RX0;
590 struct irqdesc *desc;
591
592 /* read the current pending interrupts, and the mask
593 * for what it is available */
594
595 subsrc = __raw_readl(S3C2410_SUBSRCPND);
596 submsk = __raw_readl(S3C2410_INTSUBMSK);
597
598 irqdbf2("s3c_irq_demux_uart: start=%d (%d), subsrc=0x%08x,0x%08x\n",
599 start, offset, subsrc, submsk);
600
601 subsrc &= ~submsk;
602 subsrc >>= offset;
603 subsrc &= 7;
604
605 if (subsrc != 0) {
606 desc = irq_desc + start;
607
608 if (subsrc & 1)
609 desc->handle(start, desc, regs);
610
611 desc++;
612
613 if (subsrc & 2)
614 desc->handle(start+1, desc, regs);
615
616 desc++;
617
618 if (subsrc & 4)
619 desc->handle(start+2, desc, regs);
620 }
621}
622
623/* uart demux entry points */
624
625static void
626s3c_irq_demux_uart0(unsigned int irq,
627 struct irqdesc *desc,
628 struct pt_regs *regs)
629{
630 irq = irq;
631 s3c_irq_demux_uart(IRQ_S3CUART_RX0, regs);
632}
633
634static void
635s3c_irq_demux_uart1(unsigned int irq,
636 struct irqdesc *desc,
637 struct pt_regs *regs)
638{
639 irq = irq;
640 s3c_irq_demux_uart(IRQ_S3CUART_RX1, regs);
641}
642
643static void
644s3c_irq_demux_uart2(unsigned int irq,
645 struct irqdesc *desc,
646 struct pt_regs *regs)
647{
648 irq = irq;
649 s3c_irq_demux_uart(IRQ_S3CUART_RX2, regs);
650}
651
652
653/* s3c24xx_init_irq
654 *
655 * Initialise S3C2410 IRQ system
656*/
657
658void __init s3c24xx_init_irq(void)
659{
660 unsigned long pend;
661 unsigned long last;
662 int irqno;
663 int i;
664
665 irqdbf("s3c2410_init_irq: clearing interrupt status flags\n");
666
667 /* first, clear all interrupts pending... */
668
669 last = 0;
670 for (i = 0; i < 4; i++) {
671 pend = __raw_readl(S3C2410_EINTPEND);
672
673 if (pend == 0 || pend == last)
674 break;
675
676 __raw_writel(pend, S3C2410_EINTPEND);
677 printk("irq: clearing pending ext status %08x\n", (int)pend);
678 last = pend;
679 }
680
681 last = 0;
682 for (i = 0; i < 4; i++) {
683 pend = __raw_readl(S3C2410_INTPND);
684
685 if (pend == 0 || pend == last)
686 break;
687
688 __raw_writel(pend, S3C2410_SRCPND);
689 __raw_writel(pend, S3C2410_INTPND);
690 printk("irq: clearing pending status %08x\n", (int)pend);
691 last = pend;
692 }
693
694 last = 0;
695 for (i = 0; i < 4; i++) {
696 pend = __raw_readl(S3C2410_SUBSRCPND);
697
698 if (pend == 0 || pend == last)
699 break;
700
701 printk("irq: clearing subpending status %08x\n", (int)pend);
702 __raw_writel(pend, S3C2410_SUBSRCPND);
703 last = pend;
704 }
705
706 /* register the main interrupts */
707
708 irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n");
709
710 for (irqno = IRQ_BATT_FLT; irqno <= IRQ_ADCPARENT; irqno++) {
711 /* set all the s3c2410 internal irqs */
712
713 switch (irqno) {
714 /* deal with the special IRQs (cascaded) */
715
716 case IRQ_UART0:
717 case IRQ_UART1:
718 case IRQ_UART2:
719 case IRQ_LCD:
720 case IRQ_ADCPARENT:
721 set_irq_chip(irqno, &s3c_irq_level_chip);
722 set_irq_handler(irqno, do_level_IRQ);
723 break;
724
725 case IRQ_RESERVED6:
726 case IRQ_RESERVED24:
727 /* no IRQ here */
728 break;
729
730 default:
731 //irqdbf("registering irq %d (s3c irq)\n", irqno);
732 set_irq_chip(irqno, &s3c_irq_chip);
733 set_irq_handler(irqno, do_edge_IRQ);
734 set_irq_flags(irqno, IRQF_VALID);
735 }
736 }
737
738 /* setup the cascade irq handlers */
739
740 set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
741 set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);
742 set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2);
743 set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc);
744
745
746 /* external interrupts */
747
748 for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
749 irqdbf("registering irq %d (ext int)\n", irqno);
750 set_irq_chip(irqno, &s3c_irq_eint0t4);
751 set_irq_handler(irqno, do_edge_IRQ);
752 set_irq_flags(irqno, IRQF_VALID);
753 }
754
755 for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {
756 irqdbf("registering irq %d (extended s3c irq)\n", irqno);
757 set_irq_chip(irqno, &s3c_irqext_chip);
758 set_irq_handler(irqno, do_edge_IRQ);
759 set_irq_flags(irqno, IRQF_VALID);
760 }
761
762 /* register the uart interrupts */
763
764 irqdbf("s3c2410: registering external interrupts\n");
765
766 for (irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) {
767 irqdbf("registering irq %d (s3c uart0 irq)\n", irqno);
768 set_irq_chip(irqno, &s3c_irq_uart0);
769 set_irq_handler(irqno, do_level_IRQ);
770 set_irq_flags(irqno, IRQF_VALID);
771 }
772
773 for (irqno = IRQ_S3CUART_RX1; irqno <= IRQ_S3CUART_ERR1; irqno++) {
774 irqdbf("registering irq %d (s3c uart1 irq)\n", irqno);
775 set_irq_chip(irqno, &s3c_irq_uart1);
776 set_irq_handler(irqno, do_level_IRQ);
777 set_irq_flags(irqno, IRQF_VALID);
778 }
779
780 for (irqno = IRQ_S3CUART_RX2; irqno <= IRQ_S3CUART_ERR2; irqno++) {
781 irqdbf("registering irq %d (s3c uart2 irq)\n", irqno);
782 set_irq_chip(irqno, &s3c_irq_uart2);
783 set_irq_handler(irqno, do_level_IRQ);
784 set_irq_flags(irqno, IRQF_VALID);
785 }
786
787 for (irqno = IRQ_TC; irqno <= IRQ_ADC; irqno++) {
788 irqdbf("registering irq %d (s3c adc irq)\n", irqno);
789 set_irq_chip(irqno, &s3c_irq_adc);
790 set_irq_handler(irqno, do_edge_IRQ);
791 set_irq_flags(irqno, IRQF_VALID);
792 }
793
794 irqdbf("s3c2410: registered interrupt handlers\n");
795}
796
797/* s3c2440 irq code
798*/
799
800#ifdef CONFIG_CPU_S3C2440
801
802/* WDT/AC97 */
803
804static void s3c_irq_demux_wdtac97(unsigned int irq,
805 struct irqdesc *desc,
806 struct pt_regs *regs)
807{
808 unsigned int subsrc, submsk;
809 struct irqdesc *mydesc;
810
811 /* read the current pending interrupts, and the mask
812 * for what it is available */
813
814 subsrc = __raw_readl(S3C2410_SUBSRCPND);
815 submsk = __raw_readl(S3C2410_INTSUBMSK);
816
817 subsrc &= ~submsk;
818 subsrc >>= 13;
819 subsrc &= 3;
820
821 if (subsrc != 0) {
822 if (subsrc & 1) {
823 mydesc = irq_desc + IRQ_S3C2440_WDT;
824 mydesc->handle( IRQ_S3C2440_WDT, mydesc, regs);
825 }
826 if (subsrc & 2) {
827 mydesc = irq_desc + IRQ_S3C2440_AC97;
828 mydesc->handle(IRQ_S3C2440_AC97, mydesc, regs);
829 }
830 }
831}
832
833
834#define INTMSK_WDT (1UL << (IRQ_WDT - IRQ_EINT0))
835
836static void
837s3c_irq_wdtac97_mask(unsigned int irqno)
838{
839 s3c_irqsub_mask(irqno, INTMSK_WDT, 3<<13);
840}
841
842static void
843s3c_irq_wdtac97_unmask(unsigned int irqno)
844{
845 s3c_irqsub_unmask(irqno, INTMSK_WDT);
846}
847
848static void
849s3c_irq_wdtac97_ack(unsigned int irqno)
850{
851 s3c_irqsub_maskack(irqno, INTMSK_WDT, 3<<13);
852}
853
854static struct irqchip s3c_irq_wdtac97 = {
855 .mask = s3c_irq_wdtac97_mask,
856 .unmask = s3c_irq_wdtac97_unmask,
857 .ack = s3c_irq_wdtac97_ack,
858};
859
860/* camera irq */
861
862static void s3c_irq_demux_cam(unsigned int irq,
863 struct irqdesc *desc,
864 struct pt_regs *regs)
865{
866 unsigned int subsrc, submsk;
867 struct irqdesc *mydesc;
868
869 /* read the current pending interrupts, and the mask
870 * for what it is available */
871
872 subsrc = __raw_readl(S3C2410_SUBSRCPND);
873 submsk = __raw_readl(S3C2410_INTSUBMSK);
874
875 subsrc &= ~submsk;
876 subsrc >>= 11;
877 subsrc &= 3;
878
879 if (subsrc != 0) {
880 if (subsrc & 1) {
881 mydesc = irq_desc + IRQ_S3C2440_CAM_C;
882 mydesc->handle( IRQ_S3C2440_WDT, mydesc, regs);
883 }
884 if (subsrc & 2) {
885 mydesc = irq_desc + IRQ_S3C2440_CAM_P;
886 mydesc->handle(IRQ_S3C2440_AC97, mydesc, regs);
887 }
888 }
889}
890
891#define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0))
892
893static void
894s3c_irq_cam_mask(unsigned int irqno)
895{
896 s3c_irqsub_mask(irqno, INTMSK_CAM, 3<<11);
897}
898
899static void
900s3c_irq_cam_unmask(unsigned int irqno)
901{
902 s3c_irqsub_unmask(irqno, INTMSK_CAM);
903}
904
905static void
906s3c_irq_cam_ack(unsigned int irqno)
907{
908 s3c_irqsub_maskack(irqno, INTMSK_CAM, 3<<11);
909}
910
911static struct irqchip s3c_irq_cam = {
912 .mask = s3c_irq_cam_mask,
913 .unmask = s3c_irq_cam_unmask,
914 .ack = s3c_irq_cam_ack,
915};
916
917static int s3c2440_irq_add(struct sys_device *sysdev)
918{
919 unsigned int irqno;
920
921 printk("S3C2440: IRQ Support\n");
922
923 set_irq_chip(IRQ_NFCON, &s3c_irq_level_chip);
924 set_irq_handler(IRQ_NFCON, do_level_IRQ);
925 set_irq_flags(IRQ_NFCON, IRQF_VALID);
926
927 /* add new chained handler for wdt, ac7 */
928
929 set_irq_chip(IRQ_WDT, &s3c_irq_level_chip);
930 set_irq_handler(IRQ_WDT, do_level_IRQ);
931 set_irq_chained_handler(IRQ_WDT, s3c_irq_demux_wdtac97);
932
933 for (irqno = IRQ_S3C2440_WDT; irqno <= IRQ_S3C2440_AC97; irqno++) {
934 set_irq_chip(irqno, &s3c_irq_wdtac97);
935 set_irq_handler(irqno, do_level_IRQ);
936 set_irq_flags(irqno, IRQF_VALID);
937 }
938
939 /* add chained handler for camera */
940
941 set_irq_chip(IRQ_CAM, &s3c_irq_level_chip);
942 set_irq_handler(IRQ_CAM, do_level_IRQ);
943 set_irq_chained_handler(IRQ_CAM, s3c_irq_demux_cam);
944
945 for (irqno = IRQ_S3C2440_CAM_C; irqno <= IRQ_S3C2440_CAM_P; irqno++) {
946 set_irq_chip(irqno, &s3c_irq_cam);
947 set_irq_handler(irqno, do_level_IRQ);
948 set_irq_flags(irqno, IRQF_VALID);
949 }
950
951 return 0;
952}
953
954static struct sysdev_driver s3c2440_irq_driver = {
955 .add = s3c2440_irq_add,
956};
957
958static int s3c24xx_irq_driver(void)
959{
960 return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_irq_driver);
961}
962
963arch_initcall(s3c24xx_irq_driver);
964
965#endif /* CONFIG_CPU_S3C2440 */
966
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c
new file mode 100644
index 000000000000..3bb97eb6e693
--- /dev/null
+++ b/arch/arm/mach-s3c2410/mach-bast.c
@@ -0,0 +1,409 @@
1/* linux/arch/arm/mach-s3c2410/mach-bast.c
2 *
3 * Copyright (c) 2003-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * http://www.simtec.co.uk/products/EB2410ITX/
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 version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Modifications:
13 * 14-Sep-2004 BJD USB power control
14 * 20-Aug-2004 BJD Added s3c2410_board struct
15 * 18-Aug-2004 BJD Added platform devices from default set
16 * 16-May-2003 BJD Created initial version
17 * 16-Aug-2003 BJD Fixed header files and copyright, added URL
18 * 05-Sep-2003 BJD Moved to v2.6 kernel
19 * 06-Jan-2003 BJD Updates for <arch/map.h>
20 * 18-Jan-2003 BJD Added serial port configuration
21 * 05-Oct-2004 BJD Power management code
22 * 04-Nov-2004 BJD Updated serial port clocks
23 * 04-Jan-2005 BJD New uart init call
24 * 10-Jan-2005 BJD Removed include of s3c2410.h
25 * 14-Jan-2005 BJD Add support for muitlple NAND devices
26 * 03-Mar-2005 BJD Ensured that bast-cpld.h is included
27 * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
28 * 14-Mar-2006 BJD Updated for __iomem changes
29*/
30
31#include <linux/kernel.h>
32#include <linux/types.h>
33#include <linux/interrupt.h>
34#include <linux/list.h>
35#include <linux/timer.h>
36#include <linux/init.h>
37#include <linux/device.h>
38
39#include <asm/mach/arch.h>
40#include <asm/mach/map.h>
41#include <asm/mach/irq.h>
42
43#include <asm/arch/bast-map.h>
44#include <asm/arch/bast-irq.h>
45#include <asm/arch/bast-cpld.h>
46
47#include <asm/hardware.h>
48#include <asm/io.h>
49#include <asm/irq.h>
50#include <asm/mach-types.h>
51
52//#include <asm/debug-ll.h>
53#include <asm/arch/regs-serial.h>
54#include <asm/arch/regs-gpio.h>
55#include <asm/arch/regs-mem.h>
56#include <asm/arch/nand.h>
57
58#include <linux/mtd/mtd.h>
59#include <linux/mtd/nand.h>
60#include <linux/mtd/nand_ecc.h>
61#include <linux/mtd/partitions.h>
62
63#include "clock.h"
64#include "devs.h"
65#include "cpu.h"
66#include "usb-simtec.h"
67#include "pm.h"
68
69#define COPYRIGHT ", (c) 2004-2005 Simtec Electronics"
70
71/* macros for virtual address mods for the io space entries */
72#define VA_C5(item) ((unsigned long)(item) + BAST_VAM_CS5)
73#define VA_C4(item) ((unsigned long)(item) + BAST_VAM_CS4)
74#define VA_C3(item) ((unsigned long)(item) + BAST_VAM_CS3)
75#define VA_C2(item) ((unsigned long)(item) + BAST_VAM_CS2)
76
77/* macros to modify the physical addresses for io space */
78
79#define PA_CS2(item) ((item) + S3C2410_CS2)
80#define PA_CS3(item) ((item) + S3C2410_CS3)
81#define PA_CS4(item) ((item) + S3C2410_CS4)
82#define PA_CS5(item) ((item) + S3C2410_CS5)
83
84static struct map_desc bast_iodesc[] __initdata = {
85 /* ISA IO areas */
86
87 { (u32)S3C24XX_VA_ISA_BYTE, PA_CS2(BAST_PA_ISAIO), SZ_16M, MT_DEVICE },
88 { (u32)S3C24XX_VA_ISA_WORD, PA_CS3(BAST_PA_ISAIO), SZ_16M, MT_DEVICE },
89
90 /* we could possibly compress the next set down into a set of smaller tables
91 * pagetables, but that would mean using an L2 section, and it still means
92 * we cannot actually feed the same register to an LDR due to 16K spacing
93 */
94
95 /* bast CPLD control registers, and external interrupt controls */
96 { (u32)BAST_VA_CTRL1, BAST_PA_CTRL1, SZ_1M, MT_DEVICE },
97 { (u32)BAST_VA_CTRL2, BAST_PA_CTRL2, SZ_1M, MT_DEVICE },
98 { (u32)BAST_VA_CTRL3, BAST_PA_CTRL3, SZ_1M, MT_DEVICE },
99 { (u32)BAST_VA_CTRL4, BAST_PA_CTRL4, SZ_1M, MT_DEVICE },
100
101 /* PC104 IRQ mux */
102 { (u32)BAST_VA_PC104_IRQREQ, BAST_PA_PC104_IRQREQ, SZ_1M, MT_DEVICE },
103 { (u32)BAST_VA_PC104_IRQRAW, BAST_PA_PC104_IRQRAW, SZ_1M, MT_DEVICE },
104 { (u32)BAST_VA_PC104_IRQMASK, BAST_PA_PC104_IRQMASK, SZ_1M, MT_DEVICE },
105
106 /* peripheral space... one for each of fast/slow/byte/16bit */
107 /* note, ide is only decoded in word space, even though some registers
108 * are only 8bit */
109
110 /* slow, byte */
111 { VA_C2(BAST_VA_ISAIO), PA_CS2(BAST_PA_ISAIO), SZ_16M, MT_DEVICE },
112 { VA_C2(BAST_VA_ISAMEM), PA_CS2(BAST_PA_ISAMEM), SZ_16M, MT_DEVICE },
113 { VA_C2(BAST_VA_ASIXNET), PA_CS3(BAST_PA_ASIXNET), SZ_1M, MT_DEVICE },
114 { VA_C2(BAST_VA_SUPERIO), PA_CS2(BAST_PA_SUPERIO), SZ_1M, MT_DEVICE },
115 { VA_C2(BAST_VA_DM9000), PA_CS2(BAST_PA_DM9000), SZ_1M, MT_DEVICE },
116 { VA_C2(BAST_VA_IDEPRI), PA_CS3(BAST_PA_IDEPRI), SZ_1M, MT_DEVICE },
117 { VA_C2(BAST_VA_IDESEC), PA_CS3(BAST_PA_IDESEC), SZ_1M, MT_DEVICE },
118 { VA_C2(BAST_VA_IDEPRIAUX), PA_CS3(BAST_PA_IDEPRIAUX), SZ_1M, MT_DEVICE },
119 { VA_C2(BAST_VA_IDESECAUX), PA_CS3(BAST_PA_IDESECAUX), SZ_1M, MT_DEVICE },
120
121 /* slow, word */
122 { VA_C3(BAST_VA_ISAIO), PA_CS3(BAST_PA_ISAIO), SZ_16M, MT_DEVICE },
123 { VA_C3(BAST_VA_ISAMEM), PA_CS3(BAST_PA_ISAMEM), SZ_16M, MT_DEVICE },
124 { VA_C3(BAST_VA_ASIXNET), PA_CS3(BAST_PA_ASIXNET), SZ_1M, MT_DEVICE },
125 { VA_C3(BAST_VA_SUPERIO), PA_CS3(BAST_PA_SUPERIO), SZ_1M, MT_DEVICE },
126 { VA_C3(BAST_VA_DM9000), PA_CS3(BAST_PA_DM9000), SZ_1M, MT_DEVICE },
127 { VA_C3(BAST_VA_IDEPRI), PA_CS3(BAST_PA_IDEPRI), SZ_1M, MT_DEVICE },
128 { VA_C3(BAST_VA_IDESEC), PA_CS3(BAST_PA_IDESEC), SZ_1M, MT_DEVICE },
129 { VA_C3(BAST_VA_IDEPRIAUX), PA_CS3(BAST_PA_IDEPRIAUX), SZ_1M, MT_DEVICE },
130 { VA_C3(BAST_VA_IDESECAUX), PA_CS3(BAST_PA_IDESECAUX), SZ_1M, MT_DEVICE },
131
132 /* fast, byte */
133 { VA_C4(BAST_VA_ISAIO), PA_CS4(BAST_PA_ISAIO), SZ_16M, MT_DEVICE },
134 { VA_C4(BAST_VA_ISAMEM), PA_CS4(BAST_PA_ISAMEM), SZ_16M, MT_DEVICE },
135 { VA_C4(BAST_VA_ASIXNET), PA_CS5(BAST_PA_ASIXNET), SZ_1M, MT_DEVICE },
136 { VA_C4(BAST_VA_SUPERIO), PA_CS4(BAST_PA_SUPERIO), SZ_1M, MT_DEVICE },
137 { VA_C4(BAST_VA_DM9000), PA_CS4(BAST_PA_DM9000), SZ_1M, MT_DEVICE },
138 { VA_C4(BAST_VA_IDEPRI), PA_CS5(BAST_PA_IDEPRI), SZ_1M, MT_DEVICE },
139 { VA_C4(BAST_VA_IDESEC), PA_CS5(BAST_PA_IDESEC), SZ_1M, MT_DEVICE },
140 { VA_C4(BAST_VA_IDEPRIAUX), PA_CS5(BAST_PA_IDEPRIAUX), SZ_1M, MT_DEVICE },
141 { VA_C4(BAST_VA_IDESECAUX), PA_CS5(BAST_PA_IDESECAUX), SZ_1M, MT_DEVICE },
142
143 /* fast, word */
144 { VA_C5(BAST_VA_ISAIO), PA_CS5(BAST_PA_ISAIO), SZ_16M, MT_DEVICE },
145 { VA_C5(BAST_VA_ISAMEM), PA_CS5(BAST_PA_ISAMEM), SZ_16M, MT_DEVICE },
146 { VA_C5(BAST_VA_ASIXNET), PA_CS5(BAST_PA_ASIXNET), SZ_1M, MT_DEVICE },
147 { VA_C5(BAST_VA_SUPERIO), PA_CS5(BAST_PA_SUPERIO), SZ_1M, MT_DEVICE },
148 { VA_C5(BAST_VA_DM9000), PA_CS5(BAST_PA_DM9000), SZ_1M, MT_DEVICE },
149 { VA_C5(BAST_VA_IDEPRI), PA_CS5(BAST_PA_IDEPRI), SZ_1M, MT_DEVICE },
150 { VA_C5(BAST_VA_IDESEC), PA_CS5(BAST_PA_IDESEC), SZ_1M, MT_DEVICE },
151 { VA_C5(BAST_VA_IDEPRIAUX), PA_CS5(BAST_PA_IDEPRIAUX), SZ_1M, MT_DEVICE },
152 { VA_C5(BAST_VA_IDESECAUX), PA_CS5(BAST_PA_IDESECAUX), SZ_1M, MT_DEVICE },
153};
154
155#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
156#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
157#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
158
159static struct s3c24xx_uart_clksrc bast_serial_clocks[] = {
160 [0] = {
161 .name = "uclk",
162 .divisor = 1,
163 .min_baud = 0,
164 .max_baud = 0,
165 },
166 [1] = {
167 .name = "pclk",
168 .divisor = 1,
169 .min_baud = 0,
170 .max_baud = 0.
171 }
172};
173
174
175static struct s3c2410_uartcfg bast_uartcfgs[] = {
176 [0] = {
177 .hwport = 0,
178 .flags = 0,
179 .ucon = UCON,
180 .ulcon = ULCON,
181 .ufcon = UFCON,
182 .clocks = bast_serial_clocks,
183 .clocks_size = ARRAY_SIZE(bast_serial_clocks)
184 },
185 [1] = {
186 .hwport = 1,
187 .flags = 0,
188 .ucon = UCON,
189 .ulcon = ULCON,
190 .ufcon = UFCON,
191 .clocks = bast_serial_clocks,
192 .clocks_size = ARRAY_SIZE(bast_serial_clocks)
193 },
194 /* port 2 is not actually used */
195 [2] = {
196 .hwport = 2,
197 .flags = 0,
198 .ucon = UCON,
199 .ulcon = ULCON,
200 .ufcon = UFCON,
201 .clocks = bast_serial_clocks,
202 .clocks_size = ARRAY_SIZE(bast_serial_clocks)
203 }
204};
205
206/* NOR Flash on BAST board */
207
208static struct resource bast_nor_resource[] = {
209 [0] = {
210 .start = S3C2410_CS1 + 0x4000000,
211 .end = S3C2410_CS1 + 0x4000000 + (32*1024*1024) - 1,
212 .flags = IORESOURCE_MEM,
213 }
214};
215
216static struct platform_device bast_device_nor = {
217 .name = "bast-nor",
218 .id = -1,
219 .num_resources = ARRAY_SIZE(bast_nor_resource),
220 .resource = bast_nor_resource,
221};
222
223/* NAND Flash on BAST board */
224
225
226static int smartmedia_map[] = { 0 };
227static int chip0_map[] = { 1 };
228static int chip1_map[] = { 2 };
229static int chip2_map[] = { 3 };
230
231struct mtd_partition bast_default_nand_part[] = {
232 [0] = {
233 .name = "Boot Agent",
234 .size = SZ_16K,
235 .offset = 0
236 },
237 [1] = {
238 .name = "/boot",
239 .size = SZ_4M - SZ_16K,
240 .offset = SZ_16K,
241 },
242 [2] = {
243 .name = "user",
244 .offset = SZ_4M,
245 .size = MTDPART_SIZ_FULL,
246 }
247};
248
249/* the bast has 4 selectable slots for nand-flash, the three
250 * on-board chip areas, as well as the external SmartMedia
251 * slot.
252 *
253 * Note, there is no current hot-plug support for the SmartMedia
254 * socket.
255*/
256
257static struct s3c2410_nand_set bast_nand_sets[] = {
258 [0] = {
259 .name = "SmartMedia",
260 .nr_chips = 1,
261 .nr_map = smartmedia_map,
262 .nr_partitions = ARRAY_SIZE(bast_default_nand_part),
263 .partitions = bast_default_nand_part
264 },
265 [1] = {
266 .name = "chip0",
267 .nr_chips = 1,
268 .nr_map = chip0_map,
269 .nr_partitions = ARRAY_SIZE(bast_default_nand_part),
270 .partitions = bast_default_nand_part
271 },
272 [2] = {
273 .name = "chip1",
274 .nr_chips = 1,
275 .nr_map = chip1_map,
276 .nr_partitions = ARRAY_SIZE(bast_default_nand_part),
277 .partitions = bast_default_nand_part
278 },
279 [3] = {
280 .name = "chip2",
281 .nr_chips = 1,
282 .nr_map = chip2_map,
283 .nr_partitions = ARRAY_SIZE(bast_default_nand_part),
284 .partitions = bast_default_nand_part
285 }
286};
287
288static void bast_nand_select(struct s3c2410_nand_set *set, int slot)
289{
290 unsigned int tmp;
291
292 slot = set->nr_map[slot] & 3;
293
294 pr_debug("bast_nand: selecting slot %d (set %p,%p)\n",
295 slot, set, set->nr_map);
296
297 tmp = __raw_readb(BAST_VA_CTRL2);
298 tmp &= BAST_CPLD_CTLR2_IDERST;
299 tmp |= slot;
300 tmp |= BAST_CPLD_CTRL2_WNAND;
301
302 pr_debug("bast_nand: ctrl2 now %02x\n", tmp);
303
304 __raw_writeb(tmp, BAST_VA_CTRL2);
305}
306
307static struct s3c2410_platform_nand bast_nand_info = {
308 .tacls = 80,
309 .twrph0 = 80,
310 .twrph1 = 80,
311 .nr_sets = ARRAY_SIZE(bast_nand_sets),
312 .sets = bast_nand_sets,
313 .select_chip = bast_nand_select,
314};
315
316
317/* Standard BAST devices */
318
319static struct platform_device *bast_devices[] __initdata = {
320 &s3c_device_usb,
321 &s3c_device_lcd,
322 &s3c_device_wdt,
323 &s3c_device_i2c,
324 &s3c_device_iis,
325 &s3c_device_rtc,
326 &s3c_device_nand,
327 &bast_device_nor
328};
329
330static struct clk *bast_clocks[] = {
331 &s3c24xx_dclk0,
332 &s3c24xx_dclk1,
333 &s3c24xx_clkout0,
334 &s3c24xx_clkout1,
335 &s3c24xx_uclk,
336};
337
338static struct s3c24xx_board bast_board __initdata = {
339 .devices = bast_devices,
340 .devices_count = ARRAY_SIZE(bast_devices),
341 .clocks = bast_clocks,
342 .clocks_count = ARRAY_SIZE(bast_clocks)
343};
344
345void __init bast_map_io(void)
346{
347 /* initialise the clocks */
348
349 s3c24xx_dclk0.parent = NULL;
350 s3c24xx_dclk0.rate = 12*1000*1000;
351
352 s3c24xx_dclk1.parent = NULL;
353 s3c24xx_dclk1.rate = 24*1000*1000;
354
355 s3c24xx_clkout0.parent = &s3c24xx_dclk0;
356 s3c24xx_clkout1.parent = &s3c24xx_dclk1;
357
358 s3c24xx_uclk.parent = &s3c24xx_clkout1;
359
360 s3c_device_nand.dev.platform_data = &bast_nand_info;
361
362 s3c24xx_init_io(bast_iodesc, ARRAY_SIZE(bast_iodesc));
363 s3c24xx_init_clocks(0);
364 s3c24xx_init_uarts(bast_uartcfgs, ARRAY_SIZE(bast_uartcfgs));
365 s3c24xx_set_board(&bast_board);
366 usb_simtec_init();
367}
368
369void __init bast_init_irq(void)
370{
371 s3c24xx_init_irq();
372}
373
374#ifdef CONFIG_PM
375
376/* bast_init_machine
377 *
378 * enable the power management functions for the EB2410ITX
379*/
380
381static __init void bast_init_machine(void)
382{
383 unsigned long gstatus4;
384
385 printk(KERN_INFO "BAST Power Manangement" COPYRIGHT "\n");
386
387 gstatus4 = (__raw_readl(S3C2410_BANKCON7) & 0x3) << 30;
388 gstatus4 |= (__raw_readl(S3C2410_BANKCON6) & 0x3) << 28;
389 gstatus4 |= (__raw_readl(S3C2410_BANKSIZE) & S3C2410_BANKSIZE_MASK);
390
391 __raw_writel(gstatus4, S3C2410_GSTATUS4);
392
393 s3c2410_pm_init();
394}
395
396#else
397#define bast_init_machine NULL
398#endif
399
400
401MACHINE_START(BAST, "Simtec-BAST")
402 MAINTAINER("Ben Dooks <ben@simtec.co.uk>")
403 BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
404 BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
405 MAPIO(bast_map_io)
406 INITIRQ(bast_init_irq)
407 .init_machine = bast_init_machine,
408 .timer = &s3c24xx_timer,
409MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c
new file mode 100644
index 000000000000..2924afc068a4
--- /dev/null
+++ b/arch/arm/mach-s3c2410/mach-h1940.c
@@ -0,0 +1,126 @@
1/* linux/arch/arm/mach-s3c2410/mach-h1940.c
2 *
3 * Copyright (c) 2003-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * http://www.handhelds.org/projects/h1940.html
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 version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Modifications:
13 * 16-May-2003 BJD Created initial version
14 * 16-Aug-2003 BJD Fixed header files and copyright, added URL
15 * 05-Sep-2003 BJD Moved to v2.6 kernel
16 * 06-Jan-2003 BJD Updates for <arch/map.h>
17 * 18-Jan-2003 BJD Added serial port configuration
18 * 17-Feb-2003 BJD Copied to mach-ipaq.c
19 * 21-Aug-2004 BJD Added struct s3c2410_board
20 * 04-Sep-2004 BJD Changed uart init, renamed ipaq_ -> h1940_
21 * 18-Oct-2004 BJD Updated new board structure name
22 * 04-Nov-2004 BJD Change for new serial clock
23 * 04-Jan-2005 BJD Updated uart init call
24 * 10-Jan-2005 BJD Removed include of s3c2410.h
25 * 14-Jan-2005 BJD Added clock init
26 * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
27*/
28
29#include <linux/kernel.h>
30#include <linux/types.h>
31#include <linux/interrupt.h>
32#include <linux/list.h>
33#include <linux/timer.h>
34#include <linux/init.h>
35
36#include <asm/mach/arch.h>
37#include <asm/mach/map.h>
38#include <asm/mach/irq.h>
39
40#include <asm/hardware.h>
41#include <asm/hardware/iomd.h>
42#include <asm/io.h>
43#include <asm/irq.h>
44#include <asm/mach-types.h>
45
46//#include <asm/debug-ll.h>
47#include <asm/arch/regs-serial.h>
48
49#include <linux/serial_core.h>
50
51#include "clock.h"
52#include "devs.h"
53#include "cpu.h"
54
55static struct map_desc h1940_iodesc[] __initdata = {
56 /* nothing here yet */
57};
58
59#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
60#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
61#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
62
63static struct s3c2410_uartcfg h1940_uartcfgs[] = {
64 [0] = {
65 .hwport = 0,
66 .flags = 0,
67 .ucon = 0x3c5,
68 .ulcon = 0x03,
69 .ufcon = 0x51,
70 },
71 [1] = {
72 .hwport = 1,
73 .flags = 0,
74 .ucon = 0x245,
75 .ulcon = 0x03,
76 .ufcon = 0x00,
77 },
78 /* IR port */
79 [2] = {
80 .hwport = 2,
81 .flags = 0,
82 .uart_flags = UPF_CONS_FLOW,
83 .ucon = 0x3c5,
84 .ulcon = 0x43,
85 .ufcon = 0x51,
86 }
87};
88
89
90
91
92static struct platform_device *h1940_devices[] __initdata = {
93 &s3c_device_usb,
94 &s3c_device_lcd,
95 &s3c_device_wdt,
96 &s3c_device_i2c,
97 &s3c_device_iis,
98};
99
100static struct s3c24xx_board h1940_board __initdata = {
101 .devices = h1940_devices,
102 .devices_count = ARRAY_SIZE(h1940_devices)
103};
104
105void __init h1940_map_io(void)
106{
107 s3c24xx_init_io(h1940_iodesc, ARRAY_SIZE(h1940_iodesc));
108 s3c24xx_init_clocks(0);
109 s3c24xx_init_uarts(h1940_uartcfgs, ARRAY_SIZE(h1940_uartcfgs));
110 s3c24xx_set_board(&h1940_board);
111}
112
113void __init h1940_init_irq(void)
114{
115 s3c24xx_init_irq();
116
117}
118
119MACHINE_START(H1940, "IPAQ-H1940")
120 MAINTAINER("Ben Dooks <ben@fluff.org>")
121 BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
122 BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
123 MAPIO(h1940_map_io)
124 INITIRQ(h1940_init_irq)
125 .timer = &s3c24xx_timer,
126MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c2410/mach-n30.c
new file mode 100644
index 000000000000..bd15998c129b
--- /dev/null
+++ b/arch/arm/mach-s3c2410/mach-n30.c
@@ -0,0 +1,155 @@
1/* linux/arch/arm/mach-s3c2410/mach-n30.c
2 *
3 * Copyright (c) 2003-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * Copyright (c) 2005 Christer Weinigel <christer@weinigel.se>
7 *
8 * There is a wiki with more information about the n30 port at
9 * http://handhelds.org/moin/moin.cgi/AcerN30Documentation .
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14*/
15
16#include <linux/kernel.h>
17#include <linux/types.h>
18#include <linux/interrupt.h>
19#include <linux/list.h>
20#include <linux/timer.h>
21#include <linux/init.h>
22#include <linux/delay.h>
23#include <linux/device.h>
24#include <linux/kthread.h>
25
26#include <asm/mach/arch.h>
27#include <asm/mach/map.h>
28#include <asm/mach/irq.h>
29
30#include <asm/hardware.h>
31#include <asm/hardware/iomd.h>
32#include <asm/io.h>
33#include <asm/irq.h>
34#include <asm/mach-types.h>
35
36#include <asm/arch/regs-serial.h>
37#include <asm/arch/regs-gpio.h>
38#include <asm/arch/iic.h>
39
40#include <linux/serial_core.h>
41
42#include "s3c2410.h"
43#include "clock.h"
44#include "devs.h"
45#include "cpu.h"
46
47static struct map_desc n30_iodesc[] __initdata = {
48 /* nothing here yet */
49};
50
51static struct s3c2410_uartcfg n30_uartcfgs[] = {
52 /* Normal serial port */
53 [0] = {
54 .hwport = 0,
55 .flags = 0,
56 .ucon = 0x2c5,
57 .ulcon = 0x03,
58 .ufcon = 0x51,
59 },
60 /* IR port */
61 [1] = {
62 .hwport = 1,
63 .flags = 0,
64 .uart_flags = UPF_CONS_FLOW,
65 .ucon = 0x2c5,
66 .ulcon = 0x43,
67 .ufcon = 0x51,
68 },
69 /* The BlueTooth controller is connected to port 2 */
70 [2] = {
71 .hwport = 2,
72 .flags = 0,
73 .ucon = 0x2c5,
74 .ulcon = 0x03,
75 .ufcon = 0x51,
76 },
77};
78
79static struct platform_device *n30_devices[] __initdata = {
80 &s3c_device_usb,
81 &s3c_device_lcd,
82 &s3c_device_wdt,
83 &s3c_device_i2c,
84 &s3c_device_iis,
85 &s3c_device_usbgadget,
86};
87
88static struct s3c2410_platform_i2c n30_i2ccfg = {
89 .flags = 0,
90 .slave_addr = 0x10,
91 .bus_freq = 10*1000,
92 .max_freq = 10*1000,
93};
94
95static struct s3c24xx_board n30_board __initdata = {
96 .devices = n30_devices,
97 .devices_count = ARRAY_SIZE(n30_devices)
98};
99
100void __init n30_map_io(void)
101{
102 s3c24xx_init_io(n30_iodesc, ARRAY_SIZE(n30_iodesc));
103 s3c24xx_init_clocks(0);
104 s3c24xx_init_uarts(n30_uartcfgs, ARRAY_SIZE(n30_uartcfgs));
105 s3c24xx_set_board(&n30_board);
106}
107
108void __init n30_init_irq(void)
109{
110 s3c24xx_init_irq();
111}
112
113
114static int n30_usbstart_thread(void *unused)
115{
116 /* Turn off suspend on both USB ports, and switch the
117 * selectable USB port to USB device mode. */
118 writel(readl(S3C2410_MISCCR) & ~0x00003008, S3C2410_MISCCR);
119
120 /* Turn off the D+ pull up for 3 seconds so that the USB host
121 * at the other end will do a rescan of the USB bus. */
122 s3c2410_gpio_setpin(S3C2410_GPB3, 0);
123
124 msleep_interruptible(3*HZ);
125
126 s3c2410_gpio_setpin(S3C2410_GPB3, 1);
127
128 return 0;
129}
130
131
132void __init n30_init(void)
133{
134 s3c_device_i2c.dev.platform_data = &n30_i2ccfg;
135
136 kthread_run(n30_usbstart_thread, NULL, "n30_usbstart");
137}
138
139MACHINE_START(N30, "Acer-N30")
140 MAINTAINER("Christer Weinigel <christer@weinigel.se>, Ben Dooks <ben-linux@fluff.org>")
141 BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
142 BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
143
144 .timer = &s3c24xx_timer,
145 .init_machine = n30_init,
146 .init_irq = n30_init_irq,
147 .map_io = n30_map_io,
148MACHINE_END
149
150/*
151 Local variables:
152 compile-command: "make ARCH=arm CROSS_COMPILE=/usr/local/arm/3.3.2/bin/arm-linux- -k -C ../../.."
153 c-basic-offset: 8
154 End:
155*/
diff --git a/arch/arm/mach-s3c2410/mach-nexcoder.c b/arch/arm/mach-s3c2410/mach-nexcoder.c
new file mode 100644
index 000000000000..70487bf4b71e
--- /dev/null
+++ b/arch/arm/mach-s3c2410/mach-nexcoder.c
@@ -0,0 +1,156 @@
1/* linux/arch/arm/mach-s3c2410/mach-nexcoder.c
2 *
3 * Copyright (c) 2004 Nex Vision
4 * Guillaume GOURAT <guillaume.gourat@nexvision.tv>
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 version 2 as
8 * published by the Free Software Foundation.
9 *
10 * Modifications:
11 * 15-10-2004 GG Created initial version
12 * 12-03-2005 BJD Updated for release
13 */
14
15#include <linux/kernel.h>
16#include <linux/types.h>
17#include <linux/interrupt.h>
18#include <linux/list.h>
19#include <linux/timer.h>
20#include <linux/init.h>
21#include <linux/string.h>
22#include <linux/device.h>
23
24#include <linux/mtd/map.h>
25
26#include <asm/mach/arch.h>
27#include <asm/mach/map.h>
28#include <asm/mach/irq.h>
29
30#include <asm/setup.h>
31#include <asm/hardware.h>
32#include <asm/io.h>
33#include <asm/irq.h>
34#include <asm/mach-types.h>
35
36//#include <asm/debug-ll.h>
37#include <asm/arch/regs-gpio.h>
38#include <asm/arch/regs-serial.h>
39
40#include "s3c2410.h"
41#include "s3c2440.h"
42#include "clock.h"
43#include "devs.h"
44#include "cpu.h"
45
46static struct map_desc nexcoder_iodesc[] __initdata = {
47 /* nothing here yet */
48};
49
50#define UCON S3C2410_UCON_DEFAULT
51#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
52#define UFCON S3C2410_UFCON_RXTRIG12 | S3C2410_UFCON_FIFOMODE
53
54static struct s3c2410_uartcfg nexcoder_uartcfgs[] = {
55 [0] = {
56 .hwport = 0,
57 .flags = 0,
58 .ucon = UCON,
59 .ulcon = ULCON,
60 .ufcon = UFCON,
61 },
62 [1] = {
63 .hwport = 1,
64 .flags = 0,
65 .ucon = UCON,
66 .ulcon = ULCON,
67 .ufcon = UFCON,
68 },
69 [2] = {
70 .hwport = 2,
71 .flags = 0,
72 .ucon = UCON,
73 .ulcon = ULCON,
74 .ufcon = UFCON,
75 }
76};
77
78/* NOR Flash on NexVision NexCoder 2440 board */
79
80static struct resource nexcoder_nor_resource[] = {
81 [0] = {
82 .start = S3C2410_CS0,
83 .end = S3C2410_CS0 + (8*1024*1024) - 1,
84 .flags = IORESOURCE_MEM,
85 }
86};
87
88static struct map_info nexcoder_nor_map = {
89 .bankwidth = 2,
90};
91
92static struct platform_device nexcoder_device_nor = {
93 .name = "mtd-flash",
94 .id = -1,
95 .num_resources = ARRAY_SIZE(nexcoder_nor_resource),
96 .resource = nexcoder_nor_resource,
97 .dev =
98 {
99 .platform_data = &nexcoder_nor_map,
100 }
101};
102
103/* Standard Nexcoder devices */
104
105static struct platform_device *nexcoder_devices[] __initdata = {
106 &s3c_device_usb,
107 &s3c_device_lcd,
108 &s3c_device_wdt,
109 &s3c_device_i2c,
110 &s3c_device_iis,
111 &s3c_device_rtc,
112 &s3c_device_camif,
113 &s3c_device_spi0,
114 &s3c_device_spi1,
115 &nexcoder_device_nor,
116};
117
118static struct s3c24xx_board nexcoder_board __initdata = {
119 .devices = nexcoder_devices,
120 .devices_count = ARRAY_SIZE(nexcoder_devices),
121};
122
123
124static void __init nexcoder_sensorboard_init(void)
125{
126 // Initialize SCCB bus
127 s3c2410_gpio_setpin(S3C2410_GPE14, 1); // IICSCL
128 s3c2410_gpio_cfgpin(S3C2410_GPE14, S3C2410_GPE14_OUTP);
129 s3c2410_gpio_setpin(S3C2410_GPE15, 1); // IICSDA
130 s3c2410_gpio_cfgpin(S3C2410_GPE15, S3C2410_GPE15_OUTP);
131
132 // Power up the sensor board
133 s3c2410_gpio_setpin(S3C2410_GPF1, 1);
134 s3c2410_gpio_cfgpin(S3C2410_GPF1, S3C2410_GPF1_OUTP); // CAM_GPIO7 => nLDO_PWRDN
135 s3c2410_gpio_setpin(S3C2410_GPF2, 0);
136 s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_OUTP); // CAM_GPIO6 => CAM_PWRDN
137}
138
139void __init nexcoder_map_io(void)
140{
141 s3c24xx_init_io(nexcoder_iodesc, ARRAY_SIZE(nexcoder_iodesc));
142 s3c24xx_init_clocks(0);
143 s3c24xx_init_uarts(nexcoder_uartcfgs, ARRAY_SIZE(nexcoder_uartcfgs));
144 s3c24xx_set_board(&nexcoder_board);
145 nexcoder_sensorboard_init();
146}
147
148
149MACHINE_START(NEXCODER_2440, "NexVision - Nexcoder 2440")
150 MAINTAINER("Guillaume GOURAT <guillaume.gourat@nexvision.tv>")
151 BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
152 BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
153 .map_io = nexcoder_map_io,
154 .init_irq = s3c24xx_init_irq,
155 .timer = &s3c24xx_timer,
156MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-otom.c b/arch/arm/mach-s3c2410/mach-otom.c
new file mode 100644
index 000000000000..67d8ce8fb00f
--- /dev/null
+++ b/arch/arm/mach-s3c2410/mach-otom.c
@@ -0,0 +1,124 @@
1/* linux/arch/arm/mach-s3c2410/mach-otom.c
2 *
3 * Copyright (c) 2004 Nex Vision
4 * Guillaume GOURAT <guillaume.gourat@nexvision.fr>
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 version 2 as
8 * published by the Free Software Foundation.
9 *
10 */
11
12#include <linux/kernel.h>
13#include <linux/types.h>
14#include <linux/interrupt.h>
15#include <linux/list.h>
16#include <linux/timer.h>
17#include <linux/init.h>
18#include <linux/device.h>
19
20#include <asm/mach/arch.h>
21#include <asm/mach/map.h>
22#include <asm/mach/irq.h>
23
24#include <asm/arch/otom-map.h>
25
26#include <asm/hardware.h>
27#include <asm/io.h>
28#include <asm/irq.h>
29#include <asm/mach-types.h>
30
31#include <asm/arch/regs-serial.h>
32#include <asm/arch/regs-gpio.h>
33
34#include "s3c2410.h"
35#include "clock.h"
36#include "devs.h"
37#include "cpu.h"
38
39static struct map_desc otom11_iodesc[] __initdata = {
40 /* Device area */
41 { (u32)OTOM_VA_CS8900A_BASE, OTOM_PA_CS8900A_BASE, SZ_16M, MT_DEVICE },
42};
43
44#define UCON S3C2410_UCON_DEFAULT
45#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
46#define UFCON S3C2410_UFCON_RXTRIG12 | S3C2410_UFCON_FIFOMODE
47
48static struct s3c2410_uartcfg otom11_uartcfgs[] = {
49 [0] = {
50 .hwport = 0,
51 .flags = 0,
52 .ucon = UCON,
53 .ulcon = ULCON,
54 .ufcon = UFCON,
55 },
56 [1] = {
57 .hwport = 1,
58 .flags = 0,
59 .ucon = UCON,
60 .ulcon = ULCON,
61 .ufcon = UFCON,
62 },
63 /* port 2 is not actually used */
64 [2] = {
65 .hwport = 2,
66 .flags = 0,
67 .ucon = UCON,
68 .ulcon = ULCON,
69 .ufcon = UFCON,
70 }
71};
72
73/* NOR Flash on NexVision OTOM board */
74
75static struct resource otom_nor_resource[] = {
76 [0] = {
77 .start = S3C2410_CS0,
78 .end = S3C2410_CS0 + (4*1024*1024) - 1,
79 .flags = IORESOURCE_MEM,
80 }
81};
82
83static struct platform_device otom_device_nor = {
84 .name = "mtd-flash",
85 .id = -1,
86 .num_resources = ARRAY_SIZE(otom_nor_resource),
87 .resource = otom_nor_resource,
88};
89
90/* Standard OTOM devices */
91
92static struct platform_device *otom11_devices[] __initdata = {
93 &s3c_device_usb,
94 &s3c_device_lcd,
95 &s3c_device_wdt,
96 &s3c_device_i2c,
97 &s3c_device_iis,
98 &s3c_device_rtc,
99 &otom_device_nor,
100};
101
102static struct s3c24xx_board otom11_board __initdata = {
103 .devices = otom11_devices,
104 .devices_count = ARRAY_SIZE(otom11_devices)
105};
106
107
108void __init otom11_map_io(void)
109{
110 s3c24xx_init_io(otom11_iodesc, ARRAY_SIZE(otom11_iodesc));
111 s3c24xx_init_clocks(0);
112 s3c24xx_init_uarts(otom11_uartcfgs, ARRAY_SIZE(otom11_uartcfgs));
113 s3c24xx_set_board(&otom11_board);
114}
115
116
117MACHINE_START(OTOM, "Nex Vision - Otom 1.1")
118 MAINTAINER("Guillaume GOURAT <guillaume.gourat@nexvision.tv>")
119 BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
120 BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
121 .map_io = otom11_map_io,
122 .init_irq = s3c24xx_init_irq,
123 .timer = &s3c24xx_timer,
124MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-rx3715.c b/arch/arm/mach-s3c2410/mach-rx3715.c
new file mode 100644
index 000000000000..f8d3a9784e71
--- /dev/null
+++ b/arch/arm/mach-s3c2410/mach-rx3715.c
@@ -0,0 +1,141 @@
1/* linux/arch/arm/mach-s3c2410/mach-rx3715.c
2 *
3 * Copyright (c) 2003,2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * http://www.handhelds.org/projects/rx3715.html
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 version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Modifications:
13 * 16-Sep-2004 BJD Copied from mach-h1940.c
14 * 25-Oct-2004 BJD Updates for 2.6.10-rc1
15 * 10-Jan-2005 BJD Removed include of s3c2410.h s3c2440.h
16 * 14-Jan-2005 BJD Added new clock init
17 * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
18 * 14-Mar-2005 BJD Fixed __iomem warnings
19*/
20
21#include <linux/kernel.h>
22#include <linux/types.h>
23#include <linux/interrupt.h>
24#include <linux/list.h>
25#include <linux/timer.h>
26#include <linux/init.h>
27#include <linux/tty.h>
28#include <linux/console.h>
29#include <linux/serial_core.h>
30#include <linux/serial.h>
31
32#include <asm/mach/arch.h>
33#include <asm/mach/map.h>
34#include <asm/mach/irq.h>
35
36#include <asm/hardware.h>
37#include <asm/hardware/iomd.h>
38#include <asm/io.h>
39#include <asm/irq.h>
40#include <asm/mach-types.h>
41
42#include <asm/arch/regs-serial.h>
43#include <asm/arch/regs-gpio.h>
44
45#include "clock.h"
46#include "devs.h"
47#include "cpu.h"
48#include "pm.h"
49
50static struct map_desc rx3715_iodesc[] __initdata = {
51 /* dump ISA space somewhere unused */
52
53 { (u32)S3C24XX_VA_ISA_WORD, S3C2410_CS3, SZ_16M, MT_DEVICE },
54 { (u32)S3C24XX_VA_ISA_BYTE, S3C2410_CS3, SZ_16M, MT_DEVICE },
55};
56
57
58static struct s3c24xx_uart_clksrc rx3715_serial_clocks[] = {
59 [0] = {
60 .name = "fclk",
61 .divisor = 0,
62 .min_baud = 0,
63 .max_baud = 0,
64 }
65};
66
67static struct s3c2410_uartcfg rx3715_uartcfgs[] = {
68 [0] = {
69 .hwport = 0,
70 .flags = 0,
71 .ucon = 0x3c5,
72 .ulcon = 0x03,
73 .ufcon = 0x51,
74 .clocks = rx3715_serial_clocks,
75 .clocks_size = ARRAY_SIZE(rx3715_serial_clocks),
76 },
77 [1] = {
78 .hwport = 1,
79 .flags = 0,
80 .ucon = 0x3c5,
81 .ulcon = 0x03,
82 .ufcon = 0x00,
83 .clocks = rx3715_serial_clocks,
84 .clocks_size = ARRAY_SIZE(rx3715_serial_clocks),
85 },
86 /* IR port */
87 [2] = {
88 .hwport = 2,
89 .uart_flags = UPF_CONS_FLOW,
90 .ucon = 0x3c5,
91 .ulcon = 0x43,
92 .ufcon = 0x51,
93 .clocks = rx3715_serial_clocks,
94 .clocks_size = ARRAY_SIZE(rx3715_serial_clocks),
95 }
96};
97
98static struct platform_device *rx3715_devices[] __initdata = {
99 &s3c_device_usb,
100 &s3c_device_lcd,
101 &s3c_device_wdt,
102 &s3c_device_i2c,
103 &s3c_device_iis,
104};
105
106static struct s3c24xx_board rx3715_board __initdata = {
107 .devices = rx3715_devices,
108 .devices_count = ARRAY_SIZE(rx3715_devices)
109};
110
111void __init rx3715_map_io(void)
112{
113 s3c24xx_init_io(rx3715_iodesc, ARRAY_SIZE(rx3715_iodesc));
114 s3c24xx_init_clocks(16934000);
115 s3c24xx_init_uarts(rx3715_uartcfgs, ARRAY_SIZE(rx3715_uartcfgs));
116 s3c24xx_set_board(&rx3715_board);
117}
118
119void __init rx3715_init_irq(void)
120{
121 s3c24xx_init_irq();
122}
123
124#ifdef CONFIG_PM
125static void __init rx3715_init_machine(void)
126{
127 s3c2410_pm_init();
128}
129#else
130#define rx3715_init_machine NULL
131#endif
132
133MACHINE_START(RX3715, "IPAQ-RX3715")
134 MAINTAINER("Ben Dooks <ben@fluff.org>")
135 BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
136 BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
137 MAPIO(rx3715_map_io)
138 INITIRQ(rx3715_init_irq)
139 INIT_MACHINE(rx3715_init_machine)
140 .timer = &s3c24xx_timer,
141MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c
new file mode 100644
index 000000000000..c1a4a1420ea0
--- /dev/null
+++ b/arch/arm/mach-s3c2410/mach-smdk2410.c
@@ -0,0 +1,123 @@
1/***********************************************************************
2 *
3 * linux/arch/arm/mach-s3c2410/mach-smdk2410.c
4 *
5 * Copyright (C) 2004 by FS Forth-Systeme GmbH
6 * All rights reserved.
7 *
8 * $Id: mach-smdk2410.c,v 1.1 2004/05/11 14:15:38 mpietrek Exp $
9 * @Author: Jonas Dietsche
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24 * MA 02111-1307 USA
25 *
26 * @History:
27 * derived from linux/arch/arm/mach-s3c2410/mach-bast.c, written by
28 * Ben Dooks <ben@simtec.co.uk>
29 *
30 * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
31 *
32 ***********************************************************************/
33
34#include <linux/kernel.h>
35#include <linux/types.h>
36#include <linux/interrupt.h>
37#include <linux/list.h>
38#include <linux/timer.h>
39#include <linux/init.h>
40
41#include <asm/mach/arch.h>
42#include <asm/mach/map.h>
43#include <asm/mach/irq.h>
44
45#include <asm/hardware.h>
46#include <asm/io.h>
47#include <asm/irq.h>
48#include <asm/mach-types.h>
49
50#include <asm/arch/regs-serial.h>
51
52#include "devs.h"
53#include "cpu.h"
54
55static struct map_desc smdk2410_iodesc[] __initdata = {
56 /* nothing here yet */
57};
58
59#define UCON S3C2410_UCON_DEFAULT
60#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
61#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
62
63static struct s3c2410_uartcfg smdk2410_uartcfgs[] = {
64 [0] = {
65 .hwport = 0,
66 .flags = 0,
67 .ucon = UCON,
68 .ulcon = ULCON,
69 .ufcon = UFCON,
70 },
71 [1] = {
72 .hwport = 1,
73 .flags = 0,
74 .ucon = UCON,
75 .ulcon = ULCON,
76 .ufcon = UFCON,
77 },
78 [2] = {
79 .hwport = 2,
80 .flags = 0,
81 .ucon = UCON,
82 .ulcon = ULCON,
83 .ufcon = UFCON,
84 }
85};
86
87static struct platform_device *smdk2410_devices[] __initdata = {
88 &s3c_device_usb,
89 &s3c_device_lcd,
90 &s3c_device_wdt,
91 &s3c_device_i2c,
92 &s3c_device_iis,
93};
94
95static struct s3c24xx_board smdk2410_board __initdata = {
96 .devices = smdk2410_devices,
97 .devices_count = ARRAY_SIZE(smdk2410_devices)
98};
99
100void __init smdk2410_map_io(void)
101{
102 s3c24xx_init_io(smdk2410_iodesc, ARRAY_SIZE(smdk2410_iodesc));
103 s3c24xx_init_clocks(0);
104 s3c24xx_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs));
105 s3c24xx_set_board(&smdk2410_board);
106}
107
108void __init smdk2410_init_irq(void)
109{
110 s3c24xx_init_irq();
111}
112
113MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
114 * to SMDK2410 */
115 MAINTAINER("Jonas Dietsche")
116 BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
117 BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
118 MAPIO(smdk2410_map_io)
119 INITIRQ(smdk2410_init_irq)
120 .timer = &s3c24xx_timer,
121MACHINE_END
122
123
diff --git a/arch/arm/mach-s3c2410/mach-smdk2440.c b/arch/arm/mach-s3c2410/mach-smdk2440.c
new file mode 100644
index 000000000000..7857176d9bcb
--- /dev/null
+++ b/arch/arm/mach-s3c2410/mach-smdk2440.c
@@ -0,0 +1,135 @@
1/* linux/arch/arm/mach-s3c2410/mach-smdk2440.c
2 *
3 * Copyright (c) 2004,2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * http://www.fluff.org/ben/smdk2440/
7 *
8 * Thanks to Dimity Andric and TomTom for the loan of an SMDK2440.
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 * Modifications:
15 * 01-Nov-2004 BJD Initial version
16 * 12-Nov-2004 BJD Updated for release
17 * 04-Jan-2005 BJD Fixes for pre-release
18 * 22-Feb-2005 BJD Updated for 2.6.11-rc5 relesa
19 * 10-Mar-2005 LCVR Replaced S3C2410_VA by S3C24XX_VA
20 * 14-Mar-2005 BJD void __iomem fixes
21*/
22
23#include <linux/kernel.h>
24#include <linux/types.h>
25#include <linux/interrupt.h>
26#include <linux/list.h>
27#include <linux/timer.h>
28#include <linux/init.h>
29
30#include <asm/mach/arch.h>
31#include <asm/mach/map.h>
32#include <asm/mach/irq.h>
33
34#include <asm/hardware.h>
35#include <asm/hardware/iomd.h>
36#include <asm/io.h>
37#include <asm/irq.h>
38#include <asm/mach-types.h>
39
40//#include <asm/debug-ll.h>
41#include <asm/arch/regs-serial.h>
42#include <asm/arch/regs-gpio.h>
43#include <asm/arch/idle.h>
44
45#include "s3c2410.h"
46#include "s3c2440.h"
47#include "clock.h"
48#include "devs.h"
49#include "cpu.h"
50#include "pm.h"
51
52static struct map_desc smdk2440_iodesc[] __initdata = {
53 /* ISA IO Space map (memory space selected by A24) */
54
55 { (u32)S3C24XX_VA_ISA_WORD, S3C2410_CS2, SZ_16M, MT_DEVICE },
56 { (u32)S3C24XX_VA_ISA_BYTE, S3C2410_CS2, SZ_16M, MT_DEVICE },
57};
58
59#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
60#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
61#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
62
63static struct s3c2410_uartcfg smdk2440_uartcfgs[] = {
64 [0] = {
65 .hwport = 0,
66 .flags = 0,
67 .ucon = 0x3c5,
68 .ulcon = 0x03,
69 .ufcon = 0x51,
70 },
71 [1] = {
72 .hwport = 1,
73 .flags = 0,
74 .ucon = 0x3c5,
75 .ulcon = 0x03,
76 .ufcon = 0x51,
77 },
78 /* IR port */
79 [2] = {
80 .hwport = 2,
81 .flags = 0,
82 .ucon = 0x3c5,
83 .ulcon = 0x43,
84 .ufcon = 0x51,
85 }
86};
87
88static struct platform_device *smdk2440_devices[] __initdata = {
89 &s3c_device_usb,
90 &s3c_device_lcd,
91 &s3c_device_wdt,
92 &s3c_device_i2c,
93 &s3c_device_iis,
94};
95
96static struct s3c24xx_board smdk2440_board __initdata = {
97 .devices = smdk2440_devices,
98 .devices_count = ARRAY_SIZE(smdk2440_devices)
99};
100
101void __init smdk2440_map_io(void)
102{
103 s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc));
104 s3c24xx_init_clocks(16934400);
105 s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));
106 s3c24xx_set_board(&smdk2440_board);
107}
108
109void __init smdk2440_machine_init(void)
110{
111 /* Configure the LEDs (even if we have no LED support)*/
112
113 s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_OUTP);
114 s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
115 s3c2410_gpio_cfgpin(S3C2410_GPF6, S3C2410_GPF6_OUTP);
116 s3c2410_gpio_cfgpin(S3C2410_GPF7, S3C2410_GPF7_OUTP);
117
118 s3c2410_gpio_setpin(S3C2410_GPF4, 0);
119 s3c2410_gpio_setpin(S3C2410_GPF5, 0);
120 s3c2410_gpio_setpin(S3C2410_GPF6, 0);
121 s3c2410_gpio_setpin(S3C2410_GPF7, 0);
122
123 s3c2410_pm_init();
124}
125
126MACHINE_START(S3C2440, "SMDK2440")
127 MAINTAINER("Ben Dooks <ben@fluff.org>")
128 BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
129 BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
130
131 .init_irq = s3c24xx_init_irq,
132 .map_io = smdk2440_map_io,
133 .init_machine = smdk2440_machine_init,
134 .timer = &s3c24xx_timer,
135MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c
new file mode 100644
index 000000000000..5512146b1ce4
--- /dev/null
+++ b/arch/arm/mach-s3c2410/mach-vr1000.c
@@ -0,0 +1,317 @@
1/* linux/arch/arm/mach-s3c2410/mach-vr1000.c
2 *
3 * Copyright (c) 2003-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * Machine support for Thorcom VR1000 board. Designed for Thorcom by
7 * Simtec Electronics, http://www.simtec.co.uk/
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 * Modifications:
14 * 14-Sep-2004 BJD USB Power control
15 * 04-Sep-2004 BJD Added new uart init, and io init
16 * 21-Aug-2004 BJD Added struct s3c2410_board
17 * 06-Aug-2004 BJD Fixed call to time initialisation
18 * 05-Apr-2004 BJD Copied to make mach-vr1000.c
19 * 18-Oct-2004 BJD Updated board struct
20 * 04-Nov-2004 BJD Clock and serial configuration update
21 *
22 * 04-Jan-2005 BJD Updated uart init call
23 * 10-Jan-2005 BJD Removed include of s3c2410.h
24 * 14-Jan-2005 BJD Added clock init
25 * 15-Jan-2005 BJD Add serial port device definition
26 * 20-Jan-2005 BJD Use UPF_IOREMAP for ports
27 * 10-Feb-2005 BJD Added power-off capability
28 * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
29 * 14-Mar-2006 BJD void __iomem fixes
30*/
31
32#include <linux/kernel.h>
33#include <linux/types.h>
34#include <linux/interrupt.h>
35#include <linux/list.h>
36#include <linux/timer.h>
37#include <linux/init.h>
38
39#include <linux/serial.h>
40#include <linux/tty.h>
41#include <linux/serial_8250.h>
42#include <linux/serial_reg.h>
43
44#include <asm/mach/arch.h>
45#include <asm/mach/map.h>
46#include <asm/mach/irq.h>
47
48#include <asm/arch/bast-map.h>
49#include <asm/arch/vr1000-map.h>
50#include <asm/arch/vr1000-irq.h>
51#include <asm/arch/vr1000-cpld.h>
52
53#include <asm/hardware.h>
54#include <asm/io.h>
55#include <asm/irq.h>
56#include <asm/mach-types.h>
57
58#include <asm/arch/regs-serial.h>
59#include <asm/arch/regs-gpio.h>
60
61#include "clock.h"
62#include "devs.h"
63#include "cpu.h"
64#include "usb-simtec.h"
65
66/* macros for virtual address mods for the io space entries */
67#define VA_C5(item) ((unsigned long)(item) + BAST_VAM_CS5)
68#define VA_C4(item) ((unsigned long)(item) + BAST_VAM_CS4)
69#define VA_C3(item) ((unsigned long)(item) + BAST_VAM_CS3)
70#define VA_C2(item) ((unsigned long)(item) + BAST_VAM_CS2)
71
72/* macros to modify the physical addresses for io space */
73
74#define PA_CS2(item) ((item) + S3C2410_CS2)
75#define PA_CS3(item) ((item) + S3C2410_CS3)
76#define PA_CS4(item) ((item) + S3C2410_CS4)
77#define PA_CS5(item) ((item) + S3C2410_CS5)
78
79static struct map_desc vr1000_iodesc[] __initdata = {
80 /* ISA IO areas */
81
82 { (u32)S3C24XX_VA_ISA_BYTE, PA_CS2(BAST_PA_ISAIO), SZ_16M, MT_DEVICE },
83 { (u32)S3C24XX_VA_ISA_WORD, PA_CS3(BAST_PA_ISAIO), SZ_16M, MT_DEVICE },
84
85 /* we could possibly compress the next set down into a set of smaller tables
86 * pagetables, but that would mean using an L2 section, and it still means
87 * we cannot actually feed the same register to an LDR due to 16K spacing
88 */
89
90 /* bast CPLD control registers, and external interrupt controls */
91 { (u32)VR1000_VA_CTRL1, VR1000_PA_CTRL1, SZ_1M, MT_DEVICE },
92 { (u32)VR1000_VA_CTRL2, VR1000_PA_CTRL2, SZ_1M, MT_DEVICE },
93 { (u32)VR1000_VA_CTRL3, VR1000_PA_CTRL3, SZ_1M, MT_DEVICE },
94 { (u32)VR1000_VA_CTRL4, VR1000_PA_CTRL4, SZ_1M, MT_DEVICE },
95
96 /* peripheral space... one for each of fast/slow/byte/16bit */
97 /* note, ide is only decoded in word space, even though some registers
98 * are only 8bit */
99
100 /* slow, byte */
101 { VA_C2(VR1000_VA_DM9000), PA_CS2(VR1000_PA_DM9000), SZ_1M, MT_DEVICE },
102 { VA_C2(VR1000_VA_IDEPRI), PA_CS3(VR1000_PA_IDEPRI), SZ_1M, MT_DEVICE },
103 { VA_C2(VR1000_VA_IDESEC), PA_CS3(VR1000_PA_IDESEC), SZ_1M, MT_DEVICE },
104 { VA_C2(VR1000_VA_IDEPRIAUX), PA_CS3(VR1000_PA_IDEPRIAUX), SZ_1M, MT_DEVICE },
105 { VA_C2(VR1000_VA_IDESECAUX), PA_CS3(VR1000_PA_IDESECAUX), SZ_1M, MT_DEVICE },
106
107 /* slow, word */
108 { VA_C3(VR1000_VA_DM9000), PA_CS3(VR1000_PA_DM9000), SZ_1M, MT_DEVICE },
109 { VA_C3(VR1000_VA_IDEPRI), PA_CS3(VR1000_PA_IDEPRI), SZ_1M, MT_DEVICE },
110 { VA_C3(VR1000_VA_IDESEC), PA_CS3(VR1000_PA_IDESEC), SZ_1M, MT_DEVICE },
111 { VA_C3(VR1000_VA_IDEPRIAUX), PA_CS3(VR1000_PA_IDEPRIAUX), SZ_1M, MT_DEVICE },
112 { VA_C3(VR1000_VA_IDESECAUX), PA_CS3(VR1000_PA_IDESECAUX), SZ_1M, MT_DEVICE },
113
114 /* fast, byte */
115 { VA_C4(VR1000_VA_DM9000), PA_CS4(VR1000_PA_DM9000), SZ_1M, MT_DEVICE },
116 { VA_C4(VR1000_VA_IDEPRI), PA_CS5(VR1000_PA_IDEPRI), SZ_1M, MT_DEVICE },
117 { VA_C4(VR1000_VA_IDESEC), PA_CS5(VR1000_PA_IDESEC), SZ_1M, MT_DEVICE },
118 { VA_C4(VR1000_VA_IDEPRIAUX), PA_CS5(VR1000_PA_IDEPRIAUX), SZ_1M, MT_DEVICE },
119 { VA_C4(VR1000_VA_IDESECAUX), PA_CS5(VR1000_PA_IDESECAUX), SZ_1M, MT_DEVICE },
120
121 /* fast, word */
122 { VA_C5(VR1000_VA_DM9000), PA_CS5(VR1000_PA_DM9000), SZ_1M, MT_DEVICE },
123 { VA_C5(VR1000_VA_IDEPRI), PA_CS5(VR1000_PA_IDEPRI), SZ_1M, MT_DEVICE },
124 { VA_C5(VR1000_VA_IDESEC), PA_CS5(VR1000_PA_IDESEC), SZ_1M, MT_DEVICE },
125 { VA_C5(VR1000_VA_IDEPRIAUX), PA_CS5(VR1000_PA_IDEPRIAUX), SZ_1M, MT_DEVICE },
126 { VA_C5(VR1000_VA_IDESECAUX), PA_CS5(VR1000_PA_IDESECAUX), SZ_1M, MT_DEVICE },
127};
128
129#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
130#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
131#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
132
133/* uart clock source(s) */
134
135static struct s3c24xx_uart_clksrc vr1000_serial_clocks[] = {
136 [0] = {
137 .name = "uclk",
138 .divisor = 1,
139 .min_baud = 0,
140 .max_baud = 0,
141 },
142 [1] = {
143 .name = "pclk",
144 .divisor = 1,
145 .min_baud = 0,
146 .max_baud = 0.
147 }
148};
149
150static struct s3c2410_uartcfg vr1000_uartcfgs[] = {
151 [0] = {
152 .hwport = 0,
153 .flags = 0,
154 .ucon = UCON,
155 .ulcon = ULCON,
156 .ufcon = UFCON,
157 .clocks = vr1000_serial_clocks,
158 .clocks_size = ARRAY_SIZE(vr1000_serial_clocks),
159 },
160 [1] = {
161 .hwport = 1,
162 .flags = 0,
163 .ucon = UCON,
164 .ulcon = ULCON,
165 .ufcon = UFCON,
166 .clocks = vr1000_serial_clocks,
167 .clocks_size = ARRAY_SIZE(vr1000_serial_clocks),
168 },
169 /* port 2 is not actually used */
170 [2] = {
171 .hwport = 2,
172 .flags = 0,
173 .ucon = UCON,
174 .ulcon = ULCON,
175 .ufcon = UFCON,
176 .clocks = vr1000_serial_clocks,
177 .clocks_size = ARRAY_SIZE(vr1000_serial_clocks),
178
179 }
180};
181
182/* definitions for the vr1000 extra 16550 serial ports */
183
184#define VR1000_BAUDBASE (3692307)
185
186#define VR1000_SERIAL_MAPBASE(x) (VR1000_PA_SERIAL + 0x80 + ((x) << 5))
187
188static struct plat_serial8250_port serial_platform_data[] = {
189 [0] = {
190 .mapbase = VR1000_SERIAL_MAPBASE(0),
191 .irq = IRQ_VR1000_SERIAL + 0,
192 .flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
193 .iotype = UPIO_MEM,
194 .regshift = 0,
195 .uartclk = VR1000_BAUDBASE,
196 },
197 [1] = {
198 .mapbase = VR1000_SERIAL_MAPBASE(1),
199 .irq = IRQ_VR1000_SERIAL + 1,
200 .flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
201 .iotype = UPIO_MEM,
202 .regshift = 0,
203 .uartclk = VR1000_BAUDBASE,
204 },
205 [2] = {
206 .mapbase = VR1000_SERIAL_MAPBASE(2),
207 .irq = IRQ_VR1000_SERIAL + 2,
208 .flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
209 .iotype = UPIO_MEM,
210 .regshift = 0,
211 .uartclk = VR1000_BAUDBASE,
212 },
213 [3] = {
214 .mapbase = VR1000_SERIAL_MAPBASE(3),
215 .irq = IRQ_VR1000_SERIAL + 3,
216 .flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
217 .iotype = UPIO_MEM,
218 .regshift = 0,
219 .uartclk = VR1000_BAUDBASE,
220 },
221 { },
222};
223
224static struct platform_device serial_device = {
225 .name = "serial8250",
226 .id = 0,
227 .dev = {
228 .platform_data = serial_platform_data,
229 },
230};
231
232/* MTD NOR Flash */
233
234static struct resource vr1000_nor_resource[] = {
235 [0] = {
236 .start = S3C2410_CS1 + 0x4000000,
237 .end = S3C2410_CS1 + 0x4000000 + SZ_16M - 1,
238 .flags = IORESOURCE_MEM,
239 }
240};
241
242static struct platform_device vr1000_nor = {
243 .name = "bast-nor",
244 .id = -1,
245 .num_resources = ARRAY_SIZE(vr1000_nor_resource),
246 .resource = vr1000_nor_resource,
247};
248
249
250static struct platform_device *vr1000_devices[] __initdata = {
251 &s3c_device_usb,
252 &s3c_device_lcd,
253 &s3c_device_wdt,
254 &s3c_device_i2c,
255 &s3c_device_iis,
256 &serial_device,
257 &vr1000_nor,
258};
259
260static struct clk *vr1000_clocks[] = {
261 &s3c24xx_dclk0,
262 &s3c24xx_dclk1,
263 &s3c24xx_clkout0,
264 &s3c24xx_clkout1,
265 &s3c24xx_uclk,
266};
267
268static struct s3c24xx_board vr1000_board __initdata = {
269 .devices = vr1000_devices,
270 .devices_count = ARRAY_SIZE(vr1000_devices),
271 .clocks = vr1000_clocks,
272 .clocks_count = ARRAY_SIZE(vr1000_clocks),
273};
274
275static void vr1000_power_off(void)
276{
277 s3c2410_gpio_cfgpin(S3C2410_GPB9, S3C2410_GPB9_OUTP);
278 s3c2410_gpio_setpin(S3C2410_GPB9, 1);
279}
280
281void __init vr1000_map_io(void)
282{
283 /* initialise clock sources */
284
285 s3c24xx_dclk0.parent = NULL;
286 s3c24xx_dclk0.rate = 12*1000*1000;
287
288 s3c24xx_dclk1.parent = NULL;
289 s3c24xx_dclk1.rate = 3692307;
290
291 s3c24xx_clkout0.parent = &s3c24xx_dclk0;
292 s3c24xx_clkout1.parent = &s3c24xx_dclk1;
293
294 s3c24xx_uclk.parent = &s3c24xx_clkout1;
295
296 pm_power_off = vr1000_power_off;
297
298 s3c24xx_init_io(vr1000_iodesc, ARRAY_SIZE(vr1000_iodesc));
299 s3c24xx_init_clocks(0);
300 s3c24xx_init_uarts(vr1000_uartcfgs, ARRAY_SIZE(vr1000_uartcfgs));
301 s3c24xx_set_board(&vr1000_board);
302 usb_simtec_init();
303}
304
305void __init vr1000_init_irq(void)
306{
307 s3c24xx_init_irq();
308}
309
310MACHINE_START(VR1000, "Thorcom-VR1000")
311 MAINTAINER("Ben Dooks <ben@simtec.co.uk>")
312 BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
313 BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
314 MAPIO(vr1000_map_io)
315 INITIRQ(vr1000_init_irq)
316 .timer = &s3c24xx_timer,
317MACHINE_END
diff --git a/arch/arm/mach-s3c2410/pm.c b/arch/arm/mach-s3c2410/pm.c
new file mode 100644
index 000000000000..13a48ee77484
--- /dev/null
+++ b/arch/arm/mach-s3c2410/pm.c
@@ -0,0 +1,672 @@
1/* linux/arch/arm/mach-s3c2410/pm.c
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 * 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 * Modifications:
29 * 10-Mar-2005 LCVR Changed S3C2410_VA_UART to S3C24XX_VA_UART
30*/
31
32#include <linux/config.h>
33#include <linux/init.h>
34#include <linux/suspend.h>
35#include <linux/errno.h>
36#include <linux/time.h>
37#include <linux/interrupt.h>
38#include <linux/crc32.h>
39#include <linux/ioport.h>
40#include <linux/delay.h>
41
42#include <asm/hardware.h>
43#include <asm/io.h>
44
45#include <asm/arch/regs-serial.h>
46#include <asm/arch/regs-clock.h>
47#include <asm/arch/regs-gpio.h>
48#include <asm/arch/regs-mem.h>
49#include <asm/arch/regs-irq.h>
50
51#include <asm/mach/time.h>
52
53#include "pm.h"
54
55/* for external use */
56
57unsigned long s3c_pm_flags;
58
59/* cache functions from arch/arm/mm/proc-arm920.S */
60
61extern void arm920_flush_kern_cache_all(void);
62
63#define PFX "s3c24xx-pm: "
64
65static struct sleep_save core_save[] = {
66 SAVE_ITEM(S3C2410_LOCKTIME),
67 SAVE_ITEM(S3C2410_CLKCON),
68
69 /* we restore the timings here, with the proviso that the board
70 * brings the system up in an slower, or equal frequency setting
71 * to the original system.
72 *
73 * if we cannot guarantee this, then things are going to go very
74 * wrong here, as we modify the refresh and both pll settings.
75 */
76
77 SAVE_ITEM(S3C2410_BWSCON),
78 SAVE_ITEM(S3C2410_BANKCON0),
79 SAVE_ITEM(S3C2410_BANKCON1),
80 SAVE_ITEM(S3C2410_BANKCON2),
81 SAVE_ITEM(S3C2410_BANKCON3),
82 SAVE_ITEM(S3C2410_BANKCON4),
83 SAVE_ITEM(S3C2410_BANKCON5),
84
85 SAVE_ITEM(S3C2410_CLKDIVN),
86 SAVE_ITEM(S3C2410_MPLLCON),
87 SAVE_ITEM(S3C2410_UPLLCON),
88 SAVE_ITEM(S3C2410_CLKSLOW),
89 SAVE_ITEM(S3C2410_REFRESH),
90};
91
92/* this lot should be really saved by the IRQ code */
93static struct sleep_save irq_save[] = {
94 SAVE_ITEM(S3C2410_EXTINT0),
95 SAVE_ITEM(S3C2410_EXTINT1),
96 SAVE_ITEM(S3C2410_EXTINT2),
97 SAVE_ITEM(S3C2410_EINFLT0),
98 SAVE_ITEM(S3C2410_EINFLT1),
99 SAVE_ITEM(S3C2410_EINFLT2),
100 SAVE_ITEM(S3C2410_EINFLT3),
101 SAVE_ITEM(S3C2410_EINTMASK),
102 SAVE_ITEM(S3C2410_INTMSK)
103};
104
105static struct sleep_save gpio_save[] = {
106 SAVE_ITEM(S3C2410_GPACON),
107 SAVE_ITEM(S3C2410_GPADAT),
108
109 SAVE_ITEM(S3C2410_GPBCON),
110 SAVE_ITEM(S3C2410_GPBDAT),
111 SAVE_ITEM(S3C2410_GPBUP),
112
113 SAVE_ITEM(S3C2410_GPCCON),
114 SAVE_ITEM(S3C2410_GPCDAT),
115 SAVE_ITEM(S3C2410_GPCUP),
116
117 SAVE_ITEM(S3C2410_GPDCON),
118 SAVE_ITEM(S3C2410_GPDDAT),
119 SAVE_ITEM(S3C2410_GPDUP),
120
121 SAVE_ITEM(S3C2410_GPECON),
122 SAVE_ITEM(S3C2410_GPEDAT),
123 SAVE_ITEM(S3C2410_GPEUP),
124
125 SAVE_ITEM(S3C2410_GPFCON),
126 SAVE_ITEM(S3C2410_GPFDAT),
127 SAVE_ITEM(S3C2410_GPFUP),
128
129 SAVE_ITEM(S3C2410_GPGCON),
130 SAVE_ITEM(S3C2410_GPGDAT),
131 SAVE_ITEM(S3C2410_GPGUP),
132
133 SAVE_ITEM(S3C2410_GPHCON),
134 SAVE_ITEM(S3C2410_GPHDAT),
135 SAVE_ITEM(S3C2410_GPHUP),
136
137 SAVE_ITEM(S3C2410_DCLKCON),
138};
139
140#ifdef CONFIG_S3C2410_PM_DEBUG
141
142#define SAVE_UART(va) \
143 SAVE_ITEM((va) + S3C2410_ULCON), \
144 SAVE_ITEM((va) + S3C2410_UCON), \
145 SAVE_ITEM((va) + S3C2410_UFCON), \
146 SAVE_ITEM((va) + S3C2410_UMCON), \
147 SAVE_ITEM((va) + S3C2410_UBRDIV)
148
149static struct sleep_save uart_save[] = {
150 SAVE_UART(S3C24XX_VA_UART0),
151 SAVE_UART(S3C24XX_VA_UART1),
152#ifndef CONFIG_CPU_S3C2400
153 SAVE_UART(S3C24XX_VA_UART2),
154#endif
155};
156
157/* debug
158 *
159 * we send the debug to printascii() to allow it to be seen if the
160 * system never wakes up from the sleep
161*/
162
163extern void printascii(const char *);
164
165static void pm_dbg(const char *fmt, ...)
166{
167 va_list va;
168 char buff[256];
169
170 va_start(va, fmt);
171 vsprintf(buff, fmt, va);
172 va_end(va);
173
174 printascii(buff);
175}
176
177static void s3c2410_pm_debug_init(void)
178{
179 unsigned long tmp = __raw_readl(S3C2410_CLKCON);
180
181 /* re-start uart clocks */
182 tmp |= S3C2410_CLKCON_UART0;
183 tmp |= S3C2410_CLKCON_UART1;
184 tmp |= S3C2410_CLKCON_UART2;
185
186 __raw_writel(tmp, S3C2410_CLKCON);
187 udelay(10);
188}
189
190#define DBG(fmt...) pm_dbg(fmt)
191#else
192#define DBG(fmt...) printk(KERN_DEBUG fmt)
193
194#define s3c2410_pm_debug_init() do { } while(0)
195
196static struct sleep_save uart_save[] = {};
197#endif
198
199#if defined(CONFIG_S3C2410_PM_CHECK) && CONFIG_S3C2410_PM_CHECK_CHUNKSIZE != 0
200
201/* suspend checking code...
202 *
203 * this next area does a set of crc checks over all the installed
204 * memory, so the system can verify if the resume was ok.
205 *
206 * CONFIG_S3C2410_PM_CHECK_CHUNKSIZE defines the block-size for the CRC,
207 * increasing it will mean that the area corrupted will be less easy to spot,
208 * and reducing the size will cause the CRC save area to grow
209*/
210
211#define CHECK_CHUNKSIZE (CONFIG_S3C2410_PM_CHECK_CHUNKSIZE * 1024)
212
213static u32 crc_size; /* size needed for the crc block */
214static u32 *crcs; /* allocated over suspend/resume */
215
216typedef u32 *(run_fn_t)(struct resource *ptr, u32 *arg);
217
218/* s3c2410_pm_run_res
219 *
220 * go thorugh the given resource list, and look for system ram
221*/
222
223static void s3c2410_pm_run_res(struct resource *ptr, run_fn_t fn, u32 *arg)
224{
225 while (ptr != NULL) {
226 if (ptr->child != NULL)
227 s3c2410_pm_run_res(ptr->child, fn, arg);
228
229 if ((ptr->flags & IORESOURCE_MEM) &&
230 strcmp(ptr->name, "System RAM") == 0) {
231 DBG("Found system RAM at %08lx..%08lx\n",
232 ptr->start, ptr->end);
233 arg = (fn)(ptr, arg);
234 }
235
236 ptr = ptr->sibling;
237 }
238}
239
240static void s3c2410_pm_run_sysram(run_fn_t fn, u32 *arg)
241{
242 s3c2410_pm_run_res(&iomem_resource, fn, arg);
243}
244
245static u32 *s3c2410_pm_countram(struct resource *res, u32 *val)
246{
247 u32 size = (u32)(res->end - res->start)+1;
248
249 size += CHECK_CHUNKSIZE-1;
250 size /= CHECK_CHUNKSIZE;
251
252 DBG("Area %08lx..%08lx, %d blocks\n", res->start, res->end, size);
253
254 *val += size * sizeof(u32);
255 return val;
256}
257
258/* s3c2410_pm_prepare_check
259 *
260 * prepare the necessary information for creating the CRCs. This
261 * must be done before the final save, as it will require memory
262 * allocating, and thus touching bits of the kernel we do not
263 * know about.
264*/
265
266static void s3c2410_pm_check_prepare(void)
267{
268 crc_size = 0;
269
270 s3c2410_pm_run_sysram(s3c2410_pm_countram, &crc_size);
271
272 DBG("s3c2410_pm_prepare_check: %u checks needed\n", crc_size);
273
274 crcs = kmalloc(crc_size+4, GFP_KERNEL);
275 if (crcs == NULL)
276 printk(KERN_ERR "Cannot allocated CRC save area\n");
277}
278
279static u32 *s3c2410_pm_makecheck(struct resource *res, u32 *val)
280{
281 unsigned long addr, left;
282
283 for (addr = res->start; addr < res->end;
284 addr += CHECK_CHUNKSIZE) {
285 left = res->end - addr;
286
287 if (left > CHECK_CHUNKSIZE)
288 left = CHECK_CHUNKSIZE;
289
290 *val = crc32_le(~0, phys_to_virt(addr), left);
291 val++;
292 }
293
294 return val;
295}
296
297/* s3c2410_pm_check_store
298 *
299 * compute the CRC values for the memory blocks before the final
300 * sleep.
301*/
302
303static void s3c2410_pm_check_store(void)
304{
305 if (crcs != NULL)
306 s3c2410_pm_run_sysram(s3c2410_pm_makecheck, crcs);
307}
308
309/* in_region
310 *
311 * return TRUE if the area defined by ptr..ptr+size contatins the
312 * what..what+whatsz
313*/
314
315static inline int in_region(void *ptr, int size, void *what, size_t whatsz)
316{
317 if ((what+whatsz) < ptr)
318 return 0;
319
320 if (what > (ptr+size))
321 return 0;
322
323 return 1;
324}
325
326static u32 *s3c2410_pm_runcheck(struct resource *res, u32 *val)
327{
328 void *save_at = phys_to_virt(s3c2410_sleep_save_phys);
329 unsigned long addr;
330 unsigned long left;
331 void *ptr;
332 u32 calc;
333
334 for (addr = res->start; addr < res->end;
335 addr += CHECK_CHUNKSIZE) {
336 left = res->end - addr;
337
338 if (left > CHECK_CHUNKSIZE)
339 left = CHECK_CHUNKSIZE;
340
341 ptr = phys_to_virt(addr);
342
343 if (in_region(ptr, left, crcs, crc_size)) {
344 DBG("skipping %08lx, has crc block in\n", addr);
345 goto skip_check;
346 }
347
348 if (in_region(ptr, left, save_at, 32*4 )) {
349 DBG("skipping %08lx, has save block in\n", addr);
350 goto skip_check;
351 }
352
353 /* calculate and check the checksum */
354
355 calc = crc32_le(~0, ptr, left);
356 if (calc != *val) {
357 printk(KERN_ERR PFX "Restore CRC error at "
358 "%08lx (%08x vs %08x)\n", addr, calc, *val);
359
360 DBG("Restore CRC error at %08lx (%08x vs %08x)\n",
361 addr, calc, *val);
362 }
363
364 skip_check:
365 val++;
366 }
367
368 return val;
369}
370
371/* s3c2410_pm_check_restore
372 *
373 * check the CRCs after the restore event and free the memory used
374 * to hold them
375*/
376
377static void s3c2410_pm_check_restore(void)
378{
379 if (crcs != NULL) {
380 s3c2410_pm_run_sysram(s3c2410_pm_runcheck, crcs);
381 kfree(crcs);
382 crcs = NULL;
383 }
384}
385
386#else
387
388#define s3c2410_pm_check_prepare() do { } while(0)
389#define s3c2410_pm_check_restore() do { } while(0)
390#define s3c2410_pm_check_store() do { } while(0)
391#endif
392
393/* helper functions to save and restore register state */
394
395void s3c2410_pm_do_save(struct sleep_save *ptr, int count)
396{
397 for (; count > 0; count--, ptr++) {
398 ptr->val = __raw_readl(ptr->reg);
399 DBG("saved %p value %08lx\n", ptr->reg, ptr->val);
400 }
401}
402
403/* s3c2410_pm_do_restore
404 *
405 * restore the system from the given list of saved registers
406 *
407 * Note, we do not use DBG() in here, as the system may not have
408 * restore the UARTs state yet
409*/
410
411void s3c2410_pm_do_restore(struct sleep_save *ptr, int count)
412{
413 for (; count > 0; count--, ptr++) {
414 printk(KERN_DEBUG "restore %p (restore %08lx, was %08x)\n",
415 ptr->reg, ptr->val, __raw_readl(ptr->reg));
416
417 __raw_writel(ptr->val, ptr->reg);
418 }
419}
420
421/* s3c2410_pm_do_restore_core
422 *
423 * similar to s3c2410_pm_do_restore_core
424 *
425 * WARNING: Do not put any debug in here that may effect memory or use
426 * peripherals, as things may be changing!
427*/
428
429static void s3c2410_pm_do_restore_core(struct sleep_save *ptr, int count)
430{
431 for (; count > 0; count--, ptr++) {
432 __raw_writel(ptr->val, ptr->reg);
433 }
434}
435
436/* s3c2410_pm_show_resume_irqs
437 *
438 * print any IRQs asserted at resume time (ie, we woke from)
439*/
440
441static void s3c2410_pm_show_resume_irqs(int start, unsigned long which,
442 unsigned long mask)
443{
444 int i;
445
446 which &= ~mask;
447
448 for (i = 0; i <= 31; i++) {
449 if ((which) & (1L<<i)) {
450 DBG("IRQ %d asserted at resume\n", start+i);
451 }
452 }
453}
454
455/* s3c2410_pm_check_resume_pin
456 *
457 * check to see if the pin is configured correctly for sleep mode, and
458 * make any necessary adjustments if it is not
459*/
460
461static void s3c2410_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs)
462{
463 unsigned long irqstate;
464 unsigned long pinstate;
465 int irq = s3c2410_gpio_getirq(pin);
466
467 if (irqoffs < 4)
468 irqstate = s3c_irqwake_intmask & (1L<<irqoffs);
469 else
470 irqstate = s3c_irqwake_eintmask & (1L<<irqoffs);
471
472 pinstate = s3c2410_gpio_getcfg(pin);
473 pinstate >>= S3C2410_GPIO_OFFSET(pin)*2;
474
475 if (!irqstate) {
476 if (pinstate == 0x02)
477 DBG("Leaving IRQ %d (pin %d) enabled\n", irq, pin);
478 } else {
479 if (pinstate == 0x02) {
480 DBG("Disabling IRQ %d (pin %d)\n", irq, pin);
481 s3c2410_gpio_cfgpin(pin, 0x00);
482 }
483 }
484}
485
486/* s3c2410_pm_configure_extint
487 *
488 * configure all external interrupt pins
489*/
490
491static void s3c2410_pm_configure_extint(void)
492{
493 int pin;
494
495 /* for each of the external interrupts (EINT0..EINT15) we
496 * need to check wether it is an external interrupt source,
497 * and then configure it as an input if it is not
498 */
499
500 for (pin = S3C2410_GPF0; pin <= S3C2410_GPF7; pin++) {
501 s3c2410_pm_check_resume_pin(pin, pin - S3C2410_GPF0);
502 }
503
504 for (pin = S3C2410_GPG0; pin <= S3C2410_GPG7; pin++) {
505 s3c2410_pm_check_resume_pin(pin, (pin - S3C2410_GPG0)+8);
506 }
507}
508
509#define any_allowed(mask, allow) (((mask) & (allow)) != (allow))
510
511/* s3c2410_pm_enter
512 *
513 * central control for sleep/resume process
514*/
515
516static int s3c2410_pm_enter(suspend_state_t state)
517{
518 unsigned long regs_save[16];
519 unsigned long tmp;
520
521 /* ensure the debug is initialised (if enabled) */
522
523 s3c2410_pm_debug_init();
524
525 DBG("s3c2410_pm_enter(%d)\n", state);
526
527 if (state != PM_SUSPEND_MEM) {
528 printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n");
529 return -EINVAL;
530 }
531
532 /* check if we have anything to wake-up with... bad things seem
533 * to happen if you suspend with no wakeup (system will often
534 * require a full power-cycle)
535 */
536
537 if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) &&
538 !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) {
539 printk(KERN_ERR PFX "No sources enabled for wake-up!\n");
540 printk(KERN_ERR PFX "Aborting sleep\n");
541 return -EINVAL;
542 }
543
544 /* prepare check area if configured */
545
546 s3c2410_pm_check_prepare();
547
548 /* store the physical address of the register recovery block */
549
550 s3c2410_sleep_save_phys = virt_to_phys(regs_save);
551
552 DBG("s3c2410_sleep_save_phys=0x%08lx\n", s3c2410_sleep_save_phys);
553
554 /* ensure at least GESTATUS3 has the resume address */
555
556 __raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C2410_GSTATUS3);
557
558 DBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3));
559 DBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4));
560
561 /* save all necessary core registers not covered by the drivers */
562
563 s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save));
564 s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save));
565 s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save));
566 s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save));
567
568 /* set the irq configuration for wake */
569
570 s3c2410_pm_configure_extint();
571
572 DBG("sleep: irq wakeup masks: %08lx,%08lx\n",
573 s3c_irqwake_intmask, s3c_irqwake_eintmask);
574
575 __raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK);
576 __raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK);
577
578 /* ack any outstanding external interrupts before we go to sleep */
579
580 __raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND);
581
582 /* flush cache back to ram */
583
584 arm920_flush_kern_cache_all();
585
586 s3c2410_pm_check_store();
587
588 // need to make some form of time-delta
589
590 /* send the cpu to sleep... */
591
592 __raw_writel(0x00, S3C2410_CLKCON); /* turn off clocks over sleep */
593
594 s3c2410_cpu_suspend(regs_save);
595
596 /* unset the return-from-sleep flag, to ensure reset */
597
598 tmp = __raw_readl(S3C2410_GSTATUS2);
599 tmp &= S3C2410_GSTATUS2_OFFRESET;
600 __raw_writel(tmp, S3C2410_GSTATUS2);
601
602 /* restore the system state */
603
604 s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save));
605 s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save));
606 s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
607 s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save));
608
609 s3c2410_pm_debug_init();
610
611 /* check what irq (if any) restored the system */
612
613 DBG("post sleep: IRQs 0x%08x, 0x%08x\n",
614 __raw_readl(S3C2410_SRCPND),
615 __raw_readl(S3C2410_EINTPEND));
616
617 s3c2410_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND),
618 s3c_irqwake_intmask);
619
620 s3c2410_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND),
621 s3c_irqwake_eintmask);
622
623 DBG("post sleep, preparing to return\n");
624
625 s3c2410_pm_check_restore();
626
627 /* ok, let's return from sleep */
628
629 DBG("S3C2410 PM Resume (post-restore)\n");
630 return 0;
631}
632
633/*
634 * Called after processes are frozen, but before we shut down devices.
635 */
636static int s3c2410_pm_prepare(suspend_state_t state)
637{
638 return 0;
639}
640
641/*
642 * Called after devices are re-setup, but before processes are thawed.
643 */
644static int s3c2410_pm_finish(suspend_state_t state)
645{
646 return 0;
647}
648
649/*
650 * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
651 */
652static struct pm_ops s3c2410_pm_ops = {
653 .pm_disk_mode = PM_DISK_FIRMWARE,
654 .prepare = s3c2410_pm_prepare,
655 .enter = s3c2410_pm_enter,
656 .finish = s3c2410_pm_finish,
657};
658
659/* s3c2410_pm_init
660 *
661 * Attach the power management functions. This should be called
662 * from the board specific initialisation if the board supports
663 * it.
664*/
665
666int __init s3c2410_pm_init(void)
667{
668 printk("S3C2410 Power Management, (c) 2004 Simtec Electronics\n");
669
670 pm_set_ops(&s3c2410_pm_ops);
671 return 0;
672}
diff --git a/arch/arm/mach-s3c2410/pm.h b/arch/arm/mach-s3c2410/pm.h
new file mode 100644
index 000000000000..7a5e714c7386
--- /dev/null
+++ b/arch/arm/mach-s3c2410/pm.h
@@ -0,0 +1,59 @@
1/* linux/arch/arm/mach-s3c2410/pm.h
2 *
3 * Copyright (c) 2004 Simtec Electronics
4 * Written by 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 version 2 as
8 * published by the Free Software Foundation.
9*/
10
11/* s3c2410_pm_init
12 *
13 * called from board at initialisation time to setup the power
14 * management
15*/
16
17#ifdef CONFIG_PM
18
19extern __init int s3c2410_pm_init(void);
20
21#else
22
23static inline int s3c2410_pm_init(void)
24{
25 return 0;
26}
27#endif
28
29/* configuration for the IRQ mask over sleep */
30extern unsigned long s3c_irqwake_intmask;
31extern unsigned long s3c_irqwake_eintmask;
32
33/* IRQ masks for IRQs allowed to go to sleep (see irq.c) */
34extern unsigned long s3c_irqwake_intallow;
35extern unsigned long s3c_irqwake_eintallow;
36
37/* Flags for PM Control */
38
39extern unsigned long s3c_pm_flags;
40
41/* from sleep.S */
42
43extern void s3c2410_cpu_suspend(unsigned long *saveblk);
44extern void s3c2410_cpu_resume(void);
45
46extern unsigned long s3c2410_sleep_save_phys;
47
48/* sleep save info */
49
50struct sleep_save {
51 void __iomem *reg;
52 unsigned long val;
53};
54
55#define SAVE_ITEM(x) \
56 { .reg = (x) }
57
58extern void s3c2410_pm_do_save(struct sleep_save *ptr, int count);
59extern void s3c2410_pm_do_restore(struct sleep_save *ptr, int count);
diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c
new file mode 100644
index 000000000000..ff2f25409e44
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2410.c
@@ -0,0 +1,200 @@
1/* linux/arch/arm/mach-s3c2410/s3c2410.c
2 *
3 * Copyright (c) 2003-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * http://www.simtec.co.uk/products/EB2410ITX/
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 version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Modifications:
13 * 16-May-2003 BJD Created initial version
14 * 16-Aug-2003 BJD Fixed header files and copyright, added URL
15 * 05-Sep-2003 BJD Moved to kernel v2.6
16 * 18-Jan-2004 BJD Added serial port configuration
17 * 21-Aug-2004 BJD Added new struct s3c2410_board handler
18 * 28-Sep-2004 BJD Updates for new serial port bits
19 * 04-Nov-2004 BJD Updated UART configuration process
20 * 10-Jan-2005 BJD Removed s3c2410_clock_tick_rate
21*/
22
23#include <linux/kernel.h>
24#include <linux/types.h>
25#include <linux/interrupt.h>
26#include <linux/list.h>
27#include <linux/timer.h>
28#include <linux/init.h>
29#include <linux/device.h>
30
31#include <asm/mach/arch.h>
32#include <asm/mach/map.h>
33#include <asm/mach/irq.h>
34
35#include <asm/hardware.h>
36#include <asm/io.h>
37#include <asm/irq.h>
38
39#include <asm/arch/regs-clock.h>
40#include <asm/arch/regs-serial.h>
41
42#include "s3c2410.h"
43#include "cpu.h"
44#include "clock.h"
45
46/* Initial IO mappings */
47
48static struct map_desc s3c2410_iodesc[] __initdata = {
49 IODESC_ENT(USBHOST),
50 IODESC_ENT(CLKPWR),
51 IODESC_ENT(LCD),
52 IODESC_ENT(UART),
53 IODESC_ENT(TIMER),
54 IODESC_ENT(ADC),
55 IODESC_ENT(WATCHDOG)
56};
57
58static struct resource s3c_uart0_resource[] = {
59 [0] = {
60 .start = S3C2410_PA_UART0,
61 .end = S3C2410_PA_UART0 + 0x3fff,
62 .flags = IORESOURCE_MEM,
63 },
64 [1] = {
65 .start = IRQ_S3CUART_RX0,
66 .end = IRQ_S3CUART_ERR0,
67 .flags = IORESOURCE_IRQ,
68 }
69
70};
71
72static struct resource s3c_uart1_resource[] = {
73 [0] = {
74 .start = S3C2410_PA_UART1,
75 .end = S3C2410_PA_UART1 + 0x3fff,
76 .flags = IORESOURCE_MEM,
77 },
78 [1] = {
79 .start = IRQ_S3CUART_RX1,
80 .end = IRQ_S3CUART_ERR1,
81 .flags = IORESOURCE_IRQ,
82 }
83};
84
85static struct resource s3c_uart2_resource[] = {
86 [0] = {
87 .start = S3C2410_PA_UART2,
88 .end = S3C2410_PA_UART2 + 0x3fff,
89 .flags = IORESOURCE_MEM,
90 },
91 [1] = {
92 .start = IRQ_S3CUART_RX2,
93 .end = IRQ_S3CUART_ERR2,
94 .flags = IORESOURCE_IRQ,
95 }
96};
97
98/* our uart devices */
99
100static struct platform_device s3c_uart0 = {
101 .name = "s3c2410-uart",
102 .id = 0,
103 .num_resources = ARRAY_SIZE(s3c_uart0_resource),
104 .resource = s3c_uart0_resource,
105};
106
107
108static struct platform_device s3c_uart1 = {
109 .name = "s3c2410-uart",
110 .id = 1,
111 .num_resources = ARRAY_SIZE(s3c_uart1_resource),
112 .resource = s3c_uart1_resource,
113};
114
115static struct platform_device s3c_uart2 = {
116 .name = "s3c2410-uart",
117 .id = 2,
118 .num_resources = ARRAY_SIZE(s3c_uart2_resource),
119 .resource = s3c_uart2_resource,
120};
121
122static struct platform_device *uart_devices[] __initdata = {
123 &s3c_uart0,
124 &s3c_uart1,
125 &s3c_uart2
126};
127
128/* store our uart devices for the serial driver console */
129struct platform_device *s3c2410_uart_devices[3];
130
131static int s3c2410_uart_count = 0;
132
133/* uart registration process */
134
135void __init s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no)
136{
137 struct platform_device *platdev;
138 int uart;
139
140 for (uart = 0; uart < no; uart++, cfg++) {
141 platdev = uart_devices[cfg->hwport];
142
143 s3c24xx_uart_devs[uart] = platdev;
144 platdev->dev.platform_data = cfg;
145 }
146
147 s3c2410_uart_count = uart;
148}
149
150/* s3c2410_map_io
151 *
152 * register the standard cpu IO areas, and any passed in from the
153 * machine specific initialisation.
154*/
155
156void __init s3c2410_map_io(struct map_desc *mach_desc, int mach_size)
157{
158 /* register our io-tables */
159
160 iotable_init(s3c2410_iodesc, ARRAY_SIZE(s3c2410_iodesc));
161 iotable_init(mach_desc, mach_size);
162}
163
164void __init s3c2410_init_clocks(int xtal)
165{
166 unsigned long tmp;
167 unsigned long fclk;
168 unsigned long hclk;
169 unsigned long pclk;
170
171 /* now we've got our machine bits initialised, work out what
172 * clocks we've got */
173
174 fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal);
175
176 tmp = __raw_readl(S3C2410_CLKDIVN);
177
178 /* work out clock scalings */
179
180 hclk = fclk / ((tmp & S3C2410_CLKDIVN_HDIVN) ? 2 : 1);
181 pclk = hclk / ((tmp & S3C2410_CLKDIVN_PDIVN) ? 2 : 1);
182
183 /* print brieft summary of clocks, etc */
184
185 printk("S3C2410: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
186 print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
187
188 /* initialise the clocks here, to allow other things like the
189 * console to use them
190 */
191
192 s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
193}
194
195int __init s3c2410_init(void)
196{
197 printk("S3C2410: Initialising architecture\n");
198
199 return platform_add_devices(s3c24xx_uart_devs, s3c2410_uart_count);
200}
diff --git a/arch/arm/mach-s3c2410/s3c2410.h b/arch/arm/mach-s3c2410/s3c2410.h
new file mode 100644
index 000000000000..4d5312a48209
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2410.h
@@ -0,0 +1,37 @@
1/* arch/arm/mach-s3c2410/s3c2410.h
2 *
3 * Copyright (c) 2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * Header file for s3c2410 machine directory
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 version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Modifications:
13 * 18-Aug-2004 BJD Created initial version
14 * 20-Aug-2004 BJD Added s3c2410_board struct
15 * 04-Sep-2004 BJD Added s3c2410_init_uarts() call
16 * 17-Oct-2004 BJD Moved board out to cpu
17 * 04-Jan-2005 BJD Changed uart init
18 * 10-Jan-2005 BJD Removed timer to cpu.h, moved 2410 specific bits here
19 * 14-Jan-2005 BJD Added s3c2410_init_clocks call
20*/
21
22#ifdef CONFIG_CPU_S3C2410
23
24extern int s3c2410_init(void);
25
26extern void s3c2410_map_io(struct map_desc *mach_desc, int size);
27
28extern void s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no);
29
30extern void s3c2410_init_clocks(int xtal);
31
32#else
33#define s3c2410_init_clocks NULL
34#define s3c2410_init_uarts NULL
35#define s3c2410_map_io NULL
36#define s3c2410_init NULL
37#endif
diff --git a/arch/arm/mach-s3c2410/s3c2440-dsc.c b/arch/arm/mach-s3c2410/s3c2440-dsc.c
new file mode 100644
index 000000000000..16fa2a3b38fa
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2440-dsc.c
@@ -0,0 +1,59 @@
1/* linux/arch/arm/mach-s3c2410/s3c2440-dsc.c
2 *
3 * Copyright (c) 2004-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * Samsung S3C2440 Drive Strength 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 version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Modifications:
13 * 29-Aug-2004 BJD Start of drive-strength control
14 * 09-Nov-2004 BJD Added symbol export
15 * 11-Jan-2005 BJD Include fix
16*/
17
18#include <linux/kernel.h>
19#include <linux/types.h>
20#include <linux/interrupt.h>
21#include <linux/init.h>
22#include <linux/module.h>
23
24#include <asm/mach/arch.h>
25#include <asm/mach/map.h>
26#include <asm/mach/irq.h>
27
28#include <asm/hardware.h>
29#include <asm/io.h>
30#include <asm/irq.h>
31
32#include <asm/arch/regs-gpio.h>
33#include <asm/arch/regs-dsc.h>
34
35#include "cpu.h"
36#include "s3c2440.h"
37
38int s3c2440_set_dsc(unsigned int pin, unsigned int value)
39{
40 void __iomem *base;
41 unsigned long val;
42 unsigned long flags;
43 unsigned long mask;
44
45 base = (pin & S3C2440_SELECT_DSC1) ? S3C2440_DSC1 : S3C2440_DSC0;
46 mask = 3 << S3C2440_DSC_GETSHIFT(pin);
47
48 local_irq_save(flags);
49
50 val = __raw_readl(base);
51 val &= ~mask;
52 val |= value & mask;
53 __raw_writel(val, base);
54
55 local_irq_restore(flags);
56 return 0;
57}
58
59EXPORT_SYMBOL(s3c2440_set_dsc);
diff --git a/arch/arm/mach-s3c2410/s3c2440.c b/arch/arm/mach-s3c2410/s3c2440.c
new file mode 100644
index 000000000000..9a8cc5ae2255
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2440.c
@@ -0,0 +1,281 @@
1/* linux/arch/arm/mach-s3c2410/s3c2440.c
2 *
3 * Copyright (c) 2004-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * Samsung S3C2440 Mobile CPU 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 version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Modifications:
13 * 24-Aug-2004 BJD Start of s3c2440 support
14 * 12-Oct-2004 BJD Moved clock info out to clock.c
15 * 01-Nov-2004 BJD Fixed clock build code
16 * 09-Nov-2004 BJD Added sysdev for power management
17 * 04-Nov-2004 BJD New serial registration
18 * 15-Nov-2004 BJD Rename the i2c device for the s3c2440
19 * 14-Jan-2005 BJD Moved clock init code into seperate function
20 * 14-Jan-2005 BJD Removed un-used clock bits
21*/
22
23#include <linux/kernel.h>
24#include <linux/types.h>
25#include <linux/interrupt.h>
26#include <linux/list.h>
27#include <linux/timer.h>
28#include <linux/init.h>
29#include <linux/device.h>
30#include <linux/sysdev.h>
31
32#include <asm/mach/arch.h>
33#include <asm/mach/map.h>
34#include <asm/mach/irq.h>
35
36#include <asm/hardware.h>
37#include <asm/io.h>
38#include <asm/irq.h>
39#include <asm/hardware/clock.h>
40
41#include <asm/arch/regs-clock.h>
42#include <asm/arch/regs-serial.h>
43#include <asm/arch/regs-gpio.h>
44#include <asm/arch/regs-gpioj.h>
45#include <asm/arch/regs-dsc.h>
46
47#include "s3c2440.h"
48#include "clock.h"
49#include "devs.h"
50#include "cpu.h"
51#include "pm.h"
52
53
54static struct map_desc s3c2440_iodesc[] __initdata = {
55 IODESC_ENT(USBHOST),
56 IODESC_ENT(CLKPWR),
57 IODESC_ENT(LCD),
58 IODESC_ENT(TIMER),
59 IODESC_ENT(ADC),
60 IODESC_ENT(WATCHDOG),
61};
62
63static struct resource s3c_uart0_resource[] = {
64 [0] = {
65 .start = S3C2410_PA_UART0,
66 .end = S3C2410_PA_UART0 + 0x3fff,
67 .flags = IORESOURCE_MEM,
68 },
69 [1] = {
70 .start = IRQ_S3CUART_RX0,
71 .end = IRQ_S3CUART_ERR0,
72 .flags = IORESOURCE_IRQ,
73 }
74
75};
76
77static struct resource s3c_uart1_resource[] = {
78 [0] = {
79 .start = S3C2410_PA_UART1,
80 .end = S3C2410_PA_UART1 + 0x3fff,
81 .flags = IORESOURCE_MEM,
82 },
83 [1] = {
84 .start = IRQ_S3CUART_RX1,
85 .end = IRQ_S3CUART_ERR1,
86 .flags = IORESOURCE_IRQ,
87 }
88};
89
90static struct resource s3c_uart2_resource[] = {
91 [0] = {
92 .start = S3C2410_PA_UART2,
93 .end = S3C2410_PA_UART2 + 0x3fff,
94 .flags = IORESOURCE_MEM,
95 },
96 [1] = {
97 .start = IRQ_S3CUART_RX2,
98 .end = IRQ_S3CUART_ERR2,
99 .flags = IORESOURCE_IRQ,
100 }
101};
102
103/* our uart devices */
104
105static struct platform_device s3c_uart0 = {
106 .name = "s3c2440-uart",
107 .id = 0,
108 .num_resources = ARRAY_SIZE(s3c_uart0_resource),
109 .resource = s3c_uart0_resource,
110};
111
112static struct platform_device s3c_uart1 = {
113 .name = "s3c2440-uart",
114 .id = 1,
115 .num_resources = ARRAY_SIZE(s3c_uart1_resource),
116 .resource = s3c_uart1_resource,
117};
118
119static struct platform_device s3c_uart2 = {
120 .name = "s3c2440-uart",
121 .id = 2,
122 .num_resources = ARRAY_SIZE(s3c_uart2_resource),
123 .resource = s3c_uart2_resource,
124};
125
126static struct platform_device *uart_devices[] __initdata = {
127 &s3c_uart0,
128 &s3c_uart1,
129 &s3c_uart2
130};
131
132/* uart initialisation */
133
134static int __initdata s3c2440_uart_count;
135
136void __init s3c2440_init_uarts(struct s3c2410_uartcfg *cfg, int no)
137{
138 struct platform_device *platdev;
139 int uart;
140
141 for (uart = 0; uart < no; uart++, cfg++) {
142 platdev = uart_devices[cfg->hwport];
143
144 s3c24xx_uart_devs[uart] = platdev;
145 platdev->dev.platform_data = cfg;
146 }
147
148 s3c2440_uart_count = uart;
149}
150
151
152#ifdef CONFIG_PM
153
154struct sleep_save s3c2440_sleep[] = {
155 SAVE_ITEM(S3C2440_DSC0),
156 SAVE_ITEM(S3C2440_DSC1),
157 SAVE_ITEM(S3C2440_GPJDAT),
158 SAVE_ITEM(S3C2440_GPJCON),
159 SAVE_ITEM(S3C2440_GPJUP)
160};
161
162static int s3c2440_suspend(struct sys_device *dev, pm_message_t state)
163{
164 s3c2410_pm_do_save(s3c2440_sleep, ARRAY_SIZE(s3c2440_sleep));
165 return 0;
166}
167
168static int s3c2440_resume(struct sys_device *dev)
169{
170 s3c2410_pm_do_restore(s3c2440_sleep, ARRAY_SIZE(s3c2440_sleep));
171 return 0;
172}
173
174#else
175#define s3c2440_suspend NULL
176#define s3c2440_resume NULL
177#endif
178
179struct sysdev_class s3c2440_sysclass = {
180 set_kset_name("s3c2440-core"),
181 .suspend = s3c2440_suspend,
182 .resume = s3c2440_resume
183};
184
185static struct sys_device s3c2440_sysdev = {
186 .cls = &s3c2440_sysclass,
187};
188
189void __init s3c2440_map_io(struct map_desc *mach_desc, int size)
190{
191 /* register our io-tables */
192
193 iotable_init(s3c2440_iodesc, ARRAY_SIZE(s3c2440_iodesc));
194 iotable_init(mach_desc, size);
195 /* rename any peripherals used differing from the s3c2410 */
196
197 s3c_device_i2c.name = "s3c2440-i2c";
198
199 /* change irq for watchdog */
200
201 s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT;
202 s3c_device_wdt.resource[1].end = IRQ_S3C2440_WDT;
203}
204
205void __init s3c2440_init_clocks(int xtal)
206{
207 unsigned long clkdiv;
208 unsigned long camdiv;
209 unsigned long hclk, fclk, pclk;
210 int hdiv = 1;
211
212 /* now we've got our machine bits initialised, work out what
213 * clocks we've got */
214
215 fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal) * 2;
216
217 clkdiv = __raw_readl(S3C2410_CLKDIVN);
218 camdiv = __raw_readl(S3C2440_CAMDIVN);
219
220 /* work out clock scalings */
221
222 switch (clkdiv & S3C2440_CLKDIVN_HDIVN_MASK) {
223 case S3C2440_CLKDIVN_HDIVN_1:
224 hdiv = 1;
225 break;
226
227 case S3C2440_CLKDIVN_HDIVN_2:
228 hdiv = 1;
229 break;
230
231 case S3C2440_CLKDIVN_HDIVN_4_8:
232 hdiv = (camdiv & S3C2440_CAMDIVN_HCLK4_HALF) ? 8 : 4;
233 break;
234
235 case S3C2440_CLKDIVN_HDIVN_3_6:
236 hdiv = (camdiv & S3C2440_CAMDIVN_HCLK3_HALF) ? 6 : 3;
237 break;
238 }
239
240 hclk = fclk / hdiv;
241 pclk = hclk / ((clkdiv & S3C2440_CLKDIVN_PDIVN)? 2:1);
242
243 /* print brief summary of clocks, etc */
244
245 printk("S3C2440: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
246 print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
247
248 /* initialise the clocks here, to allow other things like the
249 * console to use them, and to add new ones after the initialisation
250 */
251
252 s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
253}
254
255/* need to register class before we actually register the device, and
256 * we also need to ensure that it has been initialised before any of the
257 * drivers even try to use it (even if not on an s3c2440 based system)
258 * as a driver which may support both 2410 and 2440 may try and use it.
259*/
260
261int __init s3c2440_core_init(void)
262{
263 return sysdev_class_register(&s3c2440_sysclass);
264}
265
266core_initcall(s3c2440_core_init);
267
268int __init s3c2440_init(void)
269{
270 int ret;
271
272 printk("S3C2440: Initialising architecture\n");
273
274 ret = sysdev_register(&s3c2440_sysdev);
275 if (ret != 0)
276 printk(KERN_ERR "failed to register sysdev for s3c2440\n");
277 else
278 ret = platform_add_devices(s3c24xx_uart_devs, s3c2440_uart_count);
279
280 return ret;
281}
diff --git a/arch/arm/mach-s3c2410/s3c2440.h b/arch/arm/mach-s3c2410/s3c2440.h
new file mode 100644
index 000000000000..29cb6df65a48
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2440.h
@@ -0,0 +1,35 @@
1/* arch/arm/mach-s3c2410/s3c2440.h
2 *
3 * Copyright (c) 2004-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * Header file for s3c2440 cpu 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 version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Modifications:
13 * 24-Aug-2004 BJD Start of S3C2440 CPU support
14 * 04-Nov-2004 BJD Added s3c2440_init_uarts()
15 * 04-Jan-2005 BJD Moved uart init to cpu code
16 * 10-Jan-2005 BJD Moved 2440 specific init here
17 * 14-Jan-2005 BJD Split the clock initialisation code
18*/
19
20#ifdef CONFIG_CPU_S3C2440
21
22extern int s3c2440_init(void);
23
24extern void s3c2440_map_io(struct map_desc *mach_desc, int size);
25
26extern void s3c2440_init_uarts(struct s3c2410_uartcfg *cfg, int no);
27
28extern void s3c2440_init_clocks(int xtal);
29
30#else
31#define s3c2440_init_clocks NULL
32#define s3c2440_init_uarts NULL
33#define s3c2440_map_io NULL
34#define s3c2440_init NULL
35#endif
diff --git a/arch/arm/mach-s3c2410/sleep.S b/arch/arm/mach-s3c2410/sleep.S
new file mode 100644
index 000000000000..61768dac7fee
--- /dev/null
+++ b/arch/arm/mach-s3c2410/sleep.S
@@ -0,0 +1,180 @@
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/config.h>
28#include <linux/linkage.h>
29#include <asm/assembler.h>
30#include <asm/hardware.h>
31#include <asm/arch/map.h>
32
33#include <asm/arch/regs-gpio.h>
34#include <asm/arch/regs-clock.h>
35#include <asm/arch/regs-mem.h>
36#include <asm/arch/regs-serial.h>
37
38/* CONFIG_DEBUG_RESUME is dangerous if your bootloader does not
39 * reset the UART configuration, only enable if you really need this!
40*/
41//#define CONFIG_DEBUG_RESUME
42
43 .text
44
45 /* s3c2410_cpu_suspend
46 *
47 * put the cpu into sleep mode
48 *
49 * entry:
50 * r0 = sleep save block
51 */
52
53ENTRY(s3c2410_cpu_suspend)
54 stmfd sp!, { r4 - r12, lr }
55
56 @@ store co-processor registers
57
58 mrc p15, 0, r4, c15, c1, 0 @ CP access register
59 mrc p15, 0, r5, c13, c0, 0 @ PID
60 mrc p15, 0, r6, c3, c0, 0 @ Domain ID
61 mrc p15, 0, r7, c2, c0, 0 @ translation table base address
62 mrc p15, 0, r8, c2, c0, 0 @ auxiliary control register
63 mrc p15, 0, r9, c1, c0, 0 @ control register
64
65 stmia r0, { r4 - r13 }
66
67 @@ flush the caches to ensure everything is back out to
68 @@ SDRAM before the core powers down
69
70 bl arm920_flush_kern_cache_all
71
72 @@ prepare cpu to sleep
73
74 ldr r4, =S3C2410_REFRESH
75 ldr r5, =S3C2410_MISCCR
76 ldr r6, =S3C2410_CLKCON
77 ldr r7, [ r4 ] @ get REFRESH (and ensure in TLB)
78 ldr r8, [ r5 ] @ get MISCCR (and ensure in TLB)
79 ldr r9, [ r6 ] @ get CLKCON (and ensure in TLB)
80
81 orr r7, r7, #S3C2410_REFRESH_SELF @ SDRAM sleep command
82 orr r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals
83 orr r9, r9, #S3C2410_CLKCON_POWER @ power down command
84
85 teq pc, #0 @ first as a trial-run to load cache
86 bl s3c2410_do_sleep
87 teq r0, r0 @ now do it for real
88 b s3c2410_do_sleep @
89
90 @@ align next bit of code to cache line
91 .align 8
92s3c2410_do_sleep:
93 streq r7, [ r4 ] @ SDRAM sleep command
94 streq r8, [ r5 ] @ SDRAM power-down config
95 streq r9, [ r6 ] @ CPU sleep
961: beq 1b
97 mov pc, r14
98
99 @@ return to the caller, after having the MMU
100 @@ turned on, this restores the last bits from the
101 @@ stack
102resume_with_mmu:
103 ldmfd sp!, { r4 - r12, pc }
104
105 .ltorg
106
107 @@ the next bits sit in the .data segment, even though they
108 @@ happen to be code... the s3c2410_sleep_save_phys needs to be
109 @@ accessed by the resume code before it can restore the MMU.
110 @@ This means that the variable has to be close enough for the
111 @@ code to read it... since the .text segment needs to be RO,
112 @@ the data segment can be the only place to put this code.
113
114 .data
115
116 .global s3c2410_sleep_save_phys
117s3c2410_sleep_save_phys:
118 .word 0
119
120 /* s3c2410_cpu_resume
121 *
122 * resume code entry for bootloader to call
123 *
124 * we must put this code here in the data segment as we have no
125 * other way of restoring the stack pointer after sleep, and we
126 * must not write to the code segment (code is read-only)
127 */
128
129ENTRY(s3c2410_cpu_resume)
130 mov r0, #PSR_I_BIT | PSR_F_BIT | MODE_SVC
131 msr cpsr_c, r0
132
133 @@ load UART to allow us to print the two characters for
134 @@ resume debug
135
136 mov r2, #S3C2410_PA_UART & 0xff000000
137 orr r2, r2, #S3C2410_PA_UART & 0xff000
138
139#if 0
140 /* SMDK2440 LED set */
141 mov r14, #S3C2410_PA_GPIO
142 ldr r12, [ r14, #0x54 ]
143 bic r12, r12, #3<<4
144 orr r12, r12, #1<<7
145 str r12, [ r14, #0x54 ]
146#endif
147
148#ifdef CONFIG_DEBUG_RESUME
149 mov r3, #'L'
150 strb r3, [ r2, #S3C2410_UTXH ]
1511001:
152 ldrb r14, [ r3, #S3C2410_UTRSTAT ]
153 tst r14, #S3C2410_UTRSTAT_TXE
154 beq 1001b
155#endif /* CONFIG_DEBUG_RESUME */
156
157 mov r1, #0
158 mcr p15, 0, r1, c8, c7, 0 @@ invalidate I & D TLBs
159 mcr p15, 0, r1, c7, c7, 0 @@ invalidate I & D caches
160
161 ldr r0, s3c2410_sleep_save_phys @ address of restore block
162 ldmia r0, { r4 - r13 }
163
164 mcr p15, 0, r4, c15, c1, 0 @ CP access register
165 mcr p15, 0, r5, c13, c0, 0 @ PID
166 mcr p15, 0, r6, c3, c0, 0 @ Domain ID
167 mcr p15, 0, r7, c2, c0, 0 @ translation table base
168 mcr p15, 0, r8, c1, c1, 0 @ auxilliary control
169
170#ifdef CONFIG_DEBUG_RESUME
171 mov r3, #'R'
172 strb r3, [ r2, #S3C2410_UTXH ]
173#endif
174
175 ldr r2, =resume_with_mmu
176 mcr p15, 0, r9, c1, c0, 0 @ turn on MMU, etc
177 nop @ second-to-last before mmu
178 mov pc, r2 @ go back to virtual address
179
180 .ltorg
diff --git a/arch/arm/mach-s3c2410/time.c b/arch/arm/mach-s3c2410/time.c
new file mode 100644
index 000000000000..179f0e031af4
--- /dev/null
+++ b/arch/arm/mach-s3c2410/time.c
@@ -0,0 +1,256 @@
1/* linux/arch/arm/mach-s3c2410/time.c
2 *
3 * Copyright (C) 2003-2005 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#include <linux/config.h>
22#include <linux/kernel.h>
23#include <linux/sched.h>
24#include <linux/init.h>
25#include <linux/interrupt.h>
26#include <linux/err.h>
27
28#include <asm/system.h>
29#include <asm/leds.h>
30#include <asm/mach-types.h>
31
32#include <asm/io.h>
33#include <asm/irq.h>
34#include <asm/arch/map.h>
35#include <asm/arch/regs-timer.h>
36#include <asm/arch/regs-irq.h>
37#include <asm/mach/time.h>
38#include <asm/hardware/clock.h>
39
40#include "clock.h"
41
42static unsigned long timer_startval;
43static unsigned long timer_usec_ticks;
44
45#define TIMER_USEC_SHIFT 16
46
47/* we use the shifted arithmetic to work out the ratio of timer ticks
48 * to usecs, as often the peripheral clock is not a nice even multiple
49 * of 1MHz.
50 *
51 * shift of 14 and 15 are too low for the 12MHz, 16 seems to be ok
52 * for the current HZ value of 200 without producing overflows.
53 *
54 * Original patch by Dimitry Andric, updated by Ben Dooks
55*/
56
57
58/* timer_mask_usec_ticks
59 *
60 * given a clock and divisor, make the value to pass into timer_ticks_to_usec
61 * to scale the ticks into usecs
62*/
63
64static inline unsigned long
65timer_mask_usec_ticks(unsigned long scaler, unsigned long pclk)
66{
67 unsigned long den = pclk / 1000;
68
69 return ((1000 << TIMER_USEC_SHIFT) * scaler + (den >> 1)) / den;
70}
71
72/* timer_ticks_to_usec
73 *
74 * convert timer ticks to usec.
75*/
76
77static inline unsigned long timer_ticks_to_usec(unsigned long ticks)
78{
79 unsigned long res;
80
81 res = ticks * timer_usec_ticks;
82 res += 1 << (TIMER_USEC_SHIFT - 4); /* round up slightly */
83
84 return res >> TIMER_USEC_SHIFT;
85}
86
87/***
88 * Returns microsecond since last clock interrupt. Note that interrupts
89 * will have been disabled by do_gettimeoffset()
90 * IRQs are disabled before entering here from do_gettimeofday()
91 */
92
93#define SRCPND_TIMER4 (1<<(IRQ_TIMER4 - IRQ_EINT0))
94
95static unsigned long s3c2410_gettimeoffset (void)
96{
97 unsigned long tdone;
98 unsigned long irqpend;
99 unsigned long tval;
100
101 /* work out how many ticks have gone since last timer interrupt */
102
103 tval = __raw_readl(S3C2410_TCNTO(4));
104 tdone = timer_startval - tval;
105
106 /* check to see if there is an interrupt pending */
107
108 irqpend = __raw_readl(S3C2410_SRCPND);
109 if (irqpend & SRCPND_TIMER4) {
110 /* re-read the timer, and try and fix up for the missed
111 * interrupt. Note, the interrupt may go off before the
112 * timer has re-loaded from wrapping.
113 */
114
115 tval = __raw_readl(S3C2410_TCNTO(4));
116 tdone = timer_startval - tval;
117
118 if (tval != 0)
119 tdone += timer_startval;
120 }
121
122 return timer_ticks_to_usec(tdone);
123}
124
125
126/*
127 * IRQ handler for the timer
128 */
129static irqreturn_t
130s3c2410_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
131{
132 write_seqlock(&xtime_lock);
133 timer_tick(regs);
134 write_sequnlock(&xtime_lock);
135 return IRQ_HANDLED;
136}
137
138static struct irqaction s3c2410_timer_irq = {
139 .name = "S3C2410 Timer Tick",
140 .flags = SA_INTERRUPT,
141 .handler = s3c2410_timer_interrupt
142};
143
144/*
145 * Set up timer interrupt, and return the current time in seconds.
146 *
147 * Currently we only use timer4, as it is the only timer which has no
148 * other function that can be exploited externally
149 */
150static void s3c2410_timer_setup (void)
151{
152 unsigned long tcon;
153 unsigned long tcnt;
154 unsigned long tcfg1;
155 unsigned long tcfg0;
156
157 tcnt = 0xffff; /* default value for tcnt */
158
159 /* read the current timer configuration bits */
160
161 tcon = __raw_readl(S3C2410_TCON);
162 tcfg1 = __raw_readl(S3C2410_TCFG1);
163 tcfg0 = __raw_readl(S3C2410_TCFG0);
164
165 /* configure the system for whichever machine is in use */
166
167 if (machine_is_bast() || machine_is_vr1000()) {
168 /* timer is at 12MHz, scaler is 1 */
169 timer_usec_ticks = timer_mask_usec_ticks(1, 12000000);
170 tcnt = 12000000 / HZ;
171
172 tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
173 tcfg1 |= S3C2410_TCFG1_MUX4_TCLK1;
174 } else {
175 unsigned long pclk;
176 struct clk *clk;
177
178 /* for the h1940 (and others), we use the pclk from the core
179 * to generate the timer values. since values around 50 to
180 * 70MHz are not values we can directly generate the timer
181 * value from, we need to pre-scale and divide before using it.
182 *
183 * for instance, using 50.7MHz and dividing by 6 gives 8.45MHz
184 * (8.45 ticks per usec)
185 */
186
187 /* this is used as default if no other timer can be found */
188
189 clk = clk_get(NULL, "timers");
190 if (IS_ERR(clk))
191 panic("failed to get clock for system timer");
192
193 clk_use(clk);
194 clk_enable(clk);
195
196 pclk = clk_get_rate(clk);
197
198 /* configure clock tick */
199
200 timer_usec_ticks = timer_mask_usec_ticks(6, pclk);
201
202 tcfg1 &= ~S3C2410_TCFG1_MUX4_MASK;
203 tcfg1 |= S3C2410_TCFG1_MUX4_DIV2;
204
205 tcfg0 &= ~S3C2410_TCFG_PRESCALER1_MASK;
206 tcfg0 |= ((6 - 1) / 2) << S3C2410_TCFG_PRESCALER1_SHIFT;
207
208 tcnt = (pclk / 6) / HZ;
209 }
210
211 /* timers reload after counting zero, so reduce the count by 1 */
212
213 tcnt--;
214
215 printk("timer tcon=%08lx, tcnt %04lx, tcfg %08lx,%08lx, usec %08lx\n",
216 tcon, tcnt, tcfg0, tcfg1, timer_usec_ticks);
217
218 /* check to see if timer is within 16bit range... */
219 if (tcnt > 0xffff) {
220 panic("setup_timer: HZ is too small, cannot configure timer!");
221 return;
222 }
223
224 __raw_writel(tcfg1, S3C2410_TCFG1);
225 __raw_writel(tcfg0, S3C2410_TCFG0);
226
227 timer_startval = tcnt;
228 __raw_writel(tcnt, S3C2410_TCNTB(4));
229
230 /* ensure timer is stopped... */
231
232 tcon &= ~(7<<20);
233 tcon |= S3C2410_TCON_T4RELOAD;
234 tcon |= S3C2410_TCON_T4MANUALUPD;
235
236 __raw_writel(tcon, S3C2410_TCON);
237 __raw_writel(tcnt, S3C2410_TCNTB(4));
238 __raw_writel(tcnt, S3C2410_TCMPB(4));
239
240 /* start the timer running */
241 tcon |= S3C2410_TCON_T4START;
242 tcon &= ~S3C2410_TCON_T4MANUALUPD;
243 __raw_writel(tcon, S3C2410_TCON);
244}
245
246static void __init s3c2410_timer_init (void)
247{
248 s3c2410_timer_setup();
249 setup_irq(IRQ_TIMER4, &s3c2410_timer_irq);
250}
251
252struct sys_timer s3c24xx_timer = {
253 .init = s3c2410_timer_init,
254 .offset = s3c2410_gettimeoffset,
255 .resume = s3c2410_timer_setup
256};
diff --git a/arch/arm/mach-s3c2410/usb-simtec.c b/arch/arm/mach-s3c2410/usb-simtec.c
new file mode 100644
index 000000000000..7f2b61362976
--- /dev/null
+++ b/arch/arm/mach-s3c2410/usb-simtec.c
@@ -0,0 +1,113 @@
1/* linux/arch/arm/mach-s3c2410/usb-simtec.c
2 *
3 * Copyright (c) 2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * http://www.simtec.co.uk/products/EB2410ITX/
7 *
8 * Simtec BAST and Thorcom VR1000 USB port support functions
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 * Modifications:
15 * 14-Sep-2004 BJD Created
16 * 18-Oct-2004 BJD Cleanups, and added code to report OC cleared
17*/
18
19#define DEBUG
20
21#include <linux/kernel.h>
22#include <linux/types.h>
23#include <linux/interrupt.h>
24#include <linux/list.h>
25#include <linux/timer.h>
26#include <linux/init.h>
27#include <linux/device.h>
28
29#include <asm/mach/arch.h>
30#include <asm/mach/map.h>
31#include <asm/mach/irq.h>
32
33#include <asm/arch/bast-map.h>
34#include <asm/arch/bast-irq.h>
35#include <asm/arch/usb-control.h>
36#include <asm/arch/regs-gpio.h>
37
38#include <asm/hardware.h>
39#include <asm/io.h>
40#include <asm/irq.h>
41#include <asm/mach-types.h>
42
43#include "devs.h"
44#include "usb-simtec.h"
45
46/* control power and monitor over-current events on various Simtec
47 * designed boards.
48*/
49
50static void
51usb_simtec_powercontrol(int port, int to)
52{
53 pr_debug("usb_simtec_powercontrol(%d,%d)\n", port, to);
54
55 if (port == 1)
56 s3c2410_gpio_setpin(S3C2410_GPB4, to ? 0:1);
57}
58
59static irqreturn_t
60usb_simtec_ocirq(int irq, void *pw, struct pt_regs *regs)
61{
62 struct s3c2410_hcd_info *info = (struct s3c2410_hcd_info *)pw;
63
64 if (s3c2410_gpio_getpin(S3C2410_GPG10) == 0) {
65 pr_debug("usb_simtec: over-current irq (oc detected)\n");
66 s3c2410_report_oc(info, 3);
67 } else {
68 pr_debug("usb_simtec: over-current irq (oc cleared)\n");
69 s3c2410_report_oc(info, 0);
70 }
71
72 return IRQ_HANDLED;
73}
74
75static void usb_simtec_enableoc(struct s3c2410_hcd_info *info, int on)
76{
77 int ret;
78
79 if (on) {
80 ret = request_irq(IRQ_USBOC, usb_simtec_ocirq, SA_INTERRUPT,
81 "USB Over-current", info);
82 if (ret != 0) {
83 printk(KERN_ERR "failed to request usb oc irq\n");
84 }
85
86 set_irq_type(IRQ_USBOC, IRQT_BOTHEDGE);
87 } else {
88 free_irq(IRQ_USBOC, info);
89 }
90}
91
92static struct s3c2410_hcd_info usb_simtec_info = {
93 .port[0] = {
94 .flags = S3C_HCDFLG_USED
95 },
96 .port[1] = {
97 .flags = S3C_HCDFLG_USED
98 },
99
100 .power_control = usb_simtec_powercontrol,
101 .enable_oc = usb_simtec_enableoc,
102};
103
104
105int usb_simtec_init(void)
106{
107 printk("USB Power Control, (c) 2004 Simtec Electronics\n");
108 s3c_device_usb.dev.platform_data = &usb_simtec_info;
109
110 s3c2410_gpio_cfgpin(S3C2410_GPB4, S3C2410_GPB4_OUTP);
111 s3c2410_gpio_setpin(S3C2410_GPB4, 1);
112 return 0;
113}
diff --git a/arch/arm/mach-s3c2410/usb-simtec.h b/arch/arm/mach-s3c2410/usb-simtec.h
new file mode 100644
index 000000000000..92c0cc83aeec
--- /dev/null
+++ b/arch/arm/mach-s3c2410/usb-simtec.h
@@ -0,0 +1,19 @@
1/* linux/arch/arm/mach-s3c2410/usb-simtec.c
2 *
3 * Copyright (c) 2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * http://www.simtec.co.uk/products/EB2410ITX/
7 *
8 * Simtec BAST and Thorcom VR1000 USB port support functions
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 * Modifications:
15 * 20-Aug-2004 BJD Created
16*/
17
18extern int usb_simtec_init(void);
19