diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2023-02-19 17:16:14 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2023-02-19 17:16:14 +0000 |
commit | b7397618ce06c41adc25934314fbfddbaadbac1a (patch) | |
tree | c50fbb4a8cec8f5e562f80717b19b2f8169991c3 /sys/dev/fdt | |
parent | 0aee535ca6abf12f406bca310cd472153631518b (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.c | 26 | ||||
-rw-r--r-- | sys/dev/fdt/pscivar.h | 1 |
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); |