diff options
author | Jason Cooper <jason@lakedaemon.net> | 2015-04-10 18:57:58 -0400 |
---|---|---|
committer | Jason Cooper <jason@lakedaemon.net> | 2015-04-10 18:57:58 -0400 |
commit | fb414e908b15ae3d704aa0572f77981a516279b9 (patch) | |
tree | d0e464382dee546548ddc0d5a06b961d09a33da2 | |
parent | 07c523f1493b6860662e74a3d7e1ae0e7d67d416 (diff) | |
parent | d4ad0759cdb1c2d0971801f8876365dddea56695 (diff) |
Merge branch 'irqchip/stacked-exynos' into irqchip/core
-rw-r--r-- | Documentation/devicetree/bindings/arm/samsung/pmu.txt | 17 | ||||
-rw-r--r-- | arch/arm/boot/dts/exynos3250.dtsi | 4 | ||||
-rw-r--r-- | arch/arm/boot/dts/exynos4.dtsi | 4 | ||||
-rw-r--r-- | arch/arm/boot/dts/exynos5250.dtsi | 4 | ||||
-rw-r--r-- | arch/arm/boot/dts/exynos5420.dtsi | 4 | ||||
-rw-r--r-- | arch/arm/mach-exynos/exynos.c | 15 | ||||
-rw-r--r-- | arch/arm/mach-exynos/suspend.c | 135 |
7 files changed, 161 insertions, 22 deletions
diff --git a/Documentation/devicetree/bindings/arm/samsung/pmu.txt b/Documentation/devicetree/bindings/arm/samsung/pmu.txt index 67b211381f2b..2d6356d8daf4 100644 --- a/Documentation/devicetree/bindings/arm/samsung/pmu.txt +++ b/Documentation/devicetree/bindings/arm/samsung/pmu.txt | |||
@@ -29,10 +29,27 @@ Properties: | |||
29 | - clocks : list of phandles and specifiers to all input clocks listed in | 29 | - clocks : list of phandles and specifiers to all input clocks listed in |
30 | clock-names property. | 30 | clock-names property. |
31 | 31 | ||
32 | Optional properties: | ||
33 | |||
34 | Some PMUs are capable of behaving as an interrupt controller (mostly | ||
35 | to wake up a suspended PMU). In which case, they can have the | ||
36 | following properties: | ||
37 | |||
38 | - interrupt-controller: indicate that said PMU is an interrupt controller | ||
39 | |||
40 | - #interrupt-cells: must be identical to the that of the parent interrupt | ||
41 | controller. | ||
42 | |||
43 | - interrupt-parent: a phandle indicating which interrupt controller | ||
44 | this PMU signals interrupts to. | ||
45 | |||
32 | Example : | 46 | Example : |
33 | pmu_system_controller: system-controller@10040000 { | 47 | pmu_system_controller: system-controller@10040000 { |
34 | compatible = "samsung,exynos5250-pmu", "syscon"; | 48 | compatible = "samsung,exynos5250-pmu", "syscon"; |
35 | reg = <0x10040000 0x5000>; | 49 | reg = <0x10040000 0x5000>; |
50 | interrupt-controller; | ||
51 | #interrupt-cells = <3>; | ||
52 | interrupt-parent = <&gic>; | ||
36 | #clock-cells = <1>; | 53 | #clock-cells = <1>; |
37 | clock-names = "clkout0", "clkout1", "clkout2", "clkout3", | 54 | clock-names = "clkout0", "clkout1", "clkout2", "clkout3", |
38 | "clkout4", "clkout8", "clkout9"; | 55 | "clkout4", "clkout8", "clkout9"; |
diff --git a/arch/arm/boot/dts/exynos3250.dtsi b/arch/arm/boot/dts/exynos3250.dtsi index 277b48b0b6f9..580b21095eab 100644 --- a/arch/arm/boot/dts/exynos3250.dtsi +++ b/arch/arm/boot/dts/exynos3250.dtsi | |||
@@ -130,6 +130,9 @@ | |||
130 | pmu_system_controller: system-controller@10020000 { | 130 | pmu_system_controller: system-controller@10020000 { |
131 | compatible = "samsung,exynos3250-pmu", "syscon"; | 131 | compatible = "samsung,exynos3250-pmu", "syscon"; |
132 | reg = <0x10020000 0x4000>; | 132 | reg = <0x10020000 0x4000>; |
133 | interrupt-controller; | ||
134 | #interrupt-cells = <3>; | ||
135 | interrupt-parent = <&gic>; | ||
133 | }; | 136 | }; |
134 | 137 | ||
135 | mipi_phy: video-phy@10020710 { | 138 | mipi_phy: video-phy@10020710 { |
@@ -184,6 +187,7 @@ | |||
184 | compatible = "samsung,exynos3250-rtc"; | 187 | compatible = "samsung,exynos3250-rtc"; |
185 | reg = <0x10070000 0x100>; | 188 | reg = <0x10070000 0x100>; |
186 | interrupts = <0 73 0>, <0 74 0>; | 189 | interrupts = <0 73 0>, <0 74 0>; |
190 | interrupt-parent = <&pmu_system_controller>; | ||
187 | status = "disabled"; | 191 | status = "disabled"; |
188 | }; | 192 | }; |
189 | 193 | ||
diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi index 76173cacd450..1d21f0272390 100644 --- a/arch/arm/boot/dts/exynos4.dtsi +++ b/arch/arm/boot/dts/exynos4.dtsi | |||
@@ -152,6 +152,9 @@ | |||
152 | pmu_system_controller: system-controller@10020000 { | 152 | pmu_system_controller: system-controller@10020000 { |
153 | compatible = "samsung,exynos4210-pmu", "syscon"; | 153 | compatible = "samsung,exynos4210-pmu", "syscon"; |
154 | reg = <0x10020000 0x4000>; | 154 | reg = <0x10020000 0x4000>; |
155 | interrupt-controller; | ||
156 | #interrupt-cells = <3>; | ||
157 | interrupt-parent = <&gic>; | ||
155 | }; | 158 | }; |
156 | 159 | ||
157 | dsi_0: dsi@11C80000 { | 160 | dsi_0: dsi@11C80000 { |
@@ -264,6 +267,7 @@ | |||
264 | rtc@10070000 { | 267 | rtc@10070000 { |
265 | compatible = "samsung,s3c6410-rtc"; | 268 | compatible = "samsung,s3c6410-rtc"; |
266 | reg = <0x10070000 0x100>; | 269 | reg = <0x10070000 0x100>; |
270 | interrupt-parent = <&pmu_system_controller>; | ||
267 | interrupts = <0 44 0>, <0 45 0>; | 271 | interrupts = <0 44 0>, <0 45 0>; |
268 | clocks = <&clock CLK_RTC>; | 272 | clocks = <&clock CLK_RTC>; |
269 | clock-names = "rtc"; | 273 | clock-names = "rtc"; |
diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index 9bb1b0b738f5..72fa2d196629 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi | |||
@@ -196,6 +196,9 @@ | |||
196 | clock-names = "clkout16"; | 196 | clock-names = "clkout16"; |
197 | clocks = <&clock CLK_FIN_PLL>; | 197 | clocks = <&clock CLK_FIN_PLL>; |
198 | #clock-cells = <1>; | 198 | #clock-cells = <1>; |
199 | interrupt-controller; | ||
200 | #interrupt-cells = <3>; | ||
201 | interrupt-parent = <&gic>; | ||
199 | }; | 202 | }; |
200 | 203 | ||
201 | sysreg_system_controller: syscon@10050000 { | 204 | sysreg_system_controller: syscon@10050000 { |
@@ -232,6 +235,7 @@ | |||
232 | rtc: rtc@101E0000 { | 235 | rtc: rtc@101E0000 { |
233 | clocks = <&clock CLK_RTC>; | 236 | clocks = <&clock CLK_RTC>; |
234 | clock-names = "rtc"; | 237 | clock-names = "rtc"; |
238 | interrupt-parent = <&pmu_system_controller>; | ||
235 | status = "disabled"; | 239 | status = "disabled"; |
236 | }; | 240 | }; |
237 | 241 | ||
diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi index 9dc2e9773b30..d11a6ab4ecd2 100644 --- a/arch/arm/boot/dts/exynos5420.dtsi +++ b/arch/arm/boot/dts/exynos5420.dtsi | |||
@@ -327,6 +327,7 @@ | |||
327 | rtc: rtc@101E0000 { | 327 | rtc: rtc@101E0000 { |
328 | clocks = <&clock CLK_RTC>; | 328 | clocks = <&clock CLK_RTC>; |
329 | clock-names = "rtc"; | 329 | clock-names = "rtc"; |
330 | interrupt-parent = <&pmu_system_controller>; | ||
330 | status = "disabled"; | 331 | status = "disabled"; |
331 | }; | 332 | }; |
332 | 333 | ||
@@ -769,6 +770,9 @@ | |||
769 | clock-names = "clkout16"; | 770 | clock-names = "clkout16"; |
770 | clocks = <&clock CLK_FIN_PLL>; | 771 | clocks = <&clock CLK_FIN_PLL>; |
771 | #clock-cells = <1>; | 772 | #clock-cells = <1>; |
773 | interrupt-controller; | ||
774 | #interrupt-cells = <3>; | ||
775 | interrupt-parent = <&gic>; | ||
772 | }; | 776 | }; |
773 | 777 | ||
774 | sysreg_system_controller: syscon@10050000 { | 778 | sysreg_system_controller: syscon@10050000 { |
diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c index 9e9dfdfad9d7..f44c2e05c82e 100644 --- a/arch/arm/mach-exynos/exynos.c +++ b/arch/arm/mach-exynos/exynos.c | |||
@@ -166,16 +166,14 @@ static void __init exynos_init_io(void) | |||
166 | exynos_map_io(); | 166 | exynos_map_io(); |
167 | } | 167 | } |
168 | 168 | ||
169 | /* | ||
170 | * Apparently, these SoCs are not able to wake-up from suspend using | ||
171 | * the PMU. Too bad. Should they suddenly become capable of such a | ||
172 | * feat, the matches below should be moved to suspend.c. | ||
173 | */ | ||
169 | static const struct of_device_id exynos_dt_pmu_match[] = { | 174 | static const struct of_device_id exynos_dt_pmu_match[] = { |
170 | { .compatible = "samsung,exynos3250-pmu" }, | ||
171 | { .compatible = "samsung,exynos4210-pmu" }, | ||
172 | { .compatible = "samsung,exynos4212-pmu" }, | ||
173 | { .compatible = "samsung,exynos4412-pmu" }, | ||
174 | { .compatible = "samsung,exynos4415-pmu" }, | ||
175 | { .compatible = "samsung,exynos5250-pmu" }, | ||
176 | { .compatible = "samsung,exynos5260-pmu" }, | 175 | { .compatible = "samsung,exynos5260-pmu" }, |
177 | { .compatible = "samsung,exynos5410-pmu" }, | 176 | { .compatible = "samsung,exynos5410-pmu" }, |
178 | { .compatible = "samsung,exynos5420-pmu" }, | ||
179 | { /*sentinel*/ }, | 177 | { /*sentinel*/ }, |
180 | }; | 178 | }; |
181 | 179 | ||
@@ -186,9 +184,6 @@ static void exynos_map_pmu(void) | |||
186 | np = of_find_matching_node(NULL, exynos_dt_pmu_match); | 184 | np = of_find_matching_node(NULL, exynos_dt_pmu_match); |
187 | if (np) | 185 | if (np) |
188 | pmu_base_addr = of_iomap(np, 0); | 186 | pmu_base_addr = of_iomap(np, 0); |
189 | |||
190 | if (!pmu_base_addr) | ||
191 | panic("failed to find exynos pmu register\n"); | ||
192 | } | 187 | } |
193 | 188 | ||
194 | static void __init exynos_init_irq(void) | 189 | static void __init exynos_init_irq(void) |
diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c index 52e2b1a2fddb..7b09e7631245 100644 --- a/arch/arm/mach-exynos/suspend.c +++ b/arch/arm/mach-exynos/suspend.c | |||
@@ -18,7 +18,9 @@ | |||
18 | #include <linux/syscore_ops.h> | 18 | #include <linux/syscore_ops.h> |
19 | #include <linux/cpu_pm.h> | 19 | #include <linux/cpu_pm.h> |
20 | #include <linux/io.h> | 20 | #include <linux/io.h> |
21 | #include <linux/irqchip/arm-gic.h> | 21 | #include <linux/irq.h> |
22 | #include <linux/irqdomain.h> | ||
23 | #include <linux/of_address.h> | ||
22 | #include <linux/err.h> | 24 | #include <linux/err.h> |
23 | #include <linux/regulator/machine.h> | 25 | #include <linux/regulator/machine.h> |
24 | 26 | ||
@@ -43,8 +45,8 @@ | |||
43 | #define EXYNOS5420_CPU_STATE 0x28 | 45 | #define EXYNOS5420_CPU_STATE 0x28 |
44 | 46 | ||
45 | /** | 47 | /** |
46 | * struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping | 48 | * struct exynos_wkup_irq - PMU IRQ to mask mapping |
47 | * @hwirq: Hardware IRQ signal of the GIC | 49 | * @hwirq: Hardware IRQ signal of the PMU |
48 | * @mask: Mask in PMU wake-up mask register | 50 | * @mask: Mask in PMU wake-up mask register |
49 | */ | 51 | */ |
50 | struct exynos_wkup_irq { | 52 | struct exynos_wkup_irq { |
@@ -93,14 +95,14 @@ static const struct exynos_wkup_irq exynos3250_wkup_irq[] = { | |||
93 | }; | 95 | }; |
94 | 96 | ||
95 | static const struct exynos_wkup_irq exynos4_wkup_irq[] = { | 97 | static const struct exynos_wkup_irq exynos4_wkup_irq[] = { |
96 | { 76, BIT(1) }, /* RTC alarm */ | 98 | { 44, BIT(1) }, /* RTC alarm */ |
97 | { 77, BIT(2) }, /* RTC tick */ | 99 | { 45, BIT(2) }, /* RTC tick */ |
98 | { /* sentinel */ }, | 100 | { /* sentinel */ }, |
99 | }; | 101 | }; |
100 | 102 | ||
101 | static const struct exynos_wkup_irq exynos5250_wkup_irq[] = { | 103 | static const struct exynos_wkup_irq exynos5250_wkup_irq[] = { |
102 | { 75, BIT(1) }, /* RTC alarm */ | 104 | { 43, BIT(1) }, /* RTC alarm */ |
103 | { 76, BIT(2) }, /* RTC tick */ | 105 | { 44, BIT(2) }, /* RTC tick */ |
104 | { /* sentinel */ }, | 106 | { /* sentinel */ }, |
105 | }; | 107 | }; |
106 | 108 | ||
@@ -167,6 +169,113 @@ static int exynos_irq_set_wake(struct irq_data *data, unsigned int state) | |||
167 | return -ENOENT; | 169 | return -ENOENT; |
168 | } | 170 | } |
169 | 171 | ||
172 | static struct irq_chip exynos_pmu_chip = { | ||
173 | .name = "PMU", | ||
174 | .irq_eoi = irq_chip_eoi_parent, | ||
175 | .irq_mask = irq_chip_mask_parent, | ||
176 | .irq_unmask = irq_chip_unmask_parent, | ||
177 | .irq_retrigger = irq_chip_retrigger_hierarchy, | ||
178 | .irq_set_wake = exynos_irq_set_wake, | ||
179 | #ifdef CONFIG_SMP | ||
180 | .irq_set_affinity = irq_chip_set_affinity_parent, | ||
181 | #endif | ||
182 | }; | ||
183 | |||
184 | static int exynos_pmu_domain_xlate(struct irq_domain *domain, | ||
185 | struct device_node *controller, | ||
186 | const u32 *intspec, | ||
187 | unsigned int intsize, | ||
188 | unsigned long *out_hwirq, | ||
189 | unsigned int *out_type) | ||
190 | { | ||
191 | if (domain->of_node != controller) | ||
192 | return -EINVAL; /* Shouldn't happen, really... */ | ||
193 | if (intsize != 3) | ||
194 | return -EINVAL; /* Not GIC compliant */ | ||
195 | if (intspec[0] != 0) | ||
196 | return -EINVAL; /* No PPI should point to this domain */ | ||
197 | |||
198 | *out_hwirq = intspec[1]; | ||
199 | *out_type = intspec[2]; | ||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | static int exynos_pmu_domain_alloc(struct irq_domain *domain, | ||
204 | unsigned int virq, | ||
205 | unsigned int nr_irqs, void *data) | ||
206 | { | ||
207 | struct of_phandle_args *args = data; | ||
208 | struct of_phandle_args parent_args; | ||
209 | irq_hw_number_t hwirq; | ||
210 | int i; | ||
211 | |||
212 | if (args->args_count != 3) | ||
213 | return -EINVAL; /* Not GIC compliant */ | ||
214 | if (args->args[0] != 0) | ||
215 | return -EINVAL; /* No PPI should point to this domain */ | ||
216 | |||
217 | hwirq = args->args[1]; | ||
218 | |||
219 | for (i = 0; i < nr_irqs; i++) | ||
220 | irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, | ||
221 | &exynos_pmu_chip, NULL); | ||
222 | |||
223 | parent_args = *args; | ||
224 | parent_args.np = domain->parent->of_node; | ||
225 | return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_args); | ||
226 | } | ||
227 | |||
228 | static struct irq_domain_ops exynos_pmu_domain_ops = { | ||
229 | .xlate = exynos_pmu_domain_xlate, | ||
230 | .alloc = exynos_pmu_domain_alloc, | ||
231 | .free = irq_domain_free_irqs_common, | ||
232 | }; | ||
233 | |||
234 | static int __init exynos_pmu_irq_init(struct device_node *node, | ||
235 | struct device_node *parent) | ||
236 | { | ||
237 | struct irq_domain *parent_domain, *domain; | ||
238 | |||
239 | if (!parent) { | ||
240 | pr_err("%s: no parent, giving up\n", node->full_name); | ||
241 | return -ENODEV; | ||
242 | } | ||
243 | |||
244 | parent_domain = irq_find_host(parent); | ||
245 | if (!parent_domain) { | ||
246 | pr_err("%s: unable to obtain parent domain\n", node->full_name); | ||
247 | return -ENXIO; | ||
248 | } | ||
249 | |||
250 | pmu_base_addr = of_iomap(node, 0); | ||
251 | |||
252 | if (!pmu_base_addr) { | ||
253 | pr_err("%s: failed to find exynos pmu register\n", | ||
254 | node->full_name); | ||
255 | return -ENOMEM; | ||
256 | } | ||
257 | |||
258 | domain = irq_domain_add_hierarchy(parent_domain, 0, 0, | ||
259 | node, &exynos_pmu_domain_ops, | ||
260 | NULL); | ||
261 | if (!domain) { | ||
262 | iounmap(pmu_base_addr); | ||
263 | return -ENOMEM; | ||
264 | } | ||
265 | |||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | #define EXYNOS_PMU_IRQ(symbol, name) OF_DECLARE_2(irqchip, symbol, name, exynos_pmu_irq_init) | ||
270 | |||
271 | EXYNOS_PMU_IRQ(exynos3250_pmu_irq, "samsung,exynos3250-pmu"); | ||
272 | EXYNOS_PMU_IRQ(exynos4210_pmu_irq, "samsung,exynos4210-pmu"); | ||
273 | EXYNOS_PMU_IRQ(exynos4212_pmu_irq, "samsung,exynos4212-pmu"); | ||
274 | EXYNOS_PMU_IRQ(exynos4412_pmu_irq, "samsung,exynos4412-pmu"); | ||
275 | EXYNOS_PMU_IRQ(exynos4415_pmu_irq, "samsung,exynos4415-pmu"); | ||
276 | EXYNOS_PMU_IRQ(exynos5250_pmu_irq, "samsung,exynos5250-pmu"); | ||
277 | EXYNOS_PMU_IRQ(exynos5420_pmu_irq, "samsung,exynos5420-pmu"); | ||
278 | |||
170 | static int exynos_cpu_do_idle(void) | 279 | static int exynos_cpu_do_idle(void) |
171 | { | 280 | { |
172 | /* issue the standby signal into the pm unit. */ | 281 | /* issue the standby signal into the pm unit. */ |
@@ -615,17 +724,19 @@ static struct syscore_ops exynos_pm_syscore_ops; | |||
615 | void __init exynos_pm_init(void) | 724 | void __init exynos_pm_init(void) |
616 | { | 725 | { |
617 | const struct of_device_id *match; | 726 | const struct of_device_id *match; |
727 | struct device_node *np; | ||
618 | u32 tmp; | 728 | u32 tmp; |
619 | 729 | ||
620 | of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match); | 730 | np = of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match); |
621 | if (!match) { | 731 | if (!np) { |
622 | pr_err("Failed to find PMU node\n"); | 732 | pr_err("Failed to find PMU node\n"); |
623 | return; | 733 | return; |
624 | } | 734 | } |
625 | pm_data = (struct exynos_pm_data *) match->data; | ||
626 | 735 | ||
627 | /* Platform-specific GIC callback */ | 736 | if (WARN_ON(!of_find_property(np, "interrupt-controller", NULL))) |
628 | gic_arch_extn.irq_set_wake = exynos_irq_set_wake; | 737 | pr_warn("Outdated DT detected, suspend/resume will NOT work\n"); |
738 | |||
739 | pm_data = (struct exynos_pm_data *) match->data; | ||
629 | 740 | ||
630 | /* All wakeup disable */ | 741 | /* All wakeup disable */ |
631 | tmp = pmu_raw_readl(S5P_WAKEUP_MASK); | 742 | tmp = pmu_raw_readl(S5P_WAKEUP_MASK); |