diff options
Diffstat (limited to 'hw/arm/boot.c')
-rw-r--r-- | hw/arm/boot.c | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/hw/arm/boot.c b/hw/arm/boot.c index bb244ec359..05108bc42f 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -22,6 +22,7 @@ #include "elf.h" #include "sysemu/device_tree.h" #include "qemu/config-file.h" +#include "qemu/option.h" #include "exec/address-spaces.h" /* Kernel boot protocol is specified in the kernel docs @@ -385,6 +386,69 @@ static void set_kernel_args_old(const struct arm_boot_info *info) } } +static void fdt_add_psci_node(void *fdt) +{ + uint32_t cpu_suspend_fn; + uint32_t cpu_off_fn; + uint32_t cpu_on_fn; + uint32_t migrate_fn; + ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(0)); + const char *psci_method; + int64_t psci_conduit; + + psci_conduit = object_property_get_int(OBJECT(armcpu), + "psci-conduit", + &error_abort); + switch (psci_conduit) { + case QEMU_PSCI_CONDUIT_DISABLED: + return; + case QEMU_PSCI_CONDUIT_HVC: + psci_method = "hvc"; + break; + case QEMU_PSCI_CONDUIT_SMC: + psci_method = "smc"; + break; + default: + g_assert_not_reached(); + } + + qemu_fdt_add_subnode(fdt, "/psci"); + if (armcpu->psci_version == 2) { + const char comp[] = "arm,psci-0.2\0arm,psci"; + qemu_fdt_setprop(fdt, "/psci", "compatible", comp, sizeof(comp)); + + cpu_off_fn = QEMU_PSCI_0_2_FN_CPU_OFF; + if (arm_feature(&armcpu->env, ARM_FEATURE_AARCH64)) { + cpu_suspend_fn = QEMU_PSCI_0_2_FN64_CPU_SUSPEND; + cpu_on_fn = QEMU_PSCI_0_2_FN64_CPU_ON; + migrate_fn = QEMU_PSCI_0_2_FN64_MIGRATE; + } else { + cpu_suspend_fn = QEMU_PSCI_0_2_FN_CPU_SUSPEND; + cpu_on_fn = QEMU_PSCI_0_2_FN_CPU_ON; + migrate_fn = QEMU_PSCI_0_2_FN_MIGRATE; + } + } else { + qemu_fdt_setprop_string(fdt, "/psci", "compatible", "arm,psci"); + + cpu_suspend_fn = QEMU_PSCI_0_1_FN_CPU_SUSPEND; + cpu_off_fn = QEMU_PSCI_0_1_FN_CPU_OFF; + cpu_on_fn = QEMU_PSCI_0_1_FN_CPU_ON; + migrate_fn = QEMU_PSCI_0_1_FN_MIGRATE; + } + + /* We adopt the PSCI spec's nomenclature, and use 'conduit' to refer + * to the instruction that should be used to invoke PSCI functions. + * However, the device tree binding uses 'method' instead, so that is + * what we should use here. + */ + qemu_fdt_setprop_string(fdt, "/psci", "method", psci_method); + + qemu_fdt_setprop_cell(fdt, "/psci", "cpu_suspend", cpu_suspend_fn); + qemu_fdt_setprop_cell(fdt, "/psci", "cpu_off", cpu_off_fn); + qemu_fdt_setprop_cell(fdt, "/psci", "cpu_on", cpu_on_fn); + qemu_fdt_setprop_cell(fdt, "/psci", "migrate", migrate_fn); +} + /** * load_dtb() - load a device tree binary image into memory * @addr: the address to load the image at @@ -541,6 +605,8 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo, } } + fdt_add_psci_node(fdt); + if (binfo->modify_dtb) { binfo->modify_dtb(binfo, fdt); } |