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/psci.h> |
13 | |
14 | #ifdef CONFIG_ACPI_PROCESSOR_IDLE |
15 | |
16 | #include <acpi/processor.h> |
17 | |
18 | #define ARM64_LPI_IS_RETENTION_STATE(arch_flags) (!(arch_flags)) |
19 | |
20 | static int psci_acpi_cpu_init_idle(unsigned int cpu) |
21 | { |
22 | int i, count; |
23 | struct acpi_lpi_state *lpi; |
24 | struct acpi_processor *pr = per_cpu(processors, cpu); |
25 | |
26 | if (unlikely(!pr || !pr->flags.has_lpi)) |
27 | return -EINVAL; |
28 | |
29 | /* |
30 | * If the PSCI cpu_suspend function hook has not been initialized |
31 | * idle states must not be enabled, so bail out |
32 | */ |
33 | if (!psci_ops.cpu_suspend) |
34 | return -EOPNOTSUPP; |
35 | |
36 | count = pr->power.count - 1; |
37 | if (count <= 0) |
38 | return -ENODEV; |
39 | |
40 | for (i = 0; i < count; i++) { |
41 | u32 state; |
42 | |
43 | lpi = &pr->power.lpi_states[i + 1]; |
44 | /* |
45 | * Only bits[31:0] represent a PSCI power_state while |
46 | * bits[63:32] must be 0x0 as per ARM ACPI FFH Specification |
47 | */ |
48 | state = lpi->address; |
49 | if (!psci_power_state_is_valid(state)) { |
50 | pr_warn("Invalid PSCI power state %#x\n", state); |
51 | return -EINVAL; |
52 | } |
53 | } |
54 | |
55 | return 0; |
56 | } |
57 | |
58 | int acpi_processor_ffh_lpi_probe(unsigned int cpu) |
59 | { |
60 | return psci_acpi_cpu_init_idle(cpu); |
61 | } |
62 | |
63 | __cpuidle int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi) |
64 | { |
65 | u32 state = lpi->address; |
66 | |
67 | if (ARM64_LPI_IS_RETENTION_STATE(lpi->arch_flags)) |
68 | return CPU_PM_CPU_IDLE_ENTER_RETENTION_PARAM_RCU(psci_cpu_suspend_enter, |
69 | lpi->index, state); |
70 | else |
71 | return CPU_PM_CPU_IDLE_ENTER_PARAM_RCU(psci_cpu_suspend_enter, |
72 | lpi->index, state); |
73 | } |
74 | #endif |
75 |