Merge changes from topic "idling-during-subsystem-restart" into integration

* changes:
  fix(xilinx): add console_flush() before shutdown
  fix(xilinx): fix sending sgi to linux
  feat(xilinx): add new state to identify cpu power down
  feat(xilinx): request cpu power down from reset
  feat(xilinx): power down all cores on receiving cpu pwrdwn req
  feat(xilinx): add handler for power down req sgi irq
  feat(xilinx): add wrapper to handle cpu power down req
  fix(versal-net): use arm common GIC handlers
  fix(xilinx): rename macros to align with ARM
This commit is contained in:
Joanna Farley 2024-01-22 16:12:02 +01:00 committed by TrustedFirmware Code Review
commit 1064bc6c8c
20 changed files with 238 additions and 229 deletions

View file

@ -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

View file

@ -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

View file

@ -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 */

View file

@ -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)

View file

@ -10,6 +10,8 @@
#include <pm_common.h>
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,

View file

@ -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));

View file

@ -17,6 +17,8 @@
#include <common/runtime_svc.h>
#include <drivers/arm/gicv3.h>
#include <lib/psci/psci.h>
#include <plat/arm/common/plat_arm.h>
#include <plat/common/platform.h>
#include <plat_private.h>
@ -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.

View file

@ -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

View file

@ -9,6 +9,7 @@
#define PLATFORM_DEF_H
#include <arch.h>
#include <plat_common.h>
#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

View file

@ -14,10 +14,13 @@
#include <plat/common/platform.h>
#include <plat_arm.h>
#include "drivers/delay_timer.h"
#include <plat_private.h>
#include "pm_api_sys.h"
#include "pm_client.h"
#include <pm_common.h>
#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);
}
}
}
/**

View file

@ -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

View file

@ -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,

View file

@ -12,6 +12,7 @@
#include <platform_def.h>
.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.

View file

@ -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)

View file

@ -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

View file

@ -10,6 +10,7 @@
#define PLATFORM_DEF_H
#include <arch.h>
#include <plat_common.h>
#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

View file

@ -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)

View file

@ -14,10 +14,12 @@
#include <plat/common/platform.h>
#include <plat_arm.h>
#include <drivers/delay_timer.h>
#include <plat_private.h>
#include "pm_api_sys.h"
#include "pm_client.h"
#include <pm_common.h>
#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();
}
/**

View file

@ -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}

View file

@ -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 <common/debug.h>
#include <common/interrupt_props.h>
#include <drivers/arm/gicv3.h>
#include <lib/utils.h>
#include <plat/common/platform.h>
#include <plat_private.h>
#include <platform_def.h>
/******************************************************************************
* 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.
*/
}