aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/boot/dts/imx6qdl.dtsi7
-rw-r--r--arch/arm/boot/dts/imx6sl.dtsi6
-rw-r--r--arch/arm/boot/dts/imx6sx.dtsi6
-rw-r--r--arch/arm/mach-imx/common.h1
-rw-r--r--arch/arm/mach-imx/gpc.c127
-rw-r--r--arch/arm/mach-imx/mach-imx6q.c1
-rw-r--r--arch/arm/mach-imx/mach-imx6sl.c1
-rw-r--r--arch/arm/mach-imx/mach-imx6sx.c1
-rw-r--r--arch/arm/mach-imx/pm-imx6.c6
9 files changed, 123 insertions, 33 deletions
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 1b6f380e7eaa..da09dc456814 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -53,6 +53,7 @@
53 interrupt-controller; 53 interrupt-controller;
54 reg = <0x00a01000 0x1000>, 54 reg = <0x00a01000 0x1000>,
55 <0x00a00100 0x100>; 55 <0x00a00100 0x100>;
56 interrupt-parent = <&intc>;
56 }; 57 };
57 58
58 clocks { 59 clocks {
@@ -82,7 +83,7 @@
82 #address-cells = <1>; 83 #address-cells = <1>;
83 #size-cells = <1>; 84 #size-cells = <1>;
84 compatible = "simple-bus"; 85 compatible = "simple-bus";
85 interrupt-parent = <&intc>; 86 interrupt-parent = <&gpc>;
86 ranges; 87 ranges;
87 88
88 dma_apbh: dma-apbh@00110000 { 89 dma_apbh: dma-apbh@00110000 {
@@ -122,6 +123,7 @@
122 compatible = "arm,cortex-a9-twd-timer"; 123 compatible = "arm,cortex-a9-twd-timer";
123 reg = <0x00a00600 0x20>; 124 reg = <0x00a00600 0x20>;
124 interrupts = <1 13 0xf01>; 125 interrupts = <1 13 0xf01>;
126 interrupt-parent = <&intc>;
125 clocks = <&clks IMX6QDL_CLK_TWD>; 127 clocks = <&clks IMX6QDL_CLK_TWD>;
126 }; 128 };
127 129
@@ -693,8 +695,11 @@
693 gpc: gpc@020dc000 { 695 gpc: gpc@020dc000 {
694 compatible = "fsl,imx6q-gpc"; 696 compatible = "fsl,imx6q-gpc";
695 reg = <0x020dc000 0x4000>; 697 reg = <0x020dc000 0x4000>;
698 interrupt-controller;
699 #interrupt-cells = <3>;
696 interrupts = <0 89 IRQ_TYPE_LEVEL_HIGH>, 700 interrupts = <0 89 IRQ_TYPE_LEVEL_HIGH>,
697 <0 90 IRQ_TYPE_LEVEL_HIGH>; 701 <0 90 IRQ_TYPE_LEVEL_HIGH>;
702 interrupt-parent = <&intc>;
698 }; 703 };
699 704
700 gpr: iomuxc-gpr@020e0000 { 705 gpr: iomuxc-gpr@020e0000 {
diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi
index 36ab8e054cee..0d0962bf37c4 100644
--- a/arch/arm/boot/dts/imx6sl.dtsi
+++ b/arch/arm/boot/dts/imx6sl.dtsi
@@ -72,6 +72,7 @@
72 interrupt-controller; 72 interrupt-controller;
73 reg = <0x00a01000 0x1000>, 73 reg = <0x00a01000 0x1000>,
74 <0x00a00100 0x100>; 74 <0x00a00100 0x100>;
75 interrupt-parent = <&intc>;
75 }; 76 };
76 77
77 clocks { 78 clocks {
@@ -95,7 +96,7 @@
95 #address-cells = <1>; 96 #address-cells = <1>;
96 #size-cells = <1>; 97 #size-cells = <1>;
97 compatible = "simple-bus"; 98 compatible = "simple-bus";
98 interrupt-parent = <&intc>; 99 interrupt-parent = <&gpc>;
99 ranges; 100 ranges;
100 101
101 ocram: sram@00900000 { 102 ocram: sram@00900000 {
@@ -603,7 +604,10 @@
603 gpc: gpc@020dc000 { 604 gpc: gpc@020dc000 {
604 compatible = "fsl,imx6sl-gpc", "fsl,imx6q-gpc"; 605 compatible = "fsl,imx6sl-gpc", "fsl,imx6q-gpc";
605 reg = <0x020dc000 0x4000>; 606 reg = <0x020dc000 0x4000>;
607 interrupt-controller;
608 #interrupt-cells = <3>;
606 interrupts = <0 89 IRQ_TYPE_LEVEL_HIGH>; 609 interrupts = <0 89 IRQ_TYPE_LEVEL_HIGH>;
610 interrupt-parent = <&intc>;
607 }; 611 };
608 612
609 gpr: iomuxc-gpr@020e0000 { 613 gpr: iomuxc-gpr@020e0000 {
diff --git a/arch/arm/boot/dts/imx6sx.dtsi b/arch/arm/boot/dts/imx6sx.dtsi
index 7a24fee1e7ae..dabaf89a5dd9 100644
--- a/arch/arm/boot/dts/imx6sx.dtsi
+++ b/arch/arm/boot/dts/imx6sx.dtsi
@@ -88,6 +88,7 @@
88 interrupt-controller; 88 interrupt-controller;
89 reg = <0x00a01000 0x1000>, 89 reg = <0x00a01000 0x1000>,
90 <0x00a00100 0x100>; 90 <0x00a00100 0x100>;
91 interrupt-parent = <&intc>;
91 }; 92 };
92 93
93 clocks { 94 clocks {
@@ -131,7 +132,7 @@
131 #address-cells = <1>; 132 #address-cells = <1>;
132 #size-cells = <1>; 133 #size-cells = <1>;
133 compatible = "simple-bus"; 134 compatible = "simple-bus";
134 interrupt-parent = <&intc>; 135 interrupt-parent = <&gpc>;
135 ranges; 136 ranges;
136 137
137 pmu { 138 pmu {
@@ -700,7 +701,10 @@
700 gpc: gpc@020dc000 { 701 gpc: gpc@020dc000 {
701 compatible = "fsl,imx6sx-gpc", "fsl,imx6q-gpc"; 702 compatible = "fsl,imx6sx-gpc", "fsl,imx6q-gpc";
702 reg = <0x020dc000 0x4000>; 703 reg = <0x020dc000 0x4000>;
704 interrupt-controller;
705 #interrupt-cells = <3>;
703 interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>; 706 interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
707 interrupt-parent = <&intc>;
704 }; 708 };
705 709
706 iomuxc: iomuxc@020e0000 { 710 iomuxc: iomuxc@020e0000 {
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index 771ecfe96c14..2fbdc283bc99 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -101,7 +101,6 @@ static inline void imx_scu_map_io(void) {}
101static inline void imx_smp_prepare(void) {} 101static inline void imx_smp_prepare(void) {}
102#endif 102#endif
103void imx_src_init(void); 103void imx_src_init(void);
104void imx_gpc_init(void);
105void imx_gpc_pre_suspend(bool arm_power_off); 104void imx_gpc_pre_suspend(bool arm_power_off);
106void imx_gpc_post_resume(void); 105void imx_gpc_post_resume(void);
107void imx_gpc_mask_all(void); 106void imx_gpc_mask_all(void);
diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index 029f59ce2712..6f1f77ed0c71 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -36,6 +36,7 @@
36#define GPC_PGC_SW_SHIFT 0x0 36#define GPC_PGC_SW_SHIFT 0x0
37 37
38#define IMR_NUM 4 38#define IMR_NUM 4
39#define GPC_MAX_IRQS (IMR_NUM * 32)
39 40
40#define GPU_VPU_PUP_REQ BIT(1) 41#define GPU_VPU_PUP_REQ BIT(1)
41#define GPU_VPU_PDN_REQ BIT(0) 42#define GPU_VPU_PDN_REQ BIT(0)
@@ -99,17 +100,17 @@ void imx_gpc_post_resume(void)
99 100
100static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on) 101static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on)
101{ 102{
102 unsigned int idx = d->hwirq / 32 - 1; 103 unsigned int idx = d->hwirq / 32;
103 u32 mask; 104 u32 mask;
104 105
105 /* Sanity check for SPI irq */
106 if (d->hwirq < 32)
107 return -EINVAL;
108
109 mask = 1 << d->hwirq % 32; 106 mask = 1 << d->hwirq % 32;
110 gpc_wake_irqs[idx] = on ? gpc_wake_irqs[idx] | mask : 107 gpc_wake_irqs[idx] = on ? gpc_wake_irqs[idx] | mask :
111 gpc_wake_irqs[idx] & ~mask; 108 gpc_wake_irqs[idx] & ~mask;
112 109
110 /*
111 * Do *not* call into the parent, as the GIC doesn't have any
112 * wake-up facility...
113 */
113 return 0; 114 return 0;
114} 115}
115 116
@@ -139,7 +140,7 @@ void imx_gpc_hwirq_unmask(unsigned int hwirq)
139 void __iomem *reg; 140 void __iomem *reg;
140 u32 val; 141 u32 val;
141 142
142 reg = gpc_base + GPC_IMR1 + (hwirq / 32 - 1) * 4; 143 reg = gpc_base + GPC_IMR1 + hwirq / 32 * 4;
143 val = readl_relaxed(reg); 144 val = readl_relaxed(reg);
144 val &= ~(1 << hwirq % 32); 145 val &= ~(1 << hwirq % 32);
145 writel_relaxed(val, reg); 146 writel_relaxed(val, reg);
@@ -150,7 +151,7 @@ void imx_gpc_hwirq_mask(unsigned int hwirq)
150 void __iomem *reg; 151 void __iomem *reg;
151 u32 val; 152 u32 val;
152 153
153 reg = gpc_base + GPC_IMR1 + (hwirq / 32 - 1) * 4; 154 reg = gpc_base + GPC_IMR1 + hwirq / 32 * 4;
154 val = readl_relaxed(reg); 155 val = readl_relaxed(reg);
155 val |= 1 << (hwirq % 32); 156 val |= 1 << (hwirq % 32);
156 writel_relaxed(val, reg); 157 writel_relaxed(val, reg);
@@ -158,41 +159,119 @@ void imx_gpc_hwirq_mask(unsigned int hwirq)
158 159
159static void imx_gpc_irq_unmask(struct irq_data *d) 160static void imx_gpc_irq_unmask(struct irq_data *d)
160{ 161{
161 /* Sanity check for SPI irq */
162 if (d->hwirq < 32)
163 return;
164
165 imx_gpc_hwirq_unmask(d->hwirq); 162 imx_gpc_hwirq_unmask(d->hwirq);
163 irq_chip_unmask_parent(d);
166} 164}
167 165
168static void imx_gpc_irq_mask(struct irq_data *d) 166static void imx_gpc_irq_mask(struct irq_data *d)
169{ 167{
170 /* Sanity check for SPI irq */
171 if (d->hwirq < 32)
172 return;
173
174 imx_gpc_hwirq_mask(d->hwirq); 168 imx_gpc_hwirq_mask(d->hwirq);
169 irq_chip_mask_parent(d);
175} 170}
176 171
177void __init imx_gpc_init(void) 172static struct irq_chip imx_gpc_chip = {
173 .name = "GPC",
174 .irq_eoi = irq_chip_eoi_parent,
175 .irq_mask = imx_gpc_irq_mask,
176 .irq_unmask = imx_gpc_irq_unmask,
177 .irq_retrigger = irq_chip_retrigger_hierarchy,
178 .irq_set_wake = imx_gpc_irq_set_wake,
179};
180
181static int imx_gpc_domain_xlate(struct irq_domain *domain,
182 struct device_node *controller,
183 const u32 *intspec,
184 unsigned int intsize,
185 unsigned long *out_hwirq,
186 unsigned int *out_type)
178{ 187{
179 struct device_node *np; 188 if (domain->of_node != controller)
189 return -EINVAL; /* Shouldn't happen, really... */
190 if (intsize != 3)
191 return -EINVAL; /* Not GIC compliant */
192 if (intspec[0] != 0)
193 return -EINVAL; /* No PPI should point to this domain */
194
195 *out_hwirq = intspec[1];
196 *out_type = intspec[2];
197 return 0;
198}
199
200static int imx_gpc_domain_alloc(struct irq_domain *domain,
201 unsigned int irq,
202 unsigned int nr_irqs, void *data)
203{
204 struct of_phandle_args *args = data;
205 struct of_phandle_args parent_args;
206 irq_hw_number_t hwirq;
180 int i; 207 int i;
181 208
182 np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpc"); 209 if (args->args_count != 3)
183 gpc_base = of_iomap(np, 0); 210 return -EINVAL; /* Not GIC compliant */
184 WARN_ON(!gpc_base); 211 if (args->args[0] != 0)
212 return -EINVAL; /* No PPI should point to this domain */
213
214 hwirq = args->args[1];
215 if (hwirq >= GPC_MAX_IRQS)
216 return -EINVAL; /* Can't deal with this */
217
218 for (i = 0; i < nr_irqs; i++)
219 irq_domain_set_hwirq_and_chip(domain, irq + i, hwirq + i,
220 &imx_gpc_chip, NULL);
221
222 parent_args = *args;
223 parent_args.np = domain->parent->of_node;
224 return irq_domain_alloc_irqs_parent(domain, irq, nr_irqs, &parent_args);
225}
226
227static struct irq_domain_ops imx_gpc_domain_ops = {
228 .xlate = imx_gpc_domain_xlate,
229 .alloc = imx_gpc_domain_alloc,
230 .free = irq_domain_free_irqs_common,
231};
232
233static int __init imx_gpc_init(struct device_node *node,
234 struct device_node *parent)
235{
236 struct irq_domain *parent_domain, *domain;
237 int i;
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 gpc_base = of_iomap(node, 0);
251 if (WARN_ON(!gpc_base))
252 return -ENOMEM;
253
254 domain = irq_domain_add_hierarchy(parent_domain, 0, GPC_MAX_IRQS,
255 node, &imx_gpc_domain_ops,
256 NULL);
257 if (!domain) {
258 iounmap(gpc_base);
259 return -ENOMEM;
260 }
185 261
186 /* Initially mask all interrupts */ 262 /* Initially mask all interrupts */
187 for (i = 0; i < IMR_NUM; i++) 263 for (i = 0; i < IMR_NUM; i++)
188 writel_relaxed(~0, gpc_base + GPC_IMR1 + i * 4); 264 writel_relaxed(~0, gpc_base + GPC_IMR1 + i * 4);
189 265
190 /* Register GPC as the secondary interrupt controller behind GIC */ 266 return 0;
191 gic_arch_extn.irq_mask = imx_gpc_irq_mask;
192 gic_arch_extn.irq_unmask = imx_gpc_irq_unmask;
193 gic_arch_extn.irq_set_wake = imx_gpc_irq_set_wake;
194} 267}
195 268
269/*
270 * We cannot use the IRQCHIP_DECLARE macro that lives in
271 * drivers/irqchip, so we're forced to roll our own. Not very nice.
272 */
273OF_DECLARE_2(irqchip, imx_gpc, "fsl,imx6q-gpc", imx_gpc_init);
274
196#ifdef CONFIG_PM_GENERIC_DOMAINS 275#ifdef CONFIG_PM_GENERIC_DOMAINS
197 276
198static void _imx6q_pm_pu_power_off(struct generic_pm_domain *genpd) 277static void _imx6q_pm_pu_power_off(struct generic_pm_domain *genpd)
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index 4ad6e473cf83..6fc2b7e89c6b 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -390,7 +390,6 @@ static void __init imx6q_init_irq(void)
390 imx_init_revision_from_anatop(); 390 imx_init_revision_from_anatop();
391 imx_init_l2cache(); 391 imx_init_l2cache();
392 imx_src_init(); 392 imx_src_init();
393 imx_gpc_init();
394 irqchip_init(); 393 irqchip_init();
395} 394}
396 395
diff --git a/arch/arm/mach-imx/mach-imx6sl.c b/arch/arm/mach-imx/mach-imx6sl.c
index 24bfaaf944c8..d39c274910c5 100644
--- a/arch/arm/mach-imx/mach-imx6sl.c
+++ b/arch/arm/mach-imx/mach-imx6sl.c
@@ -64,7 +64,6 @@ static void __init imx6sl_init_irq(void)
64 imx_init_revision_from_anatop(); 64 imx_init_revision_from_anatop();
65 imx_init_l2cache(); 65 imx_init_l2cache();
66 imx_src_init(); 66 imx_src_init();
67 imx_gpc_init();
68 irqchip_init(); 67 irqchip_init();
69} 68}
70 69
diff --git a/arch/arm/mach-imx/mach-imx6sx.c b/arch/arm/mach-imx/mach-imx6sx.c
index 66988eb6a3a4..8595f9ea30a0 100644
--- a/arch/arm/mach-imx/mach-imx6sx.c
+++ b/arch/arm/mach-imx/mach-imx6sx.c
@@ -84,7 +84,6 @@ static void __init imx6sx_init_irq(void)
84 imx_init_revision_from_anatop(); 84 imx_init_revision_from_anatop();
85 imx_init_l2cache(); 85 imx_init_l2cache();
86 imx_src_init(); 86 imx_src_init();
87 imx_gpc_init();
88 irqchip_init(); 87 irqchip_init();
89} 88}
90 89
diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c
index 46fd695203c7..6a7c6fc780cc 100644
--- a/arch/arm/mach-imx/pm-imx6.c
+++ b/arch/arm/mach-imx/pm-imx6.c
@@ -310,10 +310,12 @@ int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
310 * Low-Power mode. 310 * Low-Power mode.
311 * 3) Software should mask IRQ #32 right after CCM Low-Power mode 311 * 3) Software should mask IRQ #32 right after CCM Low-Power mode
312 * is set (set bits 0-1 of CCM_CLPCR). 312 * is set (set bits 0-1 of CCM_CLPCR).
313 *
314 * Note that IRQ #32 is GIC SPI #0.
313 */ 315 */
314 imx_gpc_hwirq_unmask(32); 316 imx_gpc_hwirq_unmask(0);
315 writel_relaxed(val, ccm_base + CLPCR); 317 writel_relaxed(val, ccm_base + CLPCR);
316 imx_gpc_hwirq_mask(32); 318 imx_gpc_hwirq_mask(0);
317 319
318 return 0; 320 return 0;
319} 321}