aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2006-06-24 17:21:49 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2006-06-24 17:21:49 -0400
commite11c910b5bcc1dbc38a5af7a24be2812fc956b27 (patch)
tree38fb4c1b23bf2085cd0b05db9c85e3b91819130f /arch
parentc1e08adc86f886ba0ad7c8f29c240d6e833e7ec7 (diff)
parentc9b949a734adef5d05cbaa0b0546b924ca517155 (diff)
Merge S3C24xx branch
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-s3c2410/Kconfig20
-rw-r--r--arch/arm/mach-s3c2410/Makefile6
-rw-r--r--arch/arm/mach-s3c2410/clock.c21
-rw-r--r--arch/arm/mach-s3c2410/clock.h2
-rw-r--r--arch/arm/mach-s3c2410/cpu.c37
-rw-r--r--arch/arm/mach-s3c2410/cpu.h1
-rw-r--r--arch/arm/mach-s3c2410/irq.c57
-rw-r--r--arch/arm/mach-s3c2410/mach-smdk2413.c126
-rw-r--r--arch/arm/mach-s3c2410/pm-simtec.c3
-rw-r--r--arch/arm/mach-s3c2410/s3c2410-clock.c10
-rw-r--r--arch/arm/mach-s3c2410/s3c2410-gpio.c13
-rw-r--r--arch/arm/mach-s3c2410/s3c2412-clock.c711
-rw-r--r--arch/arm/mach-s3c2410/s3c2412.c195
-rw-r--r--arch/arm/mach-s3c2410/s3c2412.h29
-rw-r--r--arch/arm/mm/Kconfig10
15 files changed, 1197 insertions, 44 deletions
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
index 7b786d725636..f5d9cd498a5f 100644
--- a/arch/arm/mach-s3c2410/Kconfig
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -81,6 +81,12 @@ config SMDK2440_CPU2442
81 depends on ARCH_S3C2440 81 depends on ARCH_S3C2440
82 select CPU_S3C2442 82 select CPU_S3C2442
83 83
84config MACH_SMDK2413
85 bool "SMDK2413"
86 select CPU_S3C2412
87 select MACH_SMDK
88 help
89 Say Y here if you are using an SMDK2413
84 90
85config MACH_VR1000 91config MACH_VR1000
86 bool "Thorcom VR1000" 92 bool "Thorcom VR1000"
@@ -127,6 +133,20 @@ config CPU_S3C2410
127 Support for S3C2410 and S3C2410A family from the S3C24XX line 133 Support for S3C2410 and S3C2410A family from the S3C24XX line
128 of Samsung Mobile CPUs. 134 of Samsung Mobile CPUs.
129 135
136# internal node to signify if we are only dealing with an S3C2412
137
138config CPU_S3C2412_ONLY
139 bool
140 depends on ARCH_S3C2410 && !CPU_S3C2400 && !CPU_S3C2410 && \
141 !CPU_S3C2440 && !CPU_S3C2442 && CPU_S3C2412
142 default y if CPU_S3C2412
143
144config CPU_S3C2412
145 bool
146 depends on ARCH_S3C2410
147 help
148 Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line
149
130config CPU_S3C244X 150config CPU_S3C244X
131 bool 151 bool
132 depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442) 152 depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442)
diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
index 372dbcea1434..0c7938645df6 100644
--- a/arch/arm/mach-s3c2410/Makefile
+++ b/arch/arm/mach-s3c2410/Makefile
@@ -24,6 +24,11 @@ obj-$(CONFIG_S3C2410_DMA) += dma.o
24obj-$(CONFIG_PM) += pm.o sleep.o 24obj-$(CONFIG_PM) += pm.o sleep.o
25obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o 25obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o
26 26
27# S3C2412 support
28obj-$(CONFIG_CPU_S3C2412) += s3c2412.o
29obj-$(CONFIG_CPU_S3C2412) += s3c2412-clock.o
30
31#
27# S3C244X support 32# S3C244X support
28 33
29obj-$(CONFIG_CPU_S3C244X) += s3c244x.o 34obj-$(CONFIG_CPU_S3C244X) += s3c244x.o
@@ -57,6 +62,7 @@ obj-$(CONFIG_ARCH_BAST) += mach-bast.o usb-simtec.o
57obj-$(CONFIG_ARCH_H1940) += mach-h1940.o 62obj-$(CONFIG_ARCH_H1940) += mach-h1940.o
58obj-$(CONFIG_MACH_N30) += mach-n30.o 63obj-$(CONFIG_MACH_N30) += mach-n30.o
59obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o 64obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o
65obj-$(CONFIG_MACH_SMDK2413) += mach-smdk2413.o
60obj-$(CONFIG_ARCH_S3C2440) += mach-smdk2440.o 66obj-$(CONFIG_ARCH_S3C2440) += mach-smdk2440.o
61obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o 67obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o
62obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o 68obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c
index c5c93c333ac6..e13fb6778890 100644
--- a/arch/arm/mach-s3c2410/clock.c
+++ b/arch/arm/mach-s3c2410/clock.c
@@ -213,7 +213,7 @@ EXPORT_SYMBOL(clk_set_parent);
213 213
214/* base clocks */ 214/* base clocks */
215 215
216static struct clk clk_xtal = { 216struct clk clk_xtal = {
217 .name = "xtal", 217 .name = "xtal",
218 .id = -1, 218 .id = -1,
219 .rate = 0, 219 .rate = 0,
@@ -221,6 +221,11 @@ static struct clk clk_xtal = {
221 .ctrlbit = 0, 221 .ctrlbit = 0,
222}; 222};
223 223
224struct clk clk_mpll = {
225 .name = "mpll",
226 .id = -1,
227};
228
224struct clk clk_upll = { 229struct clk clk_upll = {
225 .name = "upll", 230 .name = "upll",
226 .id = -1, 231 .id = -1,
@@ -232,7 +237,7 @@ struct clk clk_f = {
232 .name = "fclk", 237 .name = "fclk",
233 .id = -1, 238 .id = -1,
234 .rate = 0, 239 .rate = 0,
235 .parent = NULL, 240 .parent = &clk_mpll,
236 .ctrlbit = 0, 241 .ctrlbit = 0,
237}; 242};
238 243
@@ -263,14 +268,14 @@ struct clk clk_usb_bus = {
263 268
264static int s3c24xx_dclk_enable(struct clk *clk, int enable) 269static int s3c24xx_dclk_enable(struct clk *clk, int enable)
265{ 270{
266 unsigned long dclkcon = __raw_readl(S3C2410_DCLKCON); 271 unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON);
267 272
268 if (enable) 273 if (enable)
269 dclkcon |= clk->ctrlbit; 274 dclkcon |= clk->ctrlbit;
270 else 275 else
271 dclkcon &= ~clk->ctrlbit; 276 dclkcon &= ~clk->ctrlbit;
272 277
273 __raw_writel(dclkcon, S3C2410_DCLKCON); 278 __raw_writel(dclkcon, S3C24XX_DCLKCON);
274 279
275 return 0; 280 return 0;
276} 281}
@@ -289,7 +294,7 @@ static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
289 294
290 clk->parent = parent; 295 clk->parent = parent;
291 296
292 dclkcon = __raw_readl(S3C2410_DCLKCON); 297 dclkcon = __raw_readl(S3C24XX_DCLKCON);
293 298
294 if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) { 299 if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) {
295 if (uclk) 300 if (uclk)
@@ -303,7 +308,7 @@ static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
303 dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK; 308 dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK;
304 } 309 }
305 310
306 __raw_writel(dclkcon, S3C2410_DCLKCON); 311 __raw_writel(dclkcon, S3C24XX_DCLKCON);
307 312
308 return 0; 313 return 0;
309} 314}
@@ -413,6 +418,7 @@ int __init s3c24xx_setup_clocks(unsigned long xtal,
413 clk_xtal.rate = xtal; 418 clk_xtal.rate = xtal;
414 clk_upll.rate = s3c2410_get_pll(__raw_readl(S3C2410_UPLLCON), xtal); 419 clk_upll.rate = s3c2410_get_pll(__raw_readl(S3C2410_UPLLCON), xtal);
415 420
421 clk_mpll.rate = fclk;
416 clk_h.rate = hclk; 422 clk_h.rate = hclk;
417 clk_p.rate = pclk; 423 clk_p.rate = pclk;
418 clk_f.rate = fclk; 424 clk_f.rate = fclk;
@@ -424,6 +430,9 @@ int __init s3c24xx_setup_clocks(unsigned long xtal,
424 if (s3c24xx_register_clock(&clk_xtal) < 0) 430 if (s3c24xx_register_clock(&clk_xtal) < 0)
425 printk(KERN_ERR "failed to register master xtal\n"); 431 printk(KERN_ERR "failed to register master xtal\n");
426 432
433 if (s3c24xx_register_clock(&clk_mpll) < 0)
434 printk(KERN_ERR "failed to register mpll clock\n");
435
427 if (s3c24xx_register_clock(&clk_upll) < 0) 436 if (s3c24xx_register_clock(&clk_upll) < 0)
428 printk(KERN_ERR "failed to register upll clock\n"); 437 printk(KERN_ERR "failed to register upll clock\n");
429 438
diff --git a/arch/arm/mach-s3c2410/clock.h b/arch/arm/mach-s3c2410/clock.h
index 9456c81eb5d3..7f0ea03e1d49 100644
--- a/arch/arm/mach-s3c2410/clock.h
+++ b/arch/arm/mach-s3c2410/clock.h
@@ -42,7 +42,9 @@ extern struct clk clk_usb_bus;
42extern struct clk clk_f; 42extern struct clk clk_f;
43extern struct clk clk_h; 43extern struct clk clk_h;
44extern struct clk clk_p; 44extern struct clk clk_p;
45extern struct clk clk_mpll;
45extern struct clk clk_upll; 46extern struct clk clk_upll;
47extern struct clk clk_xtal;
46 48
47/* exports for arch/arm/mach-s3c2410 49/* exports for arch/arm/mach-s3c2410
48 * 50 *
diff --git a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/mach-s3c2410/cpu.c
index 52842e6e86e6..1c3c6adae6c4 100644
--- a/arch/arm/mach-s3c2410/cpu.c
+++ b/arch/arm/mach-s3c2410/cpu.c
@@ -44,6 +44,7 @@
44#include "clock.h" 44#include "clock.h"
45#include "s3c2400.h" 45#include "s3c2400.h"
46#include "s3c2410.h" 46#include "s3c2410.h"
47#include "s3c2412.h"
47#include "s3c244x.h" 48#include "s3c244x.h"
48#include "s3c2440.h" 49#include "s3c2440.h"
49#include "s3c2442.h" 50#include "s3c2442.h"
@@ -62,6 +63,7 @@ struct cpu_table {
62 63
63static const char name_s3c2400[] = "S3C2400"; 64static const char name_s3c2400[] = "S3C2400";
64static const char name_s3c2410[] = "S3C2410"; 65static const char name_s3c2410[] = "S3C2410";
66static const char name_s3c2412[] = "S3C2412";
65static const char name_s3c2440[] = "S3C2440"; 67static const char name_s3c2440[] = "S3C2440";
66static const char name_s3c2442[] = "S3C2442"; 68static const char name_s3c2442[] = "S3C2442";
67static const char name_s3c2410a[] = "S3C2410A"; 69static const char name_s3c2410a[] = "S3C2410A";
@@ -114,6 +116,15 @@ static struct cpu_table cpu_ids[] __initdata = {
114 .name = name_s3c2442 116 .name = name_s3c2442
115 }, 117 },
116 { 118 {
119 .idcode = 0x32412001,
120 .idmask = 0xffffffff,
121 .map_io = s3c2412_map_io,
122 .init_clocks = s3c2412_init_clocks,
123 .init_uarts = s3c2412_init_uarts,
124 .init = s3c2412_init,
125 .name = name_s3c2412,
126 },
127 {
117 .idcode = 0x0, /* S3C2400 doesn't have an idcode */ 128 .idcode = 0x0, /* S3C2400 doesn't have an idcode */
118 .idmask = 0xffffffff, 129 .idmask = 0xffffffff,
119 .map_io = s3c2400_map_io, 130 .map_io = s3c2400_map_io,
@@ -171,6 +182,24 @@ void s3c24xx_set_board(struct s3c24xx_board *b)
171 182
172static struct cpu_table *cpu; 183static struct cpu_table *cpu;
173 184
185static unsigned long s3c24xx_read_idcode_v5(void)
186{
187#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
188 return __raw_readl(S3C2412_GSTATUS1);
189#else
190 return 1UL; /* don't look like an 2400 */
191#endif
192}
193
194static unsigned long s3c24xx_read_idcode_v4(void)
195{
196#ifndef CONFIG_CPU_S3C2400
197 return __raw_readl(S3C2410_GSTATUS1);
198#else
199 return 0UL;
200#endif
201}
202
174void __init s3c24xx_init_io(struct map_desc *mach_desc, int size) 203void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
175{ 204{
176 unsigned long idcode = 0x0; 205 unsigned long idcode = 0x0;
@@ -178,9 +207,11 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
178 /* initialise the io descriptors we need for initialisation */ 207 /* initialise the io descriptors we need for initialisation */
179 iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc)); 208 iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc));
180 209
181#ifndef CONFIG_CPU_S3C2400 210 if (cpu_architecture() >= CPU_ARCH_ARMv5) {
182 idcode = __raw_readl(S3C2410_GSTATUS1); 211 idcode = s3c24xx_read_idcode_v5();
183#endif 212 } else {
213 idcode = s3c24xx_read_idcode_v4();
214 }
184 215
185 cpu = s3c_lookup_cpu(idcode); 216 cpu = s3c_lookup_cpu(idcode);
186 217
diff --git a/arch/arm/mach-s3c2410/cpu.h b/arch/arm/mach-s3c2410/cpu.h
index 21c62dc29bb2..b0ed9d2d141b 100644
--- a/arch/arm/mach-s3c2410/cpu.h
+++ b/arch/arm/mach-s3c2410/cpu.h
@@ -74,5 +74,6 @@ extern struct sys_timer s3c24xx_timer;
74/* system device classes */ 74/* system device classes */
75 75
76extern struct sysdev_class s3c2410_sysclass; 76extern struct sysdev_class s3c2410_sysclass;
77extern struct sysdev_class s3c2412_sysclass;
77extern struct sysdev_class s3c2440_sysclass; 78extern struct sysdev_class s3c2440_sysclass;
78extern struct sysdev_class s3c2442_sysclass; 79extern struct sysdev_class s3c2442_sysclass;
diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c
index 66d8c068e940..6822dc7f7799 100644
--- a/arch/arm/mach-s3c2410/irq.c
+++ b/arch/arm/mach-s3c2410/irq.c
@@ -191,13 +191,9 @@ static struct irqchip s3c_irq_chip = {
191 .ack = s3c_irq_ack, 191 .ack = s3c_irq_ack,
192 .mask = s3c_irq_mask, 192 .mask = s3c_irq_mask,
193 .unmask = s3c_irq_unmask, 193 .unmask = s3c_irq_unmask,
194 .set_wake = s3c_irq_wake 194 .set_wake = s3c_irq_wake
195}; 195};
196 196
197/* S3C2410_EINTMASK
198 * S3C2410_EINTPEND
199 */
200
201static void 197static void
202s3c_irqext_mask(unsigned int irqno) 198s3c_irqext_mask(unsigned int irqno)
203{ 199{
@@ -205,9 +201,9 @@ s3c_irqext_mask(unsigned int irqno)
205 201
206 irqno -= EXTINT_OFF; 202 irqno -= EXTINT_OFF;
207 203
208 mask = __raw_readl(S3C2410_EINTMASK); 204 mask = __raw_readl(S3C24XX_EINTMASK);
209 mask |= ( 1UL << irqno); 205 mask |= ( 1UL << irqno);
210 __raw_writel(mask, S3C2410_EINTMASK); 206 __raw_writel(mask, S3C24XX_EINTMASK);
211 207
212 if (irqno <= (IRQ_EINT7 - EXTINT_OFF)) { 208 if (irqno <= (IRQ_EINT7 - EXTINT_OFF)) {
213 /* check to see if all need masking */ 209 /* check to see if all need masking */
@@ -232,11 +228,11 @@ s3c_irqext_ack(unsigned int irqno)
232 bit = 1UL << (irqno - EXTINT_OFF); 228 bit = 1UL << (irqno - EXTINT_OFF);
233 229
234 230
235 mask = __raw_readl(S3C2410_EINTMASK); 231 mask = __raw_readl(S3C24XX_EINTMASK);
236 232
237 __raw_writel(bit, S3C2410_EINTPEND); 233 __raw_writel(bit, S3C24XX_EINTPEND);
238 234
239 req = __raw_readl(S3C2410_EINTPEND); 235 req = __raw_readl(S3C24XX_EINTPEND);
240 req &= ~mask; 236 req &= ~mask;
241 237
242 /* not sure if we should be acking the parent irq... */ 238 /* not sure if we should be acking the parent irq... */
@@ -257,9 +253,9 @@ s3c_irqext_unmask(unsigned int irqno)
257 253
258 irqno -= EXTINT_OFF; 254 irqno -= EXTINT_OFF;
259 255
260 mask = __raw_readl(S3C2410_EINTMASK); 256 mask = __raw_readl(S3C24XX_EINTMASK);
261 mask &= ~( 1UL << irqno); 257 mask &= ~( 1UL << irqno);
262 __raw_writel(mask, S3C2410_EINTMASK); 258 __raw_writel(mask, S3C24XX_EINTMASK);
263 259
264 s3c_irq_unmask((irqno <= (IRQ_EINT7 - EXTINT_OFF)) ? IRQ_EINT4t7 : IRQ_EINT8t23); 260 s3c_irq_unmask((irqno <= (IRQ_EINT7 - EXTINT_OFF)) ? IRQ_EINT4t7 : IRQ_EINT8t23);
265} 261}
@@ -275,28 +271,28 @@ s3c_irqext_type(unsigned int irq, unsigned int type)
275 if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3)) 271 if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3))
276 { 272 {
277 gpcon_reg = S3C2410_GPFCON; 273 gpcon_reg = S3C2410_GPFCON;
278 extint_reg = S3C2410_EXTINT0; 274 extint_reg = S3C24XX_EXTINT0;
279 gpcon_offset = (irq - IRQ_EINT0) * 2; 275 gpcon_offset = (irq - IRQ_EINT0) * 2;
280 extint_offset = (irq - IRQ_EINT0) * 4; 276 extint_offset = (irq - IRQ_EINT0) * 4;
281 } 277 }
282 else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7)) 278 else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7))
283 { 279 {
284 gpcon_reg = S3C2410_GPFCON; 280 gpcon_reg = S3C2410_GPFCON;
285 extint_reg = S3C2410_EXTINT0; 281 extint_reg = S3C24XX_EXTINT0;
286 gpcon_offset = (irq - (EXTINT_OFF)) * 2; 282 gpcon_offset = (irq - (EXTINT_OFF)) * 2;
287 extint_offset = (irq - (EXTINT_OFF)) * 4; 283 extint_offset = (irq - (EXTINT_OFF)) * 4;
288 } 284 }
289 else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15)) 285 else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15))
290 { 286 {
291 gpcon_reg = S3C2410_GPGCON; 287 gpcon_reg = S3C2410_GPGCON;
292 extint_reg = S3C2410_EXTINT1; 288 extint_reg = S3C24XX_EXTINT1;
293 gpcon_offset = (irq - IRQ_EINT8) * 2; 289 gpcon_offset = (irq - IRQ_EINT8) * 2;
294 extint_offset = (irq - IRQ_EINT8) * 4; 290 extint_offset = (irq - IRQ_EINT8) * 4;
295 } 291 }
296 else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23)) 292 else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23))
297 { 293 {
298 gpcon_reg = S3C2410_GPGCON; 294 gpcon_reg = S3C2410_GPGCON;
299 extint_reg = S3C2410_EXTINT2; 295 extint_reg = S3C24XX_EXTINT2;
300 gpcon_offset = (irq - IRQ_EINT8) * 2; 296 gpcon_offset = (irq - IRQ_EINT8) * 2;
301 extint_offset = (irq - IRQ_EINT16) * 4; 297 extint_offset = (irq - IRQ_EINT16) * 4;
302 } else 298 } else
@@ -572,6 +568,23 @@ s3c_irq_demux_uart2(unsigned int irq,
572 s3c_irq_demux_uart(IRQ_S3CUART_RX2, regs); 568 s3c_irq_demux_uart(IRQ_S3CUART_RX2, regs);
573} 569}
574 570
571static void
572s3c_irq_demux_extint(unsigned int irq,
573 struct irqdesc *desc,
574 struct pt_regs *regs)
575{
576 unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
577 unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
578
579 eintpnd &= ~eintmsk;
580
581 if (eintpnd) {
582 irq = fls(eintpnd);
583 irq += (IRQ_EINT4 - (4 + 1));
584
585 desc_handle_irq(irq, irq_desc + irq, regs);
586 }
587}
575 588
576/* s3c24xx_init_irq 589/* s3c24xx_init_irq
577 * 590 *
@@ -591,12 +604,12 @@ void __init s3c24xx_init_irq(void)
591 604
592 last = 0; 605 last = 0;
593 for (i = 0; i < 4; i++) { 606 for (i = 0; i < 4; i++) {
594 pend = __raw_readl(S3C2410_EINTPEND); 607 pend = __raw_readl(S3C24XX_EINTPEND);
595 608
596 if (pend == 0 || pend == last) 609 if (pend == 0 || pend == last)
597 break; 610 break;
598 611
599 __raw_writel(pend, S3C2410_EINTPEND); 612 __raw_writel(pend, S3C24XX_EINTPEND);
600 printk("irq: clearing pending ext status %08x\n", (int)pend); 613 printk("irq: clearing pending ext status %08x\n", (int)pend);
601 last = pend; 614 last = pend;
602 } 615 }
@@ -630,12 +643,14 @@ void __init s3c24xx_init_irq(void)
630 643
631 irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n"); 644 irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n");
632 645
633 for (irqno = IRQ_BATT_FLT; irqno <= IRQ_ADCPARENT; irqno++) { 646 for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) {
634 /* set all the s3c2410 internal irqs */ 647 /* set all the s3c2410 internal irqs */
635 648
636 switch (irqno) { 649 switch (irqno) {
637 /* deal with the special IRQs (cascaded) */ 650 /* deal with the special IRQs (cascaded) */
638 651
652 case IRQ_EINT4t7:
653 case IRQ_EINT8t23:
639 case IRQ_UART0: 654 case IRQ_UART0:
640 case IRQ_UART1: 655 case IRQ_UART1:
641 case IRQ_UART2: 656 case IRQ_UART2:
@@ -659,12 +674,14 @@ void __init s3c24xx_init_irq(void)
659 674
660 /* setup the cascade irq handlers */ 675 /* setup the cascade irq handlers */
661 676
677 set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint);
678 set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint);
679
662 set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0); 680 set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
663 set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1); 681 set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);
664 set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2); 682 set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2);
665 set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc); 683 set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc);
666 684
667
668 /* external interrupts */ 685 /* external interrupts */
669 686
670 for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) { 687 for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
diff --git a/arch/arm/mach-s3c2410/mach-smdk2413.c b/arch/arm/mach-s3c2410/mach-smdk2413.c
new file mode 100644
index 000000000000..b7ef7d3c54a9
--- /dev/null
+++ b/arch/arm/mach-s3c2410/mach-smdk2413.c
@@ -0,0 +1,126 @@
1/* linux/arch/arm/mach-s3c2410/mach-smdk2413.c
2 *
3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * Thanks to Dimity Andric (TomTom) and Steven Ryu (Samsung) for the
7 * loans of SMDK2413 to work with.
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
14#include <linux/kernel.h>
15#include <linux/types.h>
16#include <linux/interrupt.h>
17#include <linux/list.h>
18#include <linux/timer.h>
19#include <linux/init.h>
20#include <linux/platform_device.h>
21
22#include <asm/mach/arch.h>
23#include <asm/mach/map.h>
24#include <asm/mach/irq.h>
25
26#include <asm/hardware.h>
27#include <asm/hardware/iomd.h>
28#include <asm/setup.h>
29#include <asm/io.h>
30#include <asm/irq.h>
31#include <asm/mach-types.h>
32
33//#include <asm/debug-ll.h>
34#include <asm/arch/regs-serial.h>
35#include <asm/arch/regs-gpio.h>
36#include <asm/arch/regs-lcd.h>
37
38#include <asm/arch/idle.h>
39#include <asm/arch/fb.h>
40
41#include "s3c2410.h"
42#include "s3c2412.h"
43#include "clock.h"
44#include "devs.h"
45#include "cpu.h"
46
47#include "common-smdk.h"
48
49static struct map_desc smdk2413_iodesc[] __initdata = {
50};
51
52static struct s3c2410_uartcfg smdk2413_uartcfgs[] __initdata = {
53 [0] = {
54 .hwport = 0,
55 .flags = 0,
56 .ucon = 0x3c5,
57 .ulcon = 0x03,
58 .ufcon = 0x51,
59 },
60 [1] = {
61 .hwport = 1,
62 .flags = 0,
63 .ucon = 0x3c5,
64 .ulcon = 0x03,
65 .ufcon = 0x51,
66 },
67 /* IR port */
68 [2] = {
69 .hwport = 2,
70 .flags = 0,
71 .ucon = 0x3c5,
72 .ulcon = 0x43,
73 .ufcon = 0x51,
74 }
75};
76
77static struct platform_device *smdk2413_devices[] __initdata = {
78 &s3c_device_usb,
79 //&s3c_device_lcd,
80 &s3c_device_wdt,
81 &s3c_device_i2c,
82 &s3c_device_iis,
83};
84
85static struct s3c24xx_board smdk2413_board __initdata = {
86 .devices = smdk2413_devices,
87 .devices_count = ARRAY_SIZE(smdk2413_devices)
88};
89
90static void __init smdk2413_fixup(struct machine_desc *desc,
91 struct tag *tags, char **cmdline,
92 struct meminfo *mi)
93{
94 if (tags != phys_to_virt(S3C2410_SDRAM_PA + 0x100)) {
95 mi->nr_banks=1;
96 mi->bank[0].start = 0x30000000;
97 mi->bank[0].size = SZ_64M;
98 mi->bank[0].node = 0;
99 }
100}
101
102static void __init smdk2413_map_io(void)
103{
104 s3c24xx_init_io(smdk2413_iodesc, ARRAY_SIZE(smdk2413_iodesc));
105 s3c24xx_init_clocks(12000000);
106 s3c24xx_init_uarts(smdk2413_uartcfgs, ARRAY_SIZE(smdk2413_uartcfgs));
107 s3c24xx_set_board(&smdk2413_board);
108}
109
110static void __init smdk2413_machine_init(void)
111{
112 smdk_machine_init();
113}
114
115MACHINE_START(S3C2413, "SMDK2413")
116 /* Maintainer: Ben Dooks <ben@fluff.org> */
117 .phys_io = S3C2410_PA_UART,
118 .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
119 .boot_params = S3C2410_SDRAM_PA + 0x100,
120
121 .fixup = smdk2413_fixup,
122 .init_irq = s3c24xx_init_irq,
123 .map_io = smdk2413_map_io,
124 .init_machine = smdk2413_machine_init,
125 .timer = &s3c24xx_timer,
126MACHINE_END
diff --git a/arch/arm/mach-s3c2410/pm-simtec.c b/arch/arm/mach-s3c2410/pm-simtec.c
index 4c7ccef6c207..7b244566a436 100644
--- a/arch/arm/mach-s3c2410/pm-simtec.c
+++ b/arch/arm/mach-s3c2410/pm-simtec.c
@@ -48,7 +48,8 @@ static __init int pm_simtec_init(void)
48 48
49 /* check which machine we are running on */ 49 /* check which machine we are running on */
50 50
51 if (!machine_is_bast() && !machine_is_vr1000() && !machine_is_anubis()) 51 if (!machine_is_bast() && !machine_is_vr1000() &&
52 !machine_is_anubis() && !machine_is_osiris())
52 return 0; 53 return 0;
53 54
54 printk(KERN_INFO "Simtec Board Power Manangement" COPYRIGHT "\n"); 55 printk(KERN_INFO "Simtec Board Power Manangement" COPYRIGHT "\n");
diff --git a/arch/arm/mach-s3c2410/s3c2410-clock.c b/arch/arm/mach-s3c2410/s3c2410-clock.c
index fd17c60e1132..99718663318e 100644
--- a/arch/arm/mach-s3c2410/s3c2410-clock.c
+++ b/arch/arm/mach-s3c2410/s3c2410-clock.c
@@ -182,7 +182,15 @@ static struct clk init_clocks[] = {
182 .id = -1, 182 .id = -1,
183 .parent = &clk_p, 183 .parent = &clk_p,
184 .ctrlbit = 0, 184 .ctrlbit = 0,
185 } 185 }, {
186 .name = "usb-bus-host",
187 .id = -1,
188 .parent = &clk_usb_bus,
189 }, {
190 .name = "usb-bus-gadget",
191 .id = -1,
192 .parent = &clk_usb_bus,
193 },
186}; 194};
187 195
188/* s3c2410_baseclk_add() 196/* s3c2410_baseclk_add()
diff --git a/arch/arm/mach-s3c2410/s3c2410-gpio.c b/arch/arm/mach-s3c2410/s3c2410-gpio.c
index d5e1caea1d23..471a71490010 100644
--- a/arch/arm/mach-s3c2410/s3c2410-gpio.c
+++ b/arch/arm/mach-s3c2410/s3c2410-gpio.c
@@ -18,9 +18,6 @@
18 * You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software 19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 * Changelog
23 * 15-Jan-2006 LCVR Splitted from gpio.c
24 */ 21 */
25 22
26#include <linux/kernel.h> 23#include <linux/kernel.h>
@@ -38,7 +35,7 @@
38int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on, 35int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
39 unsigned int config) 36 unsigned int config)
40{ 37{
41 void __iomem *reg = S3C2410_EINFLT0; 38 void __iomem *reg = S3C24XX_EINFLT0;
42 unsigned long flags; 39 unsigned long flags;
43 unsigned long val; 40 unsigned long val;
44 41
@@ -47,7 +44,7 @@ int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
47 44
48 config &= 0xff; 45 config &= 0xff;
49 46
50 pin -= S3C2410_GPG8_EINT16; 47 pin -= S3C2410_GPG8;
51 reg += pin & ~3; 48 reg += pin & ~3;
52 49
53 local_irq_save(flags); 50 local_irq_save(flags);
@@ -61,10 +58,10 @@ int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
61 58
62 /* update filter enable */ 59 /* update filter enable */
63 60
64 val = __raw_readl(S3C2410_EXTINT2); 61 val = __raw_readl(S3C24XX_EXTINT2);
65 val &= ~(1 << ((pin * 4) + 3)); 62 val &= ~(1 << ((pin * 4) + 3));
66 val |= on << ((pin * 4) + 3); 63 val |= on << ((pin * 4) + 3);
67 __raw_writel(val, S3C2410_EXTINT2); 64 __raw_writel(val, S3C24XX_EXTINT2);
68 65
69 local_irq_restore(flags); 66 local_irq_restore(flags);
70 67
@@ -75,7 +72,7 @@ EXPORT_SYMBOL(s3c2410_gpio_irqfilter);
75 72
76int s3c2410_gpio_getirq(unsigned int pin) 73int s3c2410_gpio_getirq(unsigned int pin)
77{ 74{
78 if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15_EINT23) 75 if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15)
79 return -1; /* not valid interrupts */ 76 return -1; /* not valid interrupts */
80 77
81 if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7) 78 if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7)
diff --git a/arch/arm/mach-s3c2410/s3c2412-clock.c b/arch/arm/mach-s3c2410/s3c2412-clock.c
new file mode 100644
index 000000000000..c95ed3e18580
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2412-clock.c
@@ -0,0 +1,711 @@
1/* linux/arch/arm/mach-s3c2410/s3c2412-clock.c
2 *
3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * S3C2412,S3C2413 Clock control support
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21*/
22
23#include <linux/init.h>
24#include <linux/module.h>
25#include <linux/kernel.h>
26#include <linux/list.h>
27#include <linux/errno.h>
28#include <linux/err.h>
29#include <linux/sysdev.h>
30#include <linux/clk.h>
31#include <linux/mutex.h>
32#include <linux/delay.h>
33
34#include <asm/hardware.h>
35#include <asm/io.h>
36
37#include <asm/arch/regs-clock.h>
38#include <asm/arch/regs-gpio.h>
39
40#include "clock.h"
41#include "cpu.h"
42
43/* We currently have to assume that the system is running
44 * from the XTPll input, and that all ***REFCLKs are being
45 * fed from it, as we cannot read the state of OM[4] from
46 * software.
47 *
48 * It would be possible for each board initialisation to
49 * set the correct muxing at initialisation
50*/
51
52int s3c2412_clkcon_enable(struct clk *clk, int enable)
53{
54 unsigned int clocks = clk->ctrlbit;
55 unsigned long clkcon;
56
57 clkcon = __raw_readl(S3C2410_CLKCON);
58
59 if (enable)
60 clkcon |= clocks;
61 else
62 clkcon &= ~clocks;
63
64 __raw_writel(clkcon, S3C2410_CLKCON);
65
66 return 0;
67}
68
69static int s3c2412_upll_enable(struct clk *clk, int enable)
70{
71 unsigned long upllcon = __raw_readl(S3C2410_UPLLCON);
72 unsigned long orig = upllcon;
73
74 if (!enable)
75 upllcon |= S3C2412_PLLCON_OFF;
76 else
77 upllcon &= ~S3C2412_PLLCON_OFF;
78
79 __raw_writel(upllcon, S3C2410_UPLLCON);
80
81 /* allow ~150uS for the PLL to settle and lock */
82
83 if (enable && (orig & S3C2412_PLLCON_OFF))
84 udelay(150);
85
86 return 0;
87}
88
89/* clock selections */
90
91/* CPU EXTCLK input */
92static struct clk clk_ext = {
93 .name = "extclk",
94 .id = -1,
95};
96
97static struct clk clk_erefclk = {
98 .name = "erefclk",
99 .id = -1,
100};
101
102static struct clk clk_urefclk = {
103 .name = "urefclk",
104 .id = -1,
105};
106
107static int s3c2412_setparent_usysclk(struct clk *clk, struct clk *parent)
108{
109 unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
110
111 if (parent == &clk_urefclk)
112 clksrc &= ~S3C2412_CLKSRC_USYSCLK_UPLL;
113 else if (parent == &clk_upll)
114 clksrc |= S3C2412_CLKSRC_USYSCLK_UPLL;
115 else
116 return -EINVAL;
117
118 clk->parent = parent;
119
120 __raw_writel(clksrc, S3C2412_CLKSRC);
121 return 0;
122}
123
124static struct clk clk_usysclk = {
125 .name = "usysclk",
126 .id = -1,
127 .parent = &clk_xtal,
128 .set_parent = s3c2412_setparent_usysclk,
129};
130
131static struct clk clk_mrefclk = {
132 .name = "mrefclk",
133 .parent = &clk_xtal,
134 .id = -1,
135};
136
137static struct clk clk_mdivclk = {
138 .name = "mdivclk",
139 .parent = &clk_xtal,
140 .id = -1,
141};
142
143static int s3c2412_setparent_usbsrc(struct clk *clk, struct clk *parent)
144{
145 unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
146
147 if (parent == &clk_usysclk)
148 clksrc &= ~S3C2412_CLKSRC_USBCLK_HCLK;
149 else if (parent == &clk_h)
150 clksrc |= S3C2412_CLKSRC_USBCLK_HCLK;
151 else
152 return -EINVAL;
153
154 clk->parent = parent;
155
156 __raw_writel(clksrc, S3C2412_CLKSRC);
157 return 0;
158}
159
160static unsigned long s3c2412_roundrate_usbsrc(struct clk *clk,
161 unsigned long rate)
162{
163 unsigned long parent_rate = clk_get_rate(clk->parent);
164 int div;
165
166 if (rate > parent_rate)
167 return parent_rate;
168
169 div = parent_rate / rate;
170 if (div > 2)
171 div = 2;
172
173 return parent_rate / div;
174}
175
176static unsigned long s3c2412_getrate_usbsrc(struct clk *clk)
177{
178 unsigned long parent_rate = clk_get_rate(clk->parent);
179 unsigned long div = __raw_readl(S3C2410_CLKDIVN);
180
181 return parent_rate / ((div & S3C2412_CLKDIVN_USB48DIV) ? 2 : 1);
182}
183
184static int s3c2412_setrate_usbsrc(struct clk *clk, unsigned long rate)
185{
186 unsigned long parent_rate = clk_get_rate(clk->parent);
187 unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
188
189 rate = s3c2412_roundrate_usbsrc(clk, rate);
190
191 if ((parent_rate / rate) == 2)
192 clkdivn |= S3C2412_CLKDIVN_USB48DIV;
193 else
194 clkdivn &= ~S3C2412_CLKDIVN_USB48DIV;
195
196 __raw_writel(clkdivn, S3C2410_CLKDIVN);
197 return 0;
198}
199
200static struct clk clk_usbsrc = {
201 .name = "usbsrc",
202 .id = -1,
203 .get_rate = s3c2412_getrate_usbsrc,
204 .set_rate = s3c2412_setrate_usbsrc,
205 .round_rate = s3c2412_roundrate_usbsrc,
206 .set_parent = s3c2412_setparent_usbsrc,
207};
208
209static int s3c2412_setparent_msysclk(struct clk *clk, struct clk *parent)
210{
211 unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
212
213 if (parent == &clk_mdivclk)
214 clksrc &= ~S3C2412_CLKSRC_MSYSCLK_MPLL;
215 else if (parent == &clk_upll)
216 clksrc |= S3C2412_CLKSRC_MSYSCLK_MPLL;
217 else
218 return -EINVAL;
219
220 clk->parent = parent;
221
222 __raw_writel(clksrc, S3C2412_CLKSRC);
223 return 0;
224}
225
226static struct clk clk_msysclk = {
227 .name = "msysclk",
228 .id = -1,
229 .set_parent = s3c2412_setparent_msysclk,
230};
231
232/* these next clocks have an divider immediately after them,
233 * so we can register them with their divider and leave out the
234 * intermediate clock stage
235*/
236static unsigned long s3c2412_roundrate_clksrc(struct clk *clk,
237 unsigned long rate)
238{
239 unsigned long parent_rate = clk_get_rate(clk->parent);
240 int div;
241
242 if (rate > parent_rate)
243 return parent_rate;
244
245 /* note, we remove the +/- 1 calculations as they cancel out */
246
247 div = (rate / parent_rate);
248
249 if (div < 1)
250 div = 1;
251 else if (div > 16)
252 div = 16;
253
254 return parent_rate / div;
255}
256
257static int s3c2412_setparent_uart(struct clk *clk, struct clk *parent)
258{
259 unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
260
261 if (parent == &clk_erefclk)
262 clksrc &= ~S3C2412_CLKSRC_UARTCLK_MPLL;
263 else if (parent == &clk_mpll)
264 clksrc |= S3C2412_CLKSRC_UARTCLK_MPLL;
265 else
266 return -EINVAL;
267
268 clk->parent = parent;
269
270 __raw_writel(clksrc, S3C2412_CLKSRC);
271 return 0;
272}
273
274static unsigned long s3c2412_getrate_uart(struct clk *clk)
275{
276 unsigned long parent_rate = clk_get_rate(clk->parent);
277 unsigned long div = __raw_readl(S3C2410_CLKDIVN);
278
279 div &= S3C2412_CLKDIVN_UARTDIV_MASK;
280 div >>= S3C2412_CLKDIVN_UARTDIV_SHIFT;
281
282 return parent_rate / (div + 1);
283}
284
285static int s3c2412_setrate_uart(struct clk *clk, unsigned long rate)
286{
287 unsigned long parent_rate = clk_get_rate(clk->parent);
288 unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
289
290 rate = s3c2412_roundrate_clksrc(clk, rate);
291
292 clkdivn &= ~S3C2412_CLKDIVN_UARTDIV_MASK;
293 clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_UARTDIV_SHIFT;
294
295 __raw_writel(clkdivn, S3C2410_CLKDIVN);
296 return 0;
297}
298
299static struct clk clk_uart = {
300 .name = "uartclk",
301 .id = -1,
302 .get_rate = s3c2412_getrate_uart,
303 .set_rate = s3c2412_setrate_uart,
304 .set_parent = s3c2412_setparent_uart,
305 .round_rate = s3c2412_roundrate_clksrc,
306};
307
308static int s3c2412_setparent_i2s(struct clk *clk, struct clk *parent)
309{
310 unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
311
312 if (parent == &clk_erefclk)
313 clksrc &= ~S3C2412_CLKSRC_I2SCLK_MPLL;
314 else if (parent == &clk_mpll)
315 clksrc |= S3C2412_CLKSRC_I2SCLK_MPLL;
316 else
317 return -EINVAL;
318
319 clk->parent = parent;
320
321 __raw_writel(clksrc, S3C2412_CLKSRC);
322 return 0;
323}
324
325static unsigned long s3c2412_getrate_i2s(struct clk *clk)
326{
327 unsigned long parent_rate = clk_get_rate(clk->parent);
328 unsigned long div = __raw_readl(S3C2410_CLKDIVN);
329
330 div &= S3C2412_CLKDIVN_I2SDIV_MASK;
331 div >>= S3C2412_CLKDIVN_I2SDIV_SHIFT;
332
333 return parent_rate / (div + 1);
334}
335
336static int s3c2412_setrate_i2s(struct clk *clk, unsigned long rate)
337{
338 unsigned long parent_rate = clk_get_rate(clk->parent);
339 unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
340
341 rate = s3c2412_roundrate_clksrc(clk, rate);
342
343 clkdivn &= ~S3C2412_CLKDIVN_I2SDIV_MASK;
344 clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_I2SDIV_SHIFT;
345
346 __raw_writel(clkdivn, S3C2410_CLKDIVN);
347 return 0;
348}
349
350static struct clk clk_i2s = {
351 .name = "i2sclk",
352 .id = -1,
353 .get_rate = s3c2412_getrate_i2s,
354 .set_rate = s3c2412_setrate_i2s,
355 .set_parent = s3c2412_setparent_i2s,
356 .round_rate = s3c2412_roundrate_clksrc,
357};
358
359static int s3c2412_setparent_cam(struct clk *clk, struct clk *parent)
360{
361 unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
362
363 if (parent == &clk_usysclk)
364 clksrc &= ~S3C2412_CLKSRC_CAMCLK_HCLK;
365 else if (parent == &clk_h)
366 clksrc |= S3C2412_CLKSRC_CAMCLK_HCLK;
367 else
368 return -EINVAL;
369
370 clk->parent = parent;
371
372 __raw_writel(clksrc, S3C2412_CLKSRC);
373 return 0;
374}
375static unsigned long s3c2412_getrate_cam(struct clk *clk)
376{
377 unsigned long parent_rate = clk_get_rate(clk->parent);
378 unsigned long div = __raw_readl(S3C2410_CLKDIVN);
379
380 div &= S3C2412_CLKDIVN_CAMDIV_MASK;
381 div >>= S3C2412_CLKDIVN_CAMDIV_SHIFT;
382
383 return parent_rate / (div + 1);
384}
385
386static int s3c2412_setrate_cam(struct clk *clk, unsigned long rate)
387{
388 unsigned long parent_rate = clk_get_rate(clk->parent);
389 unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
390
391 rate = s3c2412_roundrate_clksrc(clk, rate);
392
393 clkdivn &= ~S3C2412_CLKDIVN_CAMDIV_MASK;
394 clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_CAMDIV_SHIFT;
395
396 __raw_writel(clkdivn, S3C2410_CLKDIVN);
397 return 0;
398}
399
400static struct clk clk_cam = {
401 .name = "camif-upll", /* same as 2440 name */
402 .id = -1,
403 .get_rate = s3c2412_getrate_cam,
404 .set_rate = s3c2412_setrate_cam,
405 .set_parent = s3c2412_setparent_cam,
406 .round_rate = s3c2412_roundrate_clksrc,
407};
408
409/* standard clock definitions */
410
411static struct clk init_clocks_disable[] = {
412 {
413 .name = "nand",
414 .id = -1,
415 .parent = &clk_h,
416 .enable = s3c2412_clkcon_enable,
417 .ctrlbit = S3C2412_CLKCON_NAND,
418 }, {
419 .name = "sdi",
420 .id = -1,
421 .parent = &clk_p,
422 .enable = s3c2412_clkcon_enable,
423 .ctrlbit = S3C2412_CLKCON_SDI,
424 }, {
425 .name = "adc",
426 .id = -1,
427 .parent = &clk_p,
428 .enable = s3c2412_clkcon_enable,
429 .ctrlbit = S3C2412_CLKCON_ADC,
430 }, {
431 .name = "i2c",
432 .id = -1,
433 .parent = &clk_p,
434 .enable = s3c2412_clkcon_enable,
435 .ctrlbit = S3C2412_CLKCON_IIC,
436 }, {
437 .name = "iis",
438 .id = -1,
439 .parent = &clk_p,
440 .enable = s3c2412_clkcon_enable,
441 .ctrlbit = S3C2412_CLKCON_IIS,
442 }, {
443 .name = "spi",
444 .id = -1,
445 .parent = &clk_p,
446 .enable = s3c2412_clkcon_enable,
447 .ctrlbit = S3C2412_CLKCON_SPI,
448 }
449};
450
451static struct clk init_clocks[] = {
452 {
453 .name = "dma",
454 .id = 0,
455 .parent = &clk_h,
456 .enable = s3c2412_clkcon_enable,
457 .ctrlbit = S3C2412_CLKCON_DMA0,
458 }, {
459 .name = "dma",
460 .id = 1,
461 .parent = &clk_h,
462 .enable = s3c2412_clkcon_enable,
463 .ctrlbit = S3C2412_CLKCON_DMA1,
464 }, {
465 .name = "dma",
466 .id = 2,
467 .parent = &clk_h,
468 .enable = s3c2412_clkcon_enable,
469 .ctrlbit = S3C2412_CLKCON_DMA2,
470 }, {
471 .name = "dma",
472 .id = 3,
473 .parent = &clk_h,
474 .enable = s3c2412_clkcon_enable,
475 .ctrlbit = S3C2412_CLKCON_DMA3,
476 }, {
477 .name = "lcd",
478 .id = -1,
479 .parent = &clk_h,
480 .enable = s3c2412_clkcon_enable,
481 .ctrlbit = S3C2412_CLKCON_LCDC,
482 }, {
483 .name = "gpio",
484 .id = -1,
485 .parent = &clk_p,
486 .enable = s3c2412_clkcon_enable,
487 .ctrlbit = S3C2412_CLKCON_GPIO,
488 }, {
489 .name = "usb-host",
490 .id = -1,
491 .parent = &clk_h,
492 .enable = s3c2412_clkcon_enable,
493 .ctrlbit = S3C2412_CLKCON_USBH,
494 }, {
495 .name = "usb-device",
496 .id = -1,
497 .parent = &clk_h,
498 .enable = s3c2412_clkcon_enable,
499 .ctrlbit = S3C2412_CLKCON_USBD,
500 }, {
501 .name = "timers",
502 .id = -1,
503 .parent = &clk_p,
504 .enable = s3c2412_clkcon_enable,
505 .ctrlbit = S3C2412_CLKCON_PWMT,
506 }, {
507 .name = "uart",
508 .id = 0,
509 .parent = &clk_p,
510 .enable = s3c2412_clkcon_enable,
511 .ctrlbit = S3C2412_CLKCON_UART0,
512 }, {
513 .name = "uart",
514 .id = 1,
515 .parent = &clk_p,
516 .enable = s3c2412_clkcon_enable,
517 .ctrlbit = S3C2412_CLKCON_UART1,
518 }, {
519 .name = "uart",
520 .id = 2,
521 .parent = &clk_p,
522 .enable = s3c2412_clkcon_enable,
523 .ctrlbit = S3C2412_CLKCON_UART2,
524 }, {
525 .name = "rtc",
526 .id = -1,
527 .parent = &clk_p,
528 .enable = s3c2412_clkcon_enable,
529 .ctrlbit = S3C2412_CLKCON_RTC,
530 }, {
531 .name = "watchdog",
532 .id = -1,
533 .parent = &clk_p,
534 .ctrlbit = 0,
535 }, {
536 .name = "usb-bus-gadget",
537 .id = -1,
538 .parent = &clk_usb_bus,
539 .enable = s3c2412_clkcon_enable,
540 .ctrlbit = S3C2412_CLKCON_USB_DEV48,
541 }, {
542 .name = "usb-bus-host",
543 .id = -1,
544 .parent = &clk_usb_bus,
545 .enable = s3c2412_clkcon_enable,
546 .ctrlbit = S3C2412_CLKCON_USB_HOST48,
547 }
548};
549
550/* clocks to add where we need to check their parentage */
551
552struct clk_init {
553 struct clk *clk;
554 unsigned int bit;
555 struct clk *src_0;
556 struct clk *src_1;
557};
558
559struct clk_init clks_src[] __initdata = {
560 {
561 .clk = &clk_usysclk,
562 .bit = S3C2412_CLKSRC_USBCLK_HCLK,
563 .src_0 = &clk_urefclk,
564 .src_1 = &clk_upll,
565 }, {
566 .clk = &clk_i2s,
567 .bit = S3C2412_CLKSRC_I2SCLK_MPLL,
568 .src_0 = &clk_erefclk,
569 .src_1 = &clk_mpll,
570 }, {
571 .clk = &clk_cam,
572 .bit = S3C2412_CLKSRC_CAMCLK_HCLK,
573 .src_0 = &clk_usysclk,
574 .src_1 = &clk_h,
575 }, {
576 .clk = &clk_msysclk,
577 .bit = S3C2412_CLKSRC_MSYSCLK_MPLL,
578 .src_0 = &clk_mdivclk,
579 .src_1 = &clk_mpll,
580 }, {
581 .clk = &clk_uart,
582 .bit = S3C2412_CLKSRC_UARTCLK_MPLL,
583 .src_0 = &clk_erefclk,
584 .src_1 = &clk_mpll,
585 }, {
586 .clk = &clk_usbsrc,
587 .bit = S3C2412_CLKSRC_USBCLK_HCLK,
588 .src_0 = &clk_usysclk,
589 .src_1 = &clk_h,
590 },
591};
592
593/* s3c2412_clk_initparents
594 *
595 * Initialise the parents for the clocks that we get at start-time
596*/
597
598static void __init s3c2412_clk_initparents(void)
599{
600 unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
601 struct clk_init *cip = clks_src;
602 struct clk *src;
603 int ptr;
604 int ret;
605
606 for (ptr = 0; ptr < ARRAY_SIZE(clks_src); ptr++, cip++) {
607 ret = s3c24xx_register_clock(cip->clk);
608 if (ret < 0) {
609 printk(KERN_ERR "Failed to register clock %s (%d)\n",
610 cip->clk->name, ret);
611 }
612
613 src = (clksrc & cip->bit) ? cip->src_1 : cip->src_0;
614
615 printk(KERN_INFO "%s: parent %s\n", cip->clk->name, src->name);
616 clk_set_parent(cip->clk, src);
617 }
618}
619
620/* clocks to add straight away */
621
622struct clk *clks[] __initdata = {
623 &clk_ext,
624 &clk_usb_bus,
625 &clk_erefclk,
626 &clk_urefclk,
627 &clk_mrefclk,
628};
629
630int __init s3c2412_baseclk_add(void)
631{
632 unsigned long clkcon = __raw_readl(S3C2410_CLKCON);
633 struct clk *clkp;
634 int ret;
635 int ptr;
636
637 clk_upll.enable = s3c2412_upll_enable;
638 clk_usb_bus.parent = &clk_usbsrc;
639 clk_usb_bus.rate = 0x0;
640
641 s3c2412_clk_initparents();
642
643 for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
644 clkp = clks[ptr];
645
646 ret = s3c24xx_register_clock(clkp);
647 if (ret < 0) {
648 printk(KERN_ERR "Failed to register clock %s (%d)\n",
649 clkp->name, ret);
650 }
651 }
652
653 /* ensure usb bus clock is within correct rate of 48MHz */
654
655 if (clk_get_rate(&clk_usb_bus) != (48 * 1000 * 1000)) {
656 printk(KERN_INFO "Warning: USB bus clock not at 48MHz\n");
657
658 /* for the moment, let's use the UPLL, and see if we can
659 * get 48MHz */
660
661 clk_set_parent(&clk_usysclk, &clk_upll);
662 clk_set_parent(&clk_usbsrc, &clk_usysclk);
663 clk_set_rate(&clk_usbsrc, 48*1000*1000);
664 }
665
666 printk("S3C2412: upll %s, %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
667 (__raw_readl(S3C2410_UPLLCON) & S3C2412_PLLCON_OFF) ? "off":"on",
668 print_mhz(clk_get_rate(&clk_upll)),
669 print_mhz(clk_get_rate(&clk_usb_bus)));
670
671 /* register clocks from clock array */
672
673 clkp = init_clocks;
674 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
675 /* ensure that we note the clock state */
676
677 clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0;
678
679 ret = s3c24xx_register_clock(clkp);
680 if (ret < 0) {
681 printk(KERN_ERR "Failed to register clock %s (%d)\n",
682 clkp->name, ret);
683 }
684 }
685
686 /* We must be careful disabling the clocks we are not intending to
687 * be using at boot time, as subsytems such as the LCD which do
688 * their own DMA requests to the bus can cause the system to lockup
689 * if they where in the middle of requesting bus access.
690 *
691 * Disabling the LCD clock if the LCD is active is very dangerous,
692 * and therefore the bootloader should be careful to not enable
693 * the LCD clock if it is not needed.
694 */
695
696 /* install (and disable) the clocks we do not need immediately */
697
698 clkp = init_clocks_disable;
699 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
700
701 ret = s3c24xx_register_clock(clkp);
702 if (ret < 0) {
703 printk(KERN_ERR "Failed to register clock %s (%d)\n",
704 clkp->name, ret);
705 }
706
707 s3c2412_clkcon_enable(clkp, 0);
708 }
709
710 return 0;
711}
diff --git a/arch/arm/mach-s3c2410/s3c2412.c b/arch/arm/mach-s3c2410/s3c2412.c
new file mode 100644
index 000000000000..e24ffd5e478b
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2412.c
@@ -0,0 +1,195 @@
1/* linux/arch/arm/mach-s3c2410/s3c2412.c
2 *
3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * http://armlinux.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 * 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 * 13-Aug-2005 DA Removed UART from initial I/O mappings
22*/
23
24#include <linux/kernel.h>
25#include <linux/types.h>
26#include <linux/interrupt.h>
27#include <linux/list.h>
28#include <linux/timer.h>
29#include <linux/init.h>
30#include <linux/sysdev.h>
31#include <linux/platform_device.h>
32
33#include <asm/mach/arch.h>
34#include <asm/mach/map.h>
35#include <asm/mach/irq.h>
36
37#include <asm/hardware.h>
38#include <asm/io.h>
39#include <asm/irq.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 "s3c2412.h"
48#include "cpu.h"
49#include "devs.h"
50#include "clock.h"
51#include "pm.h"
52
53#ifndef CONFIG_CPU_S3C2412_ONLY
54void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO;
55#endif
56
57/* Initial IO mappings */
58
59static struct map_desc s3c2412_iodesc[] __initdata = {
60 IODESC_ENT(CLKPWR),
61 IODESC_ENT(LCD),
62 IODESC_ENT(TIMER),
63 IODESC_ENT(ADC),
64 IODESC_ENT(WATCHDOG),
65};
66
67/* uart registration process */
68
69void __init s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no)
70{
71 s3c24xx_init_uartdevs("s3c2412-uart", s3c2410_uart_resources, cfg, no);
72
73 /* rename devices that are s3c2412/s3c2413 specific */
74 s3c_device_sdi.name = "s3c2412-sdi";
75 s3c_device_nand.name = "s3c2412-nand";
76}
77
78/* s3c2412_map_io
79 *
80 * register the standard cpu IO areas, and any passed in from the
81 * machine specific initialisation.
82*/
83
84void __init s3c2412_map_io(struct map_desc *mach_desc, int mach_size)
85{
86 /* move base of IO */
87
88 s3c24xx_va_gpio2 = S3C24XX_VA_GPIO + 0x10;
89
90 /* register our io-tables */
91
92 iotable_init(s3c2412_iodesc, ARRAY_SIZE(s3c2412_iodesc));
93 iotable_init(mach_desc, mach_size);
94}
95
96void __init s3c2412_init_clocks(int xtal)
97{
98 unsigned long tmp;
99 unsigned long fclk;
100 unsigned long hclk;
101 unsigned long pclk;
102
103 /* now we've got our machine bits initialised, work out what
104 * clocks we've got */
105
106 fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal*2);
107
108 tmp = __raw_readl(S3C2410_CLKDIVN);
109
110 /* work out clock scalings */
111
112 hclk = fclk / ((tmp & S3C2412_CLKDIVN_HDIVN_MASK) + 1);
113 hclk /= ((tmp & S3C2421_CLKDIVN_ARMDIVN) ? 2 : 1);
114 pclk = hclk / ((tmp & S3C2412_CLKDIVN_PDIVN) ? 2 : 1);
115
116 /* print brieft summary of clocks, etc */
117
118 printk("S3C2412: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
119 print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
120
121 /* initialise the clocks here, to allow other things like the
122 * console to use them
123 */
124
125 s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
126 s3c2412_baseclk_add();
127}
128
129/* need to register class before we actually register the device, and
130 * we also need to ensure that it has been initialised before any of the
131 * drivers even try to use it (even if not on an s3c2412 based system)
132 * as a driver which may support both 2410 and 2440 may try and use it.
133*/
134
135#ifdef CONFIG_PM
136static struct sleep_save s3c2412_sleep[] = {
137 SAVE_ITEM(S3C2412_DSC0),
138 SAVE_ITEM(S3C2412_DSC1),
139 SAVE_ITEM(S3C2413_GPJDAT),
140 SAVE_ITEM(S3C2413_GPJCON),
141 SAVE_ITEM(S3C2413_GPJUP),
142
143 /* save the sleep configuration anyway, just in case these
144 * get damaged during wakeup */
145
146 SAVE_ITEM(S3C2412_GPBSLPCON),
147 SAVE_ITEM(S3C2412_GPCSLPCON),
148 SAVE_ITEM(S3C2412_GPDSLPCON),
149 SAVE_ITEM(S3C2412_GPESLPCON),
150 SAVE_ITEM(S3C2412_GPFSLPCON),
151 SAVE_ITEM(S3C2412_GPGSLPCON),
152 SAVE_ITEM(S3C2412_GPHSLPCON),
153 SAVE_ITEM(S3C2413_GPJSLPCON),
154};
155
156static int s3c2412_suspend(struct sys_device *dev, pm_message_t state)
157{
158 s3c2410_pm_do_save(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
159 return 0;
160}
161
162static int s3c2412_resume(struct sys_device *dev)
163{
164 s3c2410_pm_do_restore(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
165 return 0;
166}
167
168#else
169#define s3c2412_suspend NULL
170#define s3c2412_resume NULL
171#endif
172
173struct sysdev_class s3c2412_sysclass = {
174 set_kset_name("s3c2412-core"),
175 .suspend = s3c2412_suspend,
176 .resume = s3c2412_resume
177};
178
179static int __init s3c2412_core_init(void)
180{
181 return sysdev_class_register(&s3c2412_sysclass);
182}
183
184core_initcall(s3c2412_core_init);
185
186static struct sys_device s3c2412_sysdev = {
187 .cls = &s3c2412_sysclass,
188};
189
190int __init s3c2412_init(void)
191{
192 printk("S3C2412: Initialising architecture\n");
193
194 return sysdev_register(&s3c2412_sysdev);
195}
diff --git a/arch/arm/mach-s3c2410/s3c2412.h b/arch/arm/mach-s3c2410/s3c2412.h
new file mode 100644
index 000000000000..c6e56032a6e7
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2412.h
@@ -0,0 +1,29 @@
1/* arch/arm/mach-s3c2410/s3c2412.h
2 *
3 * Copyright (c) 2006 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * Header file for s3c2412 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
13#ifdef CONFIG_CPU_S3C2412
14
15extern int s3c2412_init(void);
16
17extern void s3c2412_map_io(struct map_desc *mach_desc, int size);
18
19extern void s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no);
20
21extern void s3c2412_init_clocks(int xtal);
22
23extern int s3c2412_baseclk_add(void);
24#else
25#define s3c2412_init_clocks NULL
26#define s3c2412_init_uarts NULL
27#define s3c2412_map_io NULL
28#define s3c2412_init NULL
29#endif
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 4221d054a1e9..ecf5e232a6fc 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -61,9 +61,9 @@ config CPU_ARM720T
61 61
62# ARM920T 62# ARM920T
63config CPU_ARM920T 63config CPU_ARM920T
64 bool "Support ARM920T processor" if !ARCH_S3C2410 64 bool "Support ARM920T processor"
65 depends on ARCH_EP93XX || ARCH_INTEGRATOR || ARCH_S3C2410 || ARCH_IMX || ARCH_AAEC2000 || ARCH_AT91RM9200 65 depends on ARCH_EP93XX || ARCH_INTEGRATOR || CPU_S3C2410 || CPU_S3C2440 || CPU_S3C2442 || ARCH_IMX || ARCH_AAEC2000 || ARCH_AT91RM9200
66 default y if ARCH_S3C2410 || ARCH_AT91RM9200 66 default y if CPU_S3C2410 || CPU_S3C2440 || CPU_S3C2442 || ARCH_AT91RM9200
67 select CPU_32v4 67 select CPU_32v4
68 select CPU_ABRT_EV4T 68 select CPU_ABRT_EV4T
69 select CPU_CACHE_V4WT 69 select CPU_CACHE_V4WT
@@ -121,8 +121,8 @@ config CPU_ARM925T
121# ARM926T 121# ARM926T
122config CPU_ARM926T 122config CPU_ARM926T
123 bool "Support ARM926T processor" 123 bool "Support ARM926T processor"
124 depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX 124 depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412
125 default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 || ARCH_NETX 125 default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412
126 select CPU_32v5 126 select CPU_32v5
127 select CPU_ABRT_EV5TJ 127 select CPU_ABRT_EV5TJ
128 select CPU_CACHE_VIVT 128 select CPU_CACHE_VIVT