diff --git a/dev/power/psci/include/dev/power/psci.h b/dev/power/psci/include/dev/power/psci.h new file mode 100644 index 00000000..4759834f --- /dev/null +++ b/dev/power/psci/include/dev/power/psci.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2022 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#pragma once + +#include +#include + +__BEGIN_CDECLS + +uint32_t psci_version(void); +int psci_cpu_on(int corenr, ulong entrypoint); +void psci_system_off(void); +void psci_system_reset(void); + +__END_CDECLS diff --git a/dev/power/psci/psci.c b/dev/power/psci/psci.c new file mode 100644 index 00000000..4df24b75 --- /dev/null +++ b/dev/power/psci/psci.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022 Travis Geiselbrecht + * + * Use of this source code is governed by a MIT-style + * license that can be found in the LICENSE file or at + * https://opensource.org/licenses/MIT + */ +#include + +#if WITH_LIB_CONSOLE +#include +#include +#endif + +#define PSCI_VERSION 0x84000000 +#define SYSTEM_OFF 0x84000008 +#define SYSTEM_RESET 0x84000009 + +#if ARCH_ARM +#define CPU_ON 0x84000003 +#endif + +#if ARCH_ARM64 +#define CPU_ON 0xC4000003 +#endif + +/* low level ASM routine to make the raw PSCI call */ +int psci_call(ulong arg0, ulong arg1, ulong arg2, ulong arg3); + +uint32_t psci_version(void) { + return psci_call(PSCI_VERSION, 0, 0, 0); +} + +int psci_cpu_on(int corenr, ulong entrypoint) { + return psci_call(CPU_ON, corenr, entrypoint, corenr); +} + +void psci_system_off(void) { + psci_call(SYSTEM_OFF, 0, 0, 0); +} + +void psci_system_reset(void) { + psci_call(SYSTEM_RESET, 0, 0, 0); +} + +#if WITH_LIB_CONSOLE + +static int cmd_psci_version(int argc, const console_cmd_args *argv) { + int ret = psci_version(); + printf("PSCI VERSION: 0x%x\n", ret); + return 0; +} + +STATIC_COMMAND_START +STATIC_COMMAND("psci_version", "show psci version", &cmd_psci_version) +STATIC_COMMAND_END(psci); +#endif diff --git a/platform/qemu-virt-arm/secondary_boot.S b/dev/power/psci/psci_asm.S similarity index 100% rename from platform/qemu-virt-arm/secondary_boot.S rename to dev/power/psci/psci_asm.S diff --git a/dev/power/psci/rules.mk b/dev/power/psci/rules.mk new file mode 100644 index 00000000..b9516ef6 --- /dev/null +++ b/dev/power/psci/rules.mk @@ -0,0 +1,10 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/psci.c \ + $(LOCAL_DIR)/psci_asm.S \ + +include make/module.mk + diff --git a/platform/qemu-virt-arm/platform.c b/platform/qemu-virt-arm/platform.c index 81711d5a..e79c0053 100644 --- a/platform/qemu-virt-arm/platform.c +++ b/platform/qemu-virt-arm/platform.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -65,8 +66,6 @@ static pmm_arena_t arena = { .flags = PMM_ARENA_FLAG_KMAP, }; -extern int psci_call(ulong arg0, ulong arg1, ulong arg2, ulong arg3); - // callbacks to the fdt_walk routine static void memcallback(uint64_t base, uint64_t len, void *cookie) { bool *found_mem = (bool *)cookie; @@ -157,13 +156,9 @@ void platform_early_init(void) { LTRACEF("booting %d cpus\n", cpu_count); /* boot the secondary cpus using the Power State Coordintion Interface */ - ulong psci_call_num = 0x84000000 + 3; /* SMC32 CPU_ON */ -#if ARCH_ARM64 - psci_call_num += 0x40000000; /* SMC64 */ -#endif for (int cpuid = 1; cpuid < cpu_count; cpuid++) { /* note: assumes cpuids are numbered like MPIDR 0:0:0:N */ - int ret = psci_call(psci_call_num, cpuid, MEMBASE + KERNEL_LOAD_OFFSET, cpuid); + int ret = psci_cpu_on(cpuid, MEMBASE + KERNEL_LOAD_OFFSET); if (ret != 0) { printf("ERROR: psci CPU_ON returns %d\n", ret); } @@ -287,7 +282,7 @@ status_t platform_allocate_interrupts(size_t count, uint align_log2, bool msi, u } status_t platform_compute_msi_values(unsigned int vector, unsigned int cpu, bool edge, - uint64_t *msi_address_out, uint16_t *msi_data_out) { + uint64_t *msi_address_out, uint16_t *msi_data_out) { // only handle edge triggered at the moment DEBUG_ASSERT(edge); @@ -301,3 +296,18 @@ status_t platform_compute_msi_values(unsigned int vector, unsigned int cpu, bool return NO_ERROR; } + +void platform_halt(platform_halt_action suggested_action, platform_halt_reason reason) { + switch (suggested_action) { + case HALT_ACTION_SHUTDOWN: + case HALT_ACTION_HALT: + psci_system_off(); + break; + case HALT_ACTION_REBOOT: + psci_system_reset(); + break; + } + dprintf(ALWAYS, "HALT: spinning forever... (reason = %d)\n", reason); + arch_disable_ints(); + for (;;); +} diff --git a/platform/qemu-virt-arm/rules.mk b/platform/qemu-virt-arm/rules.mk index ac5e779f..79721db2 100644 --- a/platform/qemu-virt-arm/rules.mk +++ b/platform/qemu-virt-arm/rules.mk @@ -18,7 +18,6 @@ LK_HEAP_IMPLEMENTATION ?= dlmalloc MODULE_SRCS += \ $(LOCAL_DIR)/debug.c \ $(LOCAL_DIR)/platform.c \ - $(LOCAL_DIR)/secondary_boot.S \ $(LOCAL_DIR)/uart.c MEMBASE := 0x40000000 @@ -26,15 +25,16 @@ MEMSIZE ?= 0x08000000 # 512MB KERNEL_LOAD_OFFSET := 0x100000 # 1MB MODULE_DEPS += \ - lib/cbuf \ - lib/fdtwalk \ dev/bus/pci \ dev/bus/pci/drivers \ dev/interrupt/arm_gic \ + dev/power/psci \ dev/timer/arm_generic \ dev/virtio/block \ dev/virtio/gpu \ dev/virtio/net \ + lib/cbuf \ + lib/fdtwalk \ GLOBAL_DEFINES += \ MEMBASE=$(MEMBASE) \