diff --git a/docs/plat/xilinx-versal-net.rst b/docs/plat/xilinx-versal-net.rst index 1db7695b1..3f31d40c9 100644 --- a/docs/plat/xilinx-versal-net.rst +++ b/docs/plat/xilinx-versal-net.rst @@ -40,3 +40,16 @@ Xilinx Versal NET platform specific build options * `TFA_NO_PM` : Platform Management support. - 0 : Enable Platform Management (Default) - 1 : Disable Platform Management + +* `CPU_PWRDWN_SGI`: Select the SGI for triggering CPU power down request to + secondary cores on receiving power down callback from + firmware. Options: + + - `0` : SGI 0 + - `1` : SGI 1 + - `2` : SGI 2 + - `3` : SGI 3 + - `4` : SGI 4 + - `5` : SGI 5 + - `6` : SGI 6 (Default) + - `7` : SGI 7 diff --git a/docs/plat/xilinx-versal.rst b/docs/plat/xilinx-versal.rst index e76b95574..aa094f757 100644 --- a/docs/plat/xilinx-versal.rst +++ b/docs/plat/xilinx-versal.rst @@ -56,6 +56,19 @@ Xilinx Versal platform specific build options - `spp_itr6` : SPP ITR6 - `emu_itr6` : EMU ITR6 +* `CPU_PWRDWN_SGI`: Select the SGI for triggering CPU power down request to + secondary cores on receiving power down callback from + firmware. Options: + + - `0` : SGI 0 + - `1` : SGI 1 + - `2` : SGI 2 + - `3` : SGI 3 + - `4` : SGI 4 + - `5` : SGI 5 + - `6` : SGI 6 (Default) + - `7` : SGI 7 + # PLM->TF-A Parameter Passing ------------------------------ The PLM populates a data structure with image information for the TF-A. The TF-A diff --git a/plat/xilinx/common/include/plat_common.h b/plat/xilinx/common/include/plat_common.h index 676baa2c7..2958868fc 100644 --- a/plat/xilinx/common/include/plat_common.h +++ b/plat/xilinx/common/include/plat_common.h @@ -14,4 +14,16 @@ (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \ }) +/******************************************************************************* + * interrupt handling related constants + ******************************************************************************/ +#define ARM_IRQ_SEC_SGI_0 8U +#define ARM_IRQ_SEC_SGI_1 9U +#define ARM_IRQ_SEC_SGI_2 10U +#define ARM_IRQ_SEC_SGI_3 11U +#define ARM_IRQ_SEC_SGI_4 12U +#define ARM_IRQ_SEC_SGI_5 13U +#define ARM_IRQ_SEC_SGI_6 14U +#define ARM_IRQ_SEC_SGI_7 15U + #endif /* PLAT_COMMON_H */ diff --git a/plat/xilinx/common/include/pm_defs.h b/plat/xilinx/common/include/pm_defs.h index 9cdb0ba07..c1872d0bf 100644 --- a/plat/xilinx/common/include/pm_defs.h +++ b/plat/xilinx/common/include/pm_defs.h @@ -18,6 +18,7 @@ /* State arguments of the self suspend */ #define PM_STATE_CPU_IDLE 0x0U +#define PM_STATE_CPU_OFF 0x1U #define PM_STATE_SUSPEND_TO_RAM 0xFU #define MAX_LATENCY (~0U) diff --git a/plat/xilinx/common/include/pm_svc_main.h b/plat/xilinx/common/include/pm_svc_main.h index 4cf77276e..67fbeae63 100644 --- a/plat/xilinx/common/include/pm_svc_main.h +++ b/plat/xilinx/common/include/pm_svc_main.h @@ -10,6 +10,8 @@ #include +extern bool pwrdwn_req_received; + /******************************************************************************/ /** * SECURE_REDUNDANT_CALL() - Adds redundancy to the function call. This is to @@ -30,6 +32,7 @@ status_tmp = function(__VA_ARGS__); \ } +void request_cpu_pwrdwn(void); int32_t pm_setup(void); uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, const void *cookie, void *handle, diff --git a/plat/xilinx/common/pm_service/pm_api_sys.c b/plat/xilinx/common/pm_service/pm_api_sys.c index ffc39bbef..36ea8ed8c 100644 --- a/plat/xilinx/common/pm_service/pm_api_sys.c +++ b/plat/xilinx/common/pm_service/pm_api_sys.c @@ -50,7 +50,7 @@ void pm_client_set_wakeup_sources(uint32_t node_id) { uint32_t reg_num, device_id; uint8_t pm_wakeup_nodes_set[XPM_NODEIDX_DEV_MAX] = {0U}; - uint32_t isenabler1 = PLAT_GICD_BASE_VALUE + GICD_ISENABLER + 4U; + uint32_t isenabler1 = PLAT_ARM_GICD_BASE + GICD_ISENABLER + 4U; zeromem(&pm_wakeup_nodes_set, (u_register_t)sizeof(pm_wakeup_nodes_set)); diff --git a/plat/xilinx/common/pm_service/pm_svc_main.c b/plat/xilinx/common/pm_service/pm_svc_main.c index 1e5808cfd..f9917a012 100644 --- a/plat/xilinx/common/pm_service/pm_svc_main.c +++ b/plat/xilinx/common/pm_service/pm_svc_main.c @@ -17,6 +17,8 @@ #include #include +#include +#include #include #include @@ -31,21 +33,63 @@ #define INVALID_SGI 0xFFU #define PM_INIT_SUSPEND_CB (30U) #define PM_NOTIFY_CB (32U) +#define EVENT_CPU_PWRDWN (4U) +/* 1 sec of wait timeout for secondary core down */ +#define PWRDWN_WAIT_TIMEOUT (1000U) DEFINE_RENAME_SYSREG_RW_FUNCS(icc_asgi1r_el1, S3_0_C12_C11_6) /* pm_up = true - UP, pm_up = false - DOWN */ static bool pm_up; static uint32_t sgi = (uint32_t)INVALID_SGI; +bool pwrdwn_req_received; static void notify_os(void) { - int32_t cpu; - uint32_t reg; + plat_ic_raise_ns_sgi(sgi, read_mpidr_el1()); +} - cpu = plat_my_core_pos() + 1U; +static uint64_t cpu_pwrdwn_req_handler(uint32_t id, uint32_t flags, + void *handle, void *cookie) +{ + uint32_t cpu_id = plat_my_core_pos(); - reg = (cpu | (sgi << XSCUGIC_SGIR_EL1_INITID_SHIFT)); - write_icc_asgi1r_el1(reg); + VERBOSE("Powering down CPU %d\n", cpu_id); + + /* Deactivate CPU power down SGI */ + plat_ic_end_of_interrupt(CPU_PWR_DOWN_REQ_INTR); + + return psci_cpu_off(); +} + +/** + * raise_pwr_down_interrupt() - Callback function to raise SGI. + * @mpidr: MPIDR for the target CPU. + * + * Raise SGI interrupt to trigger the CPU power down sequence on all the + * online secondary cores. + */ +static void raise_pwr_down_interrupt(u_register_t mpidr) +{ + plat_ic_raise_el3_sgi(CPU_PWR_DOWN_REQ_INTR, mpidr); +} + +void request_cpu_pwrdwn(void) +{ + enum pm_ret_status ret; + + VERBOSE("CPU power down request received\n"); + + /* Send powerdown request to online secondary core(s) */ + ret = psci_stop_other_cores(PWRDWN_WAIT_TIMEOUT, raise_pwr_down_interrupt); + if (ret != PSCI_E_SUCCESS) { + ERROR("Failed to powerdown secondary core(s)\n"); + } + + /* Clear IPI IRQ */ + pm_ipi_irq_clear(primary_proc); + + /* Deactivate IPI IRQ */ + plat_ic_end_of_interrupt(PLAT_VERSAL_IPI_IRQ); } static uint64_t ipi_fiq_handler(uint32_t id, uint32_t flags, void *handle, @@ -56,6 +100,7 @@ static uint64_t ipi_fiq_handler(uint32_t id, uint32_t flags, void *handle, VERBOSE("Received IPI FIQ from firmware\n"); + console_flush(); (void)plat_ic_acknowledge_interrupt(); ret = pm_get_callbackdata(payload, ARRAY_SIZE(payload), 0, 0); @@ -65,8 +110,22 @@ static uint64_t ipi_fiq_handler(uint32_t id, uint32_t flags, void *handle, switch (payload[0]) { case PM_INIT_SUSPEND_CB: + if (sgi != INVALID_SGI) { + notify_os(); + } + break; case PM_NOTIFY_CB: if (sgi != INVALID_SGI) { + if (payload[2] == EVENT_CPU_PWRDWN) { + if (pwrdwn_req_received) { + pwrdwn_req_received = false; + request_cpu_pwrdwn(); + (void)psci_cpu_off(); + break; + } else { + pwrdwn_req_received = true; + } + } notify_os(); } break; @@ -139,6 +198,12 @@ int32_t pm_setup(void) pm_ipi_init(primary_proc); pm_up = true; + /* register SGI handler for CPU power down request */ + ret = request_intr_type_el3(CPU_PWR_DOWN_REQ_INTR, cpu_pwrdwn_req_handler); + if (ret != 0) { + WARN("BL31: registering SGI interrupt failed\n"); + } + /* * Enable IPI IRQ * assume the rich OS is OK to handle callback IRQs now. diff --git a/plat/xilinx/versal/include/plat_macros.S b/plat/xilinx/versal/include/plat_macros.S index 41193a51e..38f47f669 100644 --- a/plat/xilinx/versal/include/plat_macros.S +++ b/plat/xilinx/versal/include/plat_macros.S @@ -103,8 +103,8 @@ exit_print_gic_regs: * --------------------------------------------- */ .macro plat_crash_print_regs - mov_imm x17, PLAT_GICD_BASE_VALUE - mov_imm x16, PLAT_GICR_BASE_VALUE + mov_imm x17, PLAT_ARM_GICD_BASE + mov_imm x16, PLAT_ARM_GICR_BASE versal_print_gic_regs .endm diff --git a/plat/xilinx/versal/include/platform_def.h b/plat/xilinx/versal/include/platform_def.h index fb815abc3..8cf8de0d4 100644 --- a/plat/xilinx/versal/include/platform_def.h +++ b/plat/xilinx/versal/include/platform_def.h @@ -9,6 +9,7 @@ #define PLATFORM_DEF_H #include +#include #include "versal_def.h" /******************************************************************************* @@ -112,8 +113,8 @@ #define CACHE_WRITEBACK_SHIFT 6 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) -#define PLAT_GICD_BASE_VALUE U(0xF9000000) -#define PLAT_GICR_BASE_VALUE U(0xF9080000) +#define PLAT_ARM_GICD_BASE U(0xF9000000) +#define PLAT_ARM_GICR_BASE U(0xF9080000) /* * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3 @@ -131,6 +132,8 @@ #define PLAT_VERSAL_G0_IRQ_PROPS(grp) \ INTR_PROP_DESC(PLAT_VERSAL_IPI_IRQ, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ + INTR_PROP_DESC(CPU_PWR_DOWN_REQ_INTR, GIC_HIGHEST_SEC_PRIORITY, grp, \ + GIC_INTR_CFG_EDGE) #define IRQ_MAX 142U diff --git a/plat/xilinx/versal/plat_psci.c b/plat/xilinx/versal/plat_psci.c index 56d98f79e..45b1f1c21 100644 --- a/plat/xilinx/versal/plat_psci.c +++ b/plat/xilinx/versal/plat_psci.c @@ -14,10 +14,13 @@ #include #include +#include "drivers/delay_timer.h" #include #include "pm_api_sys.h" #include "pm_client.h" #include +#include "pm_ipi.h" +#include "pm_svc_main.h" static uintptr_t versal_sec_entry; @@ -145,9 +148,31 @@ static void __dead2 versal_system_off(void) */ static void __dead2 versal_system_reset(void) { - /* Send the system reset request to the PMC */ - (void)pm_system_shutdown(XPM_SHUTDOWN_TYPE_RESET, - pm_get_shutdown_scope(), SECURE_FLAG); + uint32_t ret, timeout = 10000U; + + request_cpu_pwrdwn(); + + /* + * Send the system reset request to the firmware if power down request + * is not received from firmware. + */ + if (!pwrdwn_req_received) { + (void)pm_system_shutdown(XPM_SHUTDOWN_TYPE_RESET, + pm_get_shutdown_scope(), SECURE_FLAG); + + /* + * Wait for system shutdown request completed and idle callback + * not received. + */ + do { + ret = ipi_mb_enquire_status(primary_proc->ipi->local_ipi_id, + primary_proc->ipi->remote_ipi_id); + udelay(100); + timeout--; + } while ((ret != IPI_MB_STATUS_RECV_PENDING) && (timeout > 0U)); + } + + (void)psci_cpu_off(); while (1) { wfi(); @@ -161,6 +186,7 @@ static void __dead2 versal_system_reset(void) */ static void versal_pwr_domain_off(const psci_power_state_t *target_state) { + uint32_t ret, fw_api_version, version[PAYLOAD_ARG_CNT] = {0U}; uint32_t cpu_id = plat_my_core_pos(); const struct pm_proc *proc = pm_get_proc(cpu_id); @@ -180,8 +206,17 @@ static void versal_pwr_domain_off(const psci_power_state_t *target_state) * invoking CPU_on function, during which resume address will * be set. */ - (void)pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_IDLE, 0, - SECURE_FLAG); + ret = pm_feature_check((uint32_t)PM_SELF_SUSPEND, &version[0], SECURE_FLAG); + if (ret == PM_RET_SUCCESS) { + fw_api_version = version[0] & 0xFFFFU; + if (fw_api_version >= 3U) { + (void)pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_OFF, 0, + SECURE_FLAG); + } else { + (void)pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_IDLE, 0, + SECURE_FLAG); + } + } } /** diff --git a/plat/xilinx/versal/platform.mk b/plat/xilinx/versal/platform.mk index 35d6bc7e7..2f0799698 100644 --- a/plat/xilinx/versal/platform.mk +++ b/plat/xilinx/versal/platform.mk @@ -11,6 +11,8 @@ override RESET_TO_BL31 := 1 PL011_GENERIC_UART := 1 IPI_CRC_CHECK := 0 HARDEN_SLS_ALL := 0 +CPU_PWRDWN_SGI ?= 6 +$(eval $(call add_define_val,CPU_PWR_DOWN_REQ_INTR,ARM_IRQ_SEC_SGI_${CPU_PWRDWN_SGI})) # A72 Erratum for SoC ERRATA_A72_859971 := 1 diff --git a/plat/xilinx/versal/versal_gicv3.c b/plat/xilinx/versal/versal_gicv3.c index 197d047fb..1750d351a 100644 --- a/plat/xilinx/versal/versal_gicv3.c +++ b/plat/xilinx/versal/versal_gicv3.c @@ -62,8 +62,8 @@ static uint32_t versal_gicv3_mpidr_hash(u_register_t mpidr) } static const gicv3_driver_data_t versal_gic_data __unused = { - .gicd_base = PLAT_GICD_BASE_VALUE, - .gicr_base = PLAT_GICR_BASE_VALUE, + .gicd_base = PLAT_ARM_GICD_BASE, + .gicr_base = PLAT_ARM_GICR_BASE, .interrupt_props = versal_interrupt_props, .interrupt_props_num = ARRAY_SIZE(versal_interrupt_props), .rdistif_num = PLATFORM_CORE_COUNT, diff --git a/plat/xilinx/versal_net/aarch64/versal_net_helpers.S b/plat/xilinx/versal_net/aarch64/versal_net_helpers.S index dab871795..1ae879f3e 100644 --- a/plat/xilinx/versal_net/aarch64/versal_net_helpers.S +++ b/plat/xilinx/versal_net/aarch64/versal_net_helpers.S @@ -12,6 +12,7 @@ #include + .globl plat_arm_calc_core_pos .globl plat_secondary_cold_boot_setup .globl plat_is_my_cpu_primary .globl platform_mem_init @@ -58,6 +59,16 @@ func plat_my_core_pos b plat_core_pos_by_mpidr endfunc plat_my_core_pos + /* ----------------------------------------------------- + * unsigned int plat_arm_calc_core_pos(u_register_t mpidr) + * This function uses the plat_core_pos_by_mpidr() + * definition to get the index of the calling CPU. + * ----------------------------------------------------- + */ +func plat_arm_calc_core_pos + b plat_core_pos_by_mpidr +endfunc plat_arm_calc_core_pos + /* --------------------------------------------------------------------- * We don't need to carry out any memory initialization on Versal NET * platform. The Secure RAM is accessible straight away. diff --git a/plat/xilinx/versal_net/bl31_versal_net_setup.c b/plat/xilinx/versal_net/bl31_versal_net_setup.c index 283fee31c..614d6d233 100644 --- a/plat/xilinx/versal_net/bl31_versal_net_setup.c +++ b/plat/xilinx/versal_net/bl31_versal_net_setup.c @@ -216,8 +216,8 @@ void bl31_platform_setup(void) prepare_dtb(); /* Initialize the gic cpu and distributor interfaces */ - plat_versal_net_gic_driver_init(); - plat_versal_net_gic_init(); + plat_arm_gic_driver_init(); + plat_arm_gic_init(); } void bl31_plat_runtime_setup(void) diff --git a/plat/xilinx/versal_net/include/plat_macros.S b/plat/xilinx/versal_net/include/plat_macros.S index db7e42b35..57f8336b8 100644 --- a/plat/xilinx/versal_net/include/plat_macros.S +++ b/plat/xilinx/versal_net/include/plat_macros.S @@ -109,8 +109,8 @@ exit_print_gic_regs: * Uncomment it when versions are stable */ /* - mov_imm x17, PLAT_GICD_BASE_VALUE - mov_imm x16, PLAT_GICR_BASE_VALUE + mov_imm x17, PLAT_ARM_GICD_BASE + mov_imm x16, PLAT_ARM_GICR_BASE versal_net_print_gic_regs */ .endm diff --git a/plat/xilinx/versal_net/include/platform_def.h b/plat/xilinx/versal_net/include/platform_def.h index 872b6eeb8..8cb7deb1d 100644 --- a/plat/xilinx/versal_net/include/platform_def.h +++ b/plat/xilinx/versal_net/include/platform_def.h @@ -10,6 +10,7 @@ #define PLATFORM_DEF_H #include +#include #include "versal_net_def.h" /******************************************************************************* @@ -107,8 +108,8 @@ #define CACHE_WRITEBACK_SHIFT U(6) #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) -#define PLAT_GICD_BASE_VALUE U(0xE2000000) -#define PLAT_GICR_BASE_VALUE U(0xE2060000) +#define PLAT_ARM_GICD_BASE U(0xE2000000) +#define PLAT_ARM_GICR_BASE U(0xE2060000) /* * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3 @@ -118,13 +119,15 @@ #define PLAT_VERSAL_NET_IPI_IRQ 89 #define PLAT_VERSAL_IPI_IRQ PLAT_VERSAL_NET_IPI_IRQ -#define PLAT_VERSAL_NET_G1S_IRQ_PROPS(grp) \ +#define PLAT_ARM_G1S_IRQ_PROPS(grp) \ INTR_PROP_DESC(VERSAL_NET_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL) -#define PLAT_VERSAL_NET_G0_IRQ_PROPS(grp) \ +#define PLAT_ARM_G0_IRQ_PROPS(grp) \ INTR_PROP_DESC(PLAT_VERSAL_IPI_IRQ, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ + INTR_PROP_DESC(CPU_PWR_DOWN_REQ_INTR, GIC_HIGHEST_SEC_PRIORITY, grp, \ + GIC_INTR_CFG_EDGE) #define IRQ_MAX 200U diff --git a/plat/xilinx/versal_net/plat_psci.c b/plat/xilinx/versal_net/plat_psci.c index 6e556cdf0..fcb32b97f 100644 --- a/plat/xilinx/versal_net/plat_psci.c +++ b/plat/xilinx/versal_net/plat_psci.c @@ -108,8 +108,8 @@ static void zynqmp_pwr_domain_suspend(const psci_power_state_t *target_state) static void zynqmp_pwr_domain_on_finish(const psci_power_state_t *target_state) { - plat_versal_net_gic_pcpu_init(); - plat_versal_net_gic_cpuif_enable(); + plat_arm_gic_pcpu_init(); + plat_arm_gic_cpuif_enable(); } static void zynqmp_pwr_domain_suspend_finish(const psci_power_state_t *target_state) diff --git a/plat/xilinx/versal_net/plat_psci_pm.c b/plat/xilinx/versal_net/plat_psci_pm.c index 87e25bcdb..94cb7f58d 100644 --- a/plat/xilinx/versal_net/plat_psci_pm.c +++ b/plat/xilinx/versal_net/plat_psci_pm.c @@ -14,10 +14,12 @@ #include #include +#include #include #include "pm_api_sys.h" #include "pm_client.h" #include +#include "pm_ipi.h" #include "pm_svc_main.h" #include "versal_net_def.h" @@ -57,6 +59,7 @@ static int32_t versal_net_pwr_domain_on(u_register_t mpidr) */ static void versal_net_pwr_domain_off(const psci_power_state_t *target_state) { + uint32_t ret, fw_api_version, version[PAYLOAD_ARG_CNT] = {0U}; uint32_t cpu_id = plat_my_core_pos(); const struct pm_proc *proc = pm_get_proc(cpu_id); @@ -66,7 +69,7 @@ static void versal_net_pwr_domain_off(const psci_power_state_t *target_state) } /* Prevent interrupts from spuriously waking up this cpu */ - plat_versal_net_gic_cpuif_disable(); + plat_arm_gic_cpuif_disable(); /* * Send request to PMC to power down the appropriate APU CPU @@ -76,8 +79,17 @@ static void versal_net_pwr_domain_off(const psci_power_state_t *target_state) * invoking CPU_on function, during which resume address will * be set. */ - pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_IDLE, 0, - SECURE_FLAG); + ret = pm_feature_check((uint32_t)PM_SELF_SUSPEND, &version[0], SECURE_FLAG); + if (ret == PM_RET_SUCCESS) { + fw_api_version = version[0] & 0xFFFFU; + if (fw_api_version >= 3U) { + (void)pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_OFF, 0, + SECURE_FLAG); + } else { + (void)pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_IDLE, 0, + SECURE_FLAG); + } + } } /** @@ -88,9 +100,31 @@ static void versal_net_pwr_domain_off(const psci_power_state_t *target_state) */ static void __dead2 versal_net_system_reset(void) { - /* Send the system reset request to the PMC */ - pm_system_shutdown(XPM_SHUTDOWN_TYPE_RESET, - pm_get_shutdown_scope(), SECURE_FLAG); + uint32_t ret, timeout = 10000U; + + request_cpu_pwrdwn(); + + /* + * Send the system reset request to the firmware if power down request + * is not received from firmware. + */ + if (!pwrdwn_req_received) { + (void)pm_system_shutdown(XPM_SHUTDOWN_TYPE_RESET, + pm_get_shutdown_scope(), SECURE_FLAG); + + /* + * Wait for system shutdown request completed and idle callback + * not received. + */ + do { + ret = ipi_mb_enquire_status(primary_proc->ipi->local_ipi_id, + primary_proc->ipi->remote_ipi_id); + udelay(100); + timeout--; + } while ((ret != IPI_MB_STATUS_RECV_PENDING) && (timeout > 0U)); + } + + (void)psci_cpu_off(); while (1) { wfi(); @@ -114,10 +148,10 @@ static void versal_net_pwr_domain_suspend(const psci_power_state_t *target_state __func__, i, target_state->pwr_domain_state[i]); } - plat_versal_net_gic_cpuif_disable(); + plat_arm_gic_cpuif_disable(); if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) { - plat_versal_net_gic_save(); + plat_arm_gic_save(); } state = target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE ? @@ -135,10 +169,10 @@ static void versal_net_pwr_domain_on_finish(const psci_power_state_t *target_sta (void)target_state; /* Enable the gic cpu interface */ - plat_versal_net_gic_pcpu_init(); + plat_arm_gic_pcpu_init(); /* Program the gic per-cpu distributor or re-distributor interface */ - plat_versal_net_gic_cpuif_enable(); + plat_arm_gic_cpuif_enable(); } /** @@ -163,10 +197,10 @@ static void versal_net_pwr_domain_suspend_finish(const psci_power_state_t *targe /* APU was turned off, so restore GIC context */ if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) { - plat_versal_net_gic_resume(); + plat_arm_gic_resume(); } - plat_versal_net_gic_cpuif_enable(); + plat_arm_gic_cpuif_enable(); } /** diff --git a/plat/xilinx/versal_net/platform.mk b/plat/xilinx/versal_net/platform.mk index ad1ee2b04..da91abc82 100644 --- a/plat/xilinx/versal_net/platform.mk +++ b/plat/xilinx/versal_net/platform.mk @@ -21,6 +21,8 @@ IPI_CRC_CHECK := 0 GIC_ENABLE_V4_EXTN := 0 GICV3_SUPPORT_GIC600 := 1 TFA_NO_PM := 0 +CPU_PWRDWN_SGI ?= 6 +$(eval $(call add_define_val,CPU_PWR_DOWN_REQ_INTR,ARM_IRQ_SEC_SGI_${CPU_PWRDWN_SGI})) override CTX_INCLUDE_AARCH32_REGS := 0 @@ -121,6 +123,7 @@ BL31_SOURCES += plat/xilinx/common/plat_fdt.c \ ${PLAT_PATH}/bl31_versal_net_setup.c \ common/fdt_fixup.c \ common/fdt_wrappers.c \ + plat/arm/common/arm_gicv3.c \ ${LIBFDT_SRCS} \ ${PLAT_PATH}/sip_svc_setup.c \ - ${PLAT_PATH}/versal_net_gicv3.c + ${XLAT_TABLES_LIB_SRCS} diff --git a/plat/xilinx/versal_net/versal_net_gicv3.c b/plat/xilinx/versal_net/versal_net_gicv3.c deleted file mode 100644 index 2fdef12e8..000000000 --- a/plat/xilinx/versal_net/versal_net_gicv3.c +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved. - * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved. - * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include -#include -#include -#include -#include - -#include -#include - -/****************************************************************************** - * The following functions are defined as weak to allow a platform to override - * the way the GICv3 driver is initialised and used. - *****************************************************************************/ -#pragma weak plat_versal_net_gic_driver_init -#pragma weak plat_versal_net_gic_init -#pragma weak plat_versal_net_gic_cpuif_enable -#pragma weak plat_versal_net_gic_cpuif_disable -#pragma weak plat_versal_net_gic_pcpu_init -#pragma weak plat_versal_net_gic_redistif_on -#pragma weak plat_versal_net_gic_redistif_off - -/* The GICv3 driver only needs to be initialized in EL3 */ -static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT]; - -static const interrupt_prop_t versal_net_interrupt_props[] = { - PLAT_VERSAL_NET_G1S_IRQ_PROPS(INTR_GROUP1S), - PLAT_VERSAL_NET_G0_IRQ_PROPS(INTR_GROUP0) -}; - -/* - * We save and restore the GICv3 context on system suspend. Allocate the - * data in the designated EL3 Secure carve-out memory. - */ -static gicv3_redist_ctx_t rdist_ctx __section(".versal_net_el3_tzc_dram"); -static gicv3_dist_ctx_t dist_ctx __section(".versal_net_el3_tzc_dram"); - -/* - * MPIDR hashing function for translating MPIDRs read from GICR_TYPER register - * to core position. - * - * Calculating core position is dependent on MPIDR_EL1.MT bit. However, affinity - * values read from GICR_TYPER don't have an MT field. To reuse the same - * translation used for CPUs, we insert MT bit read from the PE's MPIDR into - * that read from GICR_TYPER. - * - * Assumptions: - * - * - All CPUs implemented in the system have MPIDR_EL1.MT bit set; - * - No CPUs implemented in the system use affinity level 3. - */ -static uint32_t versal_net_gicv3_mpidr_hash(u_register_t mpidr) -{ - mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK); - return plat_core_pos_by_mpidr(mpidr); -} - -static const gicv3_driver_data_t versal_net_gic_data __unused = { - .gicd_base = PLAT_GICD_BASE_VALUE, - .gicr_base = PLAT_GICR_BASE_VALUE, - .interrupt_props = versal_net_interrupt_props, - .interrupt_props_num = ARRAY_SIZE(versal_net_interrupt_props), - .rdistif_num = PLATFORM_CORE_COUNT, - .rdistif_base_addrs = rdistif_base_addrs, - .mpidr_to_core_pos = versal_net_gicv3_mpidr_hash -}; - -void __init plat_versal_net_gic_driver_init(void) -{ - /* - * The GICv3 driver is initialized in EL3 and does not need - * to be initialized again in SEL1. This is because the S-EL1 - * can use GIC system registers to manage interrupts and does - * not need GIC interface base addresses to be configured. - */ -#if IMAGE_BL31 - gicv3_driver_init(&versal_net_gic_data); -#endif -} - -/****************************************************************************** - * Versal NET common helper to initialize the GIC. Only invoked by BL31 - *****************************************************************************/ -void __init plat_versal_net_gic_init(void) -{ - gicv3_distif_init(); - gicv3_rdistif_init(plat_my_core_pos()); - gicv3_cpuif_enable(plat_my_core_pos()); -} - -/****************************************************************************** - * Versal NET common helper to enable the GIC CPU interface - *****************************************************************************/ -void plat_versal_net_gic_cpuif_enable(void) -{ - gicv3_cpuif_enable(plat_my_core_pos()); -} - -/****************************************************************************** - * Versal NET common helper to disable the GIC CPU interface - *****************************************************************************/ -void plat_versal_net_gic_cpuif_disable(void) -{ - gicv3_cpuif_disable(plat_my_core_pos()); -} - -/****************************************************************************** - * Versal NET common helper to initialize the per-cpu redistributor interface in - * GICv3 - *****************************************************************************/ -void plat_versal_net_gic_pcpu_init(void) -{ - gicv3_rdistif_init(plat_my_core_pos()); -} - -/****************************************************************************** - * Versal NET common helpers to power GIC redistributor interface - *****************************************************************************/ -void plat_versal_net_gic_redistif_on(void) -{ - gicv3_rdistif_on(plat_my_core_pos()); -} - -void plat_versal_net_gic_redistif_off(void) -{ - gicv3_rdistif_off(plat_my_core_pos()); -} - -/****************************************************************************** - * Versal NET common helper to save & restore the GICv3 on resume from system - * suspend - *****************************************************************************/ -void plat_versal_net_gic_save(void) -{ - /* - * If an ITS is available, save its context before - * the Redistributor using: - * gicv3_its_save_disable(gits_base, &its_ctx[i]) - * Additionnaly, an implementation-defined sequence may - * be required to save the whole ITS state. - */ - - /* - * Save the GIC Redistributors and ITS contexts before the - * Distributor context. As we only handle SYSTEM SUSPEND API, - * we only need to save the context of the CPU that is issuing - * the SYSTEM SUSPEND call, i.e. the current CPU. - */ - gicv3_rdistif_save(plat_my_core_pos(), &rdist_ctx); - - /* Save the GIC Distributor context */ - gicv3_distif_save(&dist_ctx); - - /* - * From here, all the components of the GIC can be safely powered down - * as long as there is an alternate way to handle wakeup interrupt - * sources. - */ -} - -void plat_versal_net_gic_resume(void) -{ - /* Restore the GIC Distributor context */ - gicv3_distif_init_restore(&dist_ctx); - - /* - * Restore the GIC Redistributor and ITS contexts after the - * Distributor context. As we only handle SYSTEM SUSPEND API, - * we only need to restore the context of the CPU that issued - * the SYSTEM SUSPEND call. - */ - gicv3_rdistif_init_restore(plat_my_core_pos(), &rdist_ctx); - - /* - * If an ITS is available, restore its context after - * the Redistributor using: - * gicv3_its_restore(gits_base, &its_ctx[i]) - * An implementation-defined sequence may be required to - * restore the whole ITS state. The ITS must also be - * re-enabled after this sequence has been executed. - */ -}