blob: 45c79204dc40ccaa2ac658d01317ba1b51315cf7 [file] [log] [blame]
Mark Rutlandb5df5b82021-06-07 10:46:24 +01001// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Low-level idle sequences
4 */
5
6#include <linux/cpu.h>
7#include <linux/irqflags.h>
8
9#include <asm/arch_gicv3.h>
10#include <asm/barrier.h>
11#include <asm/cpufeature.h>
12#include <asm/sysreg.h>
13
14static void noinstr __cpu_do_idle(void)
15{
16 dsb(sy);
17 wfi();
18}
19
20static void noinstr __cpu_do_idle_irqprio(void)
21{
22 unsigned long pmr;
23 unsigned long daif_bits;
24
25 daif_bits = read_sysreg(daif);
26 write_sysreg(daif_bits | PSR_I_BIT | PSR_F_BIT, daif);
27
28 /*
29 * Unmask PMR before going idle to make sure interrupts can
30 * be raised.
31 */
32 pmr = gic_read_pmr();
33 gic_write_pmr(GIC_PRIO_IRQON | GIC_PRIO_PSR_I_SET);
34
35 __cpu_do_idle();
36
37 gic_write_pmr(pmr);
38 write_sysreg(daif_bits, daif);
39}
40
41/*
42 * cpu_do_idle()
43 *
44 * Idle the processor (wait for interrupt).
45 *
46 * If the CPU supports priority masking we must do additional work to
47 * ensure that interrupts are not masked at the PMR (because the core will
48 * not wake up if we block the wake up signal in the interrupt controller).
49 */
50void noinstr cpu_do_idle(void)
51{
52 if (system_uses_irq_prio_masking())
53 __cpu_do_idle_irqprio();
54 else
55 __cpu_do_idle();
56}
57
58/*
59 * This is our default idle handler.
60 */
61void noinstr arch_cpu_idle(void)
62{
63 /*
64 * This should do all the clock switching and wait for interrupt
65 * tricks
66 */
67 cpu_do_idle();
68 raw_local_irq_enable();
69}