aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2013-04-09 16:05:50 -0400
committerArnd Bergmann <arnd@arndb.de>2013-04-09 16:05:50 -0400
commit894b7382cf20e81d38097d43b8802af6e79d48c4 (patch)
tree7b51fd5c6e51d60bb5e9122816dc9c09823d3578
parentab9838e145dab98744798af0d5e849f1de139bff (diff)
parentf0774d41da0e607b70e54ecc50aeb6684f54c2b1 (diff)
Merge tag 'irq-s3c24xx-for-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung into next/drivers
From Kukjin Kim <kgene.kim@samsung.com>: s3c24xx irq cleanup and move into drivers/irqchip * tag 'irq-s3c24xx-for-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung: irqchip: s3c24xx: add devicetree support irqchip: s3c24xx: make interrupt handling independent of irq_domain structure irqchip: s3c24xx: globally keep track of the created intc instances irqchip: s3c24xx: add irq_set_type callback for basic interrupt types irqchip: s3c24xx: fix irqlist of second s3c2416 controller irqchip: s3c24xx: fix comments on some camera interrupts ARM: S3C24XX: move irq driver to drivers/irqchip ARM: S3C24XX: add handle_irq function ARM: S3C24XX: make s3c24xx_init_intc static ARM: S3C24XX: move s3c24xx_init_irq to s3c2410_init_irq ARM: S3C24XX: fix irq parent check ARM: S3C24XX: fix redundant checks in the irq mapping function Signed-off-by: Arnd Bergmann <arnd@arndb.de>
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt53
-rw-r--r--arch/arm/Kconfig1
-rw-r--r--arch/arm/mach-s3c24xx/Makefile2
-rw-r--r--arch/arm/mach-s3c24xx/common.h1
-rw-r--r--arch/arm/mach-s3c24xx/include/mach/entry-macro.S70
-rw-r--r--arch/arm/mach-s3c24xx/mach-amlm5900.c2
-rw-r--r--arch/arm/mach-s3c24xx/mach-bast.c2
-rw-r--r--arch/arm/mach-s3c24xx/mach-h1940.c7
-rw-r--r--arch/arm/mach-s3c24xx/mach-n30.c4
-rw-r--r--arch/arm/mach-s3c24xx/mach-otom.c2
-rw-r--r--arch/arm/mach-s3c24xx/mach-qt2410.c2
-rw-r--r--arch/arm/mach-s3c24xx/mach-smdk2410.c2
-rw-r--r--arch/arm/mach-s3c24xx/mach-tct_hammer.c2
-rw-r--r--arch/arm/mach-s3c24xx/mach-vr1000.c2
-rw-r--r--arch/arm/plat-samsung/include/plat/cpu.h1
-rw-r--r--drivers/irqchip/Makefile1
-rw-r--r--drivers/irqchip/irq-s3c24xx.c (renamed from arch/arm/mach-s3c24xx/irq.c)523
17 files changed, 472 insertions, 205 deletions
diff --git a/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt b/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt
new file mode 100644
index 000000000000..c54c5a9a2a90
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/samsung,s3c24xx-irq.txt
@@ -0,0 +1,53 @@
1Samsung S3C24XX Interrupt Controllers
2
3The S3C24XX SoCs contain a custom set of interrupt controllers providing a
4varying number of interrupt sources. The set consists of a main- and sub-
5controller and on newer SoCs even a second main controller.
6
7Required properties:
8- compatible: Compatible property value should be "samsung,s3c2410-irq"
9 for machines before s3c2416 and "samsung,s3c2416-irq" for s3c2416 and later.
10
11- reg: Physical base address of the controller and length of memory mapped
12 region.
13
14- interrupt-controller : Identifies the node as an interrupt controller
15
16- #interrupt-cells : Specifies the number of cells needed to encode an
17 interrupt source. The value shall be 4 and interrupt descriptor shall
18 have the following format:
19 <ctrl_num parent_irq ctrl_irq type>
20
21 ctrl_num contains the controller to use:
22 - 0 ... main controller
23 - 1 ... sub controller
24 - 2 ... second main controller on s3c2416 and s3c2450
25 parent_irq contains the parent bit in the main controller and will be
26 ignored in main controllers
27 ctrl_irq contains the interrupt bit of the controller
28 type contains the trigger type to use
29
30Example:
31
32 interrupt-controller@4a000000 {
33 compatible = "samsung,s3c2410-irq";
34 reg = <0x4a000000 0x100>;
35 interrupt-controller;
36 #interrupt-cells=<4>;
37 };
38
39 [...]
40
41 serial@50000000 {
42 compatible = "samsung,s3c2410-uart";
43 reg = <0x50000000 0x4000>;
44 interrupt-parent = <&subintc>;
45 interrupts = <1 28 0 4>, <1 28 1 4>;
46 };
47
48 rtc@57000000 {
49 compatible = "samsung,s3c2410-rtc";
50 reg = <0x57000000 0x100>;
51 interrupt-parent = <&intc>;
52 interrupts = <0 30 0 3>, <0 8 0 3>;
53 };
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index ada582b15cf2..6adf79869f8c 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -778,6 +778,7 @@ config ARCH_S3C24XX
778 select HAVE_S3C2410_I2C if I2C 778 select HAVE_S3C2410_I2C if I2C
779 select HAVE_S3C2410_WATCHDOG if WATCHDOG 779 select HAVE_S3C2410_WATCHDOG if WATCHDOG
780 select HAVE_S3C_RTC if RTC_CLASS 780 select HAVE_S3C_RTC if RTC_CLASS
781 select MULTI_IRQ_HANDLER
781 select NEED_MACH_GPIO_H 782 select NEED_MACH_GPIO_H
782 select NEED_MACH_IO_H 783 select NEED_MACH_IO_H
783 help 784 help
diff --git a/arch/arm/mach-s3c24xx/Makefile b/arch/arm/mach-s3c24xx/Makefile
index be6e4d0e6f1a..6f46ecfc8396 100644
--- a/arch/arm/mach-s3c24xx/Makefile
+++ b/arch/arm/mach-s3c24xx/Makefile
@@ -14,7 +14,7 @@ obj- :=
14 14
15# core 15# core
16 16
17obj-y += common.o irq.o 17obj-y += common.o
18 18
19obj-$(CONFIG_CPU_S3C2410) += s3c2410.o 19obj-$(CONFIG_CPU_S3C2410) += s3c2410.o
20obj-$(CONFIG_S3C2410_CPUFREQ) += cpufreq-s3c2410.o 20obj-$(CONFIG_S3C2410_CPUFREQ) += cpufreq-s3c2410.o
diff --git a/arch/arm/mach-s3c24xx/common.h b/arch/arm/mach-s3c24xx/common.h
index abefeb38bba4..307c3714be55 100644
--- a/arch/arm/mach-s3c24xx/common.h
+++ b/arch/arm/mach-s3c24xx/common.h
@@ -21,6 +21,7 @@ extern void s3c2410_map_io(void);
21extern void s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no); 21extern void s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no);
22extern void s3c2410_init_clocks(int xtal); 22extern void s3c2410_init_clocks(int xtal);
23extern void s3c2410_restart(char mode, const char *cmd); 23extern void s3c2410_restart(char mode, const char *cmd);
24extern void s3c2410_init_irq(void);
24#else 25#else
25#define s3c2410_init_clocks NULL 26#define s3c2410_init_clocks NULL
26#define s3c2410_init_uarts NULL 27#define s3c2410_init_uarts NULL
diff --git a/arch/arm/mach-s3c24xx/include/mach/entry-macro.S b/arch/arm/mach-s3c24xx/include/mach/entry-macro.S
deleted file mode 100644
index 6a21beeba1da..000000000000
--- a/arch/arm/mach-s3c24xx/include/mach/entry-macro.S
+++ /dev/null
@@ -1,70 +0,0 @@
1/*
2 * arch/arm/mach-s3c2410/include/mach/entry-macro.S
3 *
4 * Low-level IRQ helper macros for S3C2410-based platforms
5 *
6 * This file is licensed under the terms of the GNU General Public
7 * License version 2. This program is licensed "as is" without any
8 * warranty of any kind, whether express or implied.
9*/
10
11/* We have a problem that the INTOFFSET register does not always
12 * show one interrupt. Occasionally we get two interrupts through
13 * the prioritiser, and this causes the INTOFFSET register to show
14 * what looks like the logical-or of the two interrupt numbers.
15 *
16 * Thanks to Klaus, Shannon, et al for helping to debug this problem
17*/
18
19#define INTPND (0x10)
20#define INTOFFSET (0x14)
21
22#include <mach/hardware.h>
23#include <asm/irq.h>
24
25 .macro get_irqnr_preamble, base, tmp
26 .endm
27
28 .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
29
30 mov \base, #S3C24XX_VA_IRQ
31
32 @@ try the interrupt offset register, since it is there
33
34 ldr \irqstat, [\base, #INTPND ]
35 teq \irqstat, #0
36 beq 1002f
37 ldr \irqnr, [\base, #INTOFFSET ]
38 mov \tmp, #1
39 tst \irqstat, \tmp, lsl \irqnr
40 bne 1001f
41
42 @@ the number specified is not a valid irq, so try
43 @@ and work it out for ourselves
44
45 mov \irqnr, #0 @@ start here
46
47 @@ work out which irq (if any) we got
48
49 movs \tmp, \irqstat, lsl#16
50 addeq \irqnr, \irqnr, #16
51 moveq \irqstat, \irqstat, lsr#16
52 tst \irqstat, #0xff
53 addeq \irqnr, \irqnr, #8
54 moveq \irqstat, \irqstat, lsr#8
55 tst \irqstat, #0xf
56 addeq \irqnr, \irqnr, #4
57 moveq \irqstat, \irqstat, lsr#4
58 tst \irqstat, #0x3
59 addeq \irqnr, \irqnr, #2
60 moveq \irqstat, \irqstat, lsr#2
61 tst \irqstat, #0x1
62 addeq \irqnr, \irqnr, #1
63
64 @@ we have the value
651001:
66 adds \irqnr, \irqnr, #IRQ_EINT0
671002:
68 @@ exit here, Z flag unset if IRQ
69
70 .endm
diff --git a/arch/arm/mach-s3c24xx/mach-amlm5900.c b/arch/arm/mach-s3c24xx/mach-amlm5900.c
index 432144cb54ae..e27b5c91b3db 100644
--- a/arch/arm/mach-s3c24xx/mach-amlm5900.c
+++ b/arch/arm/mach-s3c24xx/mach-amlm5900.c
@@ -238,7 +238,7 @@ static void __init amlm5900_init(void)
238MACHINE_START(AML_M5900, "AML_M5900") 238MACHINE_START(AML_M5900, "AML_M5900")
239 .atag_offset = 0x100, 239 .atag_offset = 0x100,
240 .map_io = amlm5900_map_io, 240 .map_io = amlm5900_map_io,
241 .init_irq = s3c24xx_init_irq, 241 .init_irq = s3c2410_init_irq,
242 .init_machine = amlm5900_init, 242 .init_machine = amlm5900_init,
243 .init_time = samsung_timer_init, 243 .init_time = samsung_timer_init,
244 .restart = s3c2410_restart, 244 .restart = s3c2410_restart,
diff --git a/arch/arm/mach-s3c24xx/mach-bast.c b/arch/arm/mach-s3c24xx/mach-bast.c
index eabe2db42ef6..22d6ae926d91 100644
--- a/arch/arm/mach-s3c24xx/mach-bast.c
+++ b/arch/arm/mach-s3c24xx/mach-bast.c
@@ -605,7 +605,7 @@ MACHINE_START(BAST, "Simtec-BAST")
605 /* Maintainer: Ben Dooks <ben@simtec.co.uk> */ 605 /* Maintainer: Ben Dooks <ben@simtec.co.uk> */
606 .atag_offset = 0x100, 606 .atag_offset = 0x100,
607 .map_io = bast_map_io, 607 .map_io = bast_map_io,
608 .init_irq = s3c24xx_init_irq, 608 .init_irq = s3c2410_init_irq,
609 .init_machine = bast_init, 609 .init_machine = bast_init,
610 .init_time = samsung_timer_init, 610 .init_time = samsung_timer_init,
611 .restart = s3c2410_restart, 611 .restart = s3c2410_restart,
diff --git a/arch/arm/mach-s3c24xx/mach-h1940.c b/arch/arm/mach-s3c24xx/mach-h1940.c
index 8dd660102846..af4334d6b4d5 100644
--- a/arch/arm/mach-s3c24xx/mach-h1940.c
+++ b/arch/arm/mach-s3c24xx/mach-h1940.c
@@ -667,11 +667,6 @@ static void __init h1940_reserve(void)
667 memblock_reserve(0x30081000, 0x1000); 667 memblock_reserve(0x30081000, 0x1000);
668} 668}
669 669
670static void __init h1940_init_irq(void)
671{
672 s3c24xx_init_irq();
673}
674
675static void __init h1940_init(void) 670static void __init h1940_init(void)
676{ 671{
677 u32 tmp; 672 u32 tmp;
@@ -740,7 +735,7 @@ MACHINE_START(H1940, "IPAQ-H1940")
740 .atag_offset = 0x100, 735 .atag_offset = 0x100,
741 .map_io = h1940_map_io, 736 .map_io = h1940_map_io,
742 .reserve = h1940_reserve, 737 .reserve = h1940_reserve,
743 .init_irq = h1940_init_irq, 738 .init_irq = s3c2410_init_irq,
744 .init_machine = h1940_init, 739 .init_machine = h1940_init,
745 .init_time = samsung_timer_init, 740 .init_time = samsung_timer_init,
746 .restart = s3c2410_restart, 741 .restart = s3c2410_restart,
diff --git a/arch/arm/mach-s3c24xx/mach-n30.c b/arch/arm/mach-s3c24xx/mach-n30.c
index 73a690f431e6..2cb46c37c920 100644
--- a/arch/arm/mach-s3c24xx/mach-n30.c
+++ b/arch/arm/mach-s3c24xx/mach-n30.c
@@ -592,7 +592,7 @@ MACHINE_START(N30, "Acer-N30")
592 .atag_offset = 0x100, 592 .atag_offset = 0x100,
593 .init_time = samsung_timer_init, 593 .init_time = samsung_timer_init,
594 .init_machine = n30_init, 594 .init_machine = n30_init,
595 .init_irq = s3c24xx_init_irq, 595 .init_irq = s3c2410_init_irq,
596 .map_io = n30_map_io, 596 .map_io = n30_map_io,
597 .restart = s3c2410_restart, 597 .restart = s3c2410_restart,
598MACHINE_END 598MACHINE_END
@@ -603,7 +603,7 @@ MACHINE_START(N35, "Acer-N35")
603 .atag_offset = 0x100, 603 .atag_offset = 0x100,
604 .init_time = samsung_timer_init, 604 .init_time = samsung_timer_init,
605 .init_machine = n30_init, 605 .init_machine = n30_init,
606 .init_irq = s3c24xx_init_irq, 606 .init_irq = s3c2410_init_irq,
607 .map_io = n30_map_io, 607 .map_io = n30_map_io,
608 .restart = s3c2410_restart, 608 .restart = s3c2410_restart,
609MACHINE_END 609MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-otom.c b/arch/arm/mach-s3c24xx/mach-otom.c
index 7b8670746b6a..7e16b0740ec1 100644
--- a/arch/arm/mach-s3c24xx/mach-otom.c
+++ b/arch/arm/mach-s3c24xx/mach-otom.c
@@ -116,7 +116,7 @@ MACHINE_START(OTOM, "Nex Vision - Otom 1.1")
116 .atag_offset = 0x100, 116 .atag_offset = 0x100,
117 .map_io = otom11_map_io, 117 .map_io = otom11_map_io,
118 .init_machine = otom11_init, 118 .init_machine = otom11_init,
119 .init_irq = s3c24xx_init_irq, 119 .init_irq = s3c2410_init_irq,
120 .init_time = samsung_timer_init, 120 .init_time = samsung_timer_init,
121 .restart = s3c2410_restart, 121 .restart = s3c2410_restart,
122MACHINE_END 122MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/mach-qt2410.c b/arch/arm/mach-s3c24xx/mach-qt2410.c
index 71cf29b12d1f..f8feaeadb55a 100644
--- a/arch/arm/mach-s3c24xx/mach-qt2410.c
+++ b/arch/arm/mach-s3c24xx/mach-qt2410.c
@@ -343,7 +343,7 @@ static void __init qt2410_machine_init(void)
343MACHINE_START(QT2410, "QT2410") 343MACHINE_START(QT2410, "QT2410")
344 .atag_offset = 0x100, 344 .atag_offset = 0x100,
345 .map_io = qt2410_map_io, 345 .map_io = qt2410_map_io,
346 .init_irq = s3c24xx_init_irq, 346 .init_irq = s3c2410_init_irq,
347 .init_machine = qt2410_machine_init, 347 .init_machine = qt2410_machine_init,
348 .init_time = samsung_timer_init, 348 .init_time = samsung_timer_init,
349 .restart = s3c2410_restart, 349 .restart = s3c2410_restart,
diff --git a/arch/arm/mach-s3c24xx/mach-smdk2410.c b/arch/arm/mach-s3c24xx/mach-smdk2410.c
index fd96f7fc330c..a773789e4f38 100644
--- a/arch/arm/mach-s3c24xx/mach-smdk2410.c
+++ b/arch/arm/mach-s3c24xx/mach-smdk2410.c
@@ -116,7 +116,7 @@ MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switc
116 /* Maintainer: Jonas Dietsche */ 116 /* Maintainer: Jonas Dietsche */
117 .atag_offset = 0x100, 117 .atag_offset = 0x100,
118 .map_io = smdk2410_map_io, 118 .map_io = smdk2410_map_io,
119 .init_irq = s3c24xx_init_irq, 119 .init_irq = s3c2410_init_irq,
120 .init_machine = smdk2410_init, 120 .init_machine = smdk2410_init,
121 .init_time = samsung_timer_init, 121 .init_time = samsung_timer_init,
122 .restart = s3c2410_restart, 122 .restart = s3c2410_restart,
diff --git a/arch/arm/mach-s3c24xx/mach-tct_hammer.c b/arch/arm/mach-s3c24xx/mach-tct_hammer.c
index 31dfe589e349..7fad8f055cab 100644
--- a/arch/arm/mach-s3c24xx/mach-tct_hammer.c
+++ b/arch/arm/mach-s3c24xx/mach-tct_hammer.c
@@ -149,7 +149,7 @@ static void __init tct_hammer_init(void)
149MACHINE_START(TCT_HAMMER, "TCT_HAMMER") 149MACHINE_START(TCT_HAMMER, "TCT_HAMMER")
150 .atag_offset = 0x100, 150 .atag_offset = 0x100,
151 .map_io = tct_hammer_map_io, 151 .map_io = tct_hammer_map_io,
152 .init_irq = s3c24xx_init_irq, 152 .init_irq = s3c2410_init_irq,
153 .init_machine = tct_hammer_init, 153 .init_machine = tct_hammer_init,
154 .init_time = samsung_timer_init, 154 .init_time = samsung_timer_init,
155 .restart = s3c2410_restart, 155 .restart = s3c2410_restart,
diff --git a/arch/arm/mach-s3c24xx/mach-vr1000.c b/arch/arm/mach-s3c24xx/mach-vr1000.c
index deeb8a0a4034..42e7187fed60 100644
--- a/arch/arm/mach-s3c24xx/mach-vr1000.c
+++ b/arch/arm/mach-s3c24xx/mach-vr1000.c
@@ -355,7 +355,7 @@ MACHINE_START(VR1000, "Thorcom-VR1000")
355 .atag_offset = 0x100, 355 .atag_offset = 0x100,
356 .map_io = vr1000_map_io, 356 .map_io = vr1000_map_io,
357 .init_machine = vr1000_init, 357 .init_machine = vr1000_init,
358 .init_irq = s3c24xx_init_irq, 358 .init_irq = s3c2410_init_irq,
359 .init_time = samsung_timer_init, 359 .init_time = samsung_timer_init,
360 .restart = s3c2410_restart, 360 .restart = s3c2410_restart,
361MACHINE_END 361MACHINE_END
diff --git a/arch/arm/plat-samsung/include/plat/cpu.h b/arch/arm/plat-samsung/include/plat/cpu.h
index 0f6c47a6475b..989fefe18be6 100644
--- a/arch/arm/plat-samsung/include/plat/cpu.h
+++ b/arch/arm/plat-samsung/include/plat/cpu.h
@@ -183,7 +183,6 @@ extern void s3c_init_cpu(unsigned long idcode,
183 183
184/* core initialisation functions */ 184/* core initialisation functions */
185 185
186extern void s3c24xx_init_irq(void);
187extern void s5p_init_irq(u32 *vic, u32 num_vic); 186extern void s5p_init_irq(u32 *vic, u32 num_vic);
188 187
189extern void s3c24xx_init_io(struct map_desc *mach_desc, int size); 188extern void s3c24xx_init_io(struct map_desc *mach_desc, int size);
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index e41ceb9bec22..acf98953272a 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -2,6 +2,7 @@ obj-$(CONFIG_IRQCHIP) += irqchip.o
2 2
3obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o 3obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o
4obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o 4obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o
5obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o
5obj-$(CONFIG_METAG) += irq-metag-ext.o 6obj-$(CONFIG_METAG) += irq-metag-ext.o
6obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o 7obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o
7obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi.o 8obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi.o
diff --git a/arch/arm/mach-s3c24xx/irq.c b/drivers/irqchip/irq-s3c24xx.c
index 3f3de7492094..5e40b3424df8 100644
--- a/arch/arm/mach-s3c24xx/irq.c
+++ b/drivers/irqchip/irq-s3c24xx.c
@@ -25,7 +25,11 @@
25#include <linux/ioport.h> 25#include <linux/ioport.h>
26#include <linux/device.h> 26#include <linux/device.h>
27#include <linux/irqdomain.h> 27#include <linux/irqdomain.h>
28#include <linux/of.h>
29#include <linux/of_irq.h>
30#include <linux/of_address.h>
28 31
32#include <asm/exception.h>
29#include <asm/mach/irq.h> 33#include <asm/mach/irq.h>
30 34
31#include <mach/regs-irq.h> 35#include <mach/regs-irq.h>
@@ -35,6 +39,8 @@
35#include <plat/regs-irqtype.h> 39#include <plat/regs-irqtype.h>
36#include <plat/pm.h> 40#include <plat/pm.h>
37 41
42#include "irqchip.h"
43
38#define S3C_IRQTYPE_NONE 0 44#define S3C_IRQTYPE_NONE 0
39#define S3C_IRQTYPE_EINT 1 45#define S3C_IRQTYPE_EINT 1
40#define S3C_IRQTYPE_EDGE 2 46#define S3C_IRQTYPE_EDGE 2
@@ -42,6 +48,7 @@
42 48
43struct s3c_irq_data { 49struct s3c_irq_data {
44 unsigned int type; 50 unsigned int type;
51 unsigned long offset;
45 unsigned long parent_irq; 52 unsigned long parent_irq;
46 53
47 /* data gets filled during init */ 54 /* data gets filled during init */
@@ -68,23 +75,34 @@ struct s3c_irq_intc {
68 struct s3c_irq_data *irqs; 75 struct s3c_irq_data *irqs;
69}; 76};
70 77
78/*
79 * Array holding pointers to the global controller structs
80 * [0] ... main_intc
81 * [1] ... sub_intc
82 * [2] ... main_intc2 on s3c2416
83 */
84static struct s3c_irq_intc *s3c_intc[3];
85
71static void s3c_irq_mask(struct irq_data *data) 86static void s3c_irq_mask(struct irq_data *data)
72{ 87{
73 struct s3c_irq_intc *intc = data->domain->host_data; 88 struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data);
89 struct s3c_irq_intc *intc = irq_data->intc;
74 struct s3c_irq_intc *parent_intc = intc->parent; 90 struct s3c_irq_intc *parent_intc = intc->parent;
75 struct s3c_irq_data *irq_data = &intc->irqs[data->hwirq];
76 struct s3c_irq_data *parent_data; 91 struct s3c_irq_data *parent_data;
77 unsigned long mask; 92 unsigned long mask;
78 unsigned int irqno; 93 unsigned int irqno;
79 94
80 mask = __raw_readl(intc->reg_mask); 95 mask = __raw_readl(intc->reg_mask);
81 mask |= (1UL << data->hwirq); 96 mask |= (1UL << irq_data->offset);
82 __raw_writel(mask, intc->reg_mask); 97 __raw_writel(mask, intc->reg_mask);
83 98
84 if (parent_intc && irq_data->parent_irq) { 99 if (parent_intc) {
85 parent_data = &parent_intc->irqs[irq_data->parent_irq]; 100 parent_data = &parent_intc->irqs[irq_data->parent_irq];
86 101
87 /* check to see if we need to mask the parent IRQ */ 102 /* check to see if we need to mask the parent IRQ
103 * The parent_irq is always in main_intc, so the hwirq
104 * for find_mapping does not need an offset in any case.
105 */
88 if ((mask & parent_data->sub_bits) == parent_data->sub_bits) { 106 if ((mask & parent_data->sub_bits) == parent_data->sub_bits) {
89 irqno = irq_find_mapping(parent_intc->domain, 107 irqno = irq_find_mapping(parent_intc->domain,
90 irq_data->parent_irq); 108 irq_data->parent_irq);
@@ -95,17 +113,17 @@ static void s3c_irq_mask(struct irq_data *data)
95 113
96static void s3c_irq_unmask(struct irq_data *data) 114static void s3c_irq_unmask(struct irq_data *data)
97{ 115{
98 struct s3c_irq_intc *intc = data->domain->host_data; 116 struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data);
117 struct s3c_irq_intc *intc = irq_data->intc;
99 struct s3c_irq_intc *parent_intc = intc->parent; 118 struct s3c_irq_intc *parent_intc = intc->parent;
100 struct s3c_irq_data *irq_data = &intc->irqs[data->hwirq];
101 unsigned long mask; 119 unsigned long mask;
102 unsigned int irqno; 120 unsigned int irqno;
103 121
104 mask = __raw_readl(intc->reg_mask); 122 mask = __raw_readl(intc->reg_mask);
105 mask &= ~(1UL << data->hwirq); 123 mask &= ~(1UL << irq_data->offset);
106 __raw_writel(mask, intc->reg_mask); 124 __raw_writel(mask, intc->reg_mask);
107 125
108 if (parent_intc && irq_data->parent_irq) { 126 if (parent_intc) {
109 irqno = irq_find_mapping(parent_intc->domain, 127 irqno = irq_find_mapping(parent_intc->domain,
110 irq_data->parent_irq); 128 irq_data->parent_irq);
111 s3c_irq_unmask(irq_get_irq_data(irqno)); 129 s3c_irq_unmask(irq_get_irq_data(irqno));
@@ -114,14 +132,37 @@ static void s3c_irq_unmask(struct irq_data *data)
114 132
115static inline void s3c_irq_ack(struct irq_data *data) 133static inline void s3c_irq_ack(struct irq_data *data)
116{ 134{
117 struct s3c_irq_intc *intc = data->domain->host_data; 135 struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data);
118 unsigned long bitval = 1UL << data->hwirq; 136 struct s3c_irq_intc *intc = irq_data->intc;
137 unsigned long bitval = 1UL << irq_data->offset;
119 138
120 __raw_writel(bitval, intc->reg_pending); 139 __raw_writel(bitval, intc->reg_pending);
121 if (intc->reg_intpnd) 140 if (intc->reg_intpnd)
122 __raw_writel(bitval, intc->reg_intpnd); 141 __raw_writel(bitval, intc->reg_intpnd);
123} 142}
124 143
144static int s3c_irq_type(struct irq_data *data, unsigned int type)
145{
146 switch (type) {
147 case IRQ_TYPE_NONE:
148 break;
149 case IRQ_TYPE_EDGE_RISING:
150 case IRQ_TYPE_EDGE_FALLING:
151 case IRQ_TYPE_EDGE_BOTH:
152 irq_set_handler(data->irq, handle_edge_irq);
153 break;
154 case IRQ_TYPE_LEVEL_LOW:
155 case IRQ_TYPE_LEVEL_HIGH:
156 irq_set_handler(data->irq, handle_level_irq);
157 break;
158 default:
159 pr_err("No such irq type %d", type);
160 return -EINVAL;
161 }
162
163 return 0;
164}
165
125static int s3c_irqext_type_set(void __iomem *gpcon_reg, 166static int s3c_irqext_type_set(void __iomem *gpcon_reg,
126 void __iomem *extint_reg, 167 void __iomem *extint_reg,
127 unsigned long gpcon_offset, 168 unsigned long gpcon_offset,
@@ -227,6 +268,7 @@ static struct irq_chip s3c_irq_chip = {
227 .irq_ack = s3c_irq_ack, 268 .irq_ack = s3c_irq_ack,
228 .irq_mask = s3c_irq_mask, 269 .irq_mask = s3c_irq_mask,
229 .irq_unmask = s3c_irq_unmask, 270 .irq_unmask = s3c_irq_unmask,
271 .irq_set_type = s3c_irq_type,
230 .irq_set_wake = s3c_irq_wake 272 .irq_set_wake = s3c_irq_wake
231}; 273};
232 274
@@ -235,6 +277,7 @@ static struct irq_chip s3c_irq_level_chip = {
235 .irq_mask = s3c_irq_mask, 277 .irq_mask = s3c_irq_mask,
236 .irq_unmask = s3c_irq_unmask, 278 .irq_unmask = s3c_irq_unmask,
237 .irq_ack = s3c_irq_ack, 279 .irq_ack = s3c_irq_ack,
280 .irq_set_type = s3c_irq_type,
238}; 281};
239 282
240static struct irq_chip s3c_irqext_chip = { 283static struct irq_chip s3c_irqext_chip = {
@@ -258,12 +301,19 @@ static struct irq_chip s3c_irq_eint0t4 = {
258static void s3c_irq_demux(unsigned int irq, struct irq_desc *desc) 301static void s3c_irq_demux(unsigned int irq, struct irq_desc *desc)
259{ 302{
260 struct irq_chip *chip = irq_desc_get_chip(desc); 303 struct irq_chip *chip = irq_desc_get_chip(desc);
261 struct s3c_irq_intc *intc = desc->irq_data.domain->host_data; 304 struct s3c_irq_data *irq_data = irq_desc_get_chip_data(desc);
262 struct s3c_irq_data *irq_data = &intc->irqs[desc->irq_data.hwirq]; 305 struct s3c_irq_intc *intc = irq_data->intc;
263 struct s3c_irq_intc *sub_intc = irq_data->sub_intc; 306 struct s3c_irq_intc *sub_intc = irq_data->sub_intc;
264 unsigned long src; 307 unsigned long src;
265 unsigned long msk; 308 unsigned long msk;
266 unsigned int n; 309 unsigned int n;
310 unsigned int offset;
311
312 /* we're using individual domains for the non-dt case
313 * and one big domain for the dt case where the subintc
314 * starts at hwirq number 32.
315 */
316 offset = (intc->domain->of_node) ? 32 : 0;
267 317
268 chained_irq_enter(chip, desc); 318 chained_irq_enter(chip, desc);
269 319
@@ -276,12 +326,64 @@ static void s3c_irq_demux(unsigned int irq, struct irq_desc *desc)
276 while (src) { 326 while (src) {
277 n = __ffs(src); 327 n = __ffs(src);
278 src &= ~(1 << n); 328 src &= ~(1 << n);
279 generic_handle_irq(irq_find_mapping(sub_intc->domain, n)); 329 irq = irq_find_mapping(sub_intc->domain, offset + n);
330 generic_handle_irq(irq);
280 } 331 }
281 332
282 chained_irq_exit(chip, desc); 333 chained_irq_exit(chip, desc);
283} 334}
284 335
336static inline int s3c24xx_handle_intc(struct s3c_irq_intc *intc,
337 struct pt_regs *regs, int intc_offset)
338{
339 int pnd;
340 int offset;
341 int irq;
342
343 pnd = __raw_readl(intc->reg_intpnd);
344 if (!pnd)
345 return false;
346
347 /* non-dt machines use individual domains */
348 if (!intc->domain->of_node)
349 intc_offset = 0;
350
351 /* We have a problem that the INTOFFSET register does not always
352 * show one interrupt. Occasionally we get two interrupts through
353 * the prioritiser, and this causes the INTOFFSET register to show
354 * what looks like the logical-or of the two interrupt numbers.
355 *
356 * Thanks to Klaus, Shannon, et al for helping to debug this problem
357 */
358 offset = __raw_readl(intc->reg_intpnd + 4);
359
360 /* Find the bit manually, when the offset is wrong.
361 * The pending register only ever contains the one bit of the next
362 * interrupt to handle.
363 */
364 if (!(pnd & (1 << offset)))
365 offset = __ffs(pnd);
366
367 irq = irq_find_mapping(intc->domain, intc_offset + offset);
368 handle_IRQ(irq, regs);
369 return true;
370}
371
372asmlinkage void __exception_irq_entry s3c24xx_handle_irq(struct pt_regs *regs)
373{
374 do {
375 if (likely(s3c_intc[0]))
376 if (s3c24xx_handle_intc(s3c_intc[0], regs, 0))
377 continue;
378
379 if (s3c_intc[2])
380 if (s3c24xx_handle_intc(s3c_intc[2], regs, 64))
381 continue;
382
383 break;
384 } while (1);
385}
386
285#ifdef CONFIG_FIQ 387#ifdef CONFIG_FIQ
286/** 388/**
287 * s3c24xx_set_fiq - set the FIQ routing 389 * s3c24xx_set_fiq - set the FIQ routing
@@ -324,18 +426,11 @@ static int s3c24xx_irq_map(struct irq_domain *h, unsigned int virq,
324 struct s3c_irq_data *parent_irq_data; 426 struct s3c_irq_data *parent_irq_data;
325 unsigned int irqno; 427 unsigned int irqno;
326 428
327 if (!intc) {
328 pr_err("irq-s3c24xx: no controller found for hwirq %lu\n", hw);
329 return -EINVAL;
330 }
331
332 if (!irq_data) {
333 pr_err("irq-s3c24xx: no irq data found for hwirq %lu\n", hw);
334 return -EINVAL;
335 }
336
337 /* attach controller pointer to irq_data */ 429 /* attach controller pointer to irq_data */
338 irq_data->intc = intc; 430 irq_data->intc = intc;
431 irq_data->offset = hw;
432
433 parent_intc = intc->parent;
339 434
340 /* set handler and flags */ 435 /* set handler and flags */
341 switch (irq_data->type) { 436 switch (irq_data->type) {
@@ -345,7 +440,7 @@ static int s3c24xx_irq_map(struct irq_domain *h, unsigned int virq,
345 /* On the S3C2412, the EINT0to3 have a parent irq 440 /* On the S3C2412, the EINT0to3 have a parent irq
346 * but need the s3c_irq_eint0t4 chip 441 * but need the s3c_irq_eint0t4 chip
347 */ 442 */
348 if (irq_data->parent_irq && (!soc_is_s3c2412() || hw >= 4)) 443 if (parent_intc && (!soc_is_s3c2412() || hw >= 4))
349 irq_set_chip_and_handler(virq, &s3c_irqext_chip, 444 irq_set_chip_and_handler(virq, &s3c_irqext_chip,
350 handle_edge_irq); 445 handle_edge_irq);
351 else 446 else
@@ -353,8 +448,7 @@ static int s3c24xx_irq_map(struct irq_domain *h, unsigned int virq,
353 handle_edge_irq); 448 handle_edge_irq);
354 break; 449 break;
355 case S3C_IRQTYPE_EDGE: 450 case S3C_IRQTYPE_EDGE:
356 if (irq_data->parent_irq || 451 if (parent_intc || intc->reg_pending == S3C2416_SRCPND2)
357 intc->reg_pending == S3C2416_SRCPND2)
358 irq_set_chip_and_handler(virq, &s3c_irq_level_chip, 452 irq_set_chip_and_handler(virq, &s3c_irq_level_chip,
359 handle_edge_irq); 453 handle_edge_irq);
360 else 454 else
@@ -362,7 +456,7 @@ static int s3c24xx_irq_map(struct irq_domain *h, unsigned int virq,
362 handle_edge_irq); 456 handle_edge_irq);
363 break; 457 break;
364 case S3C_IRQTYPE_LEVEL: 458 case S3C_IRQTYPE_LEVEL:
365 if (irq_data->parent_irq) 459 if (parent_intc)
366 irq_set_chip_and_handler(virq, &s3c_irq_level_chip, 460 irq_set_chip_and_handler(virq, &s3c_irq_level_chip,
367 handle_level_irq); 461 handle_level_irq);
368 else 462 else
@@ -373,23 +467,19 @@ static int s3c24xx_irq_map(struct irq_domain *h, unsigned int virq,
373 pr_err("irq-s3c24xx: unsupported irqtype %d\n", irq_data->type); 467 pr_err("irq-s3c24xx: unsupported irqtype %d\n", irq_data->type);
374 return -EINVAL; 468 return -EINVAL;
375 } 469 }
470
471 irq_set_chip_data(virq, irq_data);
472
376 set_irq_flags(virq, IRQF_VALID); 473 set_irq_flags(virq, IRQF_VALID);
377 474
378 if (irq_data->parent_irq) { 475 if (parent_intc && irq_data->type != S3C_IRQTYPE_NONE) {
379 parent_intc = intc->parent; 476 if (irq_data->parent_irq > 31) {
380 if (!parent_intc) { 477 pr_err("irq-s3c24xx: parent irq %lu is out of range\n",
381 pr_err("irq-s3c24xx: no parent controller found for hwirq %lu\n", 478 irq_data->parent_irq);
382 hw);
383 goto err; 479 goto err;
384 } 480 }
385 481
386 parent_irq_data = &parent_intc->irqs[irq_data->parent_irq]; 482 parent_irq_data = &parent_intc->irqs[irq_data->parent_irq];
387 if (!irq_data) {
388 pr_err("irq-s3c24xx: no irq data found for hwirq %lu\n",
389 hw);
390 goto err;
391 }
392
393 parent_irq_data->sub_intc = intc; 483 parent_irq_data->sub_intc = intc;
394 parent_irq_data->sub_bits |= (1UL << hw); 484 parent_irq_data->sub_bits |= (1UL << hw);
395 485
@@ -444,7 +534,7 @@ static void s3c24xx_clear_intc(struct s3c_irq_intc *intc)
444 } 534 }
445} 535}
446 536
447struct s3c_irq_intc *s3c24xx_init_intc(struct device_node *np, 537static struct s3c_irq_intc *s3c24xx_init_intc(struct device_node *np,
448 struct s3c_irq_data *irq_data, 538 struct s3c_irq_data *irq_data,
449 struct s3c_irq_intc *parent, 539 struct s3c_irq_intc *parent,
450 unsigned long address) 540 unsigned long address)
@@ -518,6 +608,8 @@ struct s3c_irq_intc *s3c24xx_init_intc(struct device_node *np,
518 goto err; 608 goto err;
519 } 609 }
520 610
611 set_handle_irq(s3c24xx_handle_irq);
612
521 return intc; 613 return intc;
522 614
523err: 615err:
@@ -525,12 +617,35 @@ err:
525 return ERR_PTR(ret); 617 return ERR_PTR(ret);
526} 618}
527 619
528/* s3c24xx_init_irq 620static struct s3c_irq_data init_eint[32] = {
529 * 621 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
530 * Initialise S3C2410 IRQ system 622 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
531*/ 623 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
624 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
625 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT4 */
626 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT5 */
627 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT6 */
628 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT7 */
629 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT8 */
630 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT9 */
631 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT10 */
632 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT11 */
633 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT12 */
634 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT13 */
635 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT14 */
636 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT15 */
637 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT16 */
638 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT17 */
639 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT18 */
640 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT19 */
641 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT20 */
642 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT21 */
643 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT22 */
644 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT23 */
645};
532 646
533static struct s3c_irq_data init_base[32] = { 647#ifdef CONFIG_CPU_S3C2410
648static struct s3c_irq_data init_s3c2410base[32] = {
534 { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */ 649 { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
535 { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */ 650 { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
536 { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */ 651 { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
@@ -565,34 +680,7 @@ static struct s3c_irq_data init_base[32] = {
565 { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */ 680 { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
566}; 681};
567 682
568static struct s3c_irq_data init_eint[32] = { 683static struct s3c_irq_data init_s3c2410subint[32] = {
569 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
570 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
571 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
572 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
573 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT4 */
574 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT5 */
575 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT6 */
576 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT7 */
577 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT8 */
578 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT9 */
579 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT10 */
580 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT11 */
581 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT12 */
582 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT13 */
583 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT14 */
584 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT15 */
585 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT16 */
586 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT17 */
587 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT18 */
588 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT19 */
589 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT20 */
590 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT21 */
591 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT22 */
592 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT23 */
593};
594
595static struct s3c_irq_data init_subint[32] = {
596 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */ 684 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
597 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */ 685 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
598 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */ 686 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
@@ -606,23 +694,24 @@ static struct s3c_irq_data init_subint[32] = {
606 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ 694 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
607}; 695};
608 696
609void __init s3c24xx_init_irq(void) 697void __init s3c2410_init_irq(void)
610{ 698{
611 struct s3c_irq_intc *main_intc;
612
613#ifdef CONFIG_FIQ 699#ifdef CONFIG_FIQ
614 init_FIQ(FIQ_START); 700 init_FIQ(FIQ_START);
615#endif 701#endif
616 702
617 main_intc = s3c24xx_init_intc(NULL, &init_base[0], NULL, 0x4a000000); 703 s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2410base[0], NULL,
618 if (IS_ERR(main_intc)) { 704 0x4a000000);
705 if (IS_ERR(s3c_intc[0])) {
619 pr_err("irq: could not create main interrupt controller\n"); 706 pr_err("irq: could not create main interrupt controller\n");
620 return; 707 return;
621 } 708 }
622 709
623 s3c24xx_init_intc(NULL, &init_subint[0], main_intc, 0x4a000018); 710 s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2410subint[0],
624 s3c24xx_init_intc(NULL, &init_eint[0], main_intc, 0x560000a4); 711 s3c_intc[0], 0x4a000018);
712 s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4);
625} 713}
714#endif
626 715
627#ifdef CONFIG_CPU_S3C2412 716#ifdef CONFIG_CPU_S3C2412
628static struct s3c_irq_data init_s3c2412base[32] = { 717static struct s3c_irq_data init_s3c2412base[32] = {
@@ -707,22 +796,22 @@ static struct s3c_irq_data init_s3c2412subint[32] = {
707 796
708void s3c2412_init_irq(void) 797void s3c2412_init_irq(void)
709{ 798{
710 struct s3c_irq_intc *main_intc;
711
712 pr_info("S3C2412: IRQ Support\n"); 799 pr_info("S3C2412: IRQ Support\n");
713 800
714#ifdef CONFIG_FIQ 801#ifdef CONFIG_FIQ
715 init_FIQ(FIQ_START); 802 init_FIQ(FIQ_START);
716#endif 803#endif
717 804
718 main_intc = s3c24xx_init_intc(NULL, &init_s3c2412base[0], NULL, 0x4a000000); 805 s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2412base[0], NULL,
719 if (IS_ERR(main_intc)) { 806 0x4a000000);
807 if (IS_ERR(s3c_intc[0])) {
720 pr_err("irq: could not create main interrupt controller\n"); 808 pr_err("irq: could not create main interrupt controller\n");
721 return; 809 return;
722 } 810 }
723 811
724 s3c24xx_init_intc(NULL, &init_s3c2412eint[0], main_intc, 0x560000a4); 812 s3c24xx_init_intc(NULL, &init_s3c2412eint[0], s3c_intc[0], 0x560000a4);
725 s3c24xx_init_intc(NULL, &init_s3c2412subint[0], main_intc, 0x4a000018); 813 s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2412subint[0],
814 s3c_intc[0], 0x4a000018);
726} 815}
727#endif 816#endif
728 817
@@ -796,35 +885,35 @@ static struct s3c_irq_data init_s3c2416subint[32] = {
796 885
797static struct s3c_irq_data init_s3c2416_second[32] = { 886static struct s3c_irq_data init_s3c2416_second[32] = {
798 { .type = S3C_IRQTYPE_EDGE }, /* 2D */ 887 { .type = S3C_IRQTYPE_EDGE }, /* 2D */
799 { .type = S3C_IRQTYPE_EDGE }, /* IIC1 */ 888 { .type = S3C_IRQTYPE_NONE }, /* reserved */
800 { .type = S3C_IRQTYPE_NONE }, /* reserved */ 889 { .type = S3C_IRQTYPE_NONE }, /* reserved */
801 { .type = S3C_IRQTYPE_NONE }, /* reserved */ 890 { .type = S3C_IRQTYPE_NONE }, /* reserved */
802 { .type = S3C_IRQTYPE_EDGE }, /* PCM0 */ 891 { .type = S3C_IRQTYPE_EDGE }, /* PCM0 */
803 { .type = S3C_IRQTYPE_EDGE }, /* PCM1 */ 892 { .type = S3C_IRQTYPE_NONE }, /* reserved */
804 { .type = S3C_IRQTYPE_EDGE }, /* I2S0 */ 893 { .type = S3C_IRQTYPE_EDGE }, /* I2S0 */
805 { .type = S3C_IRQTYPE_EDGE }, /* I2S1 */
806}; 894};
807 895
808void __init s3c2416_init_irq(void) 896void __init s3c2416_init_irq(void)
809{ 897{
810 struct s3c_irq_intc *main_intc;
811
812 pr_info("S3C2416: IRQ Support\n"); 898 pr_info("S3C2416: IRQ Support\n");
813 899
814#ifdef CONFIG_FIQ 900#ifdef CONFIG_FIQ
815 init_FIQ(FIQ_START); 901 init_FIQ(FIQ_START);
816#endif 902#endif
817 903
818 main_intc = s3c24xx_init_intc(NULL, &init_s3c2416base[0], NULL, 0x4a000000); 904 s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2416base[0], NULL,
819 if (IS_ERR(main_intc)) { 905 0x4a000000);
906 if (IS_ERR(s3c_intc[0])) {
820 pr_err("irq: could not create main interrupt controller\n"); 907 pr_err("irq: could not create main interrupt controller\n");
821 return; 908 return;
822 } 909 }
823 910
824 s3c24xx_init_intc(NULL, &init_eint[0], main_intc, 0x560000a4); 911 s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4);
825 s3c24xx_init_intc(NULL, &init_s3c2416subint[0], main_intc, 0x4a000018); 912 s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2416subint[0],
913 s3c_intc[0], 0x4a000018);
826 914
827 s3c24xx_init_intc(NULL, &init_s3c2416_second[0], NULL, 0x4a000040); 915 s3c_intc[2] = s3c24xx_init_intc(NULL, &init_s3c2416_second[0],
916 NULL, 0x4a000040);
828} 917}
829 918
830#endif 919#endif
@@ -877,30 +966,30 @@ static struct s3c_irq_data init_s3c2440subint[32] = {
877 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ 966 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
878 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ 967 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
879 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ 968 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
880 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* TC */ 969 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */
881 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* ADC */ 970 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */
882 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */ 971 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */
883 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */ 972 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */
884}; 973};
885 974
886void __init s3c2440_init_irq(void) 975void __init s3c2440_init_irq(void)
887{ 976{
888 struct s3c_irq_intc *main_intc;
889
890 pr_info("S3C2440: IRQ Support\n"); 977 pr_info("S3C2440: IRQ Support\n");
891 978
892#ifdef CONFIG_FIQ 979#ifdef CONFIG_FIQ
893 init_FIQ(FIQ_START); 980 init_FIQ(FIQ_START);
894#endif 981#endif
895 982
896 main_intc = s3c24xx_init_intc(NULL, &init_s3c2440base[0], NULL, 0x4a000000); 983 s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2440base[0], NULL,
897 if (IS_ERR(main_intc)) { 984 0x4a000000);
985 if (IS_ERR(s3c_intc[0])) {
898 pr_err("irq: could not create main interrupt controller\n"); 986 pr_err("irq: could not create main interrupt controller\n");
899 return; 987 return;
900 } 988 }
901 989
902 s3c24xx_init_intc(NULL, &init_eint[0], main_intc, 0x560000a4); 990 s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4);
903 s3c24xx_init_intc(NULL, &init_s3c2440subint[0], main_intc, 0x4a000018); 991 s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2440subint[0],
992 s3c_intc[0], 0x4a000018);
904} 993}
905#endif 994#endif
906 995
@@ -952,28 +1041,28 @@ static struct s3c_irq_data init_s3c2442subint[32] = {
952 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ 1041 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
953 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ 1042 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
954 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ 1043 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
955 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* TC */ 1044 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */
956 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* ADC */ 1045 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */
957}; 1046};
958 1047
959void __init s3c2442_init_irq(void) 1048void __init s3c2442_init_irq(void)
960{ 1049{
961 struct s3c_irq_intc *main_intc;
962
963 pr_info("S3C2442: IRQ Support\n"); 1050 pr_info("S3C2442: IRQ Support\n");
964 1051
965#ifdef CONFIG_FIQ 1052#ifdef CONFIG_FIQ
966 init_FIQ(FIQ_START); 1053 init_FIQ(FIQ_START);
967#endif 1054#endif
968 1055
969 main_intc = s3c24xx_init_intc(NULL, &init_s3c2442base[0], NULL, 0x4a000000); 1056 s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2442base[0], NULL,
970 if (IS_ERR(main_intc)) { 1057 0x4a000000);
1058 if (IS_ERR(s3c_intc[0])) {
971 pr_err("irq: could not create main interrupt controller\n"); 1059 pr_err("irq: could not create main interrupt controller\n");
972 return; 1060 return;
973 } 1061 }
974 1062
975 s3c24xx_init_intc(NULL, &init_eint[0], main_intc, 0x560000a4); 1063 s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4);
976 s3c24xx_init_intc(NULL, &init_s3c2442subint[0], main_intc, 0x4a000018); 1064 s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2442subint[0],
1065 s3c_intc[0], 0x4a000018);
977} 1066}
978#endif 1067#endif
979 1068
@@ -1048,21 +1137,219 @@ static struct s3c_irq_data init_s3c2443subint[32] = {
1048 1137
1049void __init s3c2443_init_irq(void) 1138void __init s3c2443_init_irq(void)
1050{ 1139{
1051 struct s3c_irq_intc *main_intc;
1052
1053 pr_info("S3C2443: IRQ Support\n"); 1140 pr_info("S3C2443: IRQ Support\n");
1054 1141
1055#ifdef CONFIG_FIQ 1142#ifdef CONFIG_FIQ
1056 init_FIQ(FIQ_START); 1143 init_FIQ(FIQ_START);
1057#endif 1144#endif
1058 1145
1059 main_intc = s3c24xx_init_intc(NULL, &init_s3c2443base[0], NULL, 0x4a000000); 1146 s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2443base[0], NULL,
1060 if (IS_ERR(main_intc)) { 1147 0x4a000000);
1148 if (IS_ERR(s3c_intc[0])) {
1061 pr_err("irq: could not create main interrupt controller\n"); 1149 pr_err("irq: could not create main interrupt controller\n");
1062 return; 1150 return;
1063 } 1151 }
1064 1152
1065 s3c24xx_init_intc(NULL, &init_eint[0], main_intc, 0x560000a4); 1153 s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4);
1066 s3c24xx_init_intc(NULL, &init_s3c2443subint[0], main_intc, 0x4a000018); 1154 s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2443subint[0],
1155 s3c_intc[0], 0x4a000018);
1156}
1157#endif
1158
1159#ifdef CONFIG_OF
1160static int s3c24xx_irq_map_of(struct irq_domain *h, unsigned int virq,
1161 irq_hw_number_t hw)
1162{
1163 unsigned int ctrl_num = hw / 32;
1164 unsigned int intc_hw = hw % 32;
1165 struct s3c_irq_intc *intc = s3c_intc[ctrl_num];
1166 struct s3c_irq_intc *parent_intc = intc->parent;
1167 struct s3c_irq_data *irq_data = &intc->irqs[intc_hw];
1168
1169 /* attach controller pointer to irq_data */
1170 irq_data->intc = intc;
1171 irq_data->offset = intc_hw;
1172
1173 if (!parent_intc)
1174 irq_set_chip_and_handler(virq, &s3c_irq_chip, handle_edge_irq);
1175 else
1176 irq_set_chip_and_handler(virq, &s3c_irq_level_chip,
1177 handle_edge_irq);
1178
1179 irq_set_chip_data(virq, irq_data);
1180
1181 set_irq_flags(virq, IRQF_VALID);
1182
1183 return 0;
1184}
1185
1186/* Translate our of irq notation
1187 * format: <ctrl_num ctrl_irq parent_irq type>
1188 */
1189static int s3c24xx_irq_xlate_of(struct irq_domain *d, struct device_node *n,
1190 const u32 *intspec, unsigned int intsize,
1191 irq_hw_number_t *out_hwirq, unsigned int *out_type)
1192{
1193 struct s3c_irq_intc *intc;
1194 struct s3c_irq_intc *parent_intc;
1195 struct s3c_irq_data *irq_data;
1196 struct s3c_irq_data *parent_irq_data;
1197 int irqno;
1198
1199 if (WARN_ON(intsize < 4))
1200 return -EINVAL;
1201
1202 if (intspec[0] > 2 || !s3c_intc[intspec[0]]) {
1203 pr_err("controller number %d invalid\n", intspec[0]);
1204 return -EINVAL;
1205 }
1206 intc = s3c_intc[intspec[0]];
1207
1208 *out_hwirq = intspec[0] * 32 + intspec[2];
1209 *out_type = intspec[3] & IRQ_TYPE_SENSE_MASK;
1210
1211 parent_intc = intc->parent;
1212 if (parent_intc) {
1213 irq_data = &intc->irqs[intspec[2]];
1214 irq_data->parent_irq = intspec[1];
1215 parent_irq_data = &parent_intc->irqs[irq_data->parent_irq];
1216 parent_irq_data->sub_intc = intc;
1217 parent_irq_data->sub_bits |= (1UL << intspec[2]);
1218
1219 /* parent_intc is always s3c_intc[0], so no offset */
1220 irqno = irq_create_mapping(parent_intc->domain, intspec[1]);
1221 if (irqno < 0) {
1222 pr_err("irq: could not map parent interrupt\n");
1223 return irqno;
1224 }
1225
1226 irq_set_chained_handler(irqno, s3c_irq_demux);
1227 }
1228
1229 return 0;
1230}
1231
1232static struct irq_domain_ops s3c24xx_irq_ops_of = {
1233 .map = s3c24xx_irq_map_of,
1234 .xlate = s3c24xx_irq_xlate_of,
1235};
1236
1237struct s3c24xx_irq_of_ctrl {
1238 char *name;
1239 unsigned long offset;
1240 struct s3c_irq_intc **handle;
1241 struct s3c_irq_intc **parent;
1242 struct irq_domain_ops *ops;
1243};
1244
1245static int __init s3c_init_intc_of(struct device_node *np,
1246 struct device_node *interrupt_parent,
1247 struct s3c24xx_irq_of_ctrl *s3c_ctrl, int num_ctrl)
1248{
1249 struct s3c_irq_intc *intc;
1250 struct s3c24xx_irq_of_ctrl *ctrl;
1251 struct irq_domain *domain;
1252 void __iomem *reg_base;
1253 int i;
1254
1255 reg_base = of_iomap(np, 0);
1256 if (!reg_base) {
1257 pr_err("irq-s3c24xx: could not map irq registers\n");
1258 return -EINVAL;
1259 }
1260
1261 domain = irq_domain_add_linear(np, num_ctrl * 32,
1262 &s3c24xx_irq_ops_of, NULL);
1263 if (!domain) {
1264 pr_err("irq: could not create irq-domain\n");
1265 return -EINVAL;
1266 }
1267
1268 for (i = 0; i < num_ctrl; i++) {
1269 ctrl = &s3c_ctrl[i];
1270
1271 pr_debug("irq: found controller %s\n", ctrl->name);
1272
1273 intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL);
1274 if (!intc)
1275 return -ENOMEM;
1276
1277 intc->domain = domain;
1278 intc->irqs = kzalloc(sizeof(struct s3c_irq_data) * 32,
1279 GFP_KERNEL);
1280 if (!intc->irqs) {
1281 kfree(intc);
1282 return -ENOMEM;
1283 }
1284
1285 if (ctrl->parent) {
1286 intc->reg_pending = reg_base + ctrl->offset;
1287 intc->reg_mask = reg_base + ctrl->offset + 0x4;
1288
1289 if (*(ctrl->parent)) {
1290 intc->parent = *(ctrl->parent);
1291 } else {
1292 pr_warn("irq: parent of %s missing\n",
1293 ctrl->name);
1294 kfree(intc->irqs);
1295 kfree(intc);
1296 continue;
1297 }
1298 } else {
1299 intc->reg_pending = reg_base + ctrl->offset;
1300 intc->reg_mask = reg_base + ctrl->offset + 0x08;
1301 intc->reg_intpnd = reg_base + ctrl->offset + 0x10;
1302 }
1303
1304 s3c24xx_clear_intc(intc);
1305 s3c_intc[i] = intc;
1306 }
1307
1308 set_handle_irq(s3c24xx_handle_irq);
1309
1310 return 0;
1311}
1312
1313static struct s3c24xx_irq_of_ctrl s3c2410_ctrl[] = {
1314 {
1315 .name = "intc",
1316 .offset = 0,
1317 }, {
1318 .name = "subintc",
1319 .offset = 0x18,
1320 .parent = &s3c_intc[0],
1321 }
1322};
1323
1324int __init s3c2410_init_intc_of(struct device_node *np,
1325 struct device_node *interrupt_parent,
1326 struct s3c24xx_irq_of_ctrl *ctrl, int num_ctrl)
1327{
1328 return s3c_init_intc_of(np, interrupt_parent,
1329 s3c2410_ctrl, ARRAY_SIZE(s3c2410_ctrl));
1330}
1331IRQCHIP_DECLARE(s3c2410_irq, "samsung,s3c2410-irq", s3c2410_init_intc_of);
1332
1333static struct s3c24xx_irq_of_ctrl s3c2416_ctrl[] = {
1334 {
1335 .name = "intc",
1336 .offset = 0,
1337 }, {
1338 .name = "subintc",
1339 .offset = 0x18,
1340 .parent = &s3c_intc[0],
1341 }, {
1342 .name = "intc2",
1343 .offset = 0x40,
1344 }
1345};
1346
1347int __init s3c2416_init_intc_of(struct device_node *np,
1348 struct device_node *interrupt_parent,
1349 struct s3c24xx_irq_of_ctrl *ctrl, int num_ctrl)
1350{
1351 return s3c_init_intc_of(np, interrupt_parent,
1352 s3c2416_ctrl, ARRAY_SIZE(s3c2416_ctrl));
1067} 1353}
1354IRQCHIP_DECLARE(s3c2416_irq, "samsung,s3c2416-irq", s3c2416_init_intc_of);
1068#endif 1355#endif