diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2012-04-28 09:33:47 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2012-05-04 11:53:37 -0400 |
commit | 3108e6ab21a9b9dbd88f0b2ff99f73e95b8b1580 (patch) | |
tree | 9e87e1e4196849090103317d109dc95ba9d159f8 /arch/arm | |
parent | 69964ea4c7b68c9399f7977aa5b9aa6539a6a98a (diff) |
ARM: 7389/2: plat-versatile: modernize FPGA IRQ controller
This does two things to the FPGA IRQ controller in the versatile
family:
- Convert to MULTI_IRQ_HANDLER so we can drop the entry macro
from the Integrator. The C IRQ handler was inspired from
arch/arm/common/vic.c, recent bug discovered in this handler was
accounted for.
- Convert to using IRQ domains so we can get rid of the NO_IRQ
mess and proceed with device tree and such stuff.
As part of the exercise, bump all the low IRQ numbers on the
Integrator PIC to start from 1 rather than 0, since IRQ 0 is
now NO_IRQ. The Linux IRQ numbers are thus entirely decoupled
from the hardware IRQ numbers in this controller.
I was unable to split this patch. The main reason is the half-done
conversion to device tree in Versatile.
Tested on Integrator/AP and Integrator/CP.
Cc: Grant Likely <grant.likely@secretlab.ca>
Acked-by: Rob Herring <rob.herring@calxeda.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-integrator/include/mach/entry-macro.S | 39 | ||||
-rw-r--r-- | arch/arm/mach-integrator/include/mach/irqs.h | 63 | ||||
-rw-r--r-- | arch/arm/mach-integrator/integrator_ap.c | 10 | ||||
-rw-r--r-- | arch/arm/mach-integrator/integrator_cp.c | 33 | ||||
-rw-r--r-- | arch/arm/mach-versatile/core.c | 13 | ||||
-rw-r--r-- | arch/arm/plat-versatile/Kconfig | 6 | ||||
-rw-r--r-- | arch/arm/plat-versatile/fpga-irq.c | 116 | ||||
-rw-r--r-- | arch/arm/plat-versatile/include/plat/fpga-irq.h | 11 |
9 files changed, 162 insertions, 130 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index cf006d40342c..2f67f6c62f56 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -280,6 +280,7 @@ config ARCH_INTEGRATOR | |||
280 | select NEED_MACH_IO_H | 280 | select NEED_MACH_IO_H |
281 | select NEED_MACH_MEMORY_H | 281 | select NEED_MACH_MEMORY_H |
282 | select SPARSE_IRQ | 282 | select SPARSE_IRQ |
283 | select MULTI_IRQ_HANDLER | ||
283 | help | 284 | help |
284 | Support for ARM's Integrator platform. | 285 | Support for ARM's Integrator platform. |
285 | 286 | ||
diff --git a/arch/arm/mach-integrator/include/mach/entry-macro.S b/arch/arm/mach-integrator/include/mach/entry-macro.S deleted file mode 100644 index 5cc7b85ad9df..000000000000 --- a/arch/arm/mach-integrator/include/mach/entry-macro.S +++ /dev/null | |||
@@ -1,39 +0,0 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-integrator/include/mach/entry-macro.S | ||
3 | * | ||
4 | * Low-level IRQ helper macros for Integrator 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 | #include <mach/hardware.h> | ||
11 | #include <mach/platform.h> | ||
12 | #include <mach/irqs.h> | ||
13 | |||
14 | .macro get_irqnr_preamble, base, tmp | ||
15 | .endm | ||
16 | |||
17 | .macro get_irqnr_and_base, irqnr, irqstat, base, tmp | ||
18 | /* FIXME: should not be using soo many LDRs here */ | ||
19 | ldr \base, =IO_ADDRESS(INTEGRATOR_IC_BASE) | ||
20 | mov \irqnr, #IRQ_PIC_START | ||
21 | ldr \irqstat, [\base, #IRQ_STATUS] @ get masked status | ||
22 | ldr \base, =IO_ADDRESS(INTEGRATOR_HDR_BASE) | ||
23 | teq \irqstat, #0 | ||
24 | ldreq \irqstat, [\base, #(INTEGRATOR_HDR_IC_OFFSET+IRQ_STATUS)] | ||
25 | moveq \irqnr, #IRQ_CIC_START | ||
26 | |||
27 | 1001: tst \irqstat, #15 | ||
28 | bne 1002f | ||
29 | add \irqnr, \irqnr, #4 | ||
30 | movs \irqstat, \irqstat, lsr #4 | ||
31 | bne 1001b | ||
32 | 1002: tst \irqstat, #1 | ||
33 | bne 1003f | ||
34 | add \irqnr, \irqnr, #1 | ||
35 | movs \irqstat, \irqstat, lsr #1 | ||
36 | bne 1002b | ||
37 | 1003: /* EQ will be set if no irqs pending */ | ||
38 | .endm | ||
39 | |||
diff --git a/arch/arm/mach-integrator/include/mach/irqs.h b/arch/arm/mach-integrator/include/mach/irqs.h index a19a1a2fcf6b..7371018455d2 100644 --- a/arch/arm/mach-integrator/include/mach/irqs.h +++ b/arch/arm/mach-integrator/include/mach/irqs.h | |||
@@ -22,37 +22,37 @@ | |||
22 | /* | 22 | /* |
23 | * Interrupt numbers | 23 | * Interrupt numbers |
24 | */ | 24 | */ |
25 | #define IRQ_PIC_START 0 | 25 | #define IRQ_PIC_START 1 |
26 | #define IRQ_SOFTINT 0 | 26 | #define IRQ_SOFTINT 1 |
27 | #define IRQ_UARTINT0 1 | 27 | #define IRQ_UARTINT0 2 |
28 | #define IRQ_UARTINT1 2 | 28 | #define IRQ_UARTINT1 3 |
29 | #define IRQ_KMIINT0 3 | 29 | #define IRQ_KMIINT0 4 |
30 | #define IRQ_KMIINT1 4 | 30 | #define IRQ_KMIINT1 5 |
31 | #define IRQ_TIMERINT0 5 | 31 | #define IRQ_TIMERINT0 6 |
32 | #define IRQ_TIMERINT1 6 | 32 | #define IRQ_TIMERINT1 7 |
33 | #define IRQ_TIMERINT2 7 | 33 | #define IRQ_TIMERINT2 8 |
34 | #define IRQ_RTCINT 8 | 34 | #define IRQ_RTCINT 9 |
35 | #define IRQ_AP_EXPINT0 9 | 35 | #define IRQ_AP_EXPINT0 10 |
36 | #define IRQ_AP_EXPINT1 10 | 36 | #define IRQ_AP_EXPINT1 11 |
37 | #define IRQ_AP_EXPINT2 11 | 37 | #define IRQ_AP_EXPINT2 12 |
38 | #define IRQ_AP_EXPINT3 12 | 38 | #define IRQ_AP_EXPINT3 13 |
39 | #define IRQ_AP_PCIINT0 13 | 39 | #define IRQ_AP_PCIINT0 14 |
40 | #define IRQ_AP_PCIINT1 14 | 40 | #define IRQ_AP_PCIINT1 15 |
41 | #define IRQ_AP_PCIINT2 15 | 41 | #define IRQ_AP_PCIINT2 16 |
42 | #define IRQ_AP_PCIINT3 16 | 42 | #define IRQ_AP_PCIINT3 17 |
43 | #define IRQ_AP_V3INT 17 | 43 | #define IRQ_AP_V3INT 18 |
44 | #define IRQ_AP_CPINT0 18 | 44 | #define IRQ_AP_CPINT0 19 |
45 | #define IRQ_AP_CPINT1 19 | 45 | #define IRQ_AP_CPINT1 20 |
46 | #define IRQ_AP_LBUSTIMEOUT 20 | 46 | #define IRQ_AP_LBUSTIMEOUT 21 |
47 | #define IRQ_AP_APCINT 21 | 47 | #define IRQ_AP_APCINT 22 |
48 | #define IRQ_CP_CLCDCINT 22 | 48 | #define IRQ_CP_CLCDCINT 23 |
49 | #define IRQ_CP_MMCIINT0 23 | 49 | #define IRQ_CP_MMCIINT0 24 |
50 | #define IRQ_CP_MMCIINT1 24 | 50 | #define IRQ_CP_MMCIINT1 25 |
51 | #define IRQ_CP_AACIINT 25 | 51 | #define IRQ_CP_AACIINT 26 |
52 | #define IRQ_CP_CPPLDINT 26 | 52 | #define IRQ_CP_CPPLDINT 27 |
53 | #define IRQ_CP_ETHINT 27 | 53 | #define IRQ_CP_ETHINT 28 |
54 | #define IRQ_CP_TSPENINT 28 | 54 | #define IRQ_CP_TSPENINT 29 |
55 | #define IRQ_PIC_END 31 | 55 | #define IRQ_PIC_END 29 |
56 | 56 | ||
57 | #define IRQ_CIC_START 32 | 57 | #define IRQ_CIC_START 32 |
58 | #define IRQ_CM_SOFTINT 32 | 58 | #define IRQ_CM_SOFTINT 32 |
@@ -80,4 +80,3 @@ | |||
80 | 80 | ||
81 | #define NR_IRQS_INTEGRATOR_AP 34 | 81 | #define NR_IRQS_INTEGRATOR_AP 34 |
82 | #define NR_IRQS_INTEGRATOR_CP 47 | 82 | #define NR_IRQS_INTEGRATOR_CP 47 |
83 | |||
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index 871f148ffd72..c857501c5783 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c | |||
@@ -162,12 +162,6 @@ static void __init ap_map_io(void) | |||
162 | 162 | ||
163 | #define INTEGRATOR_SC_VALID_INT 0x003fffff | 163 | #define INTEGRATOR_SC_VALID_INT 0x003fffff |
164 | 164 | ||
165 | static struct fpga_irq_data sc_irq_data = { | ||
166 | .base = VA_IC_BASE, | ||
167 | .irq_start = 0, | ||
168 | .chip.name = "SC", | ||
169 | }; | ||
170 | |||
171 | static void __init ap_init_irq(void) | 165 | static void __init ap_init_irq(void) |
172 | { | 166 | { |
173 | /* Disable all interrupts initially. */ | 167 | /* Disable all interrupts initially. */ |
@@ -178,7 +172,8 @@ static void __init ap_init_irq(void) | |||
178 | writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR); | 172 | writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR); |
179 | writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR); | 173 | writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR); |
180 | 174 | ||
181 | fpga_irq_init(-1, INTEGRATOR_SC_VALID_INT, &sc_irq_data); | 175 | fpga_irq_init(VA_IC_BASE, "SC", IRQ_PIC_START, |
176 | -1, INTEGRATOR_SC_VALID_INT, NULL); | ||
182 | } | 177 | } |
183 | 178 | ||
184 | #ifdef CONFIG_PM | 179 | #ifdef CONFIG_PM |
@@ -478,6 +473,7 @@ MACHINE_START(INTEGRATOR, "ARM-Integrator") | |||
478 | .nr_irqs = NR_IRQS_INTEGRATOR_AP, | 473 | .nr_irqs = NR_IRQS_INTEGRATOR_AP, |
479 | .init_early = integrator_init_early, | 474 | .init_early = integrator_init_early, |
480 | .init_irq = ap_init_irq, | 475 | .init_irq = ap_init_irq, |
476 | .handle_irq = fpga_handle_irq, | ||
481 | .timer = &ap_timer, | 477 | .timer = &ap_timer, |
482 | .init_machine = ap_init, | 478 | .init_machine = ap_init, |
483 | .restart = integrator_restart, | 479 | .restart = integrator_restart, |
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index 48a115a91d9d..a56c53608939 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c | |||
@@ -143,30 +143,14 @@ static void __init intcp_map_io(void) | |||
143 | iotable_init(intcp_io_desc, ARRAY_SIZE(intcp_io_desc)); | 143 | iotable_init(intcp_io_desc, ARRAY_SIZE(intcp_io_desc)); |
144 | } | 144 | } |
145 | 145 | ||
146 | static struct fpga_irq_data cic_irq_data = { | ||
147 | .base = INTCP_VA_CIC_BASE, | ||
148 | .irq_start = IRQ_CIC_START, | ||
149 | .chip.name = "CIC", | ||
150 | }; | ||
151 | |||
152 | static struct fpga_irq_data pic_irq_data = { | ||
153 | .base = INTCP_VA_PIC_BASE, | ||
154 | .irq_start = IRQ_PIC_START, | ||
155 | .chip.name = "PIC", | ||
156 | }; | ||
157 | |||
158 | static struct fpga_irq_data sic_irq_data = { | ||
159 | .base = INTCP_VA_SIC_BASE, | ||
160 | .irq_start = IRQ_SIC_START, | ||
161 | .chip.name = "SIC", | ||
162 | }; | ||
163 | |||
164 | static void __init intcp_init_irq(void) | 146 | static void __init intcp_init_irq(void) |
165 | { | 147 | { |
166 | u32 pic_mask, sic_mask; | 148 | u32 pic_mask, cic_mask, sic_mask; |
167 | 149 | ||
150 | /* These masks are for the HW IRQ registers */ | ||
168 | pic_mask = ~((~0u) << (11 - IRQ_PIC_START)); | 151 | pic_mask = ~((~0u) << (11 - IRQ_PIC_START)); |
169 | pic_mask |= (~((~0u) << (29 - 22))) << 22; | 152 | pic_mask |= (~((~0u) << (29 - 22))) << 22; |
153 | cic_mask = ~((~0u) << (1 + IRQ_CIC_END - IRQ_CIC_START)); | ||
170 | sic_mask = ~((~0u) << (1 + IRQ_SIC_END - IRQ_SIC_START)); | 154 | sic_mask = ~((~0u) << (1 + IRQ_SIC_END - IRQ_SIC_START)); |
171 | 155 | ||
172 | /* | 156 | /* |
@@ -179,12 +163,14 @@ static void __init intcp_init_irq(void) | |||
179 | writel(sic_mask, INTCP_VA_SIC_BASE + IRQ_ENABLE_CLEAR); | 163 | writel(sic_mask, INTCP_VA_SIC_BASE + IRQ_ENABLE_CLEAR); |
180 | writel(sic_mask, INTCP_VA_SIC_BASE + FIQ_ENABLE_CLEAR); | 164 | writel(sic_mask, INTCP_VA_SIC_BASE + FIQ_ENABLE_CLEAR); |
181 | 165 | ||
182 | fpga_irq_init(-1, pic_mask, &pic_irq_data); | 166 | fpga_irq_init(INTCP_VA_PIC_BASE, "PIC", IRQ_PIC_START, |
167 | -1, pic_mask, NULL); | ||
183 | 168 | ||
184 | fpga_irq_init(-1, ~((~0u) << (1 + IRQ_CIC_END - IRQ_CIC_START)), | 169 | fpga_irq_init(INTCP_VA_CIC_BASE, "CIC", IRQ_CIC_START, |
185 | &cic_irq_data); | 170 | -1, cic_mask, NULL); |
186 | 171 | ||
187 | fpga_irq_init(IRQ_CP_CPPLDINT, sic_mask, &sic_irq_data); | 172 | fpga_irq_init(INTCP_VA_SIC_BASE, "SIC", IRQ_SIC_START, |
173 | IRQ_CP_CPPLDINT, sic_mask, NULL); | ||
188 | } | 174 | } |
189 | 175 | ||
190 | /* | 176 | /* |
@@ -467,6 +453,7 @@ MACHINE_START(CINTEGRATOR, "ARM-IntegratorCP") | |||
467 | .nr_irqs = NR_IRQS_INTEGRATOR_CP, | 453 | .nr_irqs = NR_IRQS_INTEGRATOR_CP, |
468 | .init_early = intcp_init_early, | 454 | .init_early = intcp_init_early, |
469 | .init_irq = intcp_init_irq, | 455 | .init_irq = intcp_init_irq, |
456 | .handle_irq = fpga_handle_irq, | ||
470 | .timer = &cp_timer, | 457 | .timer = &cp_timer, |
471 | .init_machine = intcp_init, | 458 | .init_machine = intcp_init, |
472 | .restart = integrator_restart, | 459 | .restart = integrator_restart, |
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index 6bbd74e950ab..6f5fb466a273 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c | |||
@@ -66,12 +66,6 @@ | |||
66 | #define VA_VIC_BASE __io_address(VERSATILE_VIC_BASE) | 66 | #define VA_VIC_BASE __io_address(VERSATILE_VIC_BASE) |
67 | #define VA_SIC_BASE __io_address(VERSATILE_SIC_BASE) | 67 | #define VA_SIC_BASE __io_address(VERSATILE_SIC_BASE) |
68 | 68 | ||
69 | static struct fpga_irq_data sic_irq = { | ||
70 | .base = VA_SIC_BASE, | ||
71 | .irq_start = IRQ_SIC_START, | ||
72 | .chip.name = "SIC", | ||
73 | }; | ||
74 | |||
75 | #if 1 | 69 | #if 1 |
76 | #define IRQ_MMCI0A IRQ_VICSOURCE22 | 70 | #define IRQ_MMCI0A IRQ_VICSOURCE22 |
77 | #define IRQ_AACI IRQ_VICSOURCE24 | 71 | #define IRQ_AACI IRQ_VICSOURCE24 |
@@ -105,8 +99,11 @@ void __init versatile_init_irq(void) | |||
105 | 99 | ||
106 | writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR); | 100 | writel(~0, VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR); |
107 | 101 | ||
108 | fpga_irq_init(IRQ_VICSOURCE31, ~PIC_MASK, &sic_irq); | 102 | np = of_find_matching_node_by_address(NULL, sic_of_match, |
109 | irq_domain_generate_simple(sic_of_match, VERSATILE_SIC_BASE, IRQ_SIC_START); | 103 | VERSATILE_SIC_BASE); |
104 | |||
105 | fpga_irq_init(VA_SIC_BASE, "SIC", IRQ_SIC_START, | ||
106 | IRQ_VICSOURCE31, ~PIC_MASK, np); | ||
110 | 107 | ||
111 | /* | 108 | /* |
112 | * Interrupts on secondary controller from 0 to 8 are routed to | 109 | * Interrupts on secondary controller from 0 to 8 are routed to |
diff --git a/arch/arm/plat-versatile/Kconfig b/arch/arm/plat-versatile/Kconfig index 043f7b02a9e7..81ee7cc34457 100644 --- a/arch/arm/plat-versatile/Kconfig +++ b/arch/arm/plat-versatile/Kconfig | |||
@@ -5,6 +5,12 @@ config PLAT_VERSATILE_CLCD | |||
5 | 5 | ||
6 | config PLAT_VERSATILE_FPGA_IRQ | 6 | config PLAT_VERSATILE_FPGA_IRQ |
7 | bool | 7 | bool |
8 | select IRQ_DOMAIN | ||
9 | |||
10 | config PLAT_VERSATILE_FPGA_IRQ_NR | ||
11 | int | ||
12 | default 4 | ||
13 | depends on PLAT_VERSATILE_FPGA_IRQ | ||
8 | 14 | ||
9 | config PLAT_VERSATILE_LEDS | 15 | config PLAT_VERSATILE_LEDS |
10 | def_bool y if LEDS_CLASS | 16 | def_bool y if LEDS_CLASS |
diff --git a/arch/arm/plat-versatile/fpga-irq.c b/arch/arm/plat-versatile/fpga-irq.c index f0cc8e19b094..6e70d03824a1 100644 --- a/arch/arm/plat-versatile/fpga-irq.c +++ b/arch/arm/plat-versatile/fpga-irq.c | |||
@@ -3,7 +3,10 @@ | |||
3 | */ | 3 | */ |
4 | #include <linux/irq.h> | 4 | #include <linux/irq.h> |
5 | #include <linux/io.h> | 5 | #include <linux/io.h> |
6 | #include <linux/irqdomain.h> | ||
7 | #include <linux/module.h> | ||
6 | 8 | ||
9 | #include <asm/exception.h> | ||
7 | #include <asm/mach/irq.h> | 10 | #include <asm/mach/irq.h> |
8 | #include <plat/fpga-irq.h> | 11 | #include <plat/fpga-irq.h> |
9 | 12 | ||
@@ -12,10 +15,32 @@ | |||
12 | #define IRQ_ENABLE_SET 0x08 | 15 | #define IRQ_ENABLE_SET 0x08 |
13 | #define IRQ_ENABLE_CLEAR 0x0c | 16 | #define IRQ_ENABLE_CLEAR 0x0c |
14 | 17 | ||
18 | /** | ||
19 | * struct fpga_irq_data - irq data container for the FPGA IRQ controller | ||
20 | * @base: memory offset in virtual memory | ||
21 | * @irq_start: first IRQ number handled by this instance | ||
22 | * @chip: chip container for this instance | ||
23 | * @domain: IRQ domain for this instance | ||
24 | * @valid: mask for valid IRQs on this controller | ||
25 | * @used_irqs: number of active IRQs on this controller | ||
26 | */ | ||
27 | struct fpga_irq_data { | ||
28 | void __iomem *base; | ||
29 | unsigned int irq_start; | ||
30 | struct irq_chip chip; | ||
31 | u32 valid; | ||
32 | struct irq_domain *domain; | ||
33 | u8 used_irqs; | ||
34 | }; | ||
35 | |||
36 | /* we cannot allocate memory when the controllers are initially registered */ | ||
37 | static struct fpga_irq_data fpga_irq_devices[CONFIG_PLAT_VERSATILE_FPGA_IRQ_NR]; | ||
38 | static int fpga_irq_id; | ||
39 | |||
15 | static void fpga_irq_mask(struct irq_data *d) | 40 | static void fpga_irq_mask(struct irq_data *d) |
16 | { | 41 | { |
17 | struct fpga_irq_data *f = irq_data_get_irq_chip_data(d); | 42 | struct fpga_irq_data *f = irq_data_get_irq_chip_data(d); |
18 | u32 mask = 1 << (d->irq - f->irq_start); | 43 | u32 mask = 1 << d->hwirq; |
19 | 44 | ||
20 | writel(mask, f->base + IRQ_ENABLE_CLEAR); | 45 | writel(mask, f->base + IRQ_ENABLE_CLEAR); |
21 | } | 46 | } |
@@ -23,7 +48,7 @@ static void fpga_irq_mask(struct irq_data *d) | |||
23 | static void fpga_irq_unmask(struct irq_data *d) | 48 | static void fpga_irq_unmask(struct irq_data *d) |
24 | { | 49 | { |
25 | struct fpga_irq_data *f = irq_data_get_irq_chip_data(d); | 50 | struct fpga_irq_data *f = irq_data_get_irq_chip_data(d); |
26 | u32 mask = 1 << (d->irq - f->irq_start); | 51 | u32 mask = 1 << d->hwirq; |
27 | 52 | ||
28 | writel(mask, f->base + IRQ_ENABLE_SET); | 53 | writel(mask, f->base + IRQ_ENABLE_SET); |
29 | } | 54 | } |
@@ -41,32 +66,93 @@ static void fpga_irq_handle(unsigned int irq, struct irq_desc *desc) | |||
41 | do { | 66 | do { |
42 | irq = ffs(status) - 1; | 67 | irq = ffs(status) - 1; |
43 | status &= ~(1 << irq); | 68 | status &= ~(1 << irq); |
44 | 69 | generic_handle_irq(irq_find_mapping(f->domain, irq)); | |
45 | generic_handle_irq(irq + f->irq_start); | ||
46 | } while (status); | 70 | } while (status); |
47 | } | 71 | } |
48 | 72 | ||
49 | void __init fpga_irq_init(int parent_irq, u32 valid, struct fpga_irq_data *f) | 73 | /* |
74 | * Handle each interrupt in a single FPGA IRQ controller. Returns non-zero | ||
75 | * if we've handled at least one interrupt. This does a single read of the | ||
76 | * status register and handles all interrupts in order from LSB first. | ||
77 | */ | ||
78 | static int handle_one_fpga(struct fpga_irq_data *f, struct pt_regs *regs) | ||
79 | { | ||
80 | int handled = 0; | ||
81 | int irq; | ||
82 | u32 status; | ||
83 | |||
84 | while ((status = readl(f->base + IRQ_STATUS))) { | ||
85 | irq = ffs(status) - 1; | ||
86 | handle_IRQ(irq_find_mapping(f->domain, irq), regs); | ||
87 | handled = 1; | ||
88 | } | ||
89 | |||
90 | return handled; | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * Keep iterating over all registered FPGA IRQ controllers until there are | ||
95 | * no pending interrupts. | ||
96 | */ | ||
97 | asmlinkage void __exception_irq_entry fpga_handle_irq(struct pt_regs *regs) | ||
50 | { | 98 | { |
51 | unsigned int i; | 99 | int i, handled; |
52 | 100 | ||
101 | do { | ||
102 | for (i = 0, handled = 0; i < fpga_irq_id; ++i) | ||
103 | handled |= handle_one_fpga(&fpga_irq_devices[i], regs); | ||
104 | } while (handled); | ||
105 | } | ||
106 | |||
107 | static int fpga_irqdomain_map(struct irq_domain *d, unsigned int irq, | ||
108 | irq_hw_number_t hwirq) | ||
109 | { | ||
110 | struct fpga_irq_data *f = d->host_data; | ||
111 | |||
112 | /* Skip invalid IRQs, only register handlers for the real ones */ | ||
113 | if (!(f->valid & (1 << hwirq))) | ||
114 | return -ENOTSUPP; | ||
115 | irq_set_chip_data(irq, f); | ||
116 | irq_set_chip_and_handler(irq, &f->chip, | ||
117 | handle_level_irq); | ||
118 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
119 | f->used_irqs++; | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | static struct irq_domain_ops fpga_irqdomain_ops = { | ||
124 | .map = fpga_irqdomain_map, | ||
125 | .xlate = irq_domain_xlate_onetwocell, | ||
126 | }; | ||
127 | |||
128 | void __init fpga_irq_init(void __iomem *base, const char *name, int irq_start, | ||
129 | int parent_irq, u32 valid, struct device_node *node) | ||
130 | { | ||
131 | struct fpga_irq_data *f; | ||
132 | |||
133 | if (fpga_irq_id >= ARRAY_SIZE(fpga_irq_devices)) { | ||
134 | printk(KERN_ERR "%s: too few FPGA IRQ controllers, increase CONFIG_PLAT_VERSATILE_FPGA_IRQ_NR\n", __func__); | ||
135 | return; | ||
136 | } | ||
137 | |||
138 | f = &fpga_irq_devices[fpga_irq_id]; | ||
139 | f->base = base; | ||
140 | f->irq_start = irq_start; | ||
141 | f->chip.name = name; | ||
53 | f->chip.irq_ack = fpga_irq_mask; | 142 | f->chip.irq_ack = fpga_irq_mask; |
54 | f->chip.irq_mask = fpga_irq_mask; | 143 | f->chip.irq_mask = fpga_irq_mask; |
55 | f->chip.irq_unmask = fpga_irq_unmask; | 144 | f->chip.irq_unmask = fpga_irq_unmask; |
145 | f->valid = valid; | ||
56 | 146 | ||
57 | if (parent_irq != -1) { | 147 | if (parent_irq != -1) { |
58 | irq_set_handler_data(parent_irq, f); | 148 | irq_set_handler_data(parent_irq, f); |
59 | irq_set_chained_handler(parent_irq, fpga_irq_handle); | 149 | irq_set_chained_handler(parent_irq, fpga_irq_handle); |
60 | } | 150 | } |
61 | 151 | ||
62 | for (i = 0; i < 32; i++) { | 152 | f->domain = irq_domain_add_legacy(node, fls(valid), f->irq_start, 0, |
63 | if (valid & (1 << i)) { | 153 | &fpga_irqdomain_ops, f); |
64 | unsigned int irq = f->irq_start + i; | 154 | pr_info("FPGA IRQ chip %d \"%s\" @ %p, %u irqs\n", |
155 | fpga_irq_id, name, base, f->used_irqs); | ||
65 | 156 | ||
66 | irq_set_chip_data(irq, f); | 157 | fpga_irq_id++; |
67 | irq_set_chip_and_handler(irq, &f->chip, | ||
68 | handle_level_irq); | ||
69 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
70 | } | ||
71 | } | ||
72 | } | 158 | } |
diff --git a/arch/arm/plat-versatile/include/plat/fpga-irq.h b/arch/arm/plat-versatile/include/plat/fpga-irq.h index 627fafd1e595..91bcfb67551d 100644 --- a/arch/arm/plat-versatile/include/plat/fpga-irq.h +++ b/arch/arm/plat-versatile/include/plat/fpga-irq.h | |||
@@ -1,12 +1,11 @@ | |||
1 | #ifndef PLAT_FPGA_IRQ_H | 1 | #ifndef PLAT_FPGA_IRQ_H |
2 | #define PLAT_FPGA_IRQ_H | 2 | #define PLAT_FPGA_IRQ_H |
3 | 3 | ||
4 | struct fpga_irq_data { | 4 | struct device_node; |
5 | void __iomem *base; | 5 | struct pt_regs; |
6 | unsigned int irq_start; | ||
7 | struct irq_chip chip; | ||
8 | }; | ||
9 | 6 | ||
10 | void fpga_irq_init(int, u32, struct fpga_irq_data *); | 7 | void fpga_handle_irq(struct pt_regs *regs); |
8 | void fpga_irq_init(void __iomem *, const char *, int, int, u32, | ||
9 | struct device_node *node); | ||
11 | 10 | ||
12 | #endif | 11 | #endif |