diff options
Diffstat (limited to 'arch/arm/mach-davinci/cp_intc.c')
-rw-r--r-- | arch/arm/mach-davinci/cp_intc.c | 75 |
1 files changed, 60 insertions, 15 deletions
diff --git a/arch/arm/mach-davinci/cp_intc.c b/arch/arm/mach-davinci/cp_intc.c index f83152d643c5..006dae8dfe44 100644 --- a/arch/arm/mach-davinci/cp_intc.c +++ b/arch/arm/mach-davinci/cp_intc.c | |||
@@ -9,9 +9,14 @@ | |||
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> |
17 | #include <linux/of.h> | ||
18 | #include <linux/of_address.h> | ||
19 | #include <linux/of_irq.h> | ||
15 | 20 | ||
16 | #include <mach/common.h> | 21 | #include <mach/common.h> |
17 | #include <mach/cp_intc.h> | 22 | #include <mach/cp_intc.h> |
@@ -28,7 +33,7 @@ static inline void cp_intc_write(unsigned long value, unsigned offset) | |||
28 | 33 | ||
29 | static void cp_intc_ack_irq(struct irq_data *d) | 34 | static void cp_intc_ack_irq(struct irq_data *d) |
30 | { | 35 | { |
31 | cp_intc_write(d->irq, CP_INTC_SYS_STAT_IDX_CLR); | 36 | cp_intc_write(d->hwirq, CP_INTC_SYS_STAT_IDX_CLR); |
32 | } | 37 | } |
33 | 38 | ||
34 | /* Disable interrupt */ | 39 | /* Disable interrupt */ |
@@ -36,20 +41,20 @@ static void cp_intc_mask_irq(struct irq_data *d) | |||
36 | { | 41 | { |
37 | /* XXX don't know why we need to disable nIRQ here... */ | 42 | /* XXX don't know why we need to disable nIRQ here... */ |
38 | cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_CLR); | 43 | cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_CLR); |
39 | cp_intc_write(d->irq, CP_INTC_SYS_ENABLE_IDX_CLR); | 44 | cp_intc_write(d->hwirq, CP_INTC_SYS_ENABLE_IDX_CLR); |
40 | cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET); | 45 | cp_intc_write(1, CP_INTC_HOST_ENABLE_IDX_SET); |
41 | } | 46 | } |
42 | 47 | ||
43 | /* Enable interrupt */ | 48 | /* Enable interrupt */ |
44 | static void cp_intc_unmask_irq(struct irq_data *d) | 49 | static void cp_intc_unmask_irq(struct irq_data *d) |
45 | { | 50 | { |
46 | cp_intc_write(d->irq, CP_INTC_SYS_ENABLE_IDX_SET); | 51 | cp_intc_write(d->hwirq, CP_INTC_SYS_ENABLE_IDX_SET); |
47 | } | 52 | } |
48 | 53 | ||
49 | static int cp_intc_set_irq_type(struct irq_data *d, unsigned int flow_type) | 54 | static int cp_intc_set_irq_type(struct irq_data *d, unsigned int flow_type) |
50 | { | 55 | { |
51 | unsigned reg = BIT_WORD(d->irq); | 56 | unsigned reg = BIT_WORD(d->hwirq); |
52 | unsigned mask = BIT_MASK(d->irq); | 57 | unsigned mask = BIT_MASK(d->hwirq); |
53 | unsigned polarity = cp_intc_read(CP_INTC_SYS_POLARITY(reg)); | 58 | unsigned polarity = cp_intc_read(CP_INTC_SYS_POLARITY(reg)); |
54 | unsigned type = cp_intc_read(CP_INTC_SYS_TYPE(reg)); | 59 | unsigned type = cp_intc_read(CP_INTC_SYS_TYPE(reg)); |
55 | 60 | ||
@@ -99,18 +104,43 @@ static struct irq_chip cp_intc_irq_chip = { | |||
99 | .irq_set_wake = cp_intc_set_wake, | 104 | .irq_set_wake = cp_intc_set_wake, |
100 | }; | 105 | }; |
101 | 106 | ||
102 | void __init cp_intc_init(void) | 107 | static struct irq_domain *cp_intc_domain; |
108 | |||
109 | static int cp_intc_host_map(struct irq_domain *h, unsigned int virq, | ||
110 | irq_hw_number_t hw) | ||
103 | { | 111 | { |
104 | unsigned long num_irq = davinci_soc_info.intc_irq_num; | 112 | pr_debug("cp_intc_host_map(%d, 0x%lx)\n", virq, hw); |
113 | |||
114 | irq_set_chip(virq, &cp_intc_irq_chip); | ||
115 | set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); | ||
116 | irq_set_handler(virq, handle_edge_irq); | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | static const struct irq_domain_ops cp_intc_host_ops = { | ||
121 | .map = cp_intc_host_map, | ||
122 | .xlate = irq_domain_xlate_onetwocell, | ||
123 | }; | ||
124 | |||
125 | int __init cp_intc_of_init(struct device_node *node, struct device_node *parent) | ||
126 | { | ||
127 | u32 num_irq = davinci_soc_info.intc_irq_num; | ||
105 | u8 *irq_prio = davinci_soc_info.intc_irq_prios; | 128 | u8 *irq_prio = davinci_soc_info.intc_irq_prios; |
106 | u32 *host_map = davinci_soc_info.intc_host_map; | 129 | u32 *host_map = davinci_soc_info.intc_host_map; |
107 | unsigned num_reg = BITS_TO_LONGS(num_irq); | 130 | unsigned num_reg = BITS_TO_LONGS(num_irq); |
108 | int i; | 131 | int i, irq_base; |
109 | 132 | ||
110 | davinci_intc_type = DAVINCI_INTC_TYPE_CP_INTC; | 133 | davinci_intc_type = DAVINCI_INTC_TYPE_CP_INTC; |
111 | davinci_intc_base = ioremap(davinci_soc_info.intc_base, SZ_8K); | 134 | if (node) { |
135 | davinci_intc_base = of_iomap(node, 0); | ||
136 | if (of_property_read_u32(node, "ti,intc-size", &num_irq)) | ||
137 | pr_warn("unable to get intc-size, default to %d\n", | ||
138 | num_irq); | ||
139 | } else { | ||
140 | davinci_intc_base = ioremap(davinci_soc_info.intc_base, SZ_8K); | ||
141 | } | ||
112 | if (WARN_ON(!davinci_intc_base)) | 142 | if (WARN_ON(!davinci_intc_base)) |
113 | return; | 143 | return -EINVAL; |
114 | 144 | ||
115 | cp_intc_write(0, CP_INTC_GLOBAL_ENABLE); | 145 | cp_intc_write(0, CP_INTC_GLOBAL_ENABLE); |
116 | 146 | ||
@@ -165,13 +195,28 @@ void __init cp_intc_init(void) | |||
165 | for (i = 0; host_map[i] != -1; i++) | 195 | for (i = 0; host_map[i] != -1; i++) |
166 | cp_intc_write(host_map[i], CP_INTC_HOST_MAP(i)); | 196 | cp_intc_write(host_map[i], CP_INTC_HOST_MAP(i)); |
167 | 197 | ||
168 | /* Set up genirq dispatching for cp_intc */ | 198 | irq_base = irq_alloc_descs(-1, 0, num_irq, 0); |
169 | for (i = 0; i < num_irq; i++) { | 199 | if (irq_base < 0) { |
170 | irq_set_chip(i, &cp_intc_irq_chip); | 200 | pr_warn("Couldn't allocate IRQ numbers\n"); |
171 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); | 201 | irq_base = 0; |
172 | irq_set_handler(i, handle_edge_irq); | 202 | } |
203 | |||
204 | /* create a legacy host */ | ||
205 | cp_intc_domain = irq_domain_add_legacy(node, num_irq, | ||
206 | irq_base, 0, &cp_intc_host_ops, NULL); | ||
207 | |||
208 | if (!cp_intc_domain) { | ||
209 | pr_err("cp_intc: failed to allocate irq host!\n"); | ||
210 | return -EINVAL; | ||
173 | } | 211 | } |
174 | 212 | ||
175 | /* Enable global interrupt */ | 213 | /* Enable global interrupt */ |
176 | cp_intc_write(1, CP_INTC_GLOBAL_ENABLE); | 214 | cp_intc_write(1, CP_INTC_GLOBAL_ENABLE); |
215 | |||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | void __init cp_intc_init(void) | ||
220 | { | ||
221 | cp_intc_of_init(NULL, NULL); | ||
177 | } | 222 | } |