diff --git a/plat/qemu/qemu_sbsa/include/platform_def.h b/plat/qemu/qemu_sbsa/include/platform_def.h index 85fbb4dd5..deaf16ea4 100644 --- a/plat/qemu/qemu_sbsa/include/platform_def.h +++ b/plat/qemu/qemu_sbsa/include/platform_def.h @@ -215,6 +215,8 @@ /* * GIC related constants * We use GICv3 where CPU Interface registers are not memory mapped + * + * Legacy values - on platform version 0.1+ they are read from DT */ #define GICD_BASE 0x40060000 #define GICR_BASE 0x40080000 diff --git a/plat/qemu/qemu_sbsa/platform.mk b/plat/qemu/qemu_sbsa/platform.mk index f14feb52b..60d6b7e62 100644 --- a/plat/qemu/qemu_sbsa/platform.mk +++ b/plat/qemu/qemu_sbsa/platform.mk @@ -89,13 +89,13 @@ endif include drivers/arm/gic/v3/gicv3.mk QEMU_GIC_SOURCES := ${GICV3_SOURCES} \ - plat/common/plat_gicv3.c \ - ${PLAT_QEMU_COMMON_PATH}/qemu_gicv3.c + plat/common/plat_gicv3.c BL31_SOURCES += ${QEMU_CPU_LIBS} \ lib/semihosting/semihosting.c \ lib/semihosting/${ARCH}/semihosting_call.S \ plat/common/plat_psci_common.c \ + ${PLAT_QEMU_PATH}/sbsa_gic.c \ ${PLAT_QEMU_PATH}/sbsa_pm.c \ ${PLAT_QEMU_PATH}/sbsa_sip_svc.c \ ${PLAT_QEMU_PATH}/sbsa_topology.c \ diff --git a/plat/qemu/qemu_sbsa/sbsa_gic.c b/plat/qemu/qemu_sbsa/sbsa_gic.c new file mode 100644 index 000000000..962dbb3dc --- /dev/null +++ b/plat/qemu/qemu_sbsa/sbsa_gic.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023, Linaro Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +static const interrupt_prop_t qemu_interrupt_props[] = { + PLATFORM_G1S_PROPS(INTR_GROUP1S), + PLATFORM_G0_PROPS(INTR_GROUP0) +}; + +static uintptr_t qemu_rdistif_base_addrs[PLATFORM_CORE_COUNT]; + +static unsigned int qemu_mpidr_to_core_pos(unsigned long mpidr) +{ + return plat_core_pos_by_mpidr(mpidr); +} + +static gicv3_driver_data_t sbsa_gic_driver_data = { + /* we set those two values for compatibility with older QEMU */ + .gicd_base = GICD_BASE, + .gicr_base = GICR_BASE, + .interrupt_props = qemu_interrupt_props, + .interrupt_props_num = ARRAY_SIZE(qemu_interrupt_props), + .rdistif_num = PLATFORM_CORE_COUNT, + .rdistif_base_addrs = qemu_rdistif_base_addrs, + .mpidr_to_core_pos = qemu_mpidr_to_core_pos +}; + +void sbsa_set_gic_bases(const uintptr_t gicd_base, const uintptr_t gicr_base) +{ + sbsa_gic_driver_data.gicd_base = gicd_base; + sbsa_gic_driver_data.gicr_base = gicr_base; +} + +uintptr_t sbsa_get_gicd(void) +{ + return sbsa_gic_driver_data.gicd_base; +} + +uintptr_t sbsa_get_gicr(void) +{ + return sbsa_gic_driver_data.gicr_base; +} + +void plat_qemu_gic_init(void) +{ + gicv3_driver_init(&sbsa_gic_driver_data); + gicv3_distif_init(); + gicv3_rdistif_init(plat_my_core_pos()); + gicv3_cpuif_enable(plat_my_core_pos()); +} + +void qemu_pwr_gic_on_finish(void) +{ + gicv3_rdistif_init(plat_my_core_pos()); + gicv3_cpuif_enable(plat_my_core_pos()); +} + +void qemu_pwr_gic_off(void) +{ + gicv3_cpuif_disable(plat_my_core_pos()); + gicv3_rdistif_off(plat_my_core_pos()); +} diff --git a/plat/qemu/qemu_sbsa/sbsa_sip_svc.c b/plat/qemu/qemu_sbsa/sbsa_sip_svc.c index 1d318cae6..37460d71e 100644 --- a/plat/qemu/qemu_sbsa/sbsa_sip_svc.c +++ b/plat/qemu/qemu_sbsa/sbsa_sip_svc.c @@ -6,6 +6,7 @@ #include +#include #include #include #include @@ -26,6 +27,55 @@ static int platform_version_minor; */ #define SIP_SVC_VERSION SIP_FUNCTION_ID(1) +#define SIP_SVC_GET_GIC SIP_FUNCTION_ID(100) + +void sbsa_set_gic_bases(const uintptr_t gicd_base, const uintptr_t gicr_base); +uintptr_t sbsa_get_gicd(void); +uintptr_t sbsa_get_gicr(void); + +void read_platform_config_from_dt(void *dtb) +{ + int node; + const fdt64_t *data; + int err; + uintptr_t gicd_base; + uintptr_t gicr_base; + + /* + * QEMU gives us this DeviceTree node: + * + * intc { + reg = < 0x00 0x40060000 0x00 0x10000 + 0x00 0x40080000 0x00 0x4000000>; + }; + */ + node = fdt_path_offset(dtb, "/intc"); + if (node < 0) { + return; + } + + data = fdt_getprop(dtb, node, "reg", NULL); + if (data == NULL) { + return; + } + + err = fdt_get_reg_props_by_index(dtb, node, 0, &gicd_base, NULL); + if (err < 0) { + ERROR("Failed to read GICD reg property of GIC node\n"); + return; + } + INFO("GICD base = 0x%lx\n", gicd_base); + + err = fdt_get_reg_props_by_index(dtb, node, 1, &gicr_base, NULL); + if (err < 0) { + ERROR("Failed to read GICR reg property of GIC node\n"); + return; + } + INFO("GICR base = 0x%lx\n", gicr_base); + + sbsa_set_gic_bases(gicd_base, gicr_base); +} + void read_platform_version(void *dtb) { int node; @@ -60,6 +110,8 @@ void sip_svc_init(void) read_platform_version(dtb); INFO("Platform version: %d.%d\n", platform_version_major, platform_version_minor); + + read_platform_config_from_dt(dtb); } /* @@ -88,6 +140,9 @@ uintptr_t sbsa_sip_smc_handler(uint32_t smc_fid, INFO("Platform version requested\n"); SMC_RET3(handle, NULL, platform_version_major, platform_version_minor); + case SIP_SVC_GET_GIC: + SMC_RET3(handle, NULL, sbsa_get_gicd(), sbsa_get_gicr()); + default: ERROR("%s: unhandled SMC (0x%x) (function id: %d)\n", __func__, smc_fid, smc_fid - SIP_FUNCTION);