summaryrefslogtreecommitdiff
path: root/sys/dev/fdt
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2023-02-19 17:16:14 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2023-02-19 17:16:14 +0000
commitb7397618ce06c41adc25934314fbfddbaadbac1a (patch)
treec50fbb4a8cec8f5e562f80717b19b2f8169991c3 /sys/dev/fdt
parent0aee535ca6abf12f406bca310cd472153631518b (diff)
Add support for deep(er) idle states that can be entered using PSCI. For
now this only supports states advertised in device trees, but ACPI support could be added as well. The parsing of the idle states as well as the heuristic to pick the deepest one is probably a bit to simple, but more complex cases can be added later. Worst case cores will use WFI and use more power in suspend. ok phessler@
Diffstat (limited to 'sys/dev/fdt')
-rw-r--r--sys/dev/fdt/psci.c26
-rw-r--r--sys/dev/fdt/pscivar.h1
2 files changed, 25 insertions, 2 deletions
diff --git a/sys/dev/fdt/psci.c b/sys/dev/fdt/psci.c
index 469cf1f67d0..675a97d5cd8 100644
--- a/sys/dev/fdt/psci.c
+++ b/sys/dev/fdt/psci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: psci.c,v 1.13 2023/02/13 19:26:15 kettenis Exp $ */
+/* $OpenBSD: psci.c,v 1.14 2023/02/19 17:16:13 kettenis Exp $ */
/*
* Copyright (c) 2016 Jonathan Gray <jsg@openbsd.org>
@@ -37,6 +37,11 @@ extern void (*powerdownfn)(void);
#define SMCCC_ARCH_WORKAROUND_3 0x80003fff
#define PSCI_VERSION 0x84000000
+#ifdef __LP64__
+#define CPU_SUSPEND 0xc4000001
+#else
+#define CPU_SUSPEND 0x84000001
+#endif
#define CPU_OFF 0x84000002
#ifdef __LP64__
#define CPU_ON 0xc4000003
@@ -56,12 +61,13 @@ struct psci_softc {
struct device sc_dev;
register_t (*sc_callfn)(register_t, register_t, register_t,
register_t);
- uint32_t sc_psci_version;
+ uint32_t sc_psci_version;
uint32_t sc_system_off;
uint32_t sc_system_reset;
uint32_t sc_system_suspend;
uint32_t sc_cpu_on;
uint32_t sc_cpu_off;
+ uint32_t sc_cpu_suspend;
uint32_t sc_smccc_version;
uint32_t sc_method;
@@ -131,6 +137,7 @@ psci_attach(struct device *parent, struct device *self, void *aux)
sc->sc_system_reset = SYSTEM_RESET;
sc->sc_cpu_on = CPU_ON;
sc->sc_cpu_off = CPU_OFF;
+ sc->sc_cpu_suspend = CPU_SUSPEND;
} else if (OF_is_compatible(faa->fa_node, "arm,psci")) {
sc->sc_system_off = OF_getpropint(faa->fa_node,
"system_off", 0);
@@ -138,6 +145,8 @@ psci_attach(struct device *parent, struct device *self, void *aux)
"system_reset", 0);
sc->sc_cpu_on = OF_getpropint(faa->fa_node, "cpu_on", 0);
sc->sc_cpu_off = OF_getpropint(faa->fa_node, "cpu_off", 0);
+ sc->sc_cpu_suspend = OF_getpropint(faa->fa_node,
+ "cpu_suspend", 0);
}
psci_sc = sc;
@@ -333,6 +342,19 @@ psci_cpu_on(register_t target_cpu, register_t entry_point_address,
}
int32_t
+psci_cpu_suspend(register_t power_state, register_t entry_point_address,
+ register_t context_id)
+{
+ struct psci_softc *sc = psci_sc;
+
+ if (sc && sc->sc_callfn && sc->sc_cpu_suspend != 0)
+ return (*sc->sc_callfn)(sc->sc_cpu_suspend, power_state,
+ entry_point_address, context_id);
+
+ return PSCI_NOT_SUPPORTED;
+}
+
+int32_t
psci_features(uint32_t psci_func_id)
{
struct psci_softc *sc = psci_sc;
diff --git a/sys/dev/fdt/pscivar.h b/sys/dev/fdt/pscivar.h
index 9a400290f93..04e418f3190 100644
--- a/sys/dev/fdt/pscivar.h
+++ b/sys/dev/fdt/pscivar.h
@@ -15,6 +15,7 @@ int psci_can_suspend(void);
int32_t psci_system_suspend(register_t, register_t);
int32_t psci_cpu_on(register_t, register_t, register_t);
int32_t psci_cpu_off(void);
+int32_t psci_cpu_suspend(register_t, register_t, register_t);
void psci_flush_bp(void);
int psci_flush_bp_has_bhb(void);
int psci_method(void);