blob: 8dd19c696a60c3d0f0e551994bb0c836bae89944 [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>
Thomas Abraham1e60bc02012-05-15 16:18:35 +090022#include <linux/export.h>
23#include <linux/irqdomain.h>
Thomas Abrahame873a472012-05-15 16:25:23 +090024#include <linux/of_address.h>
Kukjin Kimcc511b82011-12-27 08:18:36 +010025
26#include <asm/proc-fns.h>
Arnd Bergmann40ba95f2012-01-07 11:51:28 +000027#include <asm/exception.h>
Kukjin Kimcc511b82011-12-27 08:18:36 +010028#include <asm/hardware/cache-l2x0.h>
29#include <asm/hardware/gic.h>
30#include <asm/mach/map.h>
31#include <asm/mach/irq.h>
Amit Daniel Kachhapb756a502012-03-08 02:07:41 -080032#include <asm/cacheflush.h>
Kukjin Kimcc511b82011-12-27 08:18:36 +010033
34#include <mach/regs-irq.h>
35#include <mach/regs-pmu.h>
36#include <mach/regs-gpio.h>
Amit Daniel Kachhapb756a502012-03-08 02:07:41 -080037#include <mach/pmu.h>
Kukjin Kimcc511b82011-12-27 08:18:36 +010038
39#include <plat/cpu.h>
40#include <plat/clock.h>
41#include <plat/devs.h>
42#include <plat/pm.h>
Kukjin Kimcc511b82011-12-27 08:18:36 +010043#include <plat/sdhci.h>
44#include <plat/gpio-cfg.h>
45#include <plat/adc-core.h>
46#include <plat/fb-core.h>
47#include <plat/fimc-core.h>
48#include <plat/iic-core.h>
49#include <plat/tv-core.h>
Heiko Stuebner308b3af2012-10-17 16:47:11 +090050#include <plat/spi-core.h>
Kukjin Kimcc511b82011-12-27 08:18:36 +010051#include <plat/regs-serial.h>
52
53#include "common.h"
Amit Daniel Kachhap6cdeddc2012-03-08 02:09:12 -080054#define L2_AUX_VAL 0x7C470001
55#define L2_AUX_MASK 0xC200ffff
Kukjin Kimcc511b82011-12-27 08:18:36 +010056
Kukjin Kimcc511b82011-12-27 08:18:36 +010057static const char name_exynos4210[] = "EXYNOS4210";
58static const char name_exynos4212[] = "EXYNOS4212";
59static const char name_exynos4412[] = "EXYNOS4412";
Kukjin Kim94c7ca72012-02-11 22:15:45 +090060static const char name_exynos5250[] = "EXYNOS5250";
Kukjin Kimcc511b82011-12-27 08:18:36 +010061
Kukjin Kim906c7892012-02-11 21:27:08 +090062static void exynos4_map_io(void);
Kukjin Kim94c7ca72012-02-11 22:15:45 +090063static void exynos5_map_io(void);
Kukjin Kim906c7892012-02-11 21:27:08 +090064static void exynos4_init_clocks(int xtal);
Kukjin Kim94c7ca72012-02-11 22:15:45 +090065static void exynos5_init_clocks(int xtal);
Kukjin Kim920f4882012-01-24 20:52:52 +090066static void exynos_init_uarts(struct s3c2410_uartcfg *cfg, int no);
Kukjin Kim906c7892012-02-11 21:27:08 +090067static int exynos_init(void);
Kukjin Kimcc511b82011-12-27 08:18:36 +010068
69static struct cpu_table cpu_ids[] __initdata = {
70 {
71 .idcode = EXYNOS4210_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_exynos4210,
78 }, {
79 .idcode = EXYNOS4212_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_exynos4212,
86 }, {
87 .idcode = EXYNOS4412_CPU_ID,
88 .idmask = EXYNOS4_CPU_MASK,
89 .map_io = exynos4_map_io,
90 .init_clocks = exynos4_init_clocks,
Kukjin Kim920f4882012-01-24 20:52:52 +090091 .init_uarts = exynos_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,
98 .init_clocks = exynos5_init_clocks,
99 .init_uarts = exynos_init_uarts,
100 .init = exynos_init,
101 .name = name_exynos5250,
Kukjin Kimcc511b82011-12-27 08:18:36 +0100102 },
103};
104
105/* Initial IO mappings */
106
107static struct map_desc exynos_iodesc[] __initdata = {
108 {
109 .virtual = (unsigned long)S5P_VA_CHIPID,
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900110 .pfn = __phys_to_pfn(EXYNOS_PA_CHIPID),
Kukjin Kimcc511b82011-12-27 08:18:36 +0100111 .length = SZ_4K,
112 .type = MT_DEVICE,
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900113 },
114};
115
116static struct map_desc exynos4_iodesc[] __initdata = {
117 {
Kukjin Kimcc511b82011-12-27 08:18:36 +0100118 .virtual = (unsigned long)S3C_VA_SYS,
119 .pfn = __phys_to_pfn(EXYNOS4_PA_SYSCON),
120 .length = SZ_64K,
121 .type = MT_DEVICE,
122 }, {
123 .virtual = (unsigned long)S3C_VA_TIMER,
124 .pfn = __phys_to_pfn(EXYNOS4_PA_TIMER),
125 .length = SZ_16K,
126 .type = MT_DEVICE,
127 }, {
128 .virtual = (unsigned long)S3C_VA_WATCHDOG,
129 .pfn = __phys_to_pfn(EXYNOS4_PA_WATCHDOG),
130 .length = SZ_4K,
131 .type = MT_DEVICE,
132 }, {
133 .virtual = (unsigned long)S5P_VA_SROMC,
134 .pfn = __phys_to_pfn(EXYNOS4_PA_SROMC),
135 .length = SZ_4K,
136 .type = MT_DEVICE,
137 }, {
138 .virtual = (unsigned long)S5P_VA_SYSTIMER,
139 .pfn = __phys_to_pfn(EXYNOS4_PA_SYSTIMER),
140 .length = SZ_4K,
141 .type = MT_DEVICE,
142 }, {
143 .virtual = (unsigned long)S5P_VA_PMU,
144 .pfn = __phys_to_pfn(EXYNOS4_PA_PMU),
145 .length = SZ_64K,
146 .type = MT_DEVICE,
147 }, {
148 .virtual = (unsigned long)S5P_VA_COMBINER_BASE,
149 .pfn = __phys_to_pfn(EXYNOS4_PA_COMBINER),
150 .length = SZ_4K,
151 .type = MT_DEVICE,
152 }, {
153 .virtual = (unsigned long)S5P_VA_GIC_CPU,
154 .pfn = __phys_to_pfn(EXYNOS4_PA_GIC_CPU),
155 .length = SZ_64K,
156 .type = MT_DEVICE,
157 }, {
158 .virtual = (unsigned long)S5P_VA_GIC_DIST,
159 .pfn = __phys_to_pfn(EXYNOS4_PA_GIC_DIST),
160 .length = SZ_64K,
161 .type = MT_DEVICE,
162 }, {
163 .virtual = (unsigned long)S3C_VA_UART,
164 .pfn = __phys_to_pfn(EXYNOS4_PA_UART),
165 .length = SZ_512K,
166 .type = MT_DEVICE,
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900167 }, {
Kukjin Kimcc511b82011-12-27 08:18:36 +0100168 .virtual = (unsigned long)S5P_VA_CMU,
169 .pfn = __phys_to_pfn(EXYNOS4_PA_CMU),
170 .length = SZ_128K,
171 .type = MT_DEVICE,
172 }, {
173 .virtual = (unsigned long)S5P_VA_COREPERI_BASE,
174 .pfn = __phys_to_pfn(EXYNOS4_PA_COREPERI),
175 .length = SZ_8K,
176 .type = MT_DEVICE,
177 }, {
178 .virtual = (unsigned long)S5P_VA_L2CC,
179 .pfn = __phys_to_pfn(EXYNOS4_PA_L2CC),
180 .length = SZ_4K,
181 .type = MT_DEVICE,
182 }, {
Kukjin Kimcc511b82011-12-27 08:18:36 +0100183 .virtual = (unsigned long)S5P_VA_DMC0,
184 .pfn = __phys_to_pfn(EXYNOS4_PA_DMC0),
MyungJoo Ham2bde0b02011-12-01 15:12:30 +0900185 .length = SZ_64K,
186 .type = MT_DEVICE,
187 }, {
188 .virtual = (unsigned long)S5P_VA_DMC1,
189 .pfn = __phys_to_pfn(EXYNOS4_PA_DMC1),
190 .length = SZ_64K,
Kukjin Kimcc511b82011-12-27 08:18:36 +0100191 .type = MT_DEVICE,
192 }, {
Kukjin Kimcc511b82011-12-27 08:18:36 +0100193 .virtual = (unsigned long)S3C_VA_USB_HSPHY,
194 .pfn = __phys_to_pfn(EXYNOS4_PA_HSPHY),
195 .length = SZ_4K,
196 .type = MT_DEVICE,
197 },
198};
199
200static struct map_desc exynos4_iodesc0[] __initdata = {
201 {
202 .virtual = (unsigned long)S5P_VA_SYSRAM,
203 .pfn = __phys_to_pfn(EXYNOS4_PA_SYSRAM0),
204 .length = SZ_4K,
205 .type = MT_DEVICE,
206 },
207};
208
209static struct map_desc exynos4_iodesc1[] __initdata = {
210 {
211 .virtual = (unsigned long)S5P_VA_SYSRAM,
212 .pfn = __phys_to_pfn(EXYNOS4_PA_SYSRAM1),
213 .length = SZ_4K,
214 .type = MT_DEVICE,
215 },
216};
217
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900218static struct map_desc exynos5_iodesc[] __initdata = {
219 {
220 .virtual = (unsigned long)S3C_VA_SYS,
221 .pfn = __phys_to_pfn(EXYNOS5_PA_SYSCON),
222 .length = SZ_64K,
223 .type = MT_DEVICE,
224 }, {
225 .virtual = (unsigned long)S3C_VA_TIMER,
226 .pfn = __phys_to_pfn(EXYNOS5_PA_TIMER),
227 .length = SZ_16K,
228 .type = MT_DEVICE,
229 }, {
230 .virtual = (unsigned long)S3C_VA_WATCHDOG,
231 .pfn = __phys_to_pfn(EXYNOS5_PA_WATCHDOG),
232 .length = SZ_4K,
233 .type = MT_DEVICE,
234 }, {
235 .virtual = (unsigned long)S5P_VA_SROMC,
236 .pfn = __phys_to_pfn(EXYNOS5_PA_SROMC),
237 .length = SZ_4K,
238 .type = MT_DEVICE,
239 }, {
240 .virtual = (unsigned long)S5P_VA_SYSTIMER,
241 .pfn = __phys_to_pfn(EXYNOS5_PA_SYSTIMER),
242 .length = SZ_4K,
243 .type = MT_DEVICE,
244 }, {
245 .virtual = (unsigned long)S5P_VA_SYSRAM,
246 .pfn = __phys_to_pfn(EXYNOS5_PA_SYSRAM),
247 .length = SZ_4K,
248 .type = MT_DEVICE,
249 }, {
250 .virtual = (unsigned long)S5P_VA_CMU,
251 .pfn = __phys_to_pfn(EXYNOS5_PA_CMU),
252 .length = 144 * SZ_1K,
253 .type = MT_DEVICE,
254 }, {
255 .virtual = (unsigned long)S5P_VA_PMU,
256 .pfn = __phys_to_pfn(EXYNOS5_PA_PMU),
257 .length = SZ_64K,
258 .type = MT_DEVICE,
259 }, {
260 .virtual = (unsigned long)S5P_VA_COMBINER_BASE,
261 .pfn = __phys_to_pfn(EXYNOS5_PA_COMBINER),
262 .length = SZ_4K,
263 .type = MT_DEVICE,
264 }, {
265 .virtual = (unsigned long)S3C_VA_UART,
266 .pfn = __phys_to_pfn(EXYNOS5_PA_UART),
267 .length = SZ_512K,
268 .type = MT_DEVICE,
269 }, {
270 .virtual = (unsigned long)S5P_VA_GIC_CPU,
271 .pfn = __phys_to_pfn(EXYNOS5_PA_GIC_CPU),
Changhwan Younc9ce7db2012-04-24 14:31:11 -0700272 .length = SZ_8K,
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900273 .type = MT_DEVICE,
274 }, {
275 .virtual = (unsigned long)S5P_VA_GIC_DIST,
276 .pfn = __phys_to_pfn(EXYNOS5_PA_GIC_DIST),
Changhwan Younc9ce7db2012-04-24 14:31:11 -0700277 .length = SZ_4K,
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900278 .type = MT_DEVICE,
279 },
280};
281
Russell King9eb48592012-01-03 11:56:53 +0100282void exynos4_restart(char mode, const char *cmd)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100283{
284 __raw_writel(0x1, S5P_SWRESET);
285}
286
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900287void exynos5_restart(char mode, const char *cmd)
288{
289 __raw_writel(0x1, EXYNOS_SWRESET);
290}
291
Shawn Guobb13fab2012-04-26 10:35:40 +0800292void __init exynos_init_late(void)
293{
294 exynos_pm_late_initcall();
295}
296
Kukjin Kimcc511b82011-12-27 08:18:36 +0100297/*
298 * exynos_map_io
299 *
300 * register the standard cpu IO areas
301 */
302
303void __init exynos_init_io(struct map_desc *mach_desc, int size)
304{
305 /* initialize the io descriptors we need for initialization */
306 iotable_init(exynos_iodesc, ARRAY_SIZE(exynos_iodesc));
307 if (mach_desc)
308 iotable_init(mach_desc, size);
309
310 /* detect cpu id and rev. */
311 s5p_init_cpu(S5P_VA_CHIPID);
312
313 s3c_init_cpu(samsung_cpu_id, cpu_ids, ARRAY_SIZE(cpu_ids));
314}
315
Kukjin Kim906c7892012-02-11 21:27:08 +0900316static void __init exynos4_map_io(void)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100317{
318 iotable_init(exynos4_iodesc, ARRAY_SIZE(exynos4_iodesc));
319
320 if (soc_is_exynos4210() && samsung_rev() == EXYNOS4210_REV_0)
321 iotable_init(exynos4_iodesc0, ARRAY_SIZE(exynos4_iodesc0));
322 else
323 iotable_init(exynos4_iodesc1, ARRAY_SIZE(exynos4_iodesc1));
324
325 /* initialize device information early */
326 exynos4_default_sdhci0();
327 exynos4_default_sdhci1();
328 exynos4_default_sdhci2();
329 exynos4_default_sdhci3();
330
331 s3c_adc_setname("samsung-adc-v3");
332
333 s3c_fimc_setname(0, "exynos4-fimc");
334 s3c_fimc_setname(1, "exynos4-fimc");
335 s3c_fimc_setname(2, "exynos4-fimc");
336 s3c_fimc_setname(3, "exynos4-fimc");
337
Thomas Abraham8482c812012-04-14 08:04:46 -0700338 s3c_sdhci_setname(0, "exynos4-sdhci");
339 s3c_sdhci_setname(1, "exynos4-sdhci");
340 s3c_sdhci_setname(2, "exynos4-sdhci");
341 s3c_sdhci_setname(3, "exynos4-sdhci");
342
Kukjin Kimcc511b82011-12-27 08:18:36 +0100343 /* The I2C bus controllers are directly compatible with s3c2440 */
344 s3c_i2c0_setname("s3c2440-i2c");
345 s3c_i2c1_setname("s3c2440-i2c");
346 s3c_i2c2_setname("s3c2440-i2c");
347
348 s5p_fb_setname(0, "exynos4-fb");
349 s5p_hdmi_setname("exynos4-hdmi");
Heiko Stuebner308b3af2012-10-17 16:47:11 +0900350
351 s3c64xx_spi_setname("exynos4210-spi");
Kukjin Kimcc511b82011-12-27 08:18:36 +0100352}
353
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900354static void __init exynos5_map_io(void)
355{
356 iotable_init(exynos5_iodesc, ARRAY_SIZE(exynos5_iodesc));
357
Kukjin Kimbb19a752012-01-25 13:48:11 +0900358 s3c_device_i2c0.resource[0].start = EXYNOS5_PA_IIC(0);
359 s3c_device_i2c0.resource[0].end = EXYNOS5_PA_IIC(0) + SZ_4K - 1;
360 s3c_device_i2c0.resource[1].start = EXYNOS5_IRQ_IIC;
361 s3c_device_i2c0.resource[1].end = EXYNOS5_IRQ_IIC;
362
Thomas Abraham8482c812012-04-14 08:04:46 -0700363 s3c_sdhci_setname(0, "exynos4-sdhci");
364 s3c_sdhci_setname(1, "exynos4-sdhci");
365 s3c_sdhci_setname(2, "exynos4-sdhci");
366 s3c_sdhci_setname(3, "exynos4-sdhci");
367
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900368 /* The I2C bus controllers are directly compatible with s3c2440 */
369 s3c_i2c0_setname("s3c2440-i2c");
370 s3c_i2c1_setname("s3c2440-i2c");
371 s3c_i2c2_setname("s3c2440-i2c");
Heiko Stuebner308b3af2012-10-17 16:47:11 +0900372
373 s3c64xx_spi_setname("exynos4210-spi");
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900374}
375
Kukjin Kim906c7892012-02-11 21:27:08 +0900376static void __init exynos4_init_clocks(int xtal)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100377{
378 printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
379
380 s3c24xx_register_baseclocks(xtal);
381 s5p_register_clocks(xtal);
382
383 if (soc_is_exynos4210())
384 exynos4210_register_clocks();
385 else if (soc_is_exynos4212() || soc_is_exynos4412())
386 exynos4212_register_clocks();
387
388 exynos4_register_clocks();
389 exynos4_setup_clocks();
390}
391
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900392static void __init exynos5_init_clocks(int xtal)
393{
394 printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
395
396 s3c24xx_register_baseclocks(xtal);
397 s5p_register_clocks(xtal);
398
399 exynos5_register_clocks();
400 exynos5_setup_clocks();
401}
402
Kukjin Kimcc511b82011-12-27 08:18:36 +0100403#define COMBINER_ENABLE_SET 0x0
404#define COMBINER_ENABLE_CLEAR 0x4
405#define COMBINER_INT_STATUS 0xC
406
407static DEFINE_SPINLOCK(irq_controller_lock);
408
409struct combiner_chip_data {
410 unsigned int irq_offset;
411 unsigned int irq_mask;
412 void __iomem *base;
413};
414
Thomas Abraham1e60bc02012-05-15 16:18:35 +0900415static struct irq_domain *combiner_irq_domain;
Kukjin Kimcc511b82011-12-27 08:18:36 +0100416static struct combiner_chip_data combiner_data[MAX_COMBINER_NR];
417
418static inline void __iomem *combiner_base(struct irq_data *data)
419{
420 struct combiner_chip_data *combiner_data =
421 irq_data_get_irq_chip_data(data);
422
423 return combiner_data->base;
424}
425
426static void combiner_mask_irq(struct irq_data *data)
427{
Thomas Abraham1e60bc02012-05-15 16:18:35 +0900428 u32 mask = 1 << (data->hwirq % 32);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100429
430 __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR);
431}
432
433static void combiner_unmask_irq(struct irq_data *data)
434{
Thomas Abraham1e60bc02012-05-15 16:18:35 +0900435 u32 mask = 1 << (data->hwirq % 32);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100436
437 __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET);
438}
439
440static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
441{
442 struct combiner_chip_data *chip_data = irq_get_handler_data(irq);
443 struct irq_chip *chip = irq_get_chip(irq);
444 unsigned int cascade_irq, combiner_irq;
445 unsigned long status;
446
447 chained_irq_enter(chip, desc);
448
449 spin_lock(&irq_controller_lock);
450 status = __raw_readl(chip_data->base + COMBINER_INT_STATUS);
451 spin_unlock(&irq_controller_lock);
452 status &= chip_data->irq_mask;
453
454 if (status == 0)
455 goto out;
456
457 combiner_irq = __ffs(status);
458
459 cascade_irq = combiner_irq + (chip_data->irq_offset & ~31);
460 if (unlikely(cascade_irq >= NR_IRQS))
461 do_bad_IRQ(cascade_irq, desc);
462 else
463 generic_handle_irq(cascade_irq);
464
465 out:
466 chained_irq_exit(chip, desc);
467}
468
469static struct irq_chip combiner_chip = {
470 .name = "COMBINER",
471 .irq_mask = combiner_mask_irq,
472 .irq_unmask = combiner_unmask_irq,
473};
474
475static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq)
476{
Kukjin Kimbb19a752012-01-25 13:48:11 +0900477 unsigned int max_nr;
478
479 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 if (irq_set_handler_data(irq, &combiner_data[combiner_nr]) != 0)
487 BUG();
488 irq_set_chained_handler(irq, combiner_handle_cascade_irq);
489}
490
Thomas Abraham1e60bc02012-05-15 16:18:35 +0900491static void __init combiner_init_one(unsigned int combiner_nr,
492 void __iomem *base)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100493{
Kukjin Kimcc511b82011-12-27 08:18:36 +0100494 combiner_data[combiner_nr].base = base;
Thomas Abraham1e60bc02012-05-15 16:18:35 +0900495 combiner_data[combiner_nr].irq_offset = irq_find_mapping(
496 combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100497 combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3);
498
499 /* Disable all interrupts */
Kukjin Kimcc511b82011-12-27 08:18:36 +0100500 __raw_writel(combiner_data[combiner_nr].irq_mask,
501 base + COMBINER_ENABLE_CLEAR);
Thomas Abraham1e60bc02012-05-15 16:18:35 +0900502}
Kukjin Kimcc511b82011-12-27 08:18:36 +0100503
Thomas Abrahame873a472012-05-15 16:25:23 +0900504#ifdef CONFIG_OF
505static int combiner_irq_domain_xlate(struct irq_domain *d,
506 struct device_node *controller,
507 const u32 *intspec, unsigned int intsize,
508 unsigned long *out_hwirq,
509 unsigned int *out_type)
510{
511 if (d->of_node != controller)
512 return -EINVAL;
513
514 if (intsize < 2)
515 return -EINVAL;
516
517 *out_hwirq = intspec[0] * MAX_IRQ_IN_COMBINER + intspec[1];
518 *out_type = 0;
519
520 return 0;
521}
522#else
523static int combiner_irq_domain_xlate(struct irq_domain *d,
524 struct device_node *controller,
525 const u32 *intspec, unsigned int intsize,
526 unsigned long *out_hwirq,
527 unsigned int *out_type)
528{
529 return -EINVAL;
530}
531#endif
532
Thomas Abraham1e60bc02012-05-15 16:18:35 +0900533static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq,
534 irq_hw_number_t hw)
535{
536 irq_set_chip_and_handler(irq, &combiner_chip, handle_level_irq);
537 irq_set_chip_data(irq, &combiner_data[hw >> 3]);
538 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100539
Thomas Abraham1e60bc02012-05-15 16:18:35 +0900540 return 0;
541}
542
543static struct irq_domain_ops combiner_irq_domain_ops = {
Thomas Abrahame873a472012-05-15 16:25:23 +0900544 .xlate = combiner_irq_domain_xlate,
Thomas Abraham1e60bc02012-05-15 16:18:35 +0900545 .map = combiner_irq_domain_map,
546};
547
Sachin Kamat2a2b0e22012-07-12 16:34:51 +0900548static void __init combiner_init(void __iomem *combiner_base,
549 struct device_node *np)
Thomas Abraham1e60bc02012-05-15 16:18:35 +0900550{
Thomas Abrahame873a472012-05-15 16:25:23 +0900551 int i, irq, irq_base;
Thomas Abraham1e60bc02012-05-15 16:18:35 +0900552 unsigned int max_nr, nr_irq;
553
Thomas Abrahame873a472012-05-15 16:25:23 +0900554 if (np) {
555 if (of_property_read_u32(np, "samsung,combiner-nr", &max_nr)) {
556 pr_warning("%s: number of combiners not specified, "
557 "setting default as %d.\n",
558 __func__, EXYNOS4_MAX_COMBINER_NR);
559 max_nr = EXYNOS4_MAX_COMBINER_NR;
560 }
561 } else {
562 max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR :
563 EXYNOS4_MAX_COMBINER_NR;
564 }
Thomas Abraham1e60bc02012-05-15 16:18:35 +0900565 nr_irq = max_nr * MAX_IRQ_IN_COMBINER;
566
567 irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0);
568 if (IS_ERR_VALUE(irq_base)) {
569 irq_base = COMBINER_IRQ(0, 0);
570 pr_warning("%s: irq desc alloc failed. Continuing with %d as linux irq base\n", __func__, irq_base);
571 }
572
573 combiner_irq_domain = irq_domain_add_legacy(np, nr_irq, irq_base, 0,
574 &combiner_irq_domain_ops, &combiner_data);
575 if (WARN_ON(!combiner_irq_domain)) {
576 pr_warning("%s: irq domain init failed\n", __func__);
577 return;
578 }
579
580 for (i = 0; i < max_nr; i++) {
581 combiner_init_one(i, combiner_base + (i >> 2) * 0x10);
Arnd Bergmann820f3dd2012-05-16 22:10:14 +0200582 irq = IRQ_SPI(i);
583#ifdef CONFIG_OF
584 if (np)
585 irq = irq_of_parse_and_map(np, i);
586#endif
Thomas Abrahame873a472012-05-15 16:25:23 +0900587 combiner_cascade_irq(i, irq);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100588 }
589}
590
Arnd Bergmann237c78b2012-01-07 12:30:20 +0000591#ifdef CONFIG_OF
Thomas Abrahame873a472012-05-15 16:25:23 +0900592int __init combiner_of_init(struct device_node *np, struct device_node *parent)
593{
594 void __iomem *combiner_base;
595
596 combiner_base = of_iomap(np, 0);
597 if (!combiner_base) {
598 pr_err("%s: failed to map combiner registers\n", __func__);
599 return -ENXIO;
600 }
601
602 combiner_init(combiner_base, np);
603
604 return 0;
605}
606
Arnd Bergmann237c78b2012-01-07 12:30:20 +0000607static const struct of_device_id exynos4_dt_irq_match[] = {
608 { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
Thomas Abrahame873a472012-05-15 16:25:23 +0900609 { .compatible = "samsung,exynos4210-combiner",
610 .data = combiner_of_init, },
Arnd Bergmann237c78b2012-01-07 12:30:20 +0000611 {},
612};
613#endif
Kukjin Kimcc511b82011-12-27 08:18:36 +0100614
615void __init exynos4_init_irq(void)
616{
Arnd Bergmann40ba95f2012-01-07 11:51:28 +0000617 unsigned int gic_bank_offset;
Kukjin Kimcc511b82011-12-27 08:18:36 +0100618
619 gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000;
620
Arnd Bergmann237c78b2012-01-07 12:30:20 +0000621 if (!of_have_populated_dt())
Grant Likely75294952012-02-14 14:06:57 -0700622 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 +0000623#ifdef CONFIG_OF
624 else
625 of_irq_init(exynos4_dt_irq_match);
626#endif
Kukjin Kimcc511b82011-12-27 08:18:36 +0100627
Thomas Abrahame873a472012-05-15 16:25:23 +0900628 if (!of_have_populated_dt())
629 combiner_init(S5P_VA_COMBINER_BASE, NULL);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100630
631 /*
632 * The parameters of s5p_init_irq() are for VIC init.
633 * Theses parameters should be NULL and 0 because EXYNOS4
634 * uses GIC instead of VIC.
635 */
636 s5p_init_irq(NULL, 0);
637}
638
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900639void __init exynos5_init_irq(void)
640{
Tushar Behera6fff5a12012-04-24 13:25:01 -0700641#ifdef CONFIG_OF
Thomas Abraham5699b0c2012-04-20 17:26:23 -0700642 of_irq_init(exynos4_dt_irq_match);
Tushar Behera6fff5a12012-04-24 13:25:01 -0700643#endif
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900644 /*
645 * The parameters of s5p_init_irq() are for VIC init.
646 * Theses parameters should be NULL and 0 because EXYNOS4
647 * uses GIC instead of VIC.
648 */
649 s5p_init_irq(NULL, 0);
Inderpal Singh34455132012-11-22 14:46:21 +0900650
651 gic_arch_extn.irq_set_wake = s3c_irq_wake;
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900652}
653
Thomas Abraham9ee6af92012-05-15 15:47:40 +0900654struct bus_type exynos_subsys = {
655 .name = "exynos-core",
656 .dev_name = "exynos-core",
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900657};
658
Linus Torvalds7affca32012-01-07 12:03:30 -0800659static struct device exynos4_dev = {
Thomas Abraham9ee6af92012-05-15 15:47:40 +0900660 .bus = &exynos_subsys,
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900661};
662
663static int __init exynos_core_init(void)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100664{
Thomas Abraham9ee6af92012-05-15 15:47:40 +0900665 return subsys_system_register(&exynos_subsys, NULL);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100666}
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900667core_initcall(exynos_core_init);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100668
669#ifdef CONFIG_CACHE_L2X0
670static int __init exynos4_l2x0_cache_init(void)
671{
Il Hane1b19942012-04-05 07:59:36 -0700672 int ret;
673
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900674 if (soc_is_exynos5250())
675 return 0;
676
Amit Daniel Kachhap6cdeddc2012-03-08 02:09:12 -0800677 ret = l2x0_of_init(L2_AUX_VAL, L2_AUX_MASK);
678 if (!ret) {
679 l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs);
680 clean_dcache_area(&l2x0_regs_phys, sizeof(unsigned long));
681 return 0;
682 }
Kukjin Kimcc511b82011-12-27 08:18:36 +0100683
Amit Daniel Kachhapb756a502012-03-08 02:07:41 -0800684 if (!(__raw_readl(S5P_VA_L2CC + L2X0_CTRL) & 0x1)) {
685 l2x0_saved_regs.phy_base = EXYNOS4_PA_L2CC;
686 /* TAG, Data Latency Control: 2 cycles */
687 l2x0_saved_regs.tag_latency = 0x110;
Kukjin Kimcc511b82011-12-27 08:18:36 +0100688
Amit Daniel Kachhapb756a502012-03-08 02:07:41 -0800689 if (soc_is_exynos4212() || soc_is_exynos4412())
690 l2x0_saved_regs.data_latency = 0x120;
691 else
692 l2x0_saved_regs.data_latency = 0x110;
Kukjin Kimcc511b82011-12-27 08:18:36 +0100693
Amit Daniel Kachhapb756a502012-03-08 02:07:41 -0800694 l2x0_saved_regs.prefetch_ctrl = 0x30000007;
695 l2x0_saved_regs.pwr_ctrl =
696 (L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100697
Amit Daniel Kachhapb756a502012-03-08 02:07:41 -0800698 l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100699
Amit Daniel Kachhapb756a502012-03-08 02:07:41 -0800700 __raw_writel(l2x0_saved_regs.tag_latency,
701 S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL);
702 __raw_writel(l2x0_saved_regs.data_latency,
703 S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL);
704
705 /* L2X0 Prefetch Control */
706 __raw_writel(l2x0_saved_regs.prefetch_ctrl,
707 S5P_VA_L2CC + L2X0_PREFETCH_CTRL);
708
709 /* L2X0 Power Control */
710 __raw_writel(l2x0_saved_regs.pwr_ctrl,
711 S5P_VA_L2CC + L2X0_POWER_CTRL);
712
713 clean_dcache_area(&l2x0_regs_phys, sizeof(unsigned long));
714 clean_dcache_area(&l2x0_saved_regs, sizeof(struct l2x0_regs));
715 }
Kukjin Kimcc511b82011-12-27 08:18:36 +0100716
Amit Daniel Kachhap6cdeddc2012-03-08 02:09:12 -0800717 l2x0_init(S5P_VA_L2CC, L2_AUX_VAL, L2_AUX_MASK);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100718 return 0;
719}
Kukjin Kimcc511b82011-12-27 08:18:36 +0100720early_initcall(exynos4_l2x0_cache_init);
721#endif
722
Kukjin Kim906c7892012-02-11 21:27:08 +0900723static int __init exynos_init(void)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100724{
725 printk(KERN_INFO "EXYNOS: Initializing architecture\n");
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900726
Thomas Abraham9ee6af92012-05-15 15:47:40 +0900727 return device_register(&exynos4_dev);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100728}
729
Kukjin Kimcc511b82011-12-27 08:18:36 +0100730/* uart registration process */
731
Kukjin Kim920f4882012-01-24 20:52:52 +0900732static void __init exynos_init_uarts(struct s3c2410_uartcfg *cfg, int no)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100733{
734 struct s3c2410_uartcfg *tcfg = cfg;
735 u32 ucnt;
736
Arnd Bergmann237c78b2012-01-07 12:30:20 +0000737 for (ucnt = 0; ucnt < no; ucnt++, tcfg++)
738 tcfg->has_fracval = 1;
Kukjin Kimcc511b82011-12-27 08:18:36 +0100739
Kukjin Kim171c0672012-02-10 11:57:53 +0900740 if (soc_is_exynos5250())
741 s3c24xx_init_uartdevs("exynos4210-uart", exynos5_uart_resources, cfg, no);
742 else
743 s3c24xx_init_uartdevs("exynos4210-uart", exynos4_uart_resources, cfg, no);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100744}
745
Eunki Kim330c90a2012-03-14 01:43:31 -0700746static void __iomem *exynos_eint_base;
747
Kukjin Kimcc511b82011-12-27 08:18:36 +0100748static DEFINE_SPINLOCK(eint_lock);
749
750static unsigned int eint0_15_data[16];
751
Eunki Kim330c90a2012-03-14 01:43:31 -0700752static inline int exynos4_irq_to_gpio(unsigned int irq)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100753{
Eunki Kim330c90a2012-03-14 01:43:31 -0700754 if (irq < IRQ_EINT(0))
755 return -EINVAL;
Kukjin Kimcc511b82011-12-27 08:18:36 +0100756
Eunki Kim330c90a2012-03-14 01:43:31 -0700757 irq -= IRQ_EINT(0);
758 if (irq < 8)
759 return EXYNOS4_GPX0(irq);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100760
Eunki Kim330c90a2012-03-14 01:43:31 -0700761 irq -= 8;
762 if (irq < 8)
763 return EXYNOS4_GPX1(irq);
764
765 irq -= 8;
766 if (irq < 8)
767 return EXYNOS4_GPX2(irq);
768
769 irq -= 8;
770 if (irq < 8)
771 return EXYNOS4_GPX3(irq);
772
773 return -EINVAL;
Kukjin Kimcc511b82011-12-27 08:18:36 +0100774}
775
Eunki Kim330c90a2012-03-14 01:43:31 -0700776static inline int exynos5_irq_to_gpio(unsigned int irq)
777{
778 if (irq < IRQ_EINT(0))
779 return -EINVAL;
780
781 irq -= IRQ_EINT(0);
782 if (irq < 8)
783 return EXYNOS5_GPX0(irq);
784
785 irq -= 8;
786 if (irq < 8)
787 return EXYNOS5_GPX1(irq);
788
789 irq -= 8;
790 if (irq < 8)
791 return EXYNOS5_GPX2(irq);
792
793 irq -= 8;
794 if (irq < 8)
795 return EXYNOS5_GPX3(irq);
796
797 return -EINVAL;
798}
799
Kukjin Kimbb19a752012-01-25 13:48:11 +0900800static unsigned int exynos4_eint0_15_src_int[16] = {
801 EXYNOS4_IRQ_EINT0,
802 EXYNOS4_IRQ_EINT1,
803 EXYNOS4_IRQ_EINT2,
804 EXYNOS4_IRQ_EINT3,
805 EXYNOS4_IRQ_EINT4,
806 EXYNOS4_IRQ_EINT5,
807 EXYNOS4_IRQ_EINT6,
808 EXYNOS4_IRQ_EINT7,
809 EXYNOS4_IRQ_EINT8,
810 EXYNOS4_IRQ_EINT9,
811 EXYNOS4_IRQ_EINT10,
812 EXYNOS4_IRQ_EINT11,
813 EXYNOS4_IRQ_EINT12,
814 EXYNOS4_IRQ_EINT13,
815 EXYNOS4_IRQ_EINT14,
816 EXYNOS4_IRQ_EINT15,
817};
Kukjin Kimcc511b82011-12-27 08:18:36 +0100818
Kukjin Kimbb19a752012-01-25 13:48:11 +0900819static unsigned int exynos5_eint0_15_src_int[16] = {
820 EXYNOS5_IRQ_EINT0,
821 EXYNOS5_IRQ_EINT1,
822 EXYNOS5_IRQ_EINT2,
823 EXYNOS5_IRQ_EINT3,
824 EXYNOS5_IRQ_EINT4,
825 EXYNOS5_IRQ_EINT5,
826 EXYNOS5_IRQ_EINT6,
827 EXYNOS5_IRQ_EINT7,
828 EXYNOS5_IRQ_EINT8,
829 EXYNOS5_IRQ_EINT9,
830 EXYNOS5_IRQ_EINT10,
831 EXYNOS5_IRQ_EINT11,
832 EXYNOS5_IRQ_EINT12,
833 EXYNOS5_IRQ_EINT13,
834 EXYNOS5_IRQ_EINT14,
835 EXYNOS5_IRQ_EINT15,
836};
Eunki Kim330c90a2012-03-14 01:43:31 -0700837static inline void exynos_irq_eint_mask(struct irq_data *data)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100838{
839 u32 mask;
840
841 spin_lock(&eint_lock);
Eunki Kim330c90a2012-03-14 01:43:31 -0700842 mask = __raw_readl(EINT_MASK(exynos_eint_base, data->irq));
843 mask |= EINT_OFFSET_BIT(data->irq);
844 __raw_writel(mask, EINT_MASK(exynos_eint_base, data->irq));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100845 spin_unlock(&eint_lock);
846}
847
Eunki Kim330c90a2012-03-14 01:43:31 -0700848static void exynos_irq_eint_unmask(struct irq_data *data)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100849{
850 u32 mask;
851
852 spin_lock(&eint_lock);
Eunki Kim330c90a2012-03-14 01:43:31 -0700853 mask = __raw_readl(EINT_MASK(exynos_eint_base, data->irq));
854 mask &= ~(EINT_OFFSET_BIT(data->irq));
855 __raw_writel(mask, EINT_MASK(exynos_eint_base, data->irq));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100856 spin_unlock(&eint_lock);
857}
858
Eunki Kim330c90a2012-03-14 01:43:31 -0700859static inline void exynos_irq_eint_ack(struct irq_data *data)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100860{
Eunki Kim330c90a2012-03-14 01:43:31 -0700861 __raw_writel(EINT_OFFSET_BIT(data->irq),
862 EINT_PEND(exynos_eint_base, data->irq));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100863}
864
Eunki Kim330c90a2012-03-14 01:43:31 -0700865static void exynos_irq_eint_maskack(struct irq_data *data)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100866{
Eunki Kim330c90a2012-03-14 01:43:31 -0700867 exynos_irq_eint_mask(data);
868 exynos_irq_eint_ack(data);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100869}
870
Eunki Kim330c90a2012-03-14 01:43:31 -0700871static int exynos_irq_eint_set_type(struct irq_data *data, unsigned int type)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100872{
873 int offs = EINT_OFFSET(data->irq);
874 int shift;
875 u32 ctrl, mask;
876 u32 newvalue = 0;
877
878 switch (type) {
879 case IRQ_TYPE_EDGE_RISING:
880 newvalue = S5P_IRQ_TYPE_EDGE_RISING;
881 break;
882
883 case IRQ_TYPE_EDGE_FALLING:
884 newvalue = S5P_IRQ_TYPE_EDGE_FALLING;
885 break;
886
887 case IRQ_TYPE_EDGE_BOTH:
888 newvalue = S5P_IRQ_TYPE_EDGE_BOTH;
889 break;
890
891 case IRQ_TYPE_LEVEL_LOW:
892 newvalue = S5P_IRQ_TYPE_LEVEL_LOW;
893 break;
894
895 case IRQ_TYPE_LEVEL_HIGH:
896 newvalue = S5P_IRQ_TYPE_LEVEL_HIGH;
897 break;
898
899 default:
900 printk(KERN_ERR "No such irq type %d", type);
901 return -EINVAL;
902 }
903
904 shift = (offs & 0x7) * 4;
905 mask = 0x7 << shift;
906
907 spin_lock(&eint_lock);
Eunki Kim330c90a2012-03-14 01:43:31 -0700908 ctrl = __raw_readl(EINT_CON(exynos_eint_base, data->irq));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100909 ctrl &= ~mask;
910 ctrl |= newvalue << shift;
Eunki Kim330c90a2012-03-14 01:43:31 -0700911 __raw_writel(ctrl, EINT_CON(exynos_eint_base, data->irq));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100912 spin_unlock(&eint_lock);
913
Eunki Kim330c90a2012-03-14 01:43:31 -0700914 if (soc_is_exynos5250())
915 s3c_gpio_cfgpin(exynos5_irq_to_gpio(data->irq), S3C_GPIO_SFN(0xf));
916 else
917 s3c_gpio_cfgpin(exynos4_irq_to_gpio(data->irq), S3C_GPIO_SFN(0xf));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100918
919 return 0;
920}
921
Eunki Kim330c90a2012-03-14 01:43:31 -0700922static struct irq_chip exynos_irq_eint = {
923 .name = "exynos-eint",
924 .irq_mask = exynos_irq_eint_mask,
925 .irq_unmask = exynos_irq_eint_unmask,
926 .irq_mask_ack = exynos_irq_eint_maskack,
927 .irq_ack = exynos_irq_eint_ack,
928 .irq_set_type = exynos_irq_eint_set_type,
Kukjin Kimcc511b82011-12-27 08:18:36 +0100929#ifdef CONFIG_PM
930 .irq_set_wake = s3c_irqext_wake,
931#endif
932};
933
934/*
935 * exynos4_irq_demux_eint
936 *
937 * This function demuxes the IRQ from from EINTs 16 to 31.
938 * It is designed to be inlined into the specific handler
939 * s5p_irq_demux_eintX_Y.
940 *
941 * Each EINT pend/mask registers handle eight of them.
942 */
Eunki Kim330c90a2012-03-14 01:43:31 -0700943static inline void exynos_irq_demux_eint(unsigned int start)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100944{
945 unsigned int irq;
946
Eunki Kim330c90a2012-03-14 01:43:31 -0700947 u32 status = __raw_readl(EINT_PEND(exynos_eint_base, start));
948 u32 mask = __raw_readl(EINT_MASK(exynos_eint_base, start));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100949
950 status &= ~mask;
951 status &= 0xff;
952
953 while (status) {
954 irq = fls(status) - 1;
955 generic_handle_irq(irq + start);
956 status &= ~(1 << irq);
957 }
958}
959
Eunki Kim330c90a2012-03-14 01:43:31 -0700960static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100961{
962 struct irq_chip *chip = irq_get_chip(irq);
963 chained_irq_enter(chip, desc);
Eunki Kim330c90a2012-03-14 01:43:31 -0700964 exynos_irq_demux_eint(IRQ_EINT(16));
965 exynos_irq_demux_eint(IRQ_EINT(24));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100966 chained_irq_exit(chip, desc);
967}
968
Kukjin Kimbb19a752012-01-25 13:48:11 +0900969static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100970{
971 u32 *irq_data = irq_get_handler_data(irq);
972 struct irq_chip *chip = irq_get_chip(irq);
973
974 chained_irq_enter(chip, desc);
975 chip->irq_mask(&desc->irq_data);
976
977 if (chip->irq_ack)
978 chip->irq_ack(&desc->irq_data);
979
980 generic_handle_irq(*irq_data);
981
982 chip->irq_unmask(&desc->irq_data);
983 chained_irq_exit(chip, desc);
984}
985
Eunki Kim330c90a2012-03-14 01:43:31 -0700986static int __init exynos_init_irq_eint(void)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100987{
988 int irq;
989
Thomas Abrahamfef05c22012-09-07 06:07:40 +0900990#ifdef CONFIG_PINCTRL_SAMSUNG
991 /*
992 * The Samsung pinctrl driver provides an integrated gpio/pinmux/pinconf
993 * functionality along with support for external gpio and wakeup
994 * interrupts. If the samsung pinctrl driver is enabled and includes
995 * the wakeup interrupt support, then the setting up external wakeup
996 * interrupts here can be skipped. This check here is temporary to
997 * allow exynos4 platforms that do not use Samsung pinctrl driver to
998 * co-exist with platforms that do. When all of the Samsung Exynos4
999 * platforms switch over to using the pinctrl driver, the wakeup
1000 * interrupt support code here can be completely removed.
1001 */
1002 struct device_node *pctrl_np, *wkup_np;
1003 const char *pctrl_compat = "samsung,pinctrl-exynos4210";
1004 const char *wkup_compat = "samsung,exynos4210-wakeup-eint";
1005
1006 for_each_compatible_node(pctrl_np, NULL, pctrl_compat) {
1007 if (of_device_is_available(pctrl_np)) {
1008 wkup_np = of_find_compatible_node(pctrl_np, NULL,
1009 wkup_compat);
1010 if (wkup_np)
1011 return -ENODEV;
1012 }
1013 }
1014#endif
1015
Kukjin Kim94c7ca72012-02-11 22:15:45 +09001016 if (soc_is_exynos5250())
Eunki Kim330c90a2012-03-14 01:43:31 -07001017 exynos_eint_base = ioremap(EXYNOS5_PA_GPIO1, SZ_4K);
1018 else
1019 exynos_eint_base = ioremap(EXYNOS4_PA_GPIO2, SZ_4K);
1020
1021 if (exynos_eint_base == NULL) {
1022 pr_err("unable to ioremap for EINT base address\n");
1023 return -ENOMEM;
1024 }
Kukjin Kim94c7ca72012-02-11 22:15:45 +09001025
Kukjin Kimcc511b82011-12-27 08:18:36 +01001026 for (irq = 0 ; irq <= 31 ; irq++) {
Eunki Kim330c90a2012-03-14 01:43:31 -07001027 irq_set_chip_and_handler(IRQ_EINT(irq), &exynos_irq_eint,
Kukjin Kimcc511b82011-12-27 08:18:36 +01001028 handle_level_irq);
1029 set_irq_flags(IRQ_EINT(irq), IRQF_VALID);
1030 }
1031
Eunki Kim330c90a2012-03-14 01:43:31 -07001032 irq_set_chained_handler(EXYNOS_IRQ_EINT16_31, exynos_irq_demux_eint16_31);
Kukjin Kimcc511b82011-12-27 08:18:36 +01001033
1034 for (irq = 0 ; irq <= 15 ; irq++) {
1035 eint0_15_data[irq] = IRQ_EINT(irq);
1036
Kukjin Kimbb19a752012-01-25 13:48:11 +09001037 if (soc_is_exynos5250()) {
1038 irq_set_handler_data(exynos5_eint0_15_src_int[irq],
1039 &eint0_15_data[irq]);
1040 irq_set_chained_handler(exynos5_eint0_15_src_int[irq],
1041 exynos_irq_eint0_15);
1042 } else {
1043 irq_set_handler_data(exynos4_eint0_15_src_int[irq],
1044 &eint0_15_data[irq]);
1045 irq_set_chained_handler(exynos4_eint0_15_src_int[irq],
1046 exynos_irq_eint0_15);
1047 }
Kukjin Kimcc511b82011-12-27 08:18:36 +01001048 }
1049
1050 return 0;
1051}
Eunki Kim330c90a2012-03-14 01:43:31 -07001052arch_initcall(exynos_init_irq_eint);