blob: cbbaca54966acce01f768d460586b1cb58e12237 [file] [log] [blame]
Kukjin Kimcc511b82011-12-27 08:18:36 +01001/*
2 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com
4 *
5 * Common Codes for EXYNOS
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/kernel.h>
13#include <linux/interrupt.h>
14#include <linux/irq.h>
15#include <linux/io.h>
Linus Torvalds7affca32012-01-07 12:03:30 -080016#include <linux/device.h>
Kukjin Kimcc511b82011-12-27 08:18:36 +010017#include <linux/gpio.h>
18#include <linux/sched.h>
19#include <linux/serial_core.h>
Arnd Bergmann237c78b2012-01-07 12:30:20 +000020#include <linux/of.h>
21#include <linux/of_irq.h>
Kukjin Kimcc511b82011-12-27 08:18:36 +010022
23#include <asm/proc-fns.h>
Arnd Bergmann40ba95f2012-01-07 11:51:28 +000024#include <asm/exception.h>
Kukjin Kimcc511b82011-12-27 08:18:36 +010025#include <asm/hardware/cache-l2x0.h>
26#include <asm/hardware/gic.h>
27#include <asm/mach/map.h>
28#include <asm/mach/irq.h>
29
30#include <mach/regs-irq.h>
31#include <mach/regs-pmu.h>
32#include <mach/regs-gpio.h>
33
34#include <plat/cpu.h>
35#include <plat/clock.h>
36#include <plat/devs.h>
37#include <plat/pm.h>
Kukjin Kimcc511b82011-12-27 08:18:36 +010038#include <plat/sdhci.h>
39#include <plat/gpio-cfg.h>
40#include <plat/adc-core.h>
41#include <plat/fb-core.h>
42#include <plat/fimc-core.h>
43#include <plat/iic-core.h>
44#include <plat/tv-core.h>
45#include <plat/regs-serial.h>
46
47#include "common.h"
48
Kukjin Kimcc511b82011-12-27 08:18:36 +010049static const char name_exynos4210[] = "EXYNOS4210";
50static const char name_exynos4212[] = "EXYNOS4212";
51static const char name_exynos4412[] = "EXYNOS4412";
Kukjin Kim94c7ca72012-02-11 22:15:45 +090052static const char name_exynos5250[] = "EXYNOS5250";
Kukjin Kimcc511b82011-12-27 08:18:36 +010053
Kukjin Kim906c7892012-02-11 21:27:08 +090054static void exynos4_map_io(void);
Kukjin Kim94c7ca72012-02-11 22:15:45 +090055static void exynos5_map_io(void);
Kukjin Kim906c7892012-02-11 21:27:08 +090056static void exynos4_init_clocks(int xtal);
Kukjin Kim94c7ca72012-02-11 22:15:45 +090057static void exynos5_init_clocks(int xtal);
Kukjin Kim920f4882012-01-24 20:52:52 +090058static void exynos_init_uarts(struct s3c2410_uartcfg *cfg, int no);
Kukjin Kim906c7892012-02-11 21:27:08 +090059static int exynos_init(void);
60
Kukjin Kimcc511b82011-12-27 08:18:36 +010061static struct cpu_table cpu_ids[] __initdata = {
62 {
63 .idcode = EXYNOS4210_CPU_ID,
64 .idmask = EXYNOS4_CPU_MASK,
65 .map_io = exynos4_map_io,
66 .init_clocks = exynos4_init_clocks,
Kukjin Kim920f4882012-01-24 20:52:52 +090067 .init_uarts = exynos_init_uarts,
Kukjin Kimcc511b82011-12-27 08:18:36 +010068 .init = exynos_init,
69 .name = name_exynos4210,
70 }, {
71 .idcode = EXYNOS4212_CPU_ID,
72 .idmask = EXYNOS4_CPU_MASK,
73 .map_io = exynos4_map_io,
74 .init_clocks = exynos4_init_clocks,
Kukjin Kim920f4882012-01-24 20:52:52 +090075 .init_uarts = exynos_init_uarts,
Kukjin Kimcc511b82011-12-27 08:18:36 +010076 .init = exynos_init,
77 .name = name_exynos4212,
78 }, {
79 .idcode = EXYNOS4412_CPU_ID,
80 .idmask = EXYNOS4_CPU_MASK,
81 .map_io = exynos4_map_io,
82 .init_clocks = exynos4_init_clocks,
Kukjin Kim920f4882012-01-24 20:52:52 +090083 .init_uarts = exynos_init_uarts,
Kukjin Kimcc511b82011-12-27 08:18:36 +010084 .init = exynos_init,
85 .name = name_exynos4412,
Kukjin Kim94c7ca72012-02-11 22:15:45 +090086 }, {
87 .idcode = EXYNOS5250_SOC_ID,
88 .idmask = EXYNOS5_SOC_MASK,
89 .map_io = exynos5_map_io,
90 .init_clocks = exynos5_init_clocks,
91 .init_uarts = exynos_init_uarts,
92 .init = exynos_init,
93 .name = name_exynos5250,
Kukjin Kimcc511b82011-12-27 08:18:36 +010094 },
95};
96
97/* Initial IO mappings */
98
99static struct map_desc exynos_iodesc[] __initdata = {
100 {
101 .virtual = (unsigned long)S5P_VA_CHIPID,
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900102 .pfn = __phys_to_pfn(EXYNOS_PA_CHIPID),
Kukjin Kimcc511b82011-12-27 08:18:36 +0100103 .length = SZ_4K,
104 .type = MT_DEVICE,
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900105 },
106};
107
108static struct map_desc exynos4_iodesc[] __initdata = {
109 {
Kukjin Kimcc511b82011-12-27 08:18:36 +0100110 .virtual = (unsigned long)S3C_VA_SYS,
111 .pfn = __phys_to_pfn(EXYNOS4_PA_SYSCON),
112 .length = SZ_64K,
113 .type = MT_DEVICE,
114 }, {
115 .virtual = (unsigned long)S3C_VA_TIMER,
116 .pfn = __phys_to_pfn(EXYNOS4_PA_TIMER),
117 .length = SZ_16K,
118 .type = MT_DEVICE,
119 }, {
120 .virtual = (unsigned long)S3C_VA_WATCHDOG,
121 .pfn = __phys_to_pfn(EXYNOS4_PA_WATCHDOG),
122 .length = SZ_4K,
123 .type = MT_DEVICE,
124 }, {
125 .virtual = (unsigned long)S5P_VA_SROMC,
126 .pfn = __phys_to_pfn(EXYNOS4_PA_SROMC),
127 .length = SZ_4K,
128 .type = MT_DEVICE,
129 }, {
130 .virtual = (unsigned long)S5P_VA_SYSTIMER,
131 .pfn = __phys_to_pfn(EXYNOS4_PA_SYSTIMER),
132 .length = SZ_4K,
133 .type = MT_DEVICE,
134 }, {
135 .virtual = (unsigned long)S5P_VA_PMU,
136 .pfn = __phys_to_pfn(EXYNOS4_PA_PMU),
137 .length = SZ_64K,
138 .type = MT_DEVICE,
139 }, {
140 .virtual = (unsigned long)S5P_VA_COMBINER_BASE,
141 .pfn = __phys_to_pfn(EXYNOS4_PA_COMBINER),
142 .length = SZ_4K,
143 .type = MT_DEVICE,
144 }, {
145 .virtual = (unsigned long)S5P_VA_GIC_CPU,
146 .pfn = __phys_to_pfn(EXYNOS4_PA_GIC_CPU),
147 .length = SZ_64K,
148 .type = MT_DEVICE,
149 }, {
150 .virtual = (unsigned long)S5P_VA_GIC_DIST,
151 .pfn = __phys_to_pfn(EXYNOS4_PA_GIC_DIST),
152 .length = SZ_64K,
153 .type = MT_DEVICE,
154 }, {
155 .virtual = (unsigned long)S3C_VA_UART,
156 .pfn = __phys_to_pfn(EXYNOS4_PA_UART),
157 .length = SZ_512K,
158 .type = MT_DEVICE,
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900159 }, {
Kukjin Kimcc511b82011-12-27 08:18:36 +0100160 .virtual = (unsigned long)S5P_VA_CMU,
161 .pfn = __phys_to_pfn(EXYNOS4_PA_CMU),
162 .length = SZ_128K,
163 .type = MT_DEVICE,
164 }, {
165 .virtual = (unsigned long)S5P_VA_COREPERI_BASE,
166 .pfn = __phys_to_pfn(EXYNOS4_PA_COREPERI),
167 .length = SZ_8K,
168 .type = MT_DEVICE,
169 }, {
170 .virtual = (unsigned long)S5P_VA_L2CC,
171 .pfn = __phys_to_pfn(EXYNOS4_PA_L2CC),
172 .length = SZ_4K,
173 .type = MT_DEVICE,
174 }, {
175 .virtual = (unsigned long)S5P_VA_GPIO1,
176 .pfn = __phys_to_pfn(EXYNOS4_PA_GPIO1),
177 .length = SZ_4K,
178 .type = MT_DEVICE,
179 }, {
180 .virtual = (unsigned long)S5P_VA_GPIO2,
181 .pfn = __phys_to_pfn(EXYNOS4_PA_GPIO2),
182 .length = SZ_4K,
183 .type = MT_DEVICE,
184 }, {
185 .virtual = (unsigned long)S5P_VA_GPIO3,
186 .pfn = __phys_to_pfn(EXYNOS4_PA_GPIO3),
187 .length = SZ_256,
188 .type = MT_DEVICE,
189 }, {
190 .virtual = (unsigned long)S5P_VA_DMC0,
191 .pfn = __phys_to_pfn(EXYNOS4_PA_DMC0),
192 .length = SZ_4K,
193 .type = MT_DEVICE,
194 }, {
Kukjin Kimcc511b82011-12-27 08:18:36 +0100195 .virtual = (unsigned long)S3C_VA_USB_HSPHY,
196 .pfn = __phys_to_pfn(EXYNOS4_PA_HSPHY),
197 .length = SZ_4K,
198 .type = MT_DEVICE,
199 },
200};
201
202static struct map_desc exynos4_iodesc0[] __initdata = {
203 {
204 .virtual = (unsigned long)S5P_VA_SYSRAM,
205 .pfn = __phys_to_pfn(EXYNOS4_PA_SYSRAM0),
206 .length = SZ_4K,
207 .type = MT_DEVICE,
208 },
209};
210
211static struct map_desc exynos4_iodesc1[] __initdata = {
212 {
213 .virtual = (unsigned long)S5P_VA_SYSRAM,
214 .pfn = __phys_to_pfn(EXYNOS4_PA_SYSRAM1),
215 .length = SZ_4K,
216 .type = MT_DEVICE,
217 },
218};
219
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900220static struct map_desc exynos5_iodesc[] __initdata = {
221 {
222 .virtual = (unsigned long)S3C_VA_SYS,
223 .pfn = __phys_to_pfn(EXYNOS5_PA_SYSCON),
224 .length = SZ_64K,
225 .type = MT_DEVICE,
226 }, {
227 .virtual = (unsigned long)S3C_VA_TIMER,
228 .pfn = __phys_to_pfn(EXYNOS5_PA_TIMER),
229 .length = SZ_16K,
230 .type = MT_DEVICE,
231 }, {
232 .virtual = (unsigned long)S3C_VA_WATCHDOG,
233 .pfn = __phys_to_pfn(EXYNOS5_PA_WATCHDOG),
234 .length = SZ_4K,
235 .type = MT_DEVICE,
236 }, {
237 .virtual = (unsigned long)S5P_VA_SROMC,
238 .pfn = __phys_to_pfn(EXYNOS5_PA_SROMC),
239 .length = SZ_4K,
240 .type = MT_DEVICE,
241 }, {
242 .virtual = (unsigned long)S5P_VA_SYSTIMER,
243 .pfn = __phys_to_pfn(EXYNOS5_PA_SYSTIMER),
244 .length = SZ_4K,
245 .type = MT_DEVICE,
246 }, {
247 .virtual = (unsigned long)S5P_VA_SYSRAM,
248 .pfn = __phys_to_pfn(EXYNOS5_PA_SYSRAM),
249 .length = SZ_4K,
250 .type = MT_DEVICE,
251 }, {
252 .virtual = (unsigned long)S5P_VA_CMU,
253 .pfn = __phys_to_pfn(EXYNOS5_PA_CMU),
254 .length = 144 * SZ_1K,
255 .type = MT_DEVICE,
256 }, {
257 .virtual = (unsigned long)S5P_VA_PMU,
258 .pfn = __phys_to_pfn(EXYNOS5_PA_PMU),
259 .length = SZ_64K,
260 .type = MT_DEVICE,
261 }, {
262 .virtual = (unsigned long)S5P_VA_COMBINER_BASE,
263 .pfn = __phys_to_pfn(EXYNOS5_PA_COMBINER),
264 .length = SZ_4K,
265 .type = MT_DEVICE,
266 }, {
267 .virtual = (unsigned long)S3C_VA_UART,
268 .pfn = __phys_to_pfn(EXYNOS5_PA_UART),
269 .length = SZ_512K,
270 .type = MT_DEVICE,
271 }, {
272 .virtual = (unsigned long)S5P_VA_GIC_CPU,
273 .pfn = __phys_to_pfn(EXYNOS5_PA_GIC_CPU),
274 .length = SZ_64K,
275 .type = MT_DEVICE,
276 }, {
277 .virtual = (unsigned long)S5P_VA_GIC_DIST,
278 .pfn = __phys_to_pfn(EXYNOS5_PA_GIC_DIST),
279 .length = SZ_64K,
280 .type = MT_DEVICE,
281 },
282};
283
Russell King9eb48592012-01-03 11:56:53 +0100284void exynos4_restart(char mode, const char *cmd)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100285{
286 __raw_writel(0x1, S5P_SWRESET);
287}
288
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900289void exynos5_restart(char mode, const char *cmd)
290{
291 __raw_writel(0x1, EXYNOS_SWRESET);
292}
293
Kukjin Kimcc511b82011-12-27 08:18:36 +0100294/*
295 * exynos_map_io
296 *
297 * register the standard cpu IO areas
298 */
299
300void __init exynos_init_io(struct map_desc *mach_desc, int size)
301{
302 /* initialize the io descriptors we need for initialization */
303 iotable_init(exynos_iodesc, ARRAY_SIZE(exynos_iodesc));
304 if (mach_desc)
305 iotable_init(mach_desc, size);
306
307 /* detect cpu id and rev. */
308 s5p_init_cpu(S5P_VA_CHIPID);
309
310 s3c_init_cpu(samsung_cpu_id, cpu_ids, ARRAY_SIZE(cpu_ids));
311}
312
Kukjin Kim906c7892012-02-11 21:27:08 +0900313static void __init exynos4_map_io(void)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100314{
315 iotable_init(exynos4_iodesc, ARRAY_SIZE(exynos4_iodesc));
316
317 if (soc_is_exynos4210() && samsung_rev() == EXYNOS4210_REV_0)
318 iotable_init(exynos4_iodesc0, ARRAY_SIZE(exynos4_iodesc0));
319 else
320 iotable_init(exynos4_iodesc1, ARRAY_SIZE(exynos4_iodesc1));
321
322 /* initialize device information early */
323 exynos4_default_sdhci0();
324 exynos4_default_sdhci1();
325 exynos4_default_sdhci2();
326 exynos4_default_sdhci3();
327
328 s3c_adc_setname("samsung-adc-v3");
329
330 s3c_fimc_setname(0, "exynos4-fimc");
331 s3c_fimc_setname(1, "exynos4-fimc");
332 s3c_fimc_setname(2, "exynos4-fimc");
333 s3c_fimc_setname(3, "exynos4-fimc");
334
335 /* The I2C bus controllers are directly compatible with s3c2440 */
336 s3c_i2c0_setname("s3c2440-i2c");
337 s3c_i2c1_setname("s3c2440-i2c");
338 s3c_i2c2_setname("s3c2440-i2c");
339
340 s5p_fb_setname(0, "exynos4-fb");
341 s5p_hdmi_setname("exynos4-hdmi");
342}
343
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900344static void __init exynos5_map_io(void)
345{
346 iotable_init(exynos5_iodesc, ARRAY_SIZE(exynos5_iodesc));
347
Kukjin Kimbb19a752012-01-25 13:48:11 +0900348 s3c_device_i2c0.resource[0].start = EXYNOS5_PA_IIC(0);
349 s3c_device_i2c0.resource[0].end = EXYNOS5_PA_IIC(0) + SZ_4K - 1;
350 s3c_device_i2c0.resource[1].start = EXYNOS5_IRQ_IIC;
351 s3c_device_i2c0.resource[1].end = EXYNOS5_IRQ_IIC;
352
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900353 /* The I2C bus controllers are directly compatible with s3c2440 */
354 s3c_i2c0_setname("s3c2440-i2c");
355 s3c_i2c1_setname("s3c2440-i2c");
356 s3c_i2c2_setname("s3c2440-i2c");
357}
358
Kukjin Kim906c7892012-02-11 21:27:08 +0900359static void __init exynos4_init_clocks(int xtal)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100360{
361 printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
362
363 s3c24xx_register_baseclocks(xtal);
364 s5p_register_clocks(xtal);
365
366 if (soc_is_exynos4210())
367 exynos4210_register_clocks();
368 else if (soc_is_exynos4212() || soc_is_exynos4412())
369 exynos4212_register_clocks();
370
371 exynos4_register_clocks();
372 exynos4_setup_clocks();
373}
374
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900375static void __init exynos5_init_clocks(int xtal)
376{
377 printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
378
379 s3c24xx_register_baseclocks(xtal);
380 s5p_register_clocks(xtal);
381
382 exynos5_register_clocks();
383 exynos5_setup_clocks();
384}
385
Kukjin Kimcc511b82011-12-27 08:18:36 +0100386#define COMBINER_ENABLE_SET 0x0
387#define COMBINER_ENABLE_CLEAR 0x4
388#define COMBINER_INT_STATUS 0xC
389
390static DEFINE_SPINLOCK(irq_controller_lock);
391
392struct combiner_chip_data {
393 unsigned int irq_offset;
394 unsigned int irq_mask;
395 void __iomem *base;
396};
397
398static struct combiner_chip_data combiner_data[MAX_COMBINER_NR];
399
400static inline void __iomem *combiner_base(struct irq_data *data)
401{
402 struct combiner_chip_data *combiner_data =
403 irq_data_get_irq_chip_data(data);
404
405 return combiner_data->base;
406}
407
408static void combiner_mask_irq(struct irq_data *data)
409{
410 u32 mask = 1 << (data->irq % 32);
411
412 __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR);
413}
414
415static void combiner_unmask_irq(struct irq_data *data)
416{
417 u32 mask = 1 << (data->irq % 32);
418
419 __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET);
420}
421
422static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
423{
424 struct combiner_chip_data *chip_data = irq_get_handler_data(irq);
425 struct irq_chip *chip = irq_get_chip(irq);
426 unsigned int cascade_irq, combiner_irq;
427 unsigned long status;
428
429 chained_irq_enter(chip, desc);
430
431 spin_lock(&irq_controller_lock);
432 status = __raw_readl(chip_data->base + COMBINER_INT_STATUS);
433 spin_unlock(&irq_controller_lock);
434 status &= chip_data->irq_mask;
435
436 if (status == 0)
437 goto out;
438
439 combiner_irq = __ffs(status);
440
441 cascade_irq = combiner_irq + (chip_data->irq_offset & ~31);
442 if (unlikely(cascade_irq >= NR_IRQS))
443 do_bad_IRQ(cascade_irq, desc);
444 else
445 generic_handle_irq(cascade_irq);
446
447 out:
448 chained_irq_exit(chip, desc);
449}
450
451static struct irq_chip combiner_chip = {
452 .name = "COMBINER",
453 .irq_mask = combiner_mask_irq,
454 .irq_unmask = combiner_unmask_irq,
455};
456
457static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq)
458{
Kukjin Kimbb19a752012-01-25 13:48:11 +0900459 unsigned int max_nr;
460
461 if (soc_is_exynos5250())
462 max_nr = EXYNOS5_MAX_COMBINER_NR;
463 else
464 max_nr = EXYNOS4_MAX_COMBINER_NR;
465
466 if (combiner_nr >= max_nr)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100467 BUG();
468 if (irq_set_handler_data(irq, &combiner_data[combiner_nr]) != 0)
469 BUG();
470 irq_set_chained_handler(irq, combiner_handle_cascade_irq);
471}
472
473static void __init combiner_init(unsigned int combiner_nr, void __iomem *base,
474 unsigned int irq_start)
475{
476 unsigned int i;
Kukjin Kimbb19a752012-01-25 13:48:11 +0900477 unsigned int max_nr;
Kukjin Kimcc511b82011-12-27 08:18:36 +0100478
Kukjin Kimbb19a752012-01-25 13:48:11 +0900479 if (soc_is_exynos5250())
480 max_nr = EXYNOS5_MAX_COMBINER_NR;
481 else
482 max_nr = EXYNOS4_MAX_COMBINER_NR;
483
484 if (combiner_nr >= max_nr)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100485 BUG();
486
487 combiner_data[combiner_nr].base = base;
488 combiner_data[combiner_nr].irq_offset = irq_start;
489 combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3);
490
491 /* Disable all interrupts */
492
493 __raw_writel(combiner_data[combiner_nr].irq_mask,
494 base + COMBINER_ENABLE_CLEAR);
495
496 /* Setup the Linux IRQ subsystem */
497
498 for (i = irq_start; i < combiner_data[combiner_nr].irq_offset
499 + MAX_IRQ_IN_COMBINER; i++) {
500 irq_set_chip_and_handler(i, &combiner_chip, handle_level_irq);
501 irq_set_chip_data(i, &combiner_data[combiner_nr]);
502 set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
503 }
504}
505
Arnd Bergmann237c78b2012-01-07 12:30:20 +0000506#ifdef CONFIG_OF
507static const struct of_device_id exynos4_dt_irq_match[] = {
508 { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
509 {},
510};
511#endif
Kukjin Kimcc511b82011-12-27 08:18:36 +0100512
513void __init exynos4_init_irq(void)
514{
515 int irq;
Arnd Bergmann40ba95f2012-01-07 11:51:28 +0000516 unsigned int gic_bank_offset;
Kukjin Kimcc511b82011-12-27 08:18:36 +0100517
518 gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000;
519
Arnd Bergmann237c78b2012-01-07 12:30:20 +0000520 if (!of_have_populated_dt())
521 gic_init_bases(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU, gic_bank_offset);
522#ifdef CONFIG_OF
523 else
524 of_irq_init(exynos4_dt_irq_match);
525#endif
Kukjin Kimcc511b82011-12-27 08:18:36 +0100526
Kukjin Kimbb19a752012-01-25 13:48:11 +0900527 for (irq = 0; irq < EXYNOS4_MAX_COMBINER_NR; irq++) {
Kukjin Kimcc511b82011-12-27 08:18:36 +0100528
529 combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
530 COMBINER_IRQ(irq, 0));
531 combiner_cascade_irq(irq, IRQ_SPI(irq));
532 }
533
534 /*
535 * The parameters of s5p_init_irq() are for VIC init.
536 * Theses parameters should be NULL and 0 because EXYNOS4
537 * uses GIC instead of VIC.
538 */
539 s5p_init_irq(NULL, 0);
540}
541
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900542void __init exynos5_init_irq(void)
543{
544 int irq;
545
546 gic_init(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU);
547
Kukjin Kimbb19a752012-01-25 13:48:11 +0900548 for (irq = 0; irq < EXYNOS5_MAX_COMBINER_NR; irq++) {
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900549 combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
550 COMBINER_IRQ(irq, 0));
551 combiner_cascade_irq(irq, IRQ_SPI(irq));
552 }
553
554 /*
555 * The parameters of s5p_init_irq() are for VIC init.
556 * Theses parameters should be NULL and 0 because EXYNOS4
557 * uses GIC instead of VIC.
558 */
559 s5p_init_irq(NULL, 0);
560}
561
Linus Torvalds7affca32012-01-07 12:03:30 -0800562struct bus_type exynos4_subsys = {
563 .name = "exynos4-core",
564 .dev_name = "exynos4-core",
Kukjin Kimcc511b82011-12-27 08:18:36 +0100565};
566
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900567struct bus_type exynos5_subsys = {
568 .name = "exynos5-core",
569 .dev_name = "exynos5-core",
570};
571
Linus Torvalds7affca32012-01-07 12:03:30 -0800572static struct device exynos4_dev = {
573 .bus = &exynos4_subsys,
Kukjin Kimcc511b82011-12-27 08:18:36 +0100574};
575
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900576static struct device exynos5_dev = {
577 .bus = &exynos5_subsys,
578};
579
580static int __init exynos_core_init(void)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100581{
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900582 if (soc_is_exynos5250())
583 return subsys_system_register(&exynos5_subsys, NULL);
584 else
585 return subsys_system_register(&exynos4_subsys, NULL);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100586}
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900587core_initcall(exynos_core_init);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100588
589#ifdef CONFIG_CACHE_L2X0
590static int __init exynos4_l2x0_cache_init(void)
591{
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900592 if (soc_is_exynos5250())
593 return 0;
594
Kukjin Kimcc511b82011-12-27 08:18:36 +0100595 /* TAG, Data Latency Control: 2cycle */
596 __raw_writel(0x110, S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL);
597
598 if (soc_is_exynos4210())
599 __raw_writel(0x110, S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL);
600 else if (soc_is_exynos4212() || soc_is_exynos4412())
601 __raw_writel(0x120, S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL);
602
603 /* L2X0 Prefetch Control */
604 __raw_writel(0x30000007, S5P_VA_L2CC + L2X0_PREFETCH_CTRL);
605
606 /* L2X0 Power Control */
607 __raw_writel(L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN,
608 S5P_VA_L2CC + L2X0_POWER_CTRL);
609
610 l2x0_init(S5P_VA_L2CC, 0x7C470001, 0xC200ffff);
611
612 return 0;
613}
Kukjin Kimcc511b82011-12-27 08:18:36 +0100614early_initcall(exynos4_l2x0_cache_init);
615#endif
616
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900617static int __init exynos5_l2_cache_init(void)
618{
619 unsigned int val;
620
621 if (!soc_is_exynos5250())
622 return 0;
623
624 asm volatile("mrc p15, 0, %0, c1, c0, 0\n"
625 "bic %0, %0, #(1 << 2)\n" /* cache disable */
626 "mcr p15, 0, %0, c1, c0, 0\n"
627 "mrc p15, 1, %0, c9, c0, 2\n"
628 : "=r"(val));
629
630 val |= (1 << 9) | (1 << 5) | (2 << 6) | (2 << 0);
631
632 asm volatile("mcr p15, 1, %0, c9, c0, 2\n" : : "r"(val));
633 asm volatile("mrc p15, 0, %0, c1, c0, 0\n"
634 "orr %0, %0, #(1 << 2)\n" /* cache enable */
635 "mcr p15, 0, %0, c1, c0, 0\n"
636 : : "r"(val));
637
638 return 0;
639}
640early_initcall(exynos5_l2_cache_init);
641
Kukjin Kim906c7892012-02-11 21:27:08 +0900642static int __init exynos_init(void)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100643{
644 printk(KERN_INFO "EXYNOS: Initializing architecture\n");
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900645
646 if (soc_is_exynos5250())
647 return device_register(&exynos5_dev);
648 else
649 return device_register(&exynos4_dev);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100650}
651
Kukjin Kimcc511b82011-12-27 08:18:36 +0100652/* uart registration process */
653
Kukjin Kim920f4882012-01-24 20:52:52 +0900654static void __init exynos_init_uarts(struct s3c2410_uartcfg *cfg, int no)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100655{
656 struct s3c2410_uartcfg *tcfg = cfg;
657 u32 ucnt;
658
Arnd Bergmann237c78b2012-01-07 12:30:20 +0000659 for (ucnt = 0; ucnt < no; ucnt++, tcfg++)
660 tcfg->has_fracval = 1;
Kukjin Kimcc511b82011-12-27 08:18:36 +0100661
Kukjin Kim171c0672012-02-10 11:57:53 +0900662 if (soc_is_exynos5250())
663 s3c24xx_init_uartdevs("exynos4210-uart", exynos5_uart_resources, cfg, no);
664 else
665 s3c24xx_init_uartdevs("exynos4210-uart", exynos4_uart_resources, cfg, no);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100666}
667
Eunki Kim330c90a2012-03-14 01:43:31 -0700668static void __iomem *exynos_eint_base;
669
Kukjin Kimcc511b82011-12-27 08:18:36 +0100670static DEFINE_SPINLOCK(eint_lock);
671
672static unsigned int eint0_15_data[16];
673
Eunki Kim330c90a2012-03-14 01:43:31 -0700674static inline int exynos4_irq_to_gpio(unsigned int irq)
675{
676 if (irq < IRQ_EINT(0))
677 return -EINVAL;
678
679 irq -= IRQ_EINT(0);
680 if (irq < 8)
681 return EXYNOS4_GPX0(irq);
682
683 irq -= 8;
684 if (irq < 8)
685 return EXYNOS4_GPX1(irq);
686
687 irq -= 8;
688 if (irq < 8)
689 return EXYNOS4_GPX2(irq);
690
691 irq -= 8;
692 if (irq < 8)
693 return EXYNOS4_GPX3(irq);
694
695 return -EINVAL;
696}
697
698static inline int exynos5_irq_to_gpio(unsigned int irq)
699{
700 if (irq < IRQ_EINT(0))
701 return -EINVAL;
702
703 irq -= IRQ_EINT(0);
704 if (irq < 8)
705 return EXYNOS5_GPX0(irq);
706
707 irq -= 8;
708 if (irq < 8)
709 return EXYNOS5_GPX1(irq);
710
711 irq -= 8;
712 if (irq < 8)
713 return EXYNOS5_GPX2(irq);
714
715 irq -= 8;
716 if (irq < 8)
717 return EXYNOS5_GPX3(irq);
718
719 return -EINVAL;
720}
721
Kukjin Kimbb19a752012-01-25 13:48:11 +0900722static unsigned int exynos4_eint0_15_src_int[16] = {
723 EXYNOS4_IRQ_EINT0,
724 EXYNOS4_IRQ_EINT1,
725 EXYNOS4_IRQ_EINT2,
726 EXYNOS4_IRQ_EINT3,
727 EXYNOS4_IRQ_EINT4,
728 EXYNOS4_IRQ_EINT5,
729 EXYNOS4_IRQ_EINT6,
730 EXYNOS4_IRQ_EINT7,
731 EXYNOS4_IRQ_EINT8,
732 EXYNOS4_IRQ_EINT9,
733 EXYNOS4_IRQ_EINT10,
734 EXYNOS4_IRQ_EINT11,
735 EXYNOS4_IRQ_EINT12,
736 EXYNOS4_IRQ_EINT13,
737 EXYNOS4_IRQ_EINT14,
738 EXYNOS4_IRQ_EINT15,
739};
Kukjin Kimcc511b82011-12-27 08:18:36 +0100740
Kukjin Kimbb19a752012-01-25 13:48:11 +0900741static unsigned int exynos5_eint0_15_src_int[16] = {
742 EXYNOS5_IRQ_EINT0,
743 EXYNOS5_IRQ_EINT1,
744 EXYNOS5_IRQ_EINT2,
745 EXYNOS5_IRQ_EINT3,
746 EXYNOS5_IRQ_EINT4,
747 EXYNOS5_IRQ_EINT5,
748 EXYNOS5_IRQ_EINT6,
749 EXYNOS5_IRQ_EINT7,
750 EXYNOS5_IRQ_EINT8,
751 EXYNOS5_IRQ_EINT9,
752 EXYNOS5_IRQ_EINT10,
753 EXYNOS5_IRQ_EINT11,
754 EXYNOS5_IRQ_EINT12,
755 EXYNOS5_IRQ_EINT13,
756 EXYNOS5_IRQ_EINT14,
757 EXYNOS5_IRQ_EINT15,
758};
Eunki Kim330c90a2012-03-14 01:43:31 -0700759static inline void exynos_irq_eint_mask(struct irq_data *data)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100760{
761 u32 mask;
762
763 spin_lock(&eint_lock);
Eunki Kim330c90a2012-03-14 01:43:31 -0700764 mask = __raw_readl(EINT_MASK(exynos_eint_base, data->irq));
765 mask |= EINT_OFFSET_BIT(data->irq);
766 __raw_writel(mask, EINT_MASK(exynos_eint_base, data->irq));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100767 spin_unlock(&eint_lock);
768}
769
Eunki Kim330c90a2012-03-14 01:43:31 -0700770static void exynos_irq_eint_unmask(struct irq_data *data)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100771{
772 u32 mask;
773
774 spin_lock(&eint_lock);
Eunki Kim330c90a2012-03-14 01:43:31 -0700775 mask = __raw_readl(EINT_MASK(exynos_eint_base, data->irq));
776 mask &= ~(EINT_OFFSET_BIT(data->irq));
777 __raw_writel(mask, EINT_MASK(exynos_eint_base, data->irq));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100778 spin_unlock(&eint_lock);
779}
780
Eunki Kim330c90a2012-03-14 01:43:31 -0700781static inline void exynos_irq_eint_ack(struct irq_data *data)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100782{
Eunki Kim330c90a2012-03-14 01:43:31 -0700783 __raw_writel(EINT_OFFSET_BIT(data->irq),
784 EINT_PEND(exynos_eint_base, data->irq));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100785}
786
Eunki Kim330c90a2012-03-14 01:43:31 -0700787static void exynos_irq_eint_maskack(struct irq_data *data)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100788{
Eunki Kim330c90a2012-03-14 01:43:31 -0700789 exynos_irq_eint_mask(data);
790 exynos_irq_eint_ack(data);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100791}
792
Eunki Kim330c90a2012-03-14 01:43:31 -0700793static int exynos_irq_eint_set_type(struct irq_data *data, unsigned int type)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100794{
795 int offs = EINT_OFFSET(data->irq);
796 int shift;
797 u32 ctrl, mask;
798 u32 newvalue = 0;
799
800 switch (type) {
801 case IRQ_TYPE_EDGE_RISING:
802 newvalue = S5P_IRQ_TYPE_EDGE_RISING;
803 break;
804
805 case IRQ_TYPE_EDGE_FALLING:
806 newvalue = S5P_IRQ_TYPE_EDGE_FALLING;
807 break;
808
809 case IRQ_TYPE_EDGE_BOTH:
810 newvalue = S5P_IRQ_TYPE_EDGE_BOTH;
811 break;
812
813 case IRQ_TYPE_LEVEL_LOW:
814 newvalue = S5P_IRQ_TYPE_LEVEL_LOW;
815 break;
816
817 case IRQ_TYPE_LEVEL_HIGH:
818 newvalue = S5P_IRQ_TYPE_LEVEL_HIGH;
819 break;
820
821 default:
822 printk(KERN_ERR "No such irq type %d", type);
823 return -EINVAL;
824 }
825
826 shift = (offs & 0x7) * 4;
827 mask = 0x7 << shift;
828
829 spin_lock(&eint_lock);
Eunki Kim330c90a2012-03-14 01:43:31 -0700830 ctrl = __raw_readl(EINT_CON(exynos_eint_base, data->irq));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100831 ctrl &= ~mask;
832 ctrl |= newvalue << shift;
Eunki Kim330c90a2012-03-14 01:43:31 -0700833 __raw_writel(ctrl, EINT_CON(exynos_eint_base, data->irq));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100834 spin_unlock(&eint_lock);
835
Eunki Kim330c90a2012-03-14 01:43:31 -0700836 if (soc_is_exynos5250())
837 s3c_gpio_cfgpin(exynos5_irq_to_gpio(data->irq), S3C_GPIO_SFN(0xf));
838 else
839 s3c_gpio_cfgpin(exynos4_irq_to_gpio(data->irq), S3C_GPIO_SFN(0xf));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100840
841 return 0;
842}
843
Eunki Kim330c90a2012-03-14 01:43:31 -0700844static struct irq_chip exynos_irq_eint = {
845 .name = "exynos-eint",
846 .irq_mask = exynos_irq_eint_mask,
847 .irq_unmask = exynos_irq_eint_unmask,
848 .irq_mask_ack = exynos_irq_eint_maskack,
849 .irq_ack = exynos_irq_eint_ack,
850 .irq_set_type = exynos_irq_eint_set_type,
Kukjin Kimcc511b82011-12-27 08:18:36 +0100851#ifdef CONFIG_PM
852 .irq_set_wake = s3c_irqext_wake,
853#endif
854};
855
856/*
857 * exynos4_irq_demux_eint
858 *
859 * This function demuxes the IRQ from from EINTs 16 to 31.
860 * It is designed to be inlined into the specific handler
861 * s5p_irq_demux_eintX_Y.
862 *
863 * Each EINT pend/mask registers handle eight of them.
864 */
Eunki Kim330c90a2012-03-14 01:43:31 -0700865static inline void exynos_irq_demux_eint(unsigned int start)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100866{
867 unsigned int irq;
868
Eunki Kim330c90a2012-03-14 01:43:31 -0700869 u32 status = __raw_readl(EINT_PEND(exynos_eint_base, start));
870 u32 mask = __raw_readl(EINT_MASK(exynos_eint_base, start));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100871
872 status &= ~mask;
873 status &= 0xff;
874
875 while (status) {
876 irq = fls(status) - 1;
877 generic_handle_irq(irq + start);
878 status &= ~(1 << irq);
879 }
880}
881
Eunki Kim330c90a2012-03-14 01:43:31 -0700882static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100883{
884 struct irq_chip *chip = irq_get_chip(irq);
885 chained_irq_enter(chip, desc);
Eunki Kim330c90a2012-03-14 01:43:31 -0700886 exynos_irq_demux_eint(IRQ_EINT(16));
887 exynos_irq_demux_eint(IRQ_EINT(24));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100888 chained_irq_exit(chip, desc);
889}
890
Kukjin Kimbb19a752012-01-25 13:48:11 +0900891static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100892{
893 u32 *irq_data = irq_get_handler_data(irq);
894 struct irq_chip *chip = irq_get_chip(irq);
895
896 chained_irq_enter(chip, desc);
897 chip->irq_mask(&desc->irq_data);
898
899 if (chip->irq_ack)
900 chip->irq_ack(&desc->irq_data);
901
902 generic_handle_irq(*irq_data);
903
904 chip->irq_unmask(&desc->irq_data);
905 chained_irq_exit(chip, desc);
906}
907
Eunki Kim330c90a2012-03-14 01:43:31 -0700908static int __init exynos_init_irq_eint(void)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100909{
910 int irq;
911
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900912 if (soc_is_exynos5250())
Eunki Kim330c90a2012-03-14 01:43:31 -0700913 exynos_eint_base = ioremap(EXYNOS5_PA_GPIO1, SZ_4K);
914 else
915 exynos_eint_base = ioremap(EXYNOS4_PA_GPIO2, SZ_4K);
916
917 if (exynos_eint_base == NULL) {
918 pr_err("unable to ioremap for EINT base address\n");
919 return -ENOMEM;
920 }
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900921
Kukjin Kimcc511b82011-12-27 08:18:36 +0100922 for (irq = 0 ; irq <= 31 ; irq++) {
Eunki Kim330c90a2012-03-14 01:43:31 -0700923 irq_set_chip_and_handler(IRQ_EINT(irq), &exynos_irq_eint,
Kukjin Kimcc511b82011-12-27 08:18:36 +0100924 handle_level_irq);
925 set_irq_flags(IRQ_EINT(irq), IRQF_VALID);
926 }
927
Eunki Kim330c90a2012-03-14 01:43:31 -0700928 irq_set_chained_handler(EXYNOS_IRQ_EINT16_31, exynos_irq_demux_eint16_31);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100929
930 for (irq = 0 ; irq <= 15 ; irq++) {
931 eint0_15_data[irq] = IRQ_EINT(irq);
932
Kukjin Kimbb19a752012-01-25 13:48:11 +0900933 if (soc_is_exynos5250()) {
934 irq_set_handler_data(exynos5_eint0_15_src_int[irq],
935 &eint0_15_data[irq]);
936 irq_set_chained_handler(exynos5_eint0_15_src_int[irq],
937 exynos_irq_eint0_15);
938 } else {
939 irq_set_handler_data(exynos4_eint0_15_src_int[irq],
940 &eint0_15_data[irq]);
941 irq_set_chained_handler(exynos4_eint0_15_src_int[irq],
942 exynos_irq_eint0_15);
943 }
Kukjin Kimcc511b82011-12-27 08:18:36 +0100944 }
945
946 return 0;
947}
Eunki Kim330c90a2012-03-14 01:43:31 -0700948arch_initcall(exynos_init_irq_eint);