diff options
author | Heiko Schocher <hs@denx.de> | 2012-05-30 06:18:57 -0400 |
---|---|---|
committer | Sekhar Nori <nsekhar@ti.com> | 2012-06-25 13:52:26 -0400 |
commit | 07caba966dee241cd6599618a243be721195de38 (patch) | |
tree | e42f0518b18fe1b3e9c3c1da16215b63e48e6c12 /arch/arm/mach-davinci | |
parent | 485802a6c524e62b5924849dd727ddbb1497cc71 (diff) |
ARM: davinci: cp_intc: Add irq domain support
Add irq domain support for DaVinci cp_intc.
Boot tested on AM18x EVM. Also tested with GPIO IRQ support on
AM18x EVM.
Signed-off-by: Heiko Schocher <hs@denx.de>
Cc: davinci-linux-open-source@linux.davincidsp.com
Cc: linux-arm-kernel@lists.infradead.org
Cc: devicetree-discuss@lists.ozlabs.org
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Sekhar Nori <nsekhar@ti.com>
Cc: Wolfgang Denk <wd@denx.de>
Cc: Sergei Shtylyov <sshtylyov@mvista.com>
[nsekhar@ti.com: add commit description, select IRQ_DOMAIN for CP_INTC
in Kconfig]
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
Diffstat (limited to 'arch/arm/mach-davinci')
-rw-r--r-- | arch/arm/mach-davinci/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-davinci/cp_intc.c | 63 |
2 files changed, 50 insertions, 14 deletions
diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig index 32d837d8eab9..2ce1ef07c13d 100644 --- a/arch/arm/mach-davinci/Kconfig +++ b/arch/arm/mach-davinci/Kconfig | |||
@@ -4,6 +4,7 @@ config AINTC | |||
4 | bool | 4 | bool |
5 | 5 | ||
6 | config CP_INTC | 6 | config CP_INTC |
7 | select IRQ_DOMAIN | ||
7 | bool | 8 | bool |
8 | 9 | ||
9 | config ARCH_DAVINCI_DMx | 10 | config ARCH_DAVINCI_DMx |
diff --git a/arch/arm/mach-davinci/cp_intc.c b/arch/arm/mach-davinci/cp_intc.c index f83152d643c5..45d52567ced7 100644 --- a/arch/arm/mach-davinci/cp_intc.c +++ b/arch/arm/mach-davinci/cp_intc.c | |||
@@ -9,8 +9,10 @@ | |||
9 | * kind, whether express or implied. | 9 | * kind, whether express or implied. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/export.h> | ||
12 | #include <linux/init.h> | 13 | #include <linux/init.h> |
13 | #include <linux/irq.h> | 14 | #include <linux/irq.h> |
15 | #include <linux/irqdomain.h> | ||
14 | #include <linux/io.h> | 16 | #include <linux/io.h> |
15 | 17 | ||
16 | #include <mach/common.h> | 18 | #include <mach/common.h> |
@@ -28,7 +30,7 @@ static inline void cp_intc_write(unsigned long value, unsigned offset) | |||
28 | 30 | ||
29 | static void cp_intc_ack_irq(struct irq_data *d) | 31 | static void cp_intc_ack_irq(struct irq_data *d) |
30 | { | 32 | { |
31 | cp_intc_write(d->irq, CP_INTC_SYS_STAT_IDX_CLR); | 33 | cp_intc_write(d->hwirq, CP_INTC_SYS_STAT_IDX_CLR); |
32 | } | 34 | } |
33 | 35 | ||
34 | /* Disable interrupt */ | 36 | /* Disable interrupt */ |
@@ -36,20 +38,20 @@ static void cp_intc_mask_irq(struct irq_data *d) | |||
36 | { | 38 | { |
37 | /* XXX don't know why we need to disable nIRQ here... */ | 39 | /* XXX don't know why we need to disable nIRQ here... */ |
38 | cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_CLR); | 40 | cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_CLR); |
39 | cp_intc_write(d->irq, CP_INTC_SYS_ENABLE_IDX_CLR); | 41 | cp_intc_write(d->hwirq, CP_INTC_SYS_ENABLE_IDX_CLR); |
40 | cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET); | 42 | cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET); |
41 | } | 43 | } |
42 | 44 | ||
43 | /* Enable interrupt */ | 45 | /* Enable interrupt */ |
44 | static void cp_intc_unmask_irq(struct irq_data *d) | 46 | static void cp_intc_unmask_irq(struct irq_data *d) |
45 | { | 47 | { |
46 | cp_intc_write(d->irq, CP_INTC_SYS_ENABLE_IDX_SET); | 48 | cp_intc_write(d->hwirq, CP_INTC_SYS_ENABLE_IDX_SET); |
47 | } | 49 | } |
48 | 50 | ||
49 | static int cp_intc_set_irq_type(struct irq_data *d, unsigned int flow_type) | 51 | static int cp_intc_set_irq_type(struct irq_data *d, unsigned int flow_type) |
50 | { | 52 | { |
51 | unsigned reg = BIT_WORD(d->irq); | 53 | unsigned reg = BIT_WORD(d->hwirq); |
52 | unsigned mask = BIT_MASK(d->irq); | 54 | unsigned mask = BIT_MASK(d->hwirq); |
53 | unsigned polarity = cp_intc_read(CP_INTC_SYS_POLARITY(reg)); | 55 | unsigned polarity = cp_intc_read(CP_INTC_SYS_POLARITY(reg)); |
54 | unsigned type = cp_intc_read(CP_INTC_SYS_TYPE(reg)); | 56 | unsigned type = cp_intc_read(CP_INTC_SYS_TYPE(reg)); |
55 | 57 | ||
@@ -99,18 +101,36 @@ static struct irq_chip cp_intc_irq_chip = { | |||
99 | .irq_set_wake = cp_intc_set_wake, | 101 | .irq_set_wake = cp_intc_set_wake, |
100 | }; | 102 | }; |
101 | 103 | ||
102 | void __init cp_intc_init(void) | 104 | static struct irq_domain *cp_intc_domain; |
105 | |||
106 | static int cp_intc_host_map(struct irq_domain *h, unsigned int virq, | ||
107 | irq_hw_number_t hw) | ||
108 | { | ||
109 | pr_debug("cp_intc_host_map(%d, 0x%lx)\n", virq, hw); | ||
110 | |||
111 | irq_set_chip(virq, &cp_intc_irq_chip); | ||
112 | set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); | ||
113 | irq_set_handler(virq, handle_edge_irq); | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | static const struct irq_domain_ops cp_intc_host_ops = { | ||
118 | .map = cp_intc_host_map, | ||
119 | .xlate = irq_domain_xlate_onetwocell, | ||
120 | }; | ||
121 | |||
122 | int __init __cp_intc_init(struct device_node *node) | ||
103 | { | 123 | { |
104 | unsigned long num_irq = davinci_soc_info.intc_irq_num; | 124 | u32 num_irq = davinci_soc_info.intc_irq_num; |
105 | u8 *irq_prio = davinci_soc_info.intc_irq_prios; | 125 | u8 *irq_prio = davinci_soc_info.intc_irq_prios; |
106 | u32 *host_map = davinci_soc_info.intc_host_map; | 126 | u32 *host_map = davinci_soc_info.intc_host_map; |
107 | unsigned num_reg = BITS_TO_LONGS(num_irq); | 127 | unsigned num_reg = BITS_TO_LONGS(num_irq); |
108 | int i; | 128 | int i, irq_base; |
109 | 129 | ||
110 | davinci_intc_type = DAVINCI_INTC_TYPE_CP_INTC; | 130 | davinci_intc_type = DAVINCI_INTC_TYPE_CP_INTC; |
111 | davinci_intc_base = ioremap(davinci_soc_info.intc_base, SZ_8K); | 131 | davinci_intc_base = ioremap(davinci_soc_info.intc_base, SZ_8K); |
112 | if (WARN_ON(!davinci_intc_base)) | 132 | if (WARN_ON(!davinci_intc_base)) |
113 | return; | 133 | return -EINVAL; |
114 | 134 | ||
115 | cp_intc_write(0, CP_INTC_GLOBAL_ENABLE); | 135 | cp_intc_write(0, CP_INTC_GLOBAL_ENABLE); |
116 | 136 | ||
@@ -165,13 +185,28 @@ void __init cp_intc_init(void) | |||
165 | for (i = 0; host_map[i] != -1; i++) | 185 | for (i = 0; host_map[i] != -1; i++) |
166 | cp_intc_write(host_map[i], CP_INTC_HOST_MAP(i)); | 186 | cp_intc_write(host_map[i], CP_INTC_HOST_MAP(i)); |
167 | 187 | ||
168 | /* Set up genirq dispatching for cp_intc */ | 188 | irq_base = irq_alloc_descs(-1, 0, num_irq, 0); |
169 | for (i = 0; i < num_irq; i++) { | 189 | if (irq_base < 0) { |
170 | irq_set_chip(i, &cp_intc_irq_chip); | 190 | pr_warn("Couldn't allocate IRQ numbers\n"); |
171 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); | 191 | irq_base = 0; |
172 | irq_set_handler(i, handle_edge_irq); | 192 | } |
193 | |||
194 | /* create a legacy host */ | ||
195 | cp_intc_domain = irq_domain_add_legacy(node, num_irq, | ||
196 | irq_base, 0, &cp_intc_host_ops, NULL); | ||
197 | |||
198 | if (!cp_intc_domain) { | ||
199 | pr_err("cp_intc: failed to allocate irq host!\n"); | ||
200 | return -EINVAL; | ||
173 | } | 201 | } |
174 | 202 | ||
175 | /* Enable global interrupt */ | 203 | /* Enable global interrupt */ |
176 | cp_intc_write(1, CP_INTC_GLOBAL_ENABLE); | 204 | cp_intc_write(1, CP_INTC_GLOBAL_ENABLE); |
205 | |||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | void __init cp_intc_init(void) | ||
210 | { | ||
211 | __cp_intc_init(NULL); | ||
177 | } | 212 | } |