diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/common/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/common/vic.c | 107 | ||||
-rw-r--r-- | arch/arm/include/asm/hardware/vic.h | 7 |
3 files changed, 86 insertions, 29 deletions
diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig index a11cee523cd4..10ca9749e94d 100644 --- a/arch/arm/common/Kconfig +++ b/arch/arm/common/Kconfig | |||
@@ -7,6 +7,7 @@ config GIC_NON_BANKED | |||
7 | bool | 7 | bool |
8 | 8 | ||
9 | config ARM_VIC | 9 | config ARM_VIC |
10 | select IRQ_DOMAIN | ||
10 | bool | 11 | bool |
11 | 12 | ||
12 | config ARM_VIC_NR | 13 | config ARM_VIC_NR |
diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c index 01f18a421b17..a227a7d53700 100644 --- a/arch/arm/common/vic.c +++ b/arch/arm/common/vic.c | |||
@@ -19,9 +19,14 @@ | |||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <linux/export.h> | ||
22 | #include <linux/init.h> | 23 | #include <linux/init.h> |
23 | #include <linux/list.h> | 24 | #include <linux/list.h> |
24 | #include <linux/io.h> | 25 | #include <linux/io.h> |
26 | #include <linux/irqdomain.h> | ||
27 | #include <linux/of.h> | ||
28 | #include <linux/of_address.h> | ||
29 | #include <linux/of_irq.h> | ||
25 | #include <linux/syscore_ops.h> | 30 | #include <linux/syscore_ops.h> |
26 | #include <linux/device.h> | 31 | #include <linux/device.h> |
27 | #include <linux/amba/bus.h> | 32 | #include <linux/amba/bus.h> |
@@ -29,7 +34,6 @@ | |||
29 | #include <asm/mach/irq.h> | 34 | #include <asm/mach/irq.h> |
30 | #include <asm/hardware/vic.h> | 35 | #include <asm/hardware/vic.h> |
31 | 36 | ||
32 | #ifdef CONFIG_PM | ||
33 | /** | 37 | /** |
34 | * struct vic_device - VIC PM device | 38 | * struct vic_device - VIC PM device |
35 | * @irq: The IRQ number for the base of the VIC. | 39 | * @irq: The IRQ number for the base of the VIC. |
@@ -40,6 +44,7 @@ | |||
40 | * @int_enable: Save for VIC_INT_ENABLE. | 44 | * @int_enable: Save for VIC_INT_ENABLE. |
41 | * @soft_int: Save for VIC_INT_SOFT. | 45 | * @soft_int: Save for VIC_INT_SOFT. |
42 | * @protect: Save for VIC_PROTECT. | 46 | * @protect: Save for VIC_PROTECT. |
47 | * @domain: The IRQ domain for the VIC. | ||
43 | */ | 48 | */ |
44 | struct vic_device { | 49 | struct vic_device { |
45 | void __iomem *base; | 50 | void __iomem *base; |
@@ -50,13 +55,13 @@ struct vic_device { | |||
50 | u32 int_enable; | 55 | u32 int_enable; |
51 | u32 soft_int; | 56 | u32 soft_int; |
52 | u32 protect; | 57 | u32 protect; |
58 | struct irq_domain domain; | ||
53 | }; | 59 | }; |
54 | 60 | ||
55 | /* we cannot allocate memory when VICs are initially registered */ | 61 | /* we cannot allocate memory when VICs are initially registered */ |
56 | static struct vic_device vic_devices[CONFIG_ARM_VIC_NR]; | 62 | static struct vic_device vic_devices[CONFIG_ARM_VIC_NR]; |
57 | 63 | ||
58 | static int vic_id; | 64 | static int vic_id; |
59 | #endif /* CONFIG_PM */ | ||
60 | 65 | ||
61 | /** | 66 | /** |
62 | * vic_init2 - common initialisation code | 67 | * vic_init2 - common initialisation code |
@@ -156,39 +161,50 @@ static int __init vic_pm_init(void) | |||
156 | return 0; | 161 | return 0; |
157 | } | 162 | } |
158 | late_initcall(vic_pm_init); | 163 | late_initcall(vic_pm_init); |
164 | #endif /* CONFIG_PM */ | ||
159 | 165 | ||
160 | /** | 166 | /** |
161 | * vic_pm_register - Register a VIC for later power management control | 167 | * vic_register() - Register a VIC. |
162 | * @base: The base address of the VIC. | 168 | * @base: The base address of the VIC. |
163 | * @irq: The base IRQ for the VIC. | 169 | * @irq: The base IRQ for the VIC. |
164 | * @resume_sources: bitmask of interrupts allowed for resume sources. | 170 | * @resume_sources: bitmask of interrupts allowed for resume sources. |
171 | * @node: The device tree node associated with the VIC. | ||
165 | * | 172 | * |
166 | * Register the VIC with the system device tree so that it can be notified | 173 | * Register the VIC with the system device tree so that it can be notified |
167 | * of suspend and resume requests and ensure that the correct actions are | 174 | * of suspend and resume requests and ensure that the correct actions are |
168 | * taken to re-instate the settings on resume. | 175 | * taken to re-instate the settings on resume. |
176 | * | ||
177 | * This also configures the IRQ domain for the VIC. | ||
169 | */ | 178 | */ |
170 | static void __init vic_pm_register(void __iomem *base, unsigned int irq, u32 resume_sources) | 179 | static void __init vic_register(void __iomem *base, unsigned int irq, |
180 | u32 resume_sources, struct device_node *node) | ||
171 | { | 181 | { |
172 | struct vic_device *v; | 182 | struct vic_device *v; |
173 | 183 | ||
174 | if (vic_id >= ARRAY_SIZE(vic_devices)) | 184 | if (vic_id >= ARRAY_SIZE(vic_devices)) { |
175 | printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__); | 185 | printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__); |
176 | else { | 186 | return; |
177 | v = &vic_devices[vic_id]; | ||
178 | v->base = base; | ||
179 | v->resume_sources = resume_sources; | ||
180 | v->irq = irq; | ||
181 | vic_id++; | ||
182 | } | 187 | } |
188 | |||
189 | v = &vic_devices[vic_id]; | ||
190 | v->base = base; | ||
191 | v->resume_sources = resume_sources; | ||
192 | v->irq = irq; | ||
193 | vic_id++; | ||
194 | |||
195 | v->domain.irq_base = irq; | ||
196 | v->domain.nr_irq = 32; | ||
197 | #ifdef CONFIG_OF_IRQ | ||
198 | v->domain.of_node = of_node_get(node); | ||
199 | v->domain.ops = &irq_domain_simple_ops; | ||
200 | #endif /* CONFIG_OF */ | ||
201 | irq_domain_add(&v->domain); | ||
183 | } | 202 | } |
184 | #else | ||
185 | static inline void vic_pm_register(void __iomem *base, unsigned int irq, u32 arg1) { } | ||
186 | #endif /* CONFIG_PM */ | ||
187 | 203 | ||
188 | static void vic_ack_irq(struct irq_data *d) | 204 | static void vic_ack_irq(struct irq_data *d) |
189 | { | 205 | { |
190 | void __iomem *base = irq_data_get_irq_chip_data(d); | 206 | void __iomem *base = irq_data_get_irq_chip_data(d); |
191 | unsigned int irq = d->irq & 31; | 207 | unsigned int irq = d->hwirq; |
192 | writel(1 << irq, base + VIC_INT_ENABLE_CLEAR); | 208 | writel(1 << irq, base + VIC_INT_ENABLE_CLEAR); |
193 | /* moreover, clear the soft-triggered, in case it was the reason */ | 209 | /* moreover, clear the soft-triggered, in case it was the reason */ |
194 | writel(1 << irq, base + VIC_INT_SOFT_CLEAR); | 210 | writel(1 << irq, base + VIC_INT_SOFT_CLEAR); |
@@ -197,14 +213,14 @@ static void vic_ack_irq(struct irq_data *d) | |||
197 | static void vic_mask_irq(struct irq_data *d) | 213 | static void vic_mask_irq(struct irq_data *d) |
198 | { | 214 | { |
199 | void __iomem *base = irq_data_get_irq_chip_data(d); | 215 | void __iomem *base = irq_data_get_irq_chip_data(d); |
200 | unsigned int irq = d->irq & 31; | 216 | unsigned int irq = d->hwirq; |
201 | writel(1 << irq, base + VIC_INT_ENABLE_CLEAR); | 217 | writel(1 << irq, base + VIC_INT_ENABLE_CLEAR); |
202 | } | 218 | } |
203 | 219 | ||
204 | static void vic_unmask_irq(struct irq_data *d) | 220 | static void vic_unmask_irq(struct irq_data *d) |
205 | { | 221 | { |
206 | void __iomem *base = irq_data_get_irq_chip_data(d); | 222 | void __iomem *base = irq_data_get_irq_chip_data(d); |
207 | unsigned int irq = d->irq & 31; | 223 | unsigned int irq = d->hwirq; |
208 | writel(1 << irq, base + VIC_INT_ENABLE); | 224 | writel(1 << irq, base + VIC_INT_ENABLE); |
209 | } | 225 | } |
210 | 226 | ||
@@ -226,7 +242,7 @@ static struct vic_device *vic_from_irq(unsigned int irq) | |||
226 | static int vic_set_wake(struct irq_data *d, unsigned int on) | 242 | static int vic_set_wake(struct irq_data *d, unsigned int on) |
227 | { | 243 | { |
228 | struct vic_device *v = vic_from_irq(d->irq); | 244 | struct vic_device *v = vic_from_irq(d->irq); |
229 | unsigned int off = d->irq & 31; | 245 | unsigned int off = d->hwirq; |
230 | u32 bit = 1 << off; | 246 | u32 bit = 1 << off; |
231 | 247 | ||
232 | if (!v) | 248 | if (!v) |
@@ -330,15 +346,9 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start, | |||
330 | vic_set_irq_sources(base, irq_start, vic_sources); | 346 | vic_set_irq_sources(base, irq_start, vic_sources); |
331 | } | 347 | } |
332 | 348 | ||
333 | /** | 349 | static void __init __vic_init(void __iomem *base, unsigned int irq_start, |
334 | * vic_init - initialise a vectored interrupt controller | 350 | u32 vic_sources, u32 resume_sources, |
335 | * @base: iomem base address | 351 | struct device_node *node) |
336 | * @irq_start: starting interrupt number, must be muliple of 32 | ||
337 | * @vic_sources: bitmask of interrupt sources to allow | ||
338 | * @resume_sources: bitmask of interrupt sources to allow for resume | ||
339 | */ | ||
340 | void __init vic_init(void __iomem *base, unsigned int irq_start, | ||
341 | u32 vic_sources, u32 resume_sources) | ||
342 | { | 352 | { |
343 | unsigned int i; | 353 | unsigned int i; |
344 | u32 cellid = 0; | 354 | u32 cellid = 0; |
@@ -375,5 +385,46 @@ void __init vic_init(void __iomem *base, unsigned int irq_start, | |||
375 | 385 | ||
376 | vic_set_irq_sources(base, irq_start, vic_sources); | 386 | vic_set_irq_sources(base, irq_start, vic_sources); |
377 | 387 | ||
378 | vic_pm_register(base, irq_start, resume_sources); | 388 | vic_register(base, irq_start, resume_sources, node); |
389 | } | ||
390 | |||
391 | /** | ||
392 | * vic_init() - initialise a vectored interrupt controller | ||
393 | * @base: iomem base address | ||
394 | * @irq_start: starting interrupt number, must be muliple of 32 | ||
395 | * @vic_sources: bitmask of interrupt sources to allow | ||
396 | * @resume_sources: bitmask of interrupt sources to allow for resume | ||
397 | */ | ||
398 | void __init vic_init(void __iomem *base, unsigned int irq_start, | ||
399 | u32 vic_sources, u32 resume_sources) | ||
400 | { | ||
401 | __vic_init(base, irq_start, vic_sources, resume_sources, NULL); | ||
402 | } | ||
403 | |||
404 | #ifdef CONFIG_OF | ||
405 | int __init vic_of_init(struct device_node *node, struct device_node *parent) | ||
406 | { | ||
407 | void __iomem *regs; | ||
408 | int irq_base; | ||
409 | |||
410 | if (WARN(parent, "non-root VICs are not supported")) | ||
411 | return -EINVAL; | ||
412 | |||
413 | regs = of_iomap(node, 0); | ||
414 | if (WARN_ON(!regs)) | ||
415 | return -EIO; | ||
416 | |||
417 | irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id()); | ||
418 | if (WARN_ON(irq_base < 0)) | ||
419 | goto out_unmap; | ||
420 | |||
421 | __vic_init(regs, irq_base, ~0, ~0, node); | ||
422 | |||
423 | return 0; | ||
424 | |||
425 | out_unmap: | ||
426 | iounmap(regs); | ||
427 | |||
428 | return -EIO; | ||
379 | } | 429 | } |
430 | #endif /* CONFIG OF */ | ||
diff --git a/arch/arm/include/asm/hardware/vic.h b/arch/arm/include/asm/hardware/vic.h index 5d72550a8097..b348a545de23 100644 --- a/arch/arm/include/asm/hardware/vic.h +++ b/arch/arm/include/asm/hardware/vic.h | |||
@@ -41,7 +41,12 @@ | |||
41 | #define VIC_PL192_VECT_ADDR 0xF00 | 41 | #define VIC_PL192_VECT_ADDR 0xF00 |
42 | 42 | ||
43 | #ifndef __ASSEMBLY__ | 43 | #ifndef __ASSEMBLY__ |
44 | #include <linux/compiler.h> | ||
45 | #include <linux/types.h> | ||
46 | |||
47 | struct device_node; | ||
44 | void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources); | 48 | void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources); |
45 | #endif | 49 | int vic_of_init(struct device_node *node, struct device_node *parent); |
46 | 50 | ||
51 | #endif /* __ASSEMBLY__ */ | ||
47 | #endif | 52 | #endif |