blob: 1947be8e5f5bffec59d1542e8ebbbc6bbce36970 [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);
650}
651
Thomas Abraham9ee6af92012-05-15 15:47:40 +0900652struct bus_type exynos_subsys = {
653 .name = "exynos-core",
654 .dev_name = "exynos-core",
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900655};
656
Linus Torvalds7affca32012-01-07 12:03:30 -0800657static struct device exynos4_dev = {
Thomas Abraham9ee6af92012-05-15 15:47:40 +0900658 .bus = &exynos_subsys,
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900659};
660
661static int __init exynos_core_init(void)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100662{
Thomas Abraham9ee6af92012-05-15 15:47:40 +0900663 return subsys_system_register(&exynos_subsys, NULL);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100664}
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900665core_initcall(exynos_core_init);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100666
667#ifdef CONFIG_CACHE_L2X0
668static int __init exynos4_l2x0_cache_init(void)
669{
Il Hane1b19942012-04-05 07:59:36 -0700670 int ret;
671
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900672 if (soc_is_exynos5250())
673 return 0;
674
Amit Daniel Kachhap6cdeddc2012-03-08 02:09:12 -0800675 ret = l2x0_of_init(L2_AUX_VAL, L2_AUX_MASK);
676 if (!ret) {
677 l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs);
678 clean_dcache_area(&l2x0_regs_phys, sizeof(unsigned long));
679 return 0;
680 }
Kukjin Kimcc511b82011-12-27 08:18:36 +0100681
Amit Daniel Kachhapb756a502012-03-08 02:07:41 -0800682 if (!(__raw_readl(S5P_VA_L2CC + L2X0_CTRL) & 0x1)) {
683 l2x0_saved_regs.phy_base = EXYNOS4_PA_L2CC;
684 /* TAG, Data Latency Control: 2 cycles */
685 l2x0_saved_regs.tag_latency = 0x110;
Kukjin Kimcc511b82011-12-27 08:18:36 +0100686
Amit Daniel Kachhapb756a502012-03-08 02:07:41 -0800687 if (soc_is_exynos4212() || soc_is_exynos4412())
688 l2x0_saved_regs.data_latency = 0x120;
689 else
690 l2x0_saved_regs.data_latency = 0x110;
Kukjin Kimcc511b82011-12-27 08:18:36 +0100691
Amit Daniel Kachhapb756a502012-03-08 02:07:41 -0800692 l2x0_saved_regs.prefetch_ctrl = 0x30000007;
693 l2x0_saved_regs.pwr_ctrl =
694 (L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100695
Amit Daniel Kachhapb756a502012-03-08 02:07:41 -0800696 l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100697
Amit Daniel Kachhapb756a502012-03-08 02:07:41 -0800698 __raw_writel(l2x0_saved_regs.tag_latency,
699 S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL);
700 __raw_writel(l2x0_saved_regs.data_latency,
701 S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL);
702
703 /* L2X0 Prefetch Control */
704 __raw_writel(l2x0_saved_regs.prefetch_ctrl,
705 S5P_VA_L2CC + L2X0_PREFETCH_CTRL);
706
707 /* L2X0 Power Control */
708 __raw_writel(l2x0_saved_regs.pwr_ctrl,
709 S5P_VA_L2CC + L2X0_POWER_CTRL);
710
711 clean_dcache_area(&l2x0_regs_phys, sizeof(unsigned long));
712 clean_dcache_area(&l2x0_saved_regs, sizeof(struct l2x0_regs));
713 }
Kukjin Kimcc511b82011-12-27 08:18:36 +0100714
Amit Daniel Kachhap6cdeddc2012-03-08 02:09:12 -0800715 l2x0_init(S5P_VA_L2CC, L2_AUX_VAL, L2_AUX_MASK);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100716 return 0;
717}
Kukjin Kimcc511b82011-12-27 08:18:36 +0100718early_initcall(exynos4_l2x0_cache_init);
719#endif
720
Kukjin Kim906c7892012-02-11 21:27:08 +0900721static int __init exynos_init(void)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100722{
723 printk(KERN_INFO "EXYNOS: Initializing architecture\n");
Kukjin Kim94c7ca72012-02-11 22:15:45 +0900724
Thomas Abraham9ee6af92012-05-15 15:47:40 +0900725 return device_register(&exynos4_dev);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100726}
727
Kukjin Kimcc511b82011-12-27 08:18:36 +0100728/* uart registration process */
729
Kukjin Kim920f4882012-01-24 20:52:52 +0900730static void __init exynos_init_uarts(struct s3c2410_uartcfg *cfg, int no)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100731{
732 struct s3c2410_uartcfg *tcfg = cfg;
733 u32 ucnt;
734
Arnd Bergmann237c78b2012-01-07 12:30:20 +0000735 for (ucnt = 0; ucnt < no; ucnt++, tcfg++)
736 tcfg->has_fracval = 1;
Kukjin Kimcc511b82011-12-27 08:18:36 +0100737
Kukjin Kim171c0672012-02-10 11:57:53 +0900738 if (soc_is_exynos5250())
739 s3c24xx_init_uartdevs("exynos4210-uart", exynos5_uart_resources, cfg, no);
740 else
741 s3c24xx_init_uartdevs("exynos4210-uart", exynos4_uart_resources, cfg, no);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100742}
743
Eunki Kim330c90a2012-03-14 01:43:31 -0700744static void __iomem *exynos_eint_base;
745
Kukjin Kimcc511b82011-12-27 08:18:36 +0100746static DEFINE_SPINLOCK(eint_lock);
747
748static unsigned int eint0_15_data[16];
749
Eunki Kim330c90a2012-03-14 01:43:31 -0700750static inline int exynos4_irq_to_gpio(unsigned int irq)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100751{
Eunki Kim330c90a2012-03-14 01:43:31 -0700752 if (irq < IRQ_EINT(0))
753 return -EINVAL;
Kukjin Kimcc511b82011-12-27 08:18:36 +0100754
Eunki Kim330c90a2012-03-14 01:43:31 -0700755 irq -= IRQ_EINT(0);
756 if (irq < 8)
757 return EXYNOS4_GPX0(irq);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100758
Eunki Kim330c90a2012-03-14 01:43:31 -0700759 irq -= 8;
760 if (irq < 8)
761 return EXYNOS4_GPX1(irq);
762
763 irq -= 8;
764 if (irq < 8)
765 return EXYNOS4_GPX2(irq);
766
767 irq -= 8;
768 if (irq < 8)
769 return EXYNOS4_GPX3(irq);
770
771 return -EINVAL;
Kukjin Kimcc511b82011-12-27 08:18:36 +0100772}
773
Eunki Kim330c90a2012-03-14 01:43:31 -0700774static inline int exynos5_irq_to_gpio(unsigned int irq)
775{
776 if (irq < IRQ_EINT(0))
777 return -EINVAL;
778
779 irq -= IRQ_EINT(0);
780 if (irq < 8)
781 return EXYNOS5_GPX0(irq);
782
783 irq -= 8;
784 if (irq < 8)
785 return EXYNOS5_GPX1(irq);
786
787 irq -= 8;
788 if (irq < 8)
789 return EXYNOS5_GPX2(irq);
790
791 irq -= 8;
792 if (irq < 8)
793 return EXYNOS5_GPX3(irq);
794
795 return -EINVAL;
796}
797
Kukjin Kimbb19a752012-01-25 13:48:11 +0900798static unsigned int exynos4_eint0_15_src_int[16] = {
799 EXYNOS4_IRQ_EINT0,
800 EXYNOS4_IRQ_EINT1,
801 EXYNOS4_IRQ_EINT2,
802 EXYNOS4_IRQ_EINT3,
803 EXYNOS4_IRQ_EINT4,
804 EXYNOS4_IRQ_EINT5,
805 EXYNOS4_IRQ_EINT6,
806 EXYNOS4_IRQ_EINT7,
807 EXYNOS4_IRQ_EINT8,
808 EXYNOS4_IRQ_EINT9,
809 EXYNOS4_IRQ_EINT10,
810 EXYNOS4_IRQ_EINT11,
811 EXYNOS4_IRQ_EINT12,
812 EXYNOS4_IRQ_EINT13,
813 EXYNOS4_IRQ_EINT14,
814 EXYNOS4_IRQ_EINT15,
815};
Kukjin Kimcc511b82011-12-27 08:18:36 +0100816
Kukjin Kimbb19a752012-01-25 13:48:11 +0900817static unsigned int exynos5_eint0_15_src_int[16] = {
818 EXYNOS5_IRQ_EINT0,
819 EXYNOS5_IRQ_EINT1,
820 EXYNOS5_IRQ_EINT2,
821 EXYNOS5_IRQ_EINT3,
822 EXYNOS5_IRQ_EINT4,
823 EXYNOS5_IRQ_EINT5,
824 EXYNOS5_IRQ_EINT6,
825 EXYNOS5_IRQ_EINT7,
826 EXYNOS5_IRQ_EINT8,
827 EXYNOS5_IRQ_EINT9,
828 EXYNOS5_IRQ_EINT10,
829 EXYNOS5_IRQ_EINT11,
830 EXYNOS5_IRQ_EINT12,
831 EXYNOS5_IRQ_EINT13,
832 EXYNOS5_IRQ_EINT14,
833 EXYNOS5_IRQ_EINT15,
834};
Eunki Kim330c90a2012-03-14 01:43:31 -0700835static inline void exynos_irq_eint_mask(struct irq_data *data)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100836{
837 u32 mask;
838
839 spin_lock(&eint_lock);
Eunki Kim330c90a2012-03-14 01:43:31 -0700840 mask = __raw_readl(EINT_MASK(exynos_eint_base, data->irq));
841 mask |= EINT_OFFSET_BIT(data->irq);
842 __raw_writel(mask, EINT_MASK(exynos_eint_base, data->irq));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100843 spin_unlock(&eint_lock);
844}
845
Eunki Kim330c90a2012-03-14 01:43:31 -0700846static void exynos_irq_eint_unmask(struct irq_data *data)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100847{
848 u32 mask;
849
850 spin_lock(&eint_lock);
Eunki Kim330c90a2012-03-14 01:43:31 -0700851 mask = __raw_readl(EINT_MASK(exynos_eint_base, data->irq));
852 mask &= ~(EINT_OFFSET_BIT(data->irq));
853 __raw_writel(mask, EINT_MASK(exynos_eint_base, data->irq));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100854 spin_unlock(&eint_lock);
855}
856
Eunki Kim330c90a2012-03-14 01:43:31 -0700857static inline void exynos_irq_eint_ack(struct irq_data *data)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100858{
Eunki Kim330c90a2012-03-14 01:43:31 -0700859 __raw_writel(EINT_OFFSET_BIT(data->irq),
860 EINT_PEND(exynos_eint_base, data->irq));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100861}
862
Eunki Kim330c90a2012-03-14 01:43:31 -0700863static void exynos_irq_eint_maskack(struct irq_data *data)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100864{
Eunki Kim330c90a2012-03-14 01:43:31 -0700865 exynos_irq_eint_mask(data);
866 exynos_irq_eint_ack(data);
Kukjin Kimcc511b82011-12-27 08:18:36 +0100867}
868
Eunki Kim330c90a2012-03-14 01:43:31 -0700869static int exynos_irq_eint_set_type(struct irq_data *data, unsigned int type)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100870{
871 int offs = EINT_OFFSET(data->irq);
872 int shift;
873 u32 ctrl, mask;
874 u32 newvalue = 0;
875
876 switch (type) {
877 case IRQ_TYPE_EDGE_RISING:
878 newvalue = S5P_IRQ_TYPE_EDGE_RISING;
879 break;
880
881 case IRQ_TYPE_EDGE_FALLING:
882 newvalue = S5P_IRQ_TYPE_EDGE_FALLING;
883 break;
884
885 case IRQ_TYPE_EDGE_BOTH:
886 newvalue = S5P_IRQ_TYPE_EDGE_BOTH;
887 break;
888
889 case IRQ_TYPE_LEVEL_LOW:
890 newvalue = S5P_IRQ_TYPE_LEVEL_LOW;
891 break;
892
893 case IRQ_TYPE_LEVEL_HIGH:
894 newvalue = S5P_IRQ_TYPE_LEVEL_HIGH;
895 break;
896
897 default:
898 printk(KERN_ERR "No such irq type %d", type);
899 return -EINVAL;
900 }
901
902 shift = (offs & 0x7) * 4;
903 mask = 0x7 << shift;
904
905 spin_lock(&eint_lock);
Eunki Kim330c90a2012-03-14 01:43:31 -0700906 ctrl = __raw_readl(EINT_CON(exynos_eint_base, data->irq));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100907 ctrl &= ~mask;
908 ctrl |= newvalue << shift;
Eunki Kim330c90a2012-03-14 01:43:31 -0700909 __raw_writel(ctrl, EINT_CON(exynos_eint_base, data->irq));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100910 spin_unlock(&eint_lock);
911
Eunki Kim330c90a2012-03-14 01:43:31 -0700912 if (soc_is_exynos5250())
913 s3c_gpio_cfgpin(exynos5_irq_to_gpio(data->irq), S3C_GPIO_SFN(0xf));
914 else
915 s3c_gpio_cfgpin(exynos4_irq_to_gpio(data->irq), S3C_GPIO_SFN(0xf));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100916
917 return 0;
918}
919
Eunki Kim330c90a2012-03-14 01:43:31 -0700920static struct irq_chip exynos_irq_eint = {
921 .name = "exynos-eint",
922 .irq_mask = exynos_irq_eint_mask,
923 .irq_unmask = exynos_irq_eint_unmask,
924 .irq_mask_ack = exynos_irq_eint_maskack,
925 .irq_ack = exynos_irq_eint_ack,
926 .irq_set_type = exynos_irq_eint_set_type,
Kukjin Kimcc511b82011-12-27 08:18:36 +0100927#ifdef CONFIG_PM
928 .irq_set_wake = s3c_irqext_wake,
929#endif
930};
931
932/*
933 * exynos4_irq_demux_eint
934 *
935 * This function demuxes the IRQ from from EINTs 16 to 31.
936 * It is designed to be inlined into the specific handler
937 * s5p_irq_demux_eintX_Y.
938 *
939 * Each EINT pend/mask registers handle eight of them.
940 */
Eunki Kim330c90a2012-03-14 01:43:31 -0700941static inline void exynos_irq_demux_eint(unsigned int start)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100942{
943 unsigned int irq;
944
Eunki Kim330c90a2012-03-14 01:43:31 -0700945 u32 status = __raw_readl(EINT_PEND(exynos_eint_base, start));
946 u32 mask = __raw_readl(EINT_MASK(exynos_eint_base, start));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100947
948 status &= ~mask;
949 status &= 0xff;
950
951 while (status) {
952 irq = fls(status) - 1;
953 generic_handle_irq(irq + start);
954 status &= ~(1 << irq);
955 }
956}
957
Eunki Kim330c90a2012-03-14 01:43:31 -0700958static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100959{
960 struct irq_chip *chip = irq_get_chip(irq);
961 chained_irq_enter(chip, desc);
Eunki Kim330c90a2012-03-14 01:43:31 -0700962 exynos_irq_demux_eint(IRQ_EINT(16));
963 exynos_irq_demux_eint(IRQ_EINT(24));
Kukjin Kimcc511b82011-12-27 08:18:36 +0100964 chained_irq_exit(chip, desc);
965}
966
Kukjin Kimbb19a752012-01-25 13:48:11 +0900967static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100968{
969 u32 *irq_data = irq_get_handler_data(irq);
970 struct irq_chip *chip = irq_get_chip(irq);
971
972 chained_irq_enter(chip, desc);
973 chip->irq_mask(&desc->irq_data);
974
975 if (chip->irq_ack)
976 chip->irq_ack(&desc->irq_data);
977
978 generic_handle_irq(*irq_data);
979
980 chip->irq_unmask(&desc->irq_data);
981 chained_irq_exit(chip, desc);
982}
983
Eunki Kim330c90a2012-03-14 01:43:31 -0700984static int __init exynos_init_irq_eint(void)
Kukjin Kimcc511b82011-12-27 08:18:36 +0100985{
986 int irq;
987
Thomas Abrahamfef05c22012-09-07 06:07:40 +0900988#ifdef CONFIG_PINCTRL_SAMSUNG
989 /*
990 * The Samsung pinctrl driver provides an integrated gpio/pinmux/pinconf
991 * functionality along with support for external gpio and wakeup
992 * interrupts. If the samsung pinctrl driver is enabled and includes
993 * the wakeup interrupt support, then the setting up external wakeup
994 * interrupts here can be skipped. This check here is temporary to
995 * allow exynos4 platforms that do not use Samsung pinctrl driver to
996 * co-exist with platforms that do. When all of the Samsung Exynos4
997 * platforms switch over to using the pinctrl driver, the wakeup
998 * interrupt support code here can be completely removed.
999 */
1000 struct device_node *pctrl_np, *wkup_np;
1001 const char *pctrl_compat = "samsung,pinctrl-exynos4210";
1002 const char *wkup_compat = "samsung,exynos4210-wakeup-eint";
1003
1004 for_each_compatible_node(pctrl_np, NULL, pctrl_compat) {
1005 if (of_device_is_available(pctrl_np)) {
1006 wkup_np = of_find_compatible_node(pctrl_np, NULL,
1007 wkup_compat);
1008 if (wkup_np)
1009 return -ENODEV;
1010 }
1011 }
1012#endif
1013
Kukjin Kim94c7ca72012-02-11 22:15:45 +09001014 if (soc_is_exynos5250())
Eunki Kim330c90a2012-03-14 01:43:31 -07001015 exynos_eint_base = ioremap(EXYNOS5_PA_GPIO1, SZ_4K);
1016 else
1017 exynos_eint_base = ioremap(EXYNOS4_PA_GPIO2, SZ_4K);
1018
1019 if (exynos_eint_base == NULL) {
1020 pr_err("unable to ioremap for EINT base address\n");
1021 return -ENOMEM;
1022 }
Kukjin Kim94c7ca72012-02-11 22:15:45 +09001023
Kukjin Kimcc511b82011-12-27 08:18:36 +01001024 for (irq = 0 ; irq <= 31 ; irq++) {
Eunki Kim330c90a2012-03-14 01:43:31 -07001025 irq_set_chip_and_handler(IRQ_EINT(irq), &exynos_irq_eint,
Kukjin Kimcc511b82011-12-27 08:18:36 +01001026 handle_level_irq);
1027 set_irq_flags(IRQ_EINT(irq), IRQF_VALID);
1028 }
1029
Eunki Kim330c90a2012-03-14 01:43:31 -07001030 irq_set_chained_handler(EXYNOS_IRQ_EINT16_31, exynos_irq_demux_eint16_31);
Kukjin Kimcc511b82011-12-27 08:18:36 +01001031
1032 for (irq = 0 ; irq <= 15 ; irq++) {
1033 eint0_15_data[irq] = IRQ_EINT(irq);
1034
Kukjin Kimbb19a752012-01-25 13:48:11 +09001035 if (soc_is_exynos5250()) {
1036 irq_set_handler_data(exynos5_eint0_15_src_int[irq],
1037 &eint0_15_data[irq]);
1038 irq_set_chained_handler(exynos5_eint0_15_src_int[irq],
1039 exynos_irq_eint0_15);
1040 } else {
1041 irq_set_handler_data(exynos4_eint0_15_src_int[irq],
1042 &eint0_15_data[irq]);
1043 irq_set_chained_handler(exynos4_eint0_15_src_int[irq],
1044 exynos_irq_eint0_15);
1045 }
Kukjin Kimcc511b82011-12-27 08:18:36 +01001046 }
1047
1048 return 0;
1049}
Eunki Kim330c90a2012-03-14 01:43:31 -07001050arch_initcall(exynos_init_irq_eint);