diff options
author | Arnd Bergmann <arnd@arndb.de> | 2013-04-09 16:05:50 -0400 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2013-04-09 16:05:50 -0400 |
commit | 894b7382cf20e81d38097d43b8802af6e79d48c4 (patch) | |
tree | 7b51fd5c6e51d60bb5e9122816dc9c09823d3578 | |
parent | ab9838e145dab98744798af0d5e849f1de139bff (diff) | |
parent | f0774d41da0e607b70e54ecc50aeb6684f54c2b1 (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.txt | 53 | ||||
-rw-r--r-- | arch/arm/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-s3c24xx/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-s3c24xx/common.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-s3c24xx/include/mach/entry-macro.S | 70 | ||||
-rw-r--r-- | arch/arm/mach-s3c24xx/mach-amlm5900.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-s3c24xx/mach-bast.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-s3c24xx/mach-h1940.c | 7 | ||||
-rw-r--r-- | arch/arm/mach-s3c24xx/mach-n30.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-s3c24xx/mach-otom.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-s3c24xx/mach-qt2410.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-s3c24xx/mach-smdk2410.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-s3c24xx/mach-tct_hammer.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-s3c24xx/mach-vr1000.c | 2 | ||||
-rw-r--r-- | arch/arm/plat-samsung/include/plat/cpu.h | 1 | ||||
-rw-r--r-- | drivers/irqchip/Makefile | 1 | ||||
-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 @@ | |||
1 | Samsung S3C24XX Interrupt Controllers | ||
2 | |||
3 | The S3C24XX SoCs contain a custom set of interrupt controllers providing a | ||
4 | varying number of interrupt sources. The set consists of a main- and sub- | ||
5 | controller and on newer SoCs even a second main controller. | ||
6 | |||
7 | Required 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 | |||
30 | Example: | ||
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 | ||
17 | obj-y += common.o irq.o | 17 | obj-y += common.o |
18 | 18 | ||
19 | obj-$(CONFIG_CPU_S3C2410) += s3c2410.o | 19 | obj-$(CONFIG_CPU_S3C2410) += s3c2410.o |
20 | obj-$(CONFIG_S3C2410_CPUFREQ) += cpufreq-s3c2410.o | 20 | obj-$(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); | |||
21 | extern void s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no); | 21 | extern void s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no); |
22 | extern void s3c2410_init_clocks(int xtal); | 22 | extern void s3c2410_init_clocks(int xtal); |
23 | extern void s3c2410_restart(char mode, const char *cmd); | 23 | extern void s3c2410_restart(char mode, const char *cmd); |
24 | extern 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 | ||
65 | 1001: | ||
66 | adds \irqnr, \irqnr, #IRQ_EINT0 | ||
67 | 1002: | ||
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) | |||
238 | MACHINE_START(AML_M5900, "AML_M5900") | 238 | MACHINE_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 | ||
670 | static void __init h1940_init_irq(void) | ||
671 | { | ||
672 | s3c24xx_init_irq(); | ||
673 | } | ||
674 | |||
675 | static void __init h1940_init(void) | 670 | static 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, |
598 | MACHINE_END | 598 | MACHINE_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, |
609 | MACHINE_END | 609 | MACHINE_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, |
122 | MACHINE_END | 122 | MACHINE_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) | |||
343 | MACHINE_START(QT2410, "QT2410") | 343 | MACHINE_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) | |||
149 | MACHINE_START(TCT_HAMMER, "TCT_HAMMER") | 149 | MACHINE_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, |
361 | MACHINE_END | 361 | MACHINE_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 | ||
186 | extern void s3c24xx_init_irq(void); | ||
187 | extern void s5p_init_irq(u32 *vic, u32 num_vic); | 186 | extern void s5p_init_irq(u32 *vic, u32 num_vic); |
188 | 187 | ||
189 | extern void s3c24xx_init_io(struct map_desc *mach_desc, int size); | 188 | extern 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 | ||
3 | obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o | 3 | obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o |
4 | obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o | 4 | obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o |
5 | obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o | ||
5 | obj-$(CONFIG_METAG) += irq-metag-ext.o | 6 | obj-$(CONFIG_METAG) += irq-metag-ext.o |
6 | obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o | 7 | obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o |
7 | obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi.o | 8 | obj-$(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 | ||
43 | struct s3c_irq_data { | 49 | struct 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 | */ | ||
84 | static struct s3c_irq_intc *s3c_intc[3]; | ||
85 | |||
71 | static void s3c_irq_mask(struct irq_data *data) | 86 | static 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 | ||
96 | static void s3c_irq_unmask(struct irq_data *data) | 114 | static 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 | ||
115 | static inline void s3c_irq_ack(struct irq_data *data) | 133 | static 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 | ||
144 | static 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 | |||
125 | static int s3c_irqext_type_set(void __iomem *gpcon_reg, | 166 | static 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 | ||
240 | static struct irq_chip s3c_irqext_chip = { | 283 | static struct irq_chip s3c_irqext_chip = { |
@@ -258,12 +301,19 @@ static struct irq_chip s3c_irq_eint0t4 = { | |||
258 | static void s3c_irq_demux(unsigned int irq, struct irq_desc *desc) | 301 | static 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 | ||
336 | static 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 | |||
372 | asmlinkage 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 | ||
447 | struct s3c_irq_intc *s3c24xx_init_intc(struct device_node *np, | 537 | static 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 | ||
523 | err: | 615 | err: |
@@ -525,12 +617,35 @@ err: | |||
525 | return ERR_PTR(ret); | 617 | return ERR_PTR(ret); |
526 | } | 618 | } |
527 | 619 | ||
528 | /* s3c24xx_init_irq | 620 | static 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 | ||
533 | static struct s3c_irq_data init_base[32] = { | 647 | #ifdef CONFIG_CPU_S3C2410 |
648 | static 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 | ||
568 | static struct s3c_irq_data init_eint[32] = { | 683 | static 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 | |||
595 | static 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 | ||
609 | void __init s3c24xx_init_irq(void) | 697 | void __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 |
628 | static struct s3c_irq_data init_s3c2412base[32] = { | 717 | static struct s3c_irq_data init_s3c2412base[32] = { |
@@ -707,22 +796,22 @@ static struct s3c_irq_data init_s3c2412subint[32] = { | |||
707 | 796 | ||
708 | void s3c2412_init_irq(void) | 797 | void 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 | ||
797 | static struct s3c_irq_data init_s3c2416_second[32] = { | 886 | static 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 | ||
808 | void __init s3c2416_init_irq(void) | 896 | void __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 | ||
886 | void __init s3c2440_init_irq(void) | 975 | void __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 | ||
959 | void __init s3c2442_init_irq(void) | 1048 | void __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 | ||
1049 | void __init s3c2443_init_irq(void) | 1138 | void __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 | ||
1160 | static 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 | */ | ||
1189 | static 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 | |||
1232 | static struct irq_domain_ops s3c24xx_irq_ops_of = { | ||
1233 | .map = s3c24xx_irq_map_of, | ||
1234 | .xlate = s3c24xx_irq_xlate_of, | ||
1235 | }; | ||
1236 | |||
1237 | struct 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 | |||
1245 | static 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 | |||
1313 | static 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 | |||
1324 | int __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 | } | ||
1331 | IRQCHIP_DECLARE(s3c2410_irq, "samsung,s3c2410-irq", s3c2410_init_intc_of); | ||
1332 | |||
1333 | static 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 | |||
1347 | int __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 | } |
1354 | IRQCHIP_DECLARE(s3c2416_irq, "samsung,s3c2416-irq", s3c2416_init_intc_of); | ||
1068 | #endif | 1355 | #endif |