blob: 50331790abc8dce638d3fec7543bea748339814d [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>
Rob Herringa900e5d2013-02-12 16:04:52 -060015#include <linux/irqchip.h>
Kukjin Kimcc511b82011-12-27 08:18:36 +010016#include <linux/io.h>
Linus Torvalds7affca32012-01-07 12:03:30 -080017#include <linux/device.h>
Kukjin Kimcc511b82011-12-27 08:18:36 +010018#include <linux/gpio.h>
19#include <linux/sched.h>
20#include <linux/serial_core.h>
Arnd Bergmann237c78b2012-01-07 12:30:20 +000021#include <linux/of.h>
Doug Anderson5b7897d2012-11-27 11:53:14 -080022#include <linux/of_fdt.h>
Arnd Bergmann237c78b2012-01-07 12:30:20 +000023#include <linux/of_irq.h>
Thomas Abraham1e60bc02012-05-15 16:18:35 +090024#include <linux/export.h>
25#include <linux/irqdomain.h>
Rob Herring0529e3152012-11-05 16:18:28 -060026#include <linux/irqchip.h>
Thomas Abrahame873a472012-05-15 16:25:23 +090027#include <linux/of_address.h>
Thomas Abraham6923ae42013-03-09 17:03:29 +090028#include <linux/clocksource.h>
29#include <linux/clk-provider.h>
Rob Herring520f7bd2012-12-27 13:10:24 -060030#include <linux/irqchip/arm-gic.h>
Kukjin Kimcc511b82011-12-27 08:18:36 +010031
32#include <asm/proc-fns.h>
Arnd Bergmann40ba95f2012-01-07 11:51:28 +000033#include <asm/exception.h>
Kukjin Kimcc511b82011-12-27 08:18:36 +010034#include <asm/hardware/cache-l2x0.h>
Kukjin Kimcc511b82011-12-27 08:18:36 +010035#include <asm/mach/map.h>
36#include <asm/mach/irq.h>
Amit Daniel Kachhapb756a502012-03-08 02:07:41 -080037#include <asm/cacheflush.h>
Kukjin Kimcc511b82011-12-27 08:18:36 +010038
39#include <mach/regs-irq.h>
40#include <mach/regs-pmu.h>
41#include <mach/regs-gpio.h>
42
43#include <plat/cpu.h>
Kukjin Kimcc511b82011-12-27 08:18:36 +010044#include <plat/devs.h>
45#include <plat/pm.h>
Kukjin Kimcc511b82011-12-27 08:18:36 +010046#include <plat/sdhci.h>
47#include <plat/gpio-cfg.h>
48#include <plat/adc-core.h>
49#include <plat/fb-core.h>
50#include <plat/fimc-core.h>
51#include <plat/iic-core.h>
52#include <plat/tv-core.h>
Heiko Stuebner308b3af2012-10-17 16:47:11 +090053#include <plat/spi-core.h>
Kukjin Kimcc511b82011-12-27 08:18:36 +010054#include <plat/regs-serial.h>
55
56#include "common.h"
Amit Daniel Kachhap6cdeddc2012-03-08 02:09:12 -080057#define L2_AUX_VAL 0x7C470001
58#define L2_AUX_MASK 0xC200ffff
Kukjin Kimcc511b82011-12-27 08:18:36 +010059
Kukjin Kimcc511b82011-12-27 08:18:36 +010060static const char name_exynos4210[] = "EXYNOS4210";
61static const char name_exynos4212[] = "EXYNOS4212";
62static const char name_exynos4412[] = "EXYNOS4412";
Kukjin Kim94c7ca72012-02-11 22:15:45 +090063static const char name_exynos5250[] = "EXYNOS5250";
Kukjin Kim2edb36c2012-11-15 15:48:56 +090064static const char name_exynos5440[] = "EXYNOS5440";
Kukjin Kimcc511b82011-12-27 08:18:36 +010065
Kukjin Kim906c7892012-02-11 21:27:08 +090066static void exynos4_map_io(void);
Kukjin Kim94c7ca72012-02-11 22:15:45 +090067static void exynos5_map_io(void);
Kukjin Kim2edb36c2012-11-15 15:48:56 +090068static void exynos5440_map_io(void);
Thomas Abraham55b6ef72012-10-29 19:46:49 +090069static void exynos4_init_uarts(struct s3c2410_uartcfg *cfg, int no);
Kukjin Kim906c7892012-02-11 21:27:08 +090070static int exynos_init(void);
Kukjin Kimcc511b82011-12-27 08:18:36 +010071
72static struct cpu_table cpu_ids[] __initdata = {
73 {
74 .idcode = EXYNOS4210_CPU_ID,
75 .idmask = EXYNOS4_CPU_MASK,
76 .map_io = exynos4_map_io,
Thomas Abraham55b6ef72012-10-29 19:46:49 +090077 .init_uarts = exynos4_init_uarts,
Kukjin Kimcc511b82011-12-27 08:18:36 +010078 .init = exynos_init,
79 .name = name_exynos4210,
80 }, {
81 .idcode = EXYNOS4212_CPU_ID,
82 .idmask = EXYNOS4_CPU_MASK,
83 .map_io = exynos4_map_io,
Thomas Abraham55b6ef72012-10-29 19:46:49 +090084 .init_uarts = exynos4_init_uarts,
Kukjin Kimcc511b82011-12-27 08:18:36 +010085 .init = exynos_init,
86 .name = name_exynos4212,
87 }, {
88 .idcode = EXYNOS4412_CPU_ID,
89 .idmask = EXYNOS4_CPU_MASK,
90 .map_io = exynos4_map_io,
Thomas Abraham55b6ef72012-10-29 19:46:49 +090091 .init_uarts = exynos4_init_uarts,
Kukjin Kimcc511b82011-12-27 08:18:36 +010092 .init = exynos_init,
93 .name = name_exynos4412,
Kukjin Kim94c7ca72012-02-11 22:15:45 +090094 }, {
95 .idcode = EXYNOS5250_SOC_ID,
96 .idmask = EXYNOS5_SOC_MASK,
97 .map_io = exynos5_map_io,
Kukjin Kim94c7ca72012-02-11 22:15:45 +090098 .init = exynos_init,
99 .name = name_exynos5250,
Kukjin Kim2edb36c2012-11-15 15:48:56 +0900100 }, {
101 .idcode = EXYNOS5440_SOC_ID,
102 .idmask = EXYNOS5_SOC_MASK,
103 .map_io = exynos5440_map_io,
104 .init = exynos_init,
105 .name = name_exynos5440,
Kukjin Kimcc511b82011-12-27 08:18:36 +0100106 },
107};
108
109/* Initial IO mappings */
110
111static struct map_desc exynos_iodesc[] __initdata = {
112 {
113 .virtual = (unsigned long)S5P_VA_CHIPID,
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900114 .pfn = __phys_to_pfn(EXYNOS_PA_CHIPID),
Kukjin Kimcc511b82011-12-27 08:18:36 +0100115 .length = SZ_4K,
116 .type = MT_DEVICE,
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900117 },
118};
119
Doug Anderson5b7897d2012-11-27 11:53:14 -0800120#ifdef CONFIG_ARCH_EXYNOS5
Kukjin Kim2edb36c2012-11-15 15:48:56 +0900121static struct map_desc exynos5440_iodesc[] __initdata = {
122 {
123 .virtual = (unsigned long)S5P_VA_CHIPID,
124 .pfn = __phys_to_pfn(EXYNOS5440_PA_CHIPID),
125 .length = SZ_4K,
126 .type = MT_DEVICE,
127 },
128};
Doug Anderson5b7897d2012-11-27 11:53:14 -0800129#endif
Kukjin Kim2edb36c2012-11-15 15:48:56 +0900130
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900131static struct map_desc exynos4_iodesc[] __initdata = {
132 {
Kukjin Kimcc511b82011-12-27 08:18:36 +0100133 .virtual = (unsigned long)S3C_VA_SYS,
134 .pfn = __phys_to_pfn(EXYNOS4_PA_SYSCON),
135 .length = SZ_64K,
136 .type = MT_DEVICE,
137 }, {
138 .virtual = (unsigned long)S3C_VA_TIMER,
139 .pfn = __phys_to_pfn(EXYNOS4_PA_TIMER),
140 .length = SZ_16K,
141 .type = MT_DEVICE,
142 }, {
143 .virtual = (unsigned long)S3C_VA_WATCHDOG,
144 .pfn = __phys_to_pfn(EXYNOS4_PA_WATCHDOG),
145 .length = SZ_4K,
146 .type = MT_DEVICE,
147 }, {
148 .virtual = (unsigned long)S5P_VA_SROMC,
149 .pfn = __phys_to_pfn(EXYNOS4_PA_SROMC),
150 .length = SZ_4K,
151 .type = MT_DEVICE,
152 }, {
153 .virtual = (unsigned long)S5P_VA_SYSTIMER,
154 .pfn = __phys_to_pfn(EXYNOS4_PA_SYSTIMER),
155 .length = SZ_4K,
156 .type = MT_DEVICE,
157 }, {
158 .virtual = (unsigned long)S5P_VA_PMU,
159 .pfn = __phys_to_pfn(EXYNOS4_PA_PMU),
160 .length = SZ_64K,
161 .type = MT_DEVICE,
162 }, {
163 .virtual = (unsigned long)S5P_VA_COMBINER_BASE,
164 .pfn = __phys_to_pfn(EXYNOS4_PA_COMBINER),
165 .length = SZ_4K,
166 .type = MT_DEVICE,
167 }, {
168 .virtual = (unsigned long)S5P_VA_GIC_CPU,
169 .pfn = __phys_to_pfn(EXYNOS4_PA_GIC_CPU),
170 .length = SZ_64K,
171 .type = MT_DEVICE,
172 }, {
173 .virtual = (unsigned long)S5P_VA_GIC_DIST,
174 .pfn = __phys_to_pfn(EXYNOS4_PA_GIC_DIST),
175 .length = SZ_64K,
176 .type = MT_DEVICE,
177 }, {
178 .virtual = (unsigned long)S3C_VA_UART,
179 .pfn = __phys_to_pfn(EXYNOS4_PA_UART),
180 .length = SZ_512K,
181 .type = MT_DEVICE,
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900182 }, {
Kukjin Kimcc511b82011-12-27 08:18:36 +0100183 .virtual = (unsigned long)S5P_VA_CMU,
184 .pfn = __phys_to_pfn(EXYNOS4_PA_CMU),
185 .length = SZ_128K,
186 .type = MT_DEVICE,
187 }, {
188 .virtual = (unsigned long)S5P_VA_COREPERI_BASE,
189 .pfn = __phys_to_pfn(EXYNOS4_PA_COREPERI),
190 .length = SZ_8K,
191 .type = MT_DEVICE,
192 }, {
193 .virtual = (unsigned long)S5P_VA_L2CC,
194 .pfn = __phys_to_pfn(EXYNOS4_PA_L2CC),
195 .length = SZ_4K,
196 .type = MT_DEVICE,
197 }, {
Kukjin Kimcc511b82011-12-27 08:18:36 +0100198 .virtual = (unsigned long)S5P_VA_DMC0,
199 .pfn = __phys_to_pfn(EXYNOS4_PA_DMC0),
MyungJoo Ham2bde0b02011-12-01 15:12:30 +0900200 .length = SZ_64K,
201 .type = MT_DEVICE,
202 }, {
203 .virtual = (unsigned long)S5P_VA_DMC1,
204 .pfn = __phys_to_pfn(EXYNOS4_PA_DMC1),
205 .length = SZ_64K,
Kukjin Kimcc511b82011-12-27 08:18:36 +0100206 .type = MT_DEVICE,
207 }, {
Kukjin Kimcc511b82011-12-27 08:18:36 +0100208 .virtual = (unsigned long)S3C_VA_USB_HSPHY,
209 .pfn = __phys_to_pfn(EXYNOS4_PA_HSPHY),
210 .length = SZ_4K,
211 .type = MT_DEVICE,
212 },
213};
214
215static struct map_desc exynos4_iodesc0[] __initdata = {
216 {
217 .virtual = (unsigned long)S5P_VA_SYSRAM,
218 .pfn = __phys_to_pfn(EXYNOS4_PA_SYSRAM0),
219 .length = SZ_4K,
220 .type = MT_DEVICE,
221 },
222};
223
224static struct map_desc exynos4_iodesc1[] __initdata = {
225 {
226 .virtual = (unsigned long)S5P_VA_SYSRAM,
227 .pfn = __phys_to_pfn(EXYNOS4_PA_SYSRAM1),
228 .length = SZ_4K,
229 .type = MT_DEVICE,
230 },
231};
232
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900233static struct map_desc exynos5_iodesc[] __initdata = {
234 {
235 .virtual = (unsigned long)S3C_VA_SYS,
236 .pfn = __phys_to_pfn(EXYNOS5_PA_SYSCON),
237 .length = SZ_64K,
238 .type = MT_DEVICE,
239 }, {
240 .virtual = (unsigned long)S3C_VA_TIMER,
241 .pfn = __phys_to_pfn(EXYNOS5_PA_TIMER),
242 .length = SZ_16K,
243 .type = MT_DEVICE,
244 }, {
245 .virtual = (unsigned long)S3C_VA_WATCHDOG,
246 .pfn = __phys_to_pfn(EXYNOS5_PA_WATCHDOG),
247 .length = SZ_4K,
248 .type = MT_DEVICE,
249 }, {
250 .virtual = (unsigned long)S5P_VA_SROMC,
251 .pfn = __phys_to_pfn(EXYNOS5_PA_SROMC),
252 .length = SZ_4K,
253 .type = MT_DEVICE,
254 }, {
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900255 .virtual = (unsigned long)S5P_VA_SYSRAM,
256 .pfn = __phys_to_pfn(EXYNOS5_PA_SYSRAM),
257 .length = SZ_4K,
258 .type = MT_DEVICE,
259 }, {
260 .virtual = (unsigned long)S5P_VA_CMU,
261 .pfn = __phys_to_pfn(EXYNOS5_PA_CMU),
262 .length = 144 * SZ_1K,
263 .type = MT_DEVICE,
264 }, {
265 .virtual = (unsigned long)S5P_VA_PMU,
266 .pfn = __phys_to_pfn(EXYNOS5_PA_PMU),
267 .length = SZ_64K,
268 .type = MT_DEVICE,
269 }, {
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900270 .virtual = (unsigned long)S3C_VA_UART,
271 .pfn = __phys_to_pfn(EXYNOS5_PA_UART),
272 .length = SZ_512K,
273 .type = MT_DEVICE,
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900274 },
275};
276
Kukjin Kim2edb36c2012-11-15 15:48:56 +0900277static struct map_desc exynos5440_iodesc0[] __initdata = {
278 {
279 .virtual = (unsigned long)S3C_VA_UART,
280 .pfn = __phys_to_pfn(EXYNOS5440_PA_UART0),
281 .length = SZ_512K,
282 .type = MT_DEVICE,
283 },
284};
285
Russell King9eb48592012-01-03 11:56:53 +0100286void exynos4_restart(char mode, const char *cmd)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100287{
288 __raw_writel(0x1, S5P_SWRESET);
289}
290
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900291void exynos5_restart(char mode, const char *cmd)
292{
Thomas Abraham60db7e52013-01-24 10:09:13 -0800293 struct device_node *np;
Kukjin Kim2edb36c2012-11-15 15:48:56 +0900294 u32 val;
295 void __iomem *addr;
296
297 if (of_machine_is_compatible("samsung,exynos5250")) {
298 val = 0x1;
299 addr = EXYNOS_SWRESET;
300 } else if (of_machine_is_compatible("samsung,exynos5440")) {
Thomas Abraham60db7e52013-01-24 10:09:13 -0800301 np = of_find_compatible_node(NULL, NULL, "samsung,exynos5440-clock");
302 addr = of_iomap(np, 0) + 0xcc;
303 val = (0xfff << 20) | (0x1 << 16);
Kukjin Kim2edb36c2012-11-15 15:48:56 +0900304 } else {
305 pr_err("%s: cannot support non-DT\n", __func__);
306 return;
307 }
308
309 __raw_writel(val, addr);
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900310}
311
Shawn Guobb13fab2012-04-26 10:35:40 +0800312void __init exynos_init_late(void)
313{
Kukjin Kim2edb36c2012-11-15 15:48:56 +0900314 if (of_machine_is_compatible("samsung,exynos5440"))
315 /* to be supported later */
316 return;
317
Shawn Guobb13fab2012-04-26 10:35:40 +0800318 exynos_pm_late_initcall();
319}
320
Kukjin Kimcc511b82011-12-27 08:18:36 +0100321/*
322 * exynos_map_io
323 *
324 * register the standard cpu IO areas
325 */
326
327void __init exynos_init_io(struct map_desc *mach_desc, int size)
328{
Doug Anderson5b7897d2012-11-27 11:53:14 -0800329 struct map_desc *iodesc = exynos_iodesc;
330 int iodesc_sz = ARRAY_SIZE(exynos_iodesc);
331#if defined(CONFIG_OF) && defined(CONFIG_ARCH_EXYNOS5)
332 unsigned long root = of_get_flat_dt_root();
333
Kukjin Kimcc511b82011-12-27 08:18:36 +0100334 /* initialize the io descriptors we need for initialization */
Doug Anderson5b7897d2012-11-27 11:53:14 -0800335 if (of_flat_dt_is_compatible(root, "samsung,exynos5440")) {
336 iodesc = exynos5440_iodesc;
337 iodesc_sz = ARRAY_SIZE(exynos5440_iodesc);
338 }
339#endif
340
341 iotable_init(iodesc, iodesc_sz);
Kukjin Kim2edb36c2012-11-15 15:48:56 +0900342
Kukjin Kimcc511b82011-12-27 08:18:36 +0100343 if (mach_desc)
344 iotable_init(mach_desc, size);
345
346 /* detect cpu id and rev. */
347 s5p_init_cpu(S5P_VA_CHIPID);
348
349 s3c_init_cpu(samsung_cpu_id, cpu_ids, ARRAY_SIZE(cpu_ids));
350}
351
Kukjin Kim906c7892012-02-11 21:27:08 +0900352static void __init exynos4_map_io(void)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100353{
354 iotable_init(exynos4_iodesc, ARRAY_SIZE(exynos4_iodesc));
355
356 if (soc_is_exynos4210() && samsung_rev() == EXYNOS4210_REV_0)
357 iotable_init(exynos4_iodesc0, ARRAY_SIZE(exynos4_iodesc0));
358 else
359 iotable_init(exynos4_iodesc1, ARRAY_SIZE(exynos4_iodesc1));
360
361 /* initialize device information early */
362 exynos4_default_sdhci0();
363 exynos4_default_sdhci1();
364 exynos4_default_sdhci2();
365 exynos4_default_sdhci3();
366
367 s3c_adc_setname("samsung-adc-v3");
368
369 s3c_fimc_setname(0, "exynos4-fimc");
370 s3c_fimc_setname(1, "exynos4-fimc");
371 s3c_fimc_setname(2, "exynos4-fimc");
372 s3c_fimc_setname(3, "exynos4-fimc");
373
Thomas Abraham8482c812012-04-14 08:04:46 -0700374 s3c_sdhci_setname(0, "exynos4-sdhci");
375 s3c_sdhci_setname(1, "exynos4-sdhci");
376 s3c_sdhci_setname(2, "exynos4-sdhci");
377 s3c_sdhci_setname(3, "exynos4-sdhci");
378
Kukjin Kimcc511b82011-12-27 08:18:36 +0100379 /* The I2C bus controllers are directly compatible with s3c2440 */
380 s3c_i2c0_setname("s3c2440-i2c");
381 s3c_i2c1_setname("s3c2440-i2c");
382 s3c_i2c2_setname("s3c2440-i2c");
383
384 s5p_fb_setname(0, "exynos4-fb");
385 s5p_hdmi_setname("exynos4-hdmi");
Heiko Stuebner308b3af2012-10-17 16:47:11 +0900386
387 s3c64xx_spi_setname("exynos4210-spi");
Kukjin Kimcc511b82011-12-27 08:18:36 +0100388}
389
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900390static void __init exynos5_map_io(void)
391{
392 iotable_init(exynos5_iodesc, ARRAY_SIZE(exynos5_iodesc));
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900393}
394
Kukjin Kim2edb36c2012-11-15 15:48:56 +0900395static void __init exynos5440_map_io(void)
396{
397 iotable_init(exynos5440_iodesc0, ARRAY_SIZE(exynos5440_iodesc0));
398}
399
Thomas Abraham6923ae42013-03-09 17:03:29 +0900400void __init exynos_init_time(void)
401{
402 if (of_have_populated_dt()) {
403#ifdef CONFIG_OF
404 of_clk_init(NULL);
405 clocksource_of_init();
406#endif
407 } else {
408 /* todo: remove after migrating legacy E4 platforms to dt */
409 exynos4_clk_init(NULL);
410 mct_init();
411 }
412}
413
Kukjin Kimcc511b82011-12-27 08:18:36 +0100414void __init exynos4_init_irq(void)
415{
Arnd Bergmann40ba95f2012-01-07 11:51:28 +0000416 unsigned int gic_bank_offset;
Kukjin Kimcc511b82011-12-27 08:18:36 +0100417
418 gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000;
419
Arnd Bergmann237c78b2012-01-07 12:30:20 +0000420 if (!of_have_populated_dt())
Grant Likely75294952012-02-14 14:06:57 -0700421 gic_init_bases(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU, gic_bank_offset, NULL);
Arnd Bergmann237c78b2012-01-07 12:30:20 +0000422#ifdef CONFIG_OF
423 else
Rob Herring0529e3152012-11-05 16:18:28 -0600424 irqchip_init();
Arnd Bergmann237c78b2012-01-07 12:30:20 +0000425#endif
Kukjin Kimcc511b82011-12-27 08:18:36 +0100426
Thomas Abrahame873a472012-05-15 16:25:23 +0900427 if (!of_have_populated_dt())
428 combiner_init(S5P_VA_COMBINER_BASE, NULL);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100429
430 /*
431 * The parameters of s5p_init_irq() are for VIC init.
432 * Theses parameters should be NULL and 0 because EXYNOS4
433 * uses GIC instead of VIC.
434 */
435 s5p_init_irq(NULL, 0);
436}
437
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900438void __init exynos5_init_irq(void)
439{
Tushar Behera6fff5a12012-04-24 13:25:01 -0700440#ifdef CONFIG_OF
Rob Herring0529e3152012-11-05 16:18:28 -0600441 irqchip_init();
Tushar Behera6fff5a12012-04-24 13:25:01 -0700442#endif
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900443 /*
444 * The parameters of s5p_init_irq() are for VIC init.
445 * Theses parameters should be NULL and 0 because EXYNOS4
446 * uses GIC instead of VIC.
447 */
Kukjin Kim12fee192012-12-06 15:31:10 +0900448 if (!of_machine_is_compatible("samsung,exynos5440"))
449 s5p_init_irq(NULL, 0);
Inderpal Singh34455132012-11-22 14:46:21 +0900450
451 gic_arch_extn.irq_set_wake = s3c_irq_wake;
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900452}
453
Thomas Abraham9ee6af92012-05-15 15:47:40 +0900454struct bus_type exynos_subsys = {
455 .name = "exynos-core",
456 .dev_name = "exynos-core",
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900457};
458
Linus Torvalds7affca32012-01-07 12:03:30 -0800459static struct device exynos4_dev = {
Thomas Abraham9ee6af92012-05-15 15:47:40 +0900460 .bus = &exynos_subsys,
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900461};
462
463static int __init exynos_core_init(void)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100464{
Thomas Abraham9ee6af92012-05-15 15:47:40 +0900465 return subsys_system_register(&exynos_subsys, NULL);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100466}
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900467core_initcall(exynos_core_init);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100468
469#ifdef CONFIG_CACHE_L2X0
470static int __init exynos4_l2x0_cache_init(void)
471{
Il Hane1b19942012-04-05 07:59:36 -0700472 int ret;
473
Kukjin Kim2edb36c2012-11-15 15:48:56 +0900474 if (soc_is_exynos5250() || soc_is_exynos5440())
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900475 return 0;
476
Amit Daniel Kachhap6cdeddc2012-03-08 02:09:12 -0800477 ret = l2x0_of_init(L2_AUX_VAL, L2_AUX_MASK);
478 if (!ret) {
479 l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs);
480 clean_dcache_area(&l2x0_regs_phys, sizeof(unsigned long));
481 return 0;
482 }
Kukjin Kimcc511b82011-12-27 08:18:36 +0100483
Amit Daniel Kachhapb756a502012-03-08 02:07:41 -0800484 if (!(__raw_readl(S5P_VA_L2CC + L2X0_CTRL) & 0x1)) {
485 l2x0_saved_regs.phy_base = EXYNOS4_PA_L2CC;
486 /* TAG, Data Latency Control: 2 cycles */
487 l2x0_saved_regs.tag_latency = 0x110;
Kukjin Kimcc511b82011-12-27 08:18:36 +0100488
Amit Daniel Kachhapb756a502012-03-08 02:07:41 -0800489 if (soc_is_exynos4212() || soc_is_exynos4412())
490 l2x0_saved_regs.data_latency = 0x120;
491 else
492 l2x0_saved_regs.data_latency = 0x110;
Kukjin Kimcc511b82011-12-27 08:18:36 +0100493
Amit Daniel Kachhapb756a502012-03-08 02:07:41 -0800494 l2x0_saved_regs.prefetch_ctrl = 0x30000007;
495 l2x0_saved_regs.pwr_ctrl =
496 (L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100497
Amit Daniel Kachhapb756a502012-03-08 02:07:41 -0800498 l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100499
Amit Daniel Kachhapb756a502012-03-08 02:07:41 -0800500 __raw_writel(l2x0_saved_regs.tag_latency,
501 S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL);
502 __raw_writel(l2x0_saved_regs.data_latency,
503 S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL);
504
505 /* L2X0 Prefetch Control */
506 __raw_writel(l2x0_saved_regs.prefetch_ctrl,
507 S5P_VA_L2CC + L2X0_PREFETCH_CTRL);
508
509 /* L2X0 Power Control */
510 __raw_writel(l2x0_saved_regs.pwr_ctrl,
511 S5P_VA_L2CC + L2X0_POWER_CTRL);
512
513 clean_dcache_area(&l2x0_regs_phys, sizeof(unsigned long));
514 clean_dcache_area(&l2x0_saved_regs, sizeof(struct l2x0_regs));
515 }
Kukjin Kimcc511b82011-12-27 08:18:36 +0100516
Amit Daniel Kachhap6cdeddc2012-03-08 02:09:12 -0800517 l2x0_init(S5P_VA_L2CC, L2_AUX_VAL, L2_AUX_MASK);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100518 return 0;
519}
Kukjin Kimcc511b82011-12-27 08:18:36 +0100520early_initcall(exynos4_l2x0_cache_init);
521#endif
522
Kukjin Kim906c7892012-02-11 21:27:08 +0900523static int __init exynos_init(void)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100524{
525 printk(KERN_INFO "EXYNOS: Initializing architecture\n");
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900526
Thomas Abraham9ee6af92012-05-15 15:47:40 +0900527 return device_register(&exynos4_dev);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100528}
529
Kukjin Kimcc511b82011-12-27 08:18:36 +0100530/* uart registration process */
531
Thomas Abraham55b6ef72012-10-29 19:46:49 +0900532static void __init exynos4_init_uarts(struct s3c2410_uartcfg *cfg, int no)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100533{
534 struct s3c2410_uartcfg *tcfg = cfg;
535 u32 ucnt;
536
Arnd Bergmann237c78b2012-01-07 12:30:20 +0000537 for (ucnt = 0; ucnt < no; ucnt++, tcfg++)
538 tcfg->has_fracval = 1;
Kukjin Kimcc511b82011-12-27 08:18:36 +0100539
Thomas Abraham55b6ef72012-10-29 19:46:49 +0900540 s3c24xx_init_uartdevs("exynos4210-uart", exynos4_uart_resources, cfg, no);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100541}
542
Eunki Kim330c90a2012-03-14 01:43:31 -0700543static void __iomem *exynos_eint_base;
544
Kukjin Kimcc511b82011-12-27 08:18:36 +0100545static DEFINE_SPINLOCK(eint_lock);
546
547static unsigned int eint0_15_data[16];
548
Eunki Kim330c90a2012-03-14 01:43:31 -0700549static inline int exynos4_irq_to_gpio(unsigned int irq)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100550{
Eunki Kim330c90a2012-03-14 01:43:31 -0700551 if (irq < IRQ_EINT(0))
552 return -EINVAL;
Kukjin Kimcc511b82011-12-27 08:18:36 +0100553
Eunki Kim330c90a2012-03-14 01:43:31 -0700554 irq -= IRQ_EINT(0);
555 if (irq < 8)
556 return EXYNOS4_GPX0(irq);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100557
Eunki Kim330c90a2012-03-14 01:43:31 -0700558 irq -= 8;
559 if (irq < 8)
560 return EXYNOS4_GPX1(irq);
561
562 irq -= 8;
563 if (irq < 8)
564 return EXYNOS4_GPX2(irq);
565
566 irq -= 8;
567 if (irq < 8)
568 return EXYNOS4_GPX3(irq);
569
570 return -EINVAL;
Kukjin Kimcc511b82011-12-27 08:18:36 +0100571}
572
Eunki Kim330c90a2012-03-14 01:43:31 -0700573static inline int exynos5_irq_to_gpio(unsigned int irq)
574{
575 if (irq < IRQ_EINT(0))
576 return -EINVAL;
577
578 irq -= IRQ_EINT(0);
579 if (irq < 8)
580 return EXYNOS5_GPX0(irq);
581
582 irq -= 8;
583 if (irq < 8)
584 return EXYNOS5_GPX1(irq);
585
586 irq -= 8;
587 if (irq < 8)
588 return EXYNOS5_GPX2(irq);
589
590 irq -= 8;
591 if (irq < 8)
592 return EXYNOS5_GPX3(irq);
593
594 return -EINVAL;
595}
596
Kukjin Kimbb19a752012-01-25 13:48:11 +0900597static unsigned int exynos4_eint0_15_src_int[16] = {
598 EXYNOS4_IRQ_EINT0,
599 EXYNOS4_IRQ_EINT1,
600 EXYNOS4_IRQ_EINT2,
601 EXYNOS4_IRQ_EINT3,
602 EXYNOS4_IRQ_EINT4,
603 EXYNOS4_IRQ_EINT5,
604 EXYNOS4_IRQ_EINT6,
605 EXYNOS4_IRQ_EINT7,
606 EXYNOS4_IRQ_EINT8,
607 EXYNOS4_IRQ_EINT9,
608 EXYNOS4_IRQ_EINT10,
609 EXYNOS4_IRQ_EINT11,
610 EXYNOS4_IRQ_EINT12,
611 EXYNOS4_IRQ_EINT13,
612 EXYNOS4_IRQ_EINT14,
613 EXYNOS4_IRQ_EINT15,
614};
Kukjin Kimcc511b82011-12-27 08:18:36 +0100615
Kukjin Kimbb19a752012-01-25 13:48:11 +0900616static unsigned int exynos5_eint0_15_src_int[16] = {
617 EXYNOS5_IRQ_EINT0,
618 EXYNOS5_IRQ_EINT1,
619 EXYNOS5_IRQ_EINT2,
620 EXYNOS5_IRQ_EINT3,
621 EXYNOS5_IRQ_EINT4,
622 EXYNOS5_IRQ_EINT5,
623 EXYNOS5_IRQ_EINT6,
624 EXYNOS5_IRQ_EINT7,
625 EXYNOS5_IRQ_EINT8,
626 EXYNOS5_IRQ_EINT9,
627 EXYNOS5_IRQ_EINT10,
628 EXYNOS5_IRQ_EINT11,
629 EXYNOS5_IRQ_EINT12,
630 EXYNOS5_IRQ_EINT13,
631 EXYNOS5_IRQ_EINT14,
632 EXYNOS5_IRQ_EINT15,
633};
Eunki Kim330c90a2012-03-14 01:43:31 -0700634static inline void exynos_irq_eint_mask(struct irq_data *data)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100635{
636 u32 mask;
637
638 spin_lock(&eint_lock);
Eunki Kim330c90a2012-03-14 01:43:31 -0700639 mask = __raw_readl(EINT_MASK(exynos_eint_base, data->irq));
640 mask |= EINT_OFFSET_BIT(data->irq);
641 __raw_writel(mask, EINT_MASK(exynos_eint_base, data->irq));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100642 spin_unlock(&eint_lock);
643}
644
Eunki Kim330c90a2012-03-14 01:43:31 -0700645static void exynos_irq_eint_unmask(struct irq_data *data)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100646{
647 u32 mask;
648
649 spin_lock(&eint_lock);
Eunki Kim330c90a2012-03-14 01:43:31 -0700650 mask = __raw_readl(EINT_MASK(exynos_eint_base, data->irq));
651 mask &= ~(EINT_OFFSET_BIT(data->irq));
652 __raw_writel(mask, EINT_MASK(exynos_eint_base, data->irq));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100653 spin_unlock(&eint_lock);
654}
655
Eunki Kim330c90a2012-03-14 01:43:31 -0700656static inline void exynos_irq_eint_ack(struct irq_data *data)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100657{
Eunki Kim330c90a2012-03-14 01:43:31 -0700658 __raw_writel(EINT_OFFSET_BIT(data->irq),
659 EINT_PEND(exynos_eint_base, data->irq));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100660}
661
Eunki Kim330c90a2012-03-14 01:43:31 -0700662static void exynos_irq_eint_maskack(struct irq_data *data)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100663{
Eunki Kim330c90a2012-03-14 01:43:31 -0700664 exynos_irq_eint_mask(data);
665 exynos_irq_eint_ack(data);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100666}
667
Eunki Kim330c90a2012-03-14 01:43:31 -0700668static int exynos_irq_eint_set_type(struct irq_data *data, unsigned int type)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100669{
670 int offs = EINT_OFFSET(data->irq);
671 int shift;
672 u32 ctrl, mask;
673 u32 newvalue = 0;
674
675 switch (type) {
676 case IRQ_TYPE_EDGE_RISING:
677 newvalue = S5P_IRQ_TYPE_EDGE_RISING;
678 break;
679
680 case IRQ_TYPE_EDGE_FALLING:
681 newvalue = S5P_IRQ_TYPE_EDGE_FALLING;
682 break;
683
684 case IRQ_TYPE_EDGE_BOTH:
685 newvalue = S5P_IRQ_TYPE_EDGE_BOTH;
686 break;
687
688 case IRQ_TYPE_LEVEL_LOW:
689 newvalue = S5P_IRQ_TYPE_LEVEL_LOW;
690 break;
691
692 case IRQ_TYPE_LEVEL_HIGH:
693 newvalue = S5P_IRQ_TYPE_LEVEL_HIGH;
694 break;
695
696 default:
697 printk(KERN_ERR "No such irq type %d", type);
698 return -EINVAL;
699 }
700
701 shift = (offs & 0x7) * 4;
702 mask = 0x7 << shift;
703
704 spin_lock(&eint_lock);
Eunki Kim330c90a2012-03-14 01:43:31 -0700705 ctrl = __raw_readl(EINT_CON(exynos_eint_base, data->irq));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100706 ctrl &= ~mask;
707 ctrl |= newvalue << shift;
Eunki Kim330c90a2012-03-14 01:43:31 -0700708 __raw_writel(ctrl, EINT_CON(exynos_eint_base, data->irq));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100709 spin_unlock(&eint_lock);
710
Eunki Kim330c90a2012-03-14 01:43:31 -0700711 if (soc_is_exynos5250())
712 s3c_gpio_cfgpin(exynos5_irq_to_gpio(data->irq), S3C_GPIO_SFN(0xf));
713 else
714 s3c_gpio_cfgpin(exynos4_irq_to_gpio(data->irq), S3C_GPIO_SFN(0xf));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100715
716 return 0;
717}
718
Eunki Kim330c90a2012-03-14 01:43:31 -0700719static struct irq_chip exynos_irq_eint = {
720 .name = "exynos-eint",
721 .irq_mask = exynos_irq_eint_mask,
722 .irq_unmask = exynos_irq_eint_unmask,
723 .irq_mask_ack = exynos_irq_eint_maskack,
724 .irq_ack = exynos_irq_eint_ack,
725 .irq_set_type = exynos_irq_eint_set_type,
Kukjin Kimcc511b82011-12-27 08:18:36 +0100726#ifdef CONFIG_PM
727 .irq_set_wake = s3c_irqext_wake,
728#endif
729};
730
731/*
732 * exynos4_irq_demux_eint
733 *
734 * This function demuxes the IRQ from from EINTs 16 to 31.
735 * It is designed to be inlined into the specific handler
736 * s5p_irq_demux_eintX_Y.
737 *
738 * Each EINT pend/mask registers handle eight of them.
739 */
Eunki Kim330c90a2012-03-14 01:43:31 -0700740static inline void exynos_irq_demux_eint(unsigned int start)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100741{
742 unsigned int irq;
743
Eunki Kim330c90a2012-03-14 01:43:31 -0700744 u32 status = __raw_readl(EINT_PEND(exynos_eint_base, start));
745 u32 mask = __raw_readl(EINT_MASK(exynos_eint_base, start));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100746
747 status &= ~mask;
748 status &= 0xff;
749
750 while (status) {
751 irq = fls(status) - 1;
752 generic_handle_irq(irq + start);
753 status &= ~(1 << irq);
754 }
755}
756
Eunki Kim330c90a2012-03-14 01:43:31 -0700757static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100758{
759 struct irq_chip *chip = irq_get_chip(irq);
760 chained_irq_enter(chip, desc);
Eunki Kim330c90a2012-03-14 01:43:31 -0700761 exynos_irq_demux_eint(IRQ_EINT(16));
762 exynos_irq_demux_eint(IRQ_EINT(24));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100763 chained_irq_exit(chip, desc);
764}
765
Kukjin Kimbb19a752012-01-25 13:48:11 +0900766static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100767{
768 u32 *irq_data = irq_get_handler_data(irq);
769 struct irq_chip *chip = irq_get_chip(irq);
770
771 chained_irq_enter(chip, desc);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100772 generic_handle_irq(*irq_data);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100773 chained_irq_exit(chip, desc);
774}
775
Eunki Kim330c90a2012-03-14 01:43:31 -0700776static int __init exynos_init_irq_eint(void)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100777{
778 int irq;
779
Thomas Abrahamfef05c22012-09-07 06:07:40 +0900780#ifdef CONFIG_PINCTRL_SAMSUNG
781 /*
782 * The Samsung pinctrl driver provides an integrated gpio/pinmux/pinconf
783 * functionality along with support for external gpio and wakeup
784 * interrupts. If the samsung pinctrl driver is enabled and includes
785 * the wakeup interrupt support, then the setting up external wakeup
786 * interrupts here can be skipped. This check here is temporary to
787 * allow exynos4 platforms that do not use Samsung pinctrl driver to
788 * co-exist with platforms that do. When all of the Samsung Exynos4
789 * platforms switch over to using the pinctrl driver, the wakeup
790 * interrupt support code here can be completely removed.
791 */
Tomasz Figaab7b51f2012-11-07 08:44:51 +0900792 static const struct of_device_id exynos_pinctrl_ids[] = {
Kukjin Kimb533c862013-01-02 16:05:42 -0800793 { .compatible = "samsung,exynos4210-pinctrl", },
794 { .compatible = "samsung,exynos4x12-pinctrl", },
Tomasz Figaab7b51f2012-11-07 08:44:51 +0900795 };
Thomas Abrahamfef05c22012-09-07 06:07:40 +0900796 struct device_node *pctrl_np, *wkup_np;
Thomas Abrahamfef05c22012-09-07 06:07:40 +0900797 const char *wkup_compat = "samsung,exynos4210-wakeup-eint";
798
Tomasz Figaab7b51f2012-11-07 08:44:51 +0900799 for_each_matching_node(pctrl_np, exynos_pinctrl_ids) {
Thomas Abrahamfef05c22012-09-07 06:07:40 +0900800 if (of_device_is_available(pctrl_np)) {
801 wkup_np = of_find_compatible_node(pctrl_np, NULL,
802 wkup_compat);
803 if (wkup_np)
804 return -ENODEV;
805 }
806 }
807#endif
Kukjin Kim2edb36c2012-11-15 15:48:56 +0900808 if (soc_is_exynos5440())
809 return 0;
Thomas Abrahamfef05c22012-09-07 06:07:40 +0900810
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900811 if (soc_is_exynos5250())
Eunki Kim330c90a2012-03-14 01:43:31 -0700812 exynos_eint_base = ioremap(EXYNOS5_PA_GPIO1, SZ_4K);
813 else
814 exynos_eint_base = ioremap(EXYNOS4_PA_GPIO2, SZ_4K);
815
816 if (exynos_eint_base == NULL) {
817 pr_err("unable to ioremap for EINT base address\n");
818 return -ENOMEM;
819 }
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900820
Kukjin Kimcc511b82011-12-27 08:18:36 +0100821 for (irq = 0 ; irq <= 31 ; irq++) {
Eunki Kim330c90a2012-03-14 01:43:31 -0700822 irq_set_chip_and_handler(IRQ_EINT(irq), &exynos_irq_eint,
Kukjin Kimcc511b82011-12-27 08:18:36 +0100823 handle_level_irq);
824 set_irq_flags(IRQ_EINT(irq), IRQF_VALID);
825 }
826
Eunki Kim330c90a2012-03-14 01:43:31 -0700827 irq_set_chained_handler(EXYNOS_IRQ_EINT16_31, exynos_irq_demux_eint16_31);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100828
829 for (irq = 0 ; irq <= 15 ; irq++) {
830 eint0_15_data[irq] = IRQ_EINT(irq);
831
Kukjin Kimbb19a752012-01-25 13:48:11 +0900832 if (soc_is_exynos5250()) {
833 irq_set_handler_data(exynos5_eint0_15_src_int[irq],
834 &eint0_15_data[irq]);
835 irq_set_chained_handler(exynos5_eint0_15_src_int[irq],
836 exynos_irq_eint0_15);
837 } else {
838 irq_set_handler_data(exynos4_eint0_15_src_int[irq],
839 &eint0_15_data[irq]);
840 irq_set_chained_handler(exynos4_eint0_15_src_int[irq],
841 exynos_irq_eint0_15);
842 }
Kukjin Kimcc511b82011-12-27 08:18:36 +0100843 }
844
845 return 0;
846}
Eunki Kim330c90a2012-03-14 01:43:31 -0700847arch_initcall(exynos_init_irq_eint);