diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2014-10-03 03:02:33 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2014-10-03 03:02:33 -0400 |
commit | 2828c9cdb8bd30f49c48210c014ccdd4cb994931 (patch) | |
tree | a91d42306e6aca87407df53dfce0d4a9e4eb8e0e | |
parent | db985cbd67c45f875ef43cb5febfaa8cbd203c27 (diff) | |
parent | fae119b6d427a087be0c6a85431c1b8ee9ffea96 (diff) |
Merge tag 'irqchip-core-3.18-2' of git://git.infradead.org/users/jcooper/linux into irq/core
irqchip core changes for v3.18 (round 2) from Jason Cooper
* atmel:
- Add sama5d4 support
- Correct # irqs for sama5d3
* broadcom:
- Add bcm7120 l2 interrupt controller and DT binding
* gic-v3:
- Add CPU PM notifier
- Add enable/disable support to gic_enable_redist
-rw-r--r-- | Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt | 2 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt | 86 | ||||
-rw-r--r-- | drivers/irqchip/Makefile | 3 | ||||
-rw-r--r-- | drivers/irqchip/irq-atmel-aic5.c | 12 | ||||
-rw-r--r-- | drivers/irqchip/irq-bcm7120-l2.c | 219 | ||||
-rw-r--r-- | drivers/irqchip/irq-gic-v3.c | 87 |
6 files changed, 385 insertions, 24 deletions
diff --git a/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt b/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt index 2742e9cfd6b1..f292917fa00d 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | Required properties: | 3 | Required properties: |
4 | - compatible: Should be "atmel,<chip>-aic" | 4 | - compatible: Should be "atmel,<chip>-aic" |
5 | <chip> can be "at91rm9200" or "sama5d3" | 5 | <chip> can be "at91rm9200", "sama5d3" or "sama5d4" |
6 | - interrupt-controller: Identifies the node as an interrupt controller. | 6 | - interrupt-controller: Identifies the node as an interrupt controller. |
7 | - interrupt-parent: For single AIC system, it is an empty property. | 7 | - interrupt-parent: For single AIC system, it is an empty property. |
8 | - #interrupt-cells: The number of cells to define the interrupts. It should be 3. | 8 | - #interrupt-cells: The number of cells to define the interrupts. It should be 3. |
diff --git a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt new file mode 100644 index 000000000000..ff812a8a82bc --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt | |||
@@ -0,0 +1,86 @@ | |||
1 | Broadcom BCM7120-style Level 2 interrupt controller | ||
2 | |||
3 | This interrupt controller hardware is a second level interrupt controller that | ||
4 | is hooked to a parent interrupt controller: e.g: ARM GIC for ARM-based | ||
5 | platforms. It can be found on BCM7xxx products starting with BCM7120. | ||
6 | |||
7 | Such an interrupt controller has the following hardware design: | ||
8 | |||
9 | - outputs multiple interrupts signals towards its interrupt controller parent | ||
10 | |||
11 | - controls how some of the interrupts will be flowing, whether they will | ||
12 | directly output an interrupt signal towards the interrupt controller parent, | ||
13 | or if they will output an interrupt signal at this 2nd level interrupt | ||
14 | controller, in particular for UARTs | ||
15 | |||
16 | - not all 32-bits within the interrupt controller actually map to an interrupt | ||
17 | |||
18 | The typical hardware layout for this controller is represented below: | ||
19 | |||
20 | 2nd level interrupt line Outputs for the parent controller (e.g: ARM GIC) | ||
21 | |||
22 | 0 -----[ MUX ] ------------|==========> GIC interrupt 75 | ||
23 | \-----------\ | ||
24 | | | ||
25 | 1 -----[ MUX ] --------)---|==========> GIC interrupt 76 | ||
26 | \------------| | ||
27 | | | ||
28 | 2 -----[ MUX ] --------)---|==========> GIC interrupt 77 | ||
29 | \------------| | ||
30 | | | ||
31 | 3 ---------------------| | ||
32 | 4 ---------------------| | ||
33 | 5 ---------------------| | ||
34 | 7 ---------------------|---|===========> GIC interrupt 66 | ||
35 | 9 ---------------------| | ||
36 | 10 --------------------| | ||
37 | 11 --------------------/ | ||
38 | |||
39 | 6 ------------------------\ | ||
40 | |===========> GIC interrupt 64 | ||
41 | 8 ------------------------/ | ||
42 | |||
43 | 12 ........................ X | ||
44 | 13 ........................ X (not connected) | ||
45 | .. | ||
46 | 31 ........................ X | ||
47 | |||
48 | Required properties: | ||
49 | |||
50 | - compatible: should be "brcm,bcm7120-l2-intc" | ||
51 | - reg: specifies the base physical address and size of the registers | ||
52 | - interrupt-controller: identifies the node as an interrupt controller | ||
53 | - #interrupt-cells: specifies the number of cells needed to encode an interrupt | ||
54 | source, should be 1. | ||
55 | - interrupt-parent: specifies the phandle to the parent interrupt controller | ||
56 | this one is cascaded from | ||
57 | - interrupts: specifies the interrupt line(s) in the interrupt-parent controller | ||
58 | node, valid values depend on the type of parent interrupt controller | ||
59 | - brcm,int-map-mask: 32-bits bit mask describing how many and which interrupts | ||
60 | are wired to this 2nd level interrupt controller, and how they match their | ||
61 | respective interrupt parents. Should match exactly the number of interrupts | ||
62 | specified in the 'interrupts' property. | ||
63 | |||
64 | Optional properties: | ||
65 | |||
66 | - brcm,irq-can-wake: if present, this means the L2 controller can be used as a | ||
67 | wakeup source for system suspend/resume. | ||
68 | |||
69 | - brcm,int-fwd-mask: if present, a 32-bits bit mask to configure for the | ||
70 | interrupts which have a mux gate, typically UARTs. Setting these bits will | ||
71 | make their respective interrupts outputs bypass this 2nd level interrupt | ||
72 | controller completely, it completely transparent for the interrupt controller | ||
73 | parent | ||
74 | |||
75 | Example: | ||
76 | |||
77 | irq0_intc: interrupt-controller@f0406800 { | ||
78 | compatible = "brcm,bcm7120-l2-intc"; | ||
79 | interrupt-parent = <&intc>; | ||
80 | #interrupt-cells = <1>; | ||
81 | reg = <0xf0406800 0x8>; | ||
82 | interrupt-controller; | ||
83 | interrupts = <0x0 0x42 0x0>, <0x0 0x40 0x0>; | ||
84 | brcm,int-map-mask = <0xeb8>, <0x140>; | ||
85 | brcm,int-fwd-mask = <0x7>; | ||
86 | }; | ||
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index fc2e4f77d3db..bec790678016 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile | |||
@@ -34,5 +34,6 @@ obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o | |||
34 | obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o | 34 | obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o |
35 | obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o | 35 | obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o |
36 | obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o | 36 | obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o |
37 | obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o | 37 | obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o \ |
38 | irq-bcm7120-l2.o | ||
38 | obj-$(CONFIG_KEYSTONE_IRQ) += irq-keystone.o | 39 | obj-$(CONFIG_KEYSTONE_IRQ) += irq-keystone.o |
diff --git a/drivers/irqchip/irq-atmel-aic5.c b/drivers/irqchip/irq-atmel-aic5.c index 04fe2c1b5178..a11aae8fb006 100644 --- a/drivers/irqchip/irq-atmel-aic5.c +++ b/drivers/irqchip/irq-atmel-aic5.c | |||
@@ -295,6 +295,7 @@ static void __init sama5d3_aic_irq_fixup(struct device_node *root) | |||
295 | 295 | ||
296 | static const struct of_device_id __initdata aic5_irq_fixups[] = { | 296 | static const struct of_device_id __initdata aic5_irq_fixups[] = { |
297 | { .compatible = "atmel,sama5d3", .data = sama5d3_aic_irq_fixup }, | 297 | { .compatible = "atmel,sama5d3", .data = sama5d3_aic_irq_fixup }, |
298 | { .compatible = "atmel,sama5d4", .data = sama5d3_aic_irq_fixup }, | ||
298 | { /* sentinel */ }, | 299 | { /* sentinel */ }, |
299 | }; | 300 | }; |
300 | 301 | ||
@@ -341,7 +342,7 @@ static int __init aic5_of_init(struct device_node *node, | |||
341 | return 0; | 342 | return 0; |
342 | } | 343 | } |
343 | 344 | ||
344 | #define NR_SAMA5D3_IRQS 50 | 345 | #define NR_SAMA5D3_IRQS 48 |
345 | 346 | ||
346 | static int __init sama5d3_aic5_of_init(struct device_node *node, | 347 | static int __init sama5d3_aic5_of_init(struct device_node *node, |
347 | struct device_node *parent) | 348 | struct device_node *parent) |
@@ -349,3 +350,12 @@ static int __init sama5d3_aic5_of_init(struct device_node *node, | |||
349 | return aic5_of_init(node, parent, NR_SAMA5D3_IRQS); | 350 | return aic5_of_init(node, parent, NR_SAMA5D3_IRQS); |
350 | } | 351 | } |
351 | IRQCHIP_DECLARE(sama5d3_aic5, "atmel,sama5d3-aic", sama5d3_aic5_of_init); | 352 | IRQCHIP_DECLARE(sama5d3_aic5, "atmel,sama5d3-aic", sama5d3_aic5_of_init); |
353 | |||
354 | #define NR_SAMA5D4_IRQS 68 | ||
355 | |||
356 | static int __init sama5d4_aic5_of_init(struct device_node *node, | ||
357 | struct device_node *parent) | ||
358 | { | ||
359 | return aic5_of_init(node, parent, NR_SAMA5D4_IRQS); | ||
360 | } | ||
361 | IRQCHIP_DECLARE(sama5d4_aic5, "atmel,sama5d4-aic", sama5d4_aic5_of_init); | ||
diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c new file mode 100644 index 000000000000..b9f4fb808e49 --- /dev/null +++ b/drivers/irqchip/irq-bcm7120-l2.c | |||
@@ -0,0 +1,219 @@ | |||
1 | /* | ||
2 | * Broadcom BCM7120 style Level 2 interrupt controller driver | ||
3 | * | ||
4 | * Copyright (C) 2014 Broadcom Corporation | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
12 | |||
13 | #include <linux/init.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/of.h> | ||
18 | #include <linux/of_irq.h> | ||
19 | #include <linux/of_address.h> | ||
20 | #include <linux/of_platform.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/irq.h> | ||
23 | #include <linux/io.h> | ||
24 | #include <linux/irqdomain.h> | ||
25 | #include <linux/reboot.h> | ||
26 | #include <linux/irqchip/chained_irq.h> | ||
27 | |||
28 | #include "irqchip.h" | ||
29 | |||
30 | #include <asm/mach/irq.h> | ||
31 | |||
32 | /* Register offset in the L2 interrupt controller */ | ||
33 | #define IRQEN 0x00 | ||
34 | #define IRQSTAT 0x04 | ||
35 | |||
36 | struct bcm7120_l2_intc_data { | ||
37 | void __iomem *base; | ||
38 | struct irq_domain *domain; | ||
39 | bool can_wake; | ||
40 | u32 irq_fwd_mask; | ||
41 | u32 irq_map_mask; | ||
42 | u32 saved_mask; | ||
43 | }; | ||
44 | |||
45 | static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc) | ||
46 | { | ||
47 | struct bcm7120_l2_intc_data *b = irq_desc_get_handler_data(desc); | ||
48 | struct irq_chip *chip = irq_desc_get_chip(desc); | ||
49 | u32 status; | ||
50 | |||
51 | chained_irq_enter(chip, desc); | ||
52 | |||
53 | status = __raw_readl(b->base + IRQSTAT); | ||
54 | |||
55 | if (status == 0) { | ||
56 | do_bad_IRQ(irq, desc); | ||
57 | goto out; | ||
58 | } | ||
59 | |||
60 | do { | ||
61 | irq = ffs(status) - 1; | ||
62 | status &= ~(1 << irq); | ||
63 | generic_handle_irq(irq_find_mapping(b->domain, irq)); | ||
64 | } while (status); | ||
65 | |||
66 | out: | ||
67 | chained_irq_exit(chip, desc); | ||
68 | } | ||
69 | |||
70 | static void bcm7120_l2_intc_suspend(struct irq_data *d) | ||
71 | { | ||
72 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
73 | struct bcm7120_l2_intc_data *b = gc->private; | ||
74 | u32 reg; | ||
75 | |||
76 | irq_gc_lock(gc); | ||
77 | /* Save the current mask and the interrupt forward mask */ | ||
78 | b->saved_mask = __raw_readl(b->base) | b->irq_fwd_mask; | ||
79 | if (b->can_wake) { | ||
80 | reg = b->saved_mask | gc->wake_active; | ||
81 | __raw_writel(reg, b->base); | ||
82 | } | ||
83 | irq_gc_unlock(gc); | ||
84 | } | ||
85 | |||
86 | static void bcm7120_l2_intc_resume(struct irq_data *d) | ||
87 | { | ||
88 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
89 | struct bcm7120_l2_intc_data *b = gc->private; | ||
90 | |||
91 | /* Restore the saved mask */ | ||
92 | irq_gc_lock(gc); | ||
93 | __raw_writel(b->saved_mask, b->base); | ||
94 | irq_gc_unlock(gc); | ||
95 | } | ||
96 | |||
97 | static int bcm7120_l2_intc_init_one(struct device_node *dn, | ||
98 | struct bcm7120_l2_intc_data *data, | ||
99 | int irq, const __be32 *map_mask) | ||
100 | { | ||
101 | int parent_irq; | ||
102 | |||
103 | parent_irq = irq_of_parse_and_map(dn, irq); | ||
104 | if (parent_irq < 0) { | ||
105 | pr_err("failed to map interrupt %d\n", irq); | ||
106 | return parent_irq; | ||
107 | } | ||
108 | |||
109 | data->irq_map_mask |= be32_to_cpup(map_mask + irq); | ||
110 | |||
111 | irq_set_handler_data(parent_irq, data); | ||
112 | irq_set_chained_handler(parent_irq, bcm7120_l2_intc_irq_handle); | ||
113 | |||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | int __init bcm7120_l2_intc_of_init(struct device_node *dn, | ||
118 | struct device_node *parent) | ||
119 | { | ||
120 | unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; | ||
121 | struct bcm7120_l2_intc_data *data; | ||
122 | struct irq_chip_generic *gc; | ||
123 | struct irq_chip_type *ct; | ||
124 | const __be32 *map_mask; | ||
125 | int num_parent_irqs; | ||
126 | int ret = 0, len, irq; | ||
127 | |||
128 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
129 | if (!data) | ||
130 | return -ENOMEM; | ||
131 | |||
132 | data->base = of_iomap(dn, 0); | ||
133 | if (!data->base) { | ||
134 | pr_err("failed to remap intc L2 registers\n"); | ||
135 | ret = -ENOMEM; | ||
136 | goto out_free; | ||
137 | } | ||
138 | |||
139 | if (of_property_read_u32(dn, "brcm,int-fwd-mask", &data->irq_fwd_mask)) | ||
140 | data->irq_fwd_mask = 0; | ||
141 | |||
142 | /* Enable all interrupt specified in the interrupt forward mask and have | ||
143 | * the other disabled | ||
144 | */ | ||
145 | __raw_writel(data->irq_fwd_mask, data->base + IRQEN); | ||
146 | |||
147 | num_parent_irqs = of_irq_count(dn); | ||
148 | if (num_parent_irqs <= 0) { | ||
149 | pr_err("invalid number of parent interrupts\n"); | ||
150 | ret = -ENOMEM; | ||
151 | goto out_unmap; | ||
152 | } | ||
153 | |||
154 | map_mask = of_get_property(dn, "brcm,int-map-mask", &len); | ||
155 | if (!map_mask || (len != (sizeof(*map_mask) * num_parent_irqs))) { | ||
156 | pr_err("invalid brcm,int-map-mask property\n"); | ||
157 | ret = -EINVAL; | ||
158 | goto out_unmap; | ||
159 | } | ||
160 | |||
161 | for (irq = 0; irq < num_parent_irqs; irq++) { | ||
162 | ret = bcm7120_l2_intc_init_one(dn, data, irq, map_mask); | ||
163 | if (ret) | ||
164 | goto out_unmap; | ||
165 | } | ||
166 | |||
167 | data->domain = irq_domain_add_linear(dn, 32, | ||
168 | &irq_generic_chip_ops, NULL); | ||
169 | if (!data->domain) { | ||
170 | ret = -ENOMEM; | ||
171 | goto out_unmap; | ||
172 | } | ||
173 | |||
174 | ret = irq_alloc_domain_generic_chips(data->domain, 32, 1, | ||
175 | dn->full_name, handle_level_irq, clr, 0, | ||
176 | IRQ_GC_INIT_MASK_CACHE); | ||
177 | if (ret) { | ||
178 | pr_err("failed to allocate generic irq chip\n"); | ||
179 | goto out_free_domain; | ||
180 | } | ||
181 | |||
182 | gc = irq_get_domain_generic_chip(data->domain, 0); | ||
183 | gc->unused = 0xfffffff & ~data->irq_map_mask; | ||
184 | gc->reg_base = data->base; | ||
185 | gc->private = data; | ||
186 | ct = gc->chip_types; | ||
187 | |||
188 | ct->regs.mask = IRQEN; | ||
189 | ct->chip.irq_mask = irq_gc_mask_clr_bit; | ||
190 | ct->chip.irq_unmask = irq_gc_mask_set_bit; | ||
191 | ct->chip.irq_ack = irq_gc_noop; | ||
192 | ct->chip.irq_suspend = bcm7120_l2_intc_suspend; | ||
193 | ct->chip.irq_resume = bcm7120_l2_intc_resume; | ||
194 | |||
195 | if (of_property_read_bool(dn, "brcm,irq-can-wake")) { | ||
196 | data->can_wake = true; | ||
197 | /* This IRQ chip can wake the system, set all relevant child | ||
198 | * interupts in wake_enabled mask | ||
199 | */ | ||
200 | gc->wake_enabled = 0xffffffff; | ||
201 | gc->wake_enabled &= ~gc->unused; | ||
202 | ct->chip.irq_set_wake = irq_gc_set_wake; | ||
203 | } | ||
204 | |||
205 | pr_info("registered BCM7120 L2 intc (mem: 0x%p, parent IRQ(s): %d)\n", | ||
206 | data->base, num_parent_irqs); | ||
207 | |||
208 | return 0; | ||
209 | |||
210 | out_free_domain: | ||
211 | irq_domain_remove(data->domain); | ||
212 | out_unmap: | ||
213 | iounmap(data->base); | ||
214 | out_free: | ||
215 | kfree(data); | ||
216 | return ret; | ||
217 | } | ||
218 | IRQCHIP_DECLARE(brcmstb_l2_intc, "brcm,bcm7120-l2-intc", | ||
219 | bcm7120_l2_intc_of_init); | ||
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 9e3144975696..7247a3cc7ba1 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c | |||
@@ -16,6 +16,7 @@ | |||
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/cpu.h> | 18 | #include <linux/cpu.h> |
19 | #include <linux/cpu_pm.h> | ||
19 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
20 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
21 | #include <linux/of.h> | 22 | #include <linux/of.h> |
@@ -155,7 +156,7 @@ static void gic_enable_sre(void) | |||
155 | pr_err("GIC: unable to set SRE (disabled at EL2), panic ahead\n"); | 156 | pr_err("GIC: unable to set SRE (disabled at EL2), panic ahead\n"); |
156 | } | 157 | } |
157 | 158 | ||
158 | static void gic_enable_redist(void) | 159 | static void gic_enable_redist(bool enable) |
159 | { | 160 | { |
160 | void __iomem *rbase; | 161 | void __iomem *rbase; |
161 | u32 count = 1000000; /* 1s! */ | 162 | u32 count = 1000000; /* 1s! */ |
@@ -163,20 +164,30 @@ static void gic_enable_redist(void) | |||
163 | 164 | ||
164 | rbase = gic_data_rdist_rd_base(); | 165 | rbase = gic_data_rdist_rd_base(); |
165 | 166 | ||
166 | /* Wake up this CPU redistributor */ | ||
167 | val = readl_relaxed(rbase + GICR_WAKER); | 167 | val = readl_relaxed(rbase + GICR_WAKER); |
168 | val &= ~GICR_WAKER_ProcessorSleep; | 168 | if (enable) |
169 | /* Wake up this CPU redistributor */ | ||
170 | val &= ~GICR_WAKER_ProcessorSleep; | ||
171 | else | ||
172 | val |= GICR_WAKER_ProcessorSleep; | ||
169 | writel_relaxed(val, rbase + GICR_WAKER); | 173 | writel_relaxed(val, rbase + GICR_WAKER); |
170 | 174 | ||
171 | while (readl_relaxed(rbase + GICR_WAKER) & GICR_WAKER_ChildrenAsleep) { | 175 | if (!enable) { /* Check that GICR_WAKER is writeable */ |
172 | count--; | 176 | val = readl_relaxed(rbase + GICR_WAKER); |
173 | if (!count) { | 177 | if (!(val & GICR_WAKER_ProcessorSleep)) |
174 | pr_err_ratelimited("redist didn't wake up...\n"); | 178 | return; /* No PM support in this redistributor */ |
175 | return; | 179 | } |
176 | } | 180 | |
181 | while (count--) { | ||
182 | val = readl_relaxed(rbase + GICR_WAKER); | ||
183 | if (enable ^ (val & GICR_WAKER_ChildrenAsleep)) | ||
184 | break; | ||
177 | cpu_relax(); | 185 | cpu_relax(); |
178 | udelay(1); | 186 | udelay(1); |
179 | }; | 187 | }; |
188 | if (!count) | ||
189 | pr_err_ratelimited("redistributor failed to %s...\n", | ||
190 | enable ? "wakeup" : "sleep"); | ||
180 | } | 191 | } |
181 | 192 | ||
182 | /* | 193 | /* |
@@ -372,6 +383,21 @@ static int gic_populate_rdist(void) | |||
372 | return -ENODEV; | 383 | return -ENODEV; |
373 | } | 384 | } |
374 | 385 | ||
386 | static void gic_cpu_sys_reg_init(void) | ||
387 | { | ||
388 | /* Enable system registers */ | ||
389 | gic_enable_sre(); | ||
390 | |||
391 | /* Set priority mask register */ | ||
392 | gic_write_pmr(DEFAULT_PMR_VALUE); | ||
393 | |||
394 | /* EOI deactivates interrupt too (mode 0) */ | ||
395 | gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop_dir); | ||
396 | |||
397 | /* ... and let's hit the road... */ | ||
398 | gic_write_grpen1(1); | ||
399 | } | ||
400 | |||
375 | static void gic_cpu_init(void) | 401 | static void gic_cpu_init(void) |
376 | { | 402 | { |
377 | void __iomem *rbase; | 403 | void __iomem *rbase; |
@@ -380,23 +406,14 @@ static void gic_cpu_init(void) | |||
380 | if (gic_populate_rdist()) | 406 | if (gic_populate_rdist()) |
381 | return; | 407 | return; |
382 | 408 | ||
383 | gic_enable_redist(); | 409 | gic_enable_redist(true); |
384 | 410 | ||
385 | rbase = gic_data_rdist_sgi_base(); | 411 | rbase = gic_data_rdist_sgi_base(); |
386 | 412 | ||
387 | gic_cpu_config(rbase, gic_redist_wait_for_rwp); | 413 | gic_cpu_config(rbase, gic_redist_wait_for_rwp); |
388 | 414 | ||
389 | /* Enable system registers */ | 415 | /* initialise system registers */ |
390 | gic_enable_sre(); | 416 | gic_cpu_sys_reg_init(); |
391 | |||
392 | /* Set priority mask register */ | ||
393 | gic_write_pmr(DEFAULT_PMR_VALUE); | ||
394 | |||
395 | /* EOI deactivates interrupt too (mode 0) */ | ||
396 | gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop_dir); | ||
397 | |||
398 | /* ... and let's hit the road... */ | ||
399 | gic_write_grpen1(1); | ||
400 | } | 417 | } |
401 | 418 | ||
402 | #ifdef CONFIG_SMP | 419 | #ifdef CONFIG_SMP |
@@ -532,6 +549,33 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, | |||
532 | #define gic_smp_init() do { } while(0) | 549 | #define gic_smp_init() do { } while(0) |
533 | #endif | 550 | #endif |
534 | 551 | ||
552 | #ifdef CONFIG_CPU_PM | ||
553 | static int gic_cpu_pm_notifier(struct notifier_block *self, | ||
554 | unsigned long cmd, void *v) | ||
555 | { | ||
556 | if (cmd == CPU_PM_EXIT) { | ||
557 | gic_enable_redist(true); | ||
558 | gic_cpu_sys_reg_init(); | ||
559 | } else if (cmd == CPU_PM_ENTER) { | ||
560 | gic_write_grpen1(0); | ||
561 | gic_enable_redist(false); | ||
562 | } | ||
563 | return NOTIFY_OK; | ||
564 | } | ||
565 | |||
566 | static struct notifier_block gic_cpu_pm_notifier_block = { | ||
567 | .notifier_call = gic_cpu_pm_notifier, | ||
568 | }; | ||
569 | |||
570 | static void gic_cpu_pm_init(void) | ||
571 | { | ||
572 | cpu_pm_register_notifier(&gic_cpu_pm_notifier_block); | ||
573 | } | ||
574 | |||
575 | #else | ||
576 | static inline void gic_cpu_pm_init(void) { } | ||
577 | #endif /* CONFIG_CPU_PM */ | ||
578 | |||
535 | static struct irq_chip gic_chip = { | 579 | static struct irq_chip gic_chip = { |
536 | .name = "GICv3", | 580 | .name = "GICv3", |
537 | .irq_mask = gic_mask_irq, | 581 | .irq_mask = gic_mask_irq, |
@@ -671,6 +715,7 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare | |||
671 | gic_smp_init(); | 715 | gic_smp_init(); |
672 | gic_dist_init(); | 716 | gic_dist_init(); |
673 | gic_cpu_init(); | 717 | gic_cpu_init(); |
718 | gic_cpu_pm_init(); | ||
674 | 719 | ||
675 | return 0; | 720 | return 0; |
676 | 721 | ||