blob: 7fdb139bc25ba78edf9f0202218b070a5d268b9e [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
348 /* The I2C bus controllers are directly compatible with s3c2440 */
349 s3c_i2c0_setname("s3c2440-i2c");
350 s3c_i2c1_setname("s3c2440-i2c");
351 s3c_i2c2_setname("s3c2440-i2c");
352}
353
Kukjin Kim906c7892012-02-11 21:27:08 +0900354static void __init exynos4_init_clocks(int xtal)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100355{
356 printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
357
358 s3c24xx_register_baseclocks(xtal);
359 s5p_register_clocks(xtal);
360
361 if (soc_is_exynos4210())
362 exynos4210_register_clocks();
363 else if (soc_is_exynos4212() || soc_is_exynos4412())
364 exynos4212_register_clocks();
365
366 exynos4_register_clocks();
367 exynos4_setup_clocks();
368}
369
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900370static void __init exynos5_init_clocks(int xtal)
371{
372 printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
373
374 s3c24xx_register_baseclocks(xtal);
375 s5p_register_clocks(xtal);
376
377 exynos5_register_clocks();
378 exynos5_setup_clocks();
379}
380
Kukjin Kimcc511b82011-12-27 08:18:36 +0100381#define COMBINER_ENABLE_SET 0x0
382#define COMBINER_ENABLE_CLEAR 0x4
383#define COMBINER_INT_STATUS 0xC
384
385static DEFINE_SPINLOCK(irq_controller_lock);
386
387struct combiner_chip_data {
388 unsigned int irq_offset;
389 unsigned int irq_mask;
390 void __iomem *base;
391};
392
393static struct combiner_chip_data combiner_data[MAX_COMBINER_NR];
394
395static inline void __iomem *combiner_base(struct irq_data *data)
396{
397 struct combiner_chip_data *combiner_data =
398 irq_data_get_irq_chip_data(data);
399
400 return combiner_data->base;
401}
402
403static void combiner_mask_irq(struct irq_data *data)
404{
405 u32 mask = 1 << (data->irq % 32);
406
407 __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR);
408}
409
410static void combiner_unmask_irq(struct irq_data *data)
411{
412 u32 mask = 1 << (data->irq % 32);
413
414 __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET);
415}
416
417static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
418{
419 struct combiner_chip_data *chip_data = irq_get_handler_data(irq);
420 struct irq_chip *chip = irq_get_chip(irq);
421 unsigned int cascade_irq, combiner_irq;
422 unsigned long status;
423
424 chained_irq_enter(chip, desc);
425
426 spin_lock(&irq_controller_lock);
427 status = __raw_readl(chip_data->base + COMBINER_INT_STATUS);
428 spin_unlock(&irq_controller_lock);
429 status &= chip_data->irq_mask;
430
431 if (status == 0)
432 goto out;
433
434 combiner_irq = __ffs(status);
435
436 cascade_irq = combiner_irq + (chip_data->irq_offset & ~31);
437 if (unlikely(cascade_irq >= NR_IRQS))
438 do_bad_IRQ(cascade_irq, desc);
439 else
440 generic_handle_irq(cascade_irq);
441
442 out:
443 chained_irq_exit(chip, desc);
444}
445
446static struct irq_chip combiner_chip = {
447 .name = "COMBINER",
448 .irq_mask = combiner_mask_irq,
449 .irq_unmask = combiner_unmask_irq,
450};
451
452static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq)
453{
454 if (combiner_nr >= MAX_COMBINER_NR)
455 BUG();
456 if (irq_set_handler_data(irq, &combiner_data[combiner_nr]) != 0)
457 BUG();
458 irq_set_chained_handler(irq, combiner_handle_cascade_irq);
459}
460
461static void __init combiner_init(unsigned int combiner_nr, void __iomem *base,
462 unsigned int irq_start)
463{
464 unsigned int i;
465
466 if (combiner_nr >= MAX_COMBINER_NR)
467 BUG();
468
469 combiner_data[combiner_nr].base = base;
470 combiner_data[combiner_nr].irq_offset = irq_start;
471 combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3);
472
473 /* Disable all interrupts */
474
475 __raw_writel(combiner_data[combiner_nr].irq_mask,
476 base + COMBINER_ENABLE_CLEAR);
477
478 /* Setup the Linux IRQ subsystem */
479
480 for (i = irq_start; i < combiner_data[combiner_nr].irq_offset
481 + MAX_IRQ_IN_COMBINER; i++) {
482 irq_set_chip_and_handler(i, &combiner_chip, handle_level_irq);
483 irq_set_chip_data(i, &combiner_data[combiner_nr]);
484 set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
485 }
486}
487
Arnd Bergmann237c78b2012-01-07 12:30:20 +0000488#ifdef CONFIG_OF
489static const struct of_device_id exynos4_dt_irq_match[] = {
490 { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
491 {},
492};
493#endif
Kukjin Kimcc511b82011-12-27 08:18:36 +0100494
495void __init exynos4_init_irq(void)
496{
497 int irq;
Arnd Bergmann40ba95f2012-01-07 11:51:28 +0000498 unsigned int gic_bank_offset;
Kukjin Kimcc511b82011-12-27 08:18:36 +0100499
500 gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000;
501
Arnd Bergmann237c78b2012-01-07 12:30:20 +0000502 if (!of_have_populated_dt())
503 gic_init_bases(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU, gic_bank_offset);
504#ifdef CONFIG_OF
505 else
506 of_irq_init(exynos4_dt_irq_match);
507#endif
Kukjin Kimcc511b82011-12-27 08:18:36 +0100508
509 for (irq = 0; irq < MAX_COMBINER_NR; irq++) {
510
511 combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
512 COMBINER_IRQ(irq, 0));
513 combiner_cascade_irq(irq, IRQ_SPI(irq));
514 }
515
516 /*
517 * The parameters of s5p_init_irq() are for VIC init.
518 * Theses parameters should be NULL and 0 because EXYNOS4
519 * uses GIC instead of VIC.
520 */
521 s5p_init_irq(NULL, 0);
522}
523
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900524void __init exynos5_init_irq(void)
525{
526 int irq;
527
528 gic_init(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU);
529
530 for (irq = 0; irq < MAX_COMBINER_NR; irq++) {
531 combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
532 COMBINER_IRQ(irq, 0));
533 combiner_cascade_irq(irq, IRQ_SPI(irq));
534 }
535
536 /*
537 * The parameters of s5p_init_irq() are for VIC init.
538 * Theses parameters should be NULL and 0 because EXYNOS4
539 * uses GIC instead of VIC.
540 */
541 s5p_init_irq(NULL, 0);
542}
543
Linus Torvalds7affca32012-01-07 12:03:30 -0800544struct bus_type exynos4_subsys = {
545 .name = "exynos4-core",
546 .dev_name = "exynos4-core",
Kukjin Kimcc511b82011-12-27 08:18:36 +0100547};
548
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900549struct bus_type exynos5_subsys = {
550 .name = "exynos5-core",
551 .dev_name = "exynos5-core",
552};
553
Linus Torvalds7affca32012-01-07 12:03:30 -0800554static struct device exynos4_dev = {
555 .bus = &exynos4_subsys,
Kukjin Kimcc511b82011-12-27 08:18:36 +0100556};
557
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900558static struct device exynos5_dev = {
559 .bus = &exynos5_subsys,
560};
561
562static int __init exynos_core_init(void)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100563{
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900564 if (soc_is_exynos5250())
565 return subsys_system_register(&exynos5_subsys, NULL);
566 else
567 return subsys_system_register(&exynos4_subsys, NULL);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100568}
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900569core_initcall(exynos_core_init);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100570
571#ifdef CONFIG_CACHE_L2X0
572static int __init exynos4_l2x0_cache_init(void)
573{
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900574 if (soc_is_exynos5250())
575 return 0;
576
Kukjin Kimcc511b82011-12-27 08:18:36 +0100577 /* TAG, Data Latency Control: 2cycle */
578 __raw_writel(0x110, S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL);
579
580 if (soc_is_exynos4210())
581 __raw_writel(0x110, S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL);
582 else if (soc_is_exynos4212() || soc_is_exynos4412())
583 __raw_writel(0x120, S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL);
584
585 /* L2X0 Prefetch Control */
586 __raw_writel(0x30000007, S5P_VA_L2CC + L2X0_PREFETCH_CTRL);
587
588 /* L2X0 Power Control */
589 __raw_writel(L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN,
590 S5P_VA_L2CC + L2X0_POWER_CTRL);
591
592 l2x0_init(S5P_VA_L2CC, 0x7C470001, 0xC200ffff);
593
594 return 0;
595}
Kukjin Kimcc511b82011-12-27 08:18:36 +0100596early_initcall(exynos4_l2x0_cache_init);
597#endif
598
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900599static int __init exynos5_l2_cache_init(void)
600{
601 unsigned int val;
602
603 if (!soc_is_exynos5250())
604 return 0;
605
606 asm volatile("mrc p15, 0, %0, c1, c0, 0\n"
607 "bic %0, %0, #(1 << 2)\n" /* cache disable */
608 "mcr p15, 0, %0, c1, c0, 0\n"
609 "mrc p15, 1, %0, c9, c0, 2\n"
610 : "=r"(val));
611
612 val |= (1 << 9) | (1 << 5) | (2 << 6) | (2 << 0);
613
614 asm volatile("mcr p15, 1, %0, c9, c0, 2\n" : : "r"(val));
615 asm volatile("mrc p15, 0, %0, c1, c0, 0\n"
616 "orr %0, %0, #(1 << 2)\n" /* cache enable */
617 "mcr p15, 0, %0, c1, c0, 0\n"
618 : : "r"(val));
619
620 return 0;
621}
622early_initcall(exynos5_l2_cache_init);
623
Kukjin Kim906c7892012-02-11 21:27:08 +0900624static int __init exynos_init(void)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100625{
626 printk(KERN_INFO "EXYNOS: Initializing architecture\n");
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900627
628 if (soc_is_exynos5250())
629 return device_register(&exynos5_dev);
630 else
631 return device_register(&exynos4_dev);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100632}
633
Kukjin Kimcc511b82011-12-27 08:18:36 +0100634/* uart registration process */
635
Kukjin Kim920f4882012-01-24 20:52:52 +0900636static void __init exynos_init_uarts(struct s3c2410_uartcfg *cfg, int no)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100637{
638 struct s3c2410_uartcfg *tcfg = cfg;
639 u32 ucnt;
640
Arnd Bergmann237c78b2012-01-07 12:30:20 +0000641 for (ucnt = 0; ucnt < no; ucnt++, tcfg++)
642 tcfg->has_fracval = 1;
Kukjin Kimcc511b82011-12-27 08:18:36 +0100643
Kukjin Kim171c0672012-02-10 11:57:53 +0900644 if (soc_is_exynos5250())
645 s3c24xx_init_uartdevs("exynos4210-uart", exynos5_uart_resources, cfg, no);
646 else
647 s3c24xx_init_uartdevs("exynos4210-uart", exynos4_uart_resources, cfg, no);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100648}
649
650static DEFINE_SPINLOCK(eint_lock);
651
652static unsigned int eint0_15_data[16];
653
654static unsigned int exynos4_get_irq_nr(unsigned int number)
655{
656 u32 ret = 0;
657
658 switch (number) {
659 case 0 ... 3:
660 ret = (number + IRQ_EINT0);
661 break;
662 case 4 ... 7:
663 ret = (number + (IRQ_EINT4 - 4));
664 break;
665 case 8 ... 15:
666 ret = (number + (IRQ_EINT8 - 8));
667 break;
668 default:
669 printk(KERN_ERR "number available : %d\n", number);
670 }
671
672 return ret;
673}
674
675static inline void exynos4_irq_eint_mask(struct irq_data *data)
676{
677 u32 mask;
678
679 spin_lock(&eint_lock);
680 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
681 mask |= eint_irq_to_bit(data->irq);
682 __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
683 spin_unlock(&eint_lock);
684}
685
686static void exynos4_irq_eint_unmask(struct irq_data *data)
687{
688 u32 mask;
689
690 spin_lock(&eint_lock);
691 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(data->irq)));
692 mask &= ~(eint_irq_to_bit(data->irq));
693 __raw_writel(mask, S5P_EINT_MASK(EINT_REG_NR(data->irq)));
694 spin_unlock(&eint_lock);
695}
696
697static inline void exynos4_irq_eint_ack(struct irq_data *data)
698{
699 __raw_writel(eint_irq_to_bit(data->irq),
700 S5P_EINT_PEND(EINT_REG_NR(data->irq)));
701}
702
703static void exynos4_irq_eint_maskack(struct irq_data *data)
704{
705 exynos4_irq_eint_mask(data);
706 exynos4_irq_eint_ack(data);
707}
708
709static int exynos4_irq_eint_set_type(struct irq_data *data, unsigned int type)
710{
711 int offs = EINT_OFFSET(data->irq);
712 int shift;
713 u32 ctrl, mask;
714 u32 newvalue = 0;
715
716 switch (type) {
717 case IRQ_TYPE_EDGE_RISING:
718 newvalue = S5P_IRQ_TYPE_EDGE_RISING;
719 break;
720
721 case IRQ_TYPE_EDGE_FALLING:
722 newvalue = S5P_IRQ_TYPE_EDGE_FALLING;
723 break;
724
725 case IRQ_TYPE_EDGE_BOTH:
726 newvalue = S5P_IRQ_TYPE_EDGE_BOTH;
727 break;
728
729 case IRQ_TYPE_LEVEL_LOW:
730 newvalue = S5P_IRQ_TYPE_LEVEL_LOW;
731 break;
732
733 case IRQ_TYPE_LEVEL_HIGH:
734 newvalue = S5P_IRQ_TYPE_LEVEL_HIGH;
735 break;
736
737 default:
738 printk(KERN_ERR "No such irq type %d", type);
739 return -EINVAL;
740 }
741
742 shift = (offs & 0x7) * 4;
743 mask = 0x7 << shift;
744
745 spin_lock(&eint_lock);
746 ctrl = __raw_readl(S5P_EINT_CON(EINT_REG_NR(data->irq)));
747 ctrl &= ~mask;
748 ctrl |= newvalue << shift;
749 __raw_writel(ctrl, S5P_EINT_CON(EINT_REG_NR(data->irq)));
750 spin_unlock(&eint_lock);
751
752 switch (offs) {
753 case 0 ... 7:
754 s3c_gpio_cfgpin(EINT_GPIO_0(offs & 0x7), EINT_MODE);
755 break;
756 case 8 ... 15:
757 s3c_gpio_cfgpin(EINT_GPIO_1(offs & 0x7), EINT_MODE);
758 break;
759 case 16 ... 23:
760 s3c_gpio_cfgpin(EINT_GPIO_2(offs & 0x7), EINT_MODE);
761 break;
762 case 24 ... 31:
763 s3c_gpio_cfgpin(EINT_GPIO_3(offs & 0x7), EINT_MODE);
764 break;
765 default:
766 printk(KERN_ERR "No such irq number %d", offs);
767 }
768
769 return 0;
770}
771
772static struct irq_chip exynos4_irq_eint = {
773 .name = "exynos4-eint",
774 .irq_mask = exynos4_irq_eint_mask,
775 .irq_unmask = exynos4_irq_eint_unmask,
776 .irq_mask_ack = exynos4_irq_eint_maskack,
777 .irq_ack = exynos4_irq_eint_ack,
778 .irq_set_type = exynos4_irq_eint_set_type,
779#ifdef CONFIG_PM
780 .irq_set_wake = s3c_irqext_wake,
781#endif
782};
783
784/*
785 * exynos4_irq_demux_eint
786 *
787 * This function demuxes the IRQ from from EINTs 16 to 31.
788 * It is designed to be inlined into the specific handler
789 * s5p_irq_demux_eintX_Y.
790 *
791 * Each EINT pend/mask registers handle eight of them.
792 */
793static inline void exynos4_irq_demux_eint(unsigned int start)
794{
795 unsigned int irq;
796
797 u32 status = __raw_readl(S5P_EINT_PEND(EINT_REG_NR(start)));
798 u32 mask = __raw_readl(S5P_EINT_MASK(EINT_REG_NR(start)));
799
800 status &= ~mask;
801 status &= 0xff;
802
803 while (status) {
804 irq = fls(status) - 1;
805 generic_handle_irq(irq + start);
806 status &= ~(1 << irq);
807 }
808}
809
810static void exynos4_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
811{
812 struct irq_chip *chip = irq_get_chip(irq);
813 chained_irq_enter(chip, desc);
814 exynos4_irq_demux_eint(IRQ_EINT(16));
815 exynos4_irq_demux_eint(IRQ_EINT(24));
816 chained_irq_exit(chip, desc);
817}
818
819static void exynos4_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
820{
821 u32 *irq_data = irq_get_handler_data(irq);
822 struct irq_chip *chip = irq_get_chip(irq);
823
824 chained_irq_enter(chip, desc);
825 chip->irq_mask(&desc->irq_data);
826
827 if (chip->irq_ack)
828 chip->irq_ack(&desc->irq_data);
829
830 generic_handle_irq(*irq_data);
831
832 chip->irq_unmask(&desc->irq_data);
833 chained_irq_exit(chip, desc);
834}
835
Kukjin Kime745e062012-01-21 10:47:14 +0900836static int __init exynos4_init_irq_eint(void)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100837{
838 int irq;
839
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900840 if (soc_is_exynos5250())
841 return 0;
842
Kukjin Kimcc511b82011-12-27 08:18:36 +0100843 for (irq = 0 ; irq <= 31 ; irq++) {
844 irq_set_chip_and_handler(IRQ_EINT(irq), &exynos4_irq_eint,
845 handle_level_irq);
846 set_irq_flags(IRQ_EINT(irq), IRQF_VALID);
847 }
848
849 irq_set_chained_handler(IRQ_EINT16_31, exynos4_irq_demux_eint16_31);
850
851 for (irq = 0 ; irq <= 15 ; irq++) {
852 eint0_15_data[irq] = IRQ_EINT(irq);
853
854 irq_set_handler_data(exynos4_get_irq_nr(irq),
855 &eint0_15_data[irq]);
856 irq_set_chained_handler(exynos4_get_irq_nr(irq),
857 exynos4_irq_eint0_15);
858 }
859
860 return 0;
861}
862arch_initcall(exynos4_init_irq_eint);