aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Cooper <jason@lakedaemon.net>2015-04-10 18:57:58 -0400
committerJason Cooper <jason@lakedaemon.net>2015-04-10 18:57:58 -0400
commitfb414e908b15ae3d704aa0572f77981a516279b9 (patch)
treed0e464382dee546548ddc0d5a06b961d09a33da2
parent07c523f1493b6860662e74a3d7e1ae0e7d67d416 (diff)
parentd4ad0759cdb1c2d0971801f8876365dddea56695 (diff)
Merge branch 'irqchip/stacked-exynos' into irqchip/core
-rw-r--r--Documentation/devicetree/bindings/arm/samsung/pmu.txt17
-rw-r--r--arch/arm/boot/dts/exynos3250.dtsi4
-rw-r--r--arch/arm/boot/dts/exynos4.dtsi4
-rw-r--r--arch/arm/boot/dts/exynos5250.dtsi4
-rw-r--r--arch/arm/boot/dts/exynos5420.dtsi4
-rw-r--r--arch/arm/mach-exynos/exynos.c15
-rw-r--r--arch/arm/mach-exynos/suspend.c135
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
32Optional properties:
33
34Some PMUs are capable of behaving as an interrupt controller (mostly
35to wake up a suspended PMU). In which case, they can have the
36following 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
32Example : 46Example :
33pmu_system_controller: system-controller@10040000 { 47pmu_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 */
169static const struct of_device_id exynos_dt_pmu_match[] = { 174static 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
194static void __init exynos_init_irq(void) 189static 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 */
50struct exynos_wkup_irq { 52struct exynos_wkup_irq {
@@ -93,14 +95,14 @@ static const struct exynos_wkup_irq exynos3250_wkup_irq[] = {
93}; 95};
94 96
95static const struct exynos_wkup_irq exynos4_wkup_irq[] = { 97static 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
101static const struct exynos_wkup_irq exynos5250_wkup_irq[] = { 103static 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
172static 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
184static 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
203static 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
228static 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
234static 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
271EXYNOS_PMU_IRQ(exynos3250_pmu_irq, "samsung,exynos3250-pmu");
272EXYNOS_PMU_IRQ(exynos4210_pmu_irq, "samsung,exynos4210-pmu");
273EXYNOS_PMU_IRQ(exynos4212_pmu_irq, "samsung,exynos4212-pmu");
274EXYNOS_PMU_IRQ(exynos4412_pmu_irq, "samsung,exynos4412-pmu");
275EXYNOS_PMU_IRQ(exynos4415_pmu_irq, "samsung,exynos4415-pmu");
276EXYNOS_PMU_IRQ(exynos5250_pmu_irq, "samsung,exynos5250-pmu");
277EXYNOS_PMU_IRQ(exynos5420_pmu_irq, "samsung,exynos5420-pmu");
278
170static int exynos_cpu_do_idle(void) 279static 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;
615void __init exynos_pm_init(void) 724void __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);