dt-bindings: soc: bcm: use absolute path to other schema
[linux-2.6-microblaze.git] / arch / arm64 / kernel / cpuidle.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * ARM64 CPU idle arch support
4  *
5  * Copyright (C) 2014 ARM Ltd.
6  * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
7  */
8
9 #include <linux/acpi.h>
10 #include <linux/cpuidle.h>
11 #include <linux/cpu_pm.h>
12 #include <linux/of.h>
13 #include <linux/of_device.h>
14 #include <linux/psci.h>
15
16 #include <asm/cpuidle.h>
17 #include <asm/cpu_ops.h>
18
19 int arm_cpuidle_init(unsigned int cpu)
20 {
21         const struct cpu_operations *ops = get_cpu_ops(cpu);
22         int ret = -EOPNOTSUPP;
23
24         if (ops && ops->cpu_suspend && ops->cpu_init_idle)
25                 ret = ops->cpu_init_idle(cpu);
26
27         return ret;
28 }
29
30 /**
31  * arm_cpuidle_suspend() - function to enter a low-power idle state
32  * @index: argument to pass to CPU suspend operations
33  *
34  * Return: 0 on success, -EOPNOTSUPP if CPU suspend hook not initialized, CPU
35  * operations back-end error code otherwise.
36  */
37 int arm_cpuidle_suspend(int index)
38 {
39         int cpu = smp_processor_id();
40         const struct cpu_operations *ops = get_cpu_ops(cpu);
41
42         return ops->cpu_suspend(index);
43 }
44
45 #ifdef CONFIG_ACPI
46
47 #include <acpi/processor.h>
48
49 #define ARM64_LPI_IS_RETENTION_STATE(arch_flags) (!(arch_flags))
50
51 static int psci_acpi_cpu_init_idle(unsigned int cpu)
52 {
53         int i, count;
54         struct acpi_lpi_state *lpi;
55         struct acpi_processor *pr = per_cpu(processors, cpu);
56
57         if (unlikely(!pr || !pr->flags.has_lpi))
58                 return -EINVAL;
59
60         /*
61          * If the PSCI cpu_suspend function hook has not been initialized
62          * idle states must not be enabled, so bail out
63          */
64         if (!psci_ops.cpu_suspend)
65                 return -EOPNOTSUPP;
66
67         count = pr->power.count - 1;
68         if (count <= 0)
69                 return -ENODEV;
70
71         for (i = 0; i < count; i++) {
72                 u32 state;
73
74                 lpi = &pr->power.lpi_states[i + 1];
75                 /*
76                  * Only bits[31:0] represent a PSCI power_state while
77                  * bits[63:32] must be 0x0 as per ARM ACPI FFH Specification
78                  */
79                 state = lpi->address;
80                 if (!psci_power_state_is_valid(state)) {
81                         pr_warn("Invalid PSCI power state %#x\n", state);
82                         return -EINVAL;
83                 }
84         }
85
86         return 0;
87 }
88
89 int acpi_processor_ffh_lpi_probe(unsigned int cpu)
90 {
91         return psci_acpi_cpu_init_idle(cpu);
92 }
93
94 int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi)
95 {
96         u32 state = lpi->address;
97
98         if (ARM64_LPI_IS_RETENTION_STATE(lpi->arch_flags))
99                 return CPU_PM_CPU_IDLE_ENTER_RETENTION_PARAM(psci_cpu_suspend_enter,
100                                                 lpi->index, state);
101         else
102                 return CPU_PM_CPU_IDLE_ENTER_PARAM(psci_cpu_suspend_enter,
103                                              lpi->index, state);
104 }
105 #endif