aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/irqchip/irq-gic-v3.c
diff options
context:
space:
mode:
authorJason Cooper <jason@lakedaemon.net>2014-10-02 09:04:58 -0400
committerJason Cooper <jason@lakedaemon.net>2014-10-02 09:04:58 -0400
commitfae119b6d427a087be0c6a85431c1b8ee9ffea96 (patch)
treea91d42306e6aca87407df53dfce0d4a9e4eb8e0e /drivers/irqchip/irq-gic-v3.c
parentf7472655fbe70f422c08f78d107ca24a791d7b14 (diff)
parent3708d52fc6bb34ae16399fe998d515dd7d188ab0 (diff)
Merge branch 'irqchip/gic' into irqchip/core
Diffstat (limited to 'drivers/irqchip/irq-gic-v3.c')
-rw-r--r--drivers/irqchip/irq-gic-v3.c87
1 files changed, 66 insertions, 21 deletions
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
158static void gic_enable_redist(void) 159static 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
386static 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
375static void gic_cpu_init(void) 401static 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
553static 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
566static struct notifier_block gic_cpu_pm_notifier_block = {
567 .notifier_call = gic_cpu_pm_notifier,
568};
569
570static void gic_cpu_pm_init(void)
571{
572 cpu_pm_register_notifier(&gic_cpu_pm_notifier_block);
573}
574
575#else
576static inline void gic_cpu_pm_init(void) { }
577#endif /* CONFIG_CPU_PM */
578
535static struct irq_chip gic_chip = { 579static 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