Merge changes from topic "xlnx_tfa_passthrough_plm_ipi_cmd" into integration

* changes:
  docs(xilinx): update SMC documentation in TF-A
  feat(xilinx): add feature check function for TF-A specific APIs
  feat(xilinx): update SiP SVC version number
  feat(xilinx): update TF-A to passthrough all PLM commands
  fix(xilinx): fix logic to read ipi response
This commit is contained in:
Joanna Farley 2024-08-12 11:48:46 +02:00 committed by TrustedFirmware Code Review
commit 778e2452b1
15 changed files with 187 additions and 41 deletions

View file

@ -75,7 +75,7 @@ IPI SMC call ranges
| 0xc2001000-0xc2001FFF | Fast SMC64 SiP Service call range used for AMD-Xilinx IPI |
+---------------------------+-----------------------------------------------------------+
PM SMC call ranges
PM SMC call ranges for SiP SVC version 0.1
--------------------------------------------------------
+---------------------------+---------------------------------------------------------------------------+
@ -84,6 +84,19 @@ PM SMC call ranges
| 0xc2000000-0xc2000FFF | Fast SMC64 SiP Service call range used for AMD-Xilinx Platform Management |
+---------------------------+---------------------------------------------------------------------------+
PM SMC call ranges for SiP SVC version 0.2
--------------------------------------------------------
+---------------------------+---------------------------------------------------------------------------+
| SMC Function Identifier | Service type |
+---------------------------+---------------------------------------------------------------------------+
| 0xc2000FFF | Fast SMC64 SiP Service call used for pass-through of AMD-Xilinx Platform |
| | Management APIs to firmware |
+---------------------------+---------------------------------------------------------------------------+
| 0xc2000A00-0xc2000AFF | Fast SMC64 SiP Service call range used for AMD-Xilinx Platform Management |
| | specific TF-A APIs |
+---------------------------+---------------------------------------------------------------------------+
SMC function IDs for SiP Service queries
----------------------------------------------

View file

@ -98,8 +98,8 @@ IPI SMC call ranges
| 0xc2001000-0xc2001FFF | Fast SMC64 SiP Service call range used for AMD-Xilinx IPI |
+---------------------------+-----------------------------------------------------------+
PM SMC call ranges
------------------
PM SMC call ranges for SiP SVC version 0.1
--------------------------------------------------------
+---------------------------+---------------------------------------------------------------------------+
| SMC Function Identifier | Service type |
@ -107,6 +107,19 @@ PM SMC call ranges
| 0xc2000000-0xc2000FFF | Fast SMC64 SiP Service call range used for AMD-Xilinx Platform Management |
+---------------------------+---------------------------------------------------------------------------+
PM SMC call ranges for SiP SVC version 0.2
--------------------------------------------------------
+---------------------------+---------------------------------------------------------------------------+
| SMC Function Identifier | Service type |
+---------------------------+---------------------------------------------------------------------------+
| 0xc2000FFF | Fast SMC64 SiP Service call used for pass-through of AMD-Xilinx Platform |
| | Management APIs to firmware |
+---------------------------+---------------------------------------------------------------------------+
| 0xc2000A00-0xc2000AFF | Fast SMC64 SiP Service call range used for AMD-Xilinx Platform Management |
| | specific TF-A APIs |
+---------------------------+---------------------------------------------------------------------------+
SMC function IDs for SiP Service queries
----------------------------------------

View file

@ -64,6 +64,7 @@ enum pm_ret_status pm_register_notifier(uint32_t device_id, uint32_t event,
uint32_t wake, uint32_t enable,
uint32_t flag);
enum pm_ret_status pm_get_chipid(uint32_t *value);
enum pm_ret_status eemi_feature_check(uint32_t api_id, uint32_t *ret_payload);
/*
* Assigning of argument values into array elements.
@ -97,4 +98,9 @@ enum pm_ret_status pm_get_chipid(uint32_t *value);
PM_PACK_PAYLOAD5(pl, (mid), (flag), (arg0), (arg1), (arg2), (arg3), (arg4)); \
}
#define PM_PACK_PAYLOAD7(pl, mid, flag, arg0, arg1, arg2, arg3, arg4, arg5, arg6) { \
pl[6] = (uint32_t)(arg6); \
PM_PACK_PAYLOAD6(pl, (mid), (flag), (arg0), (arg1), (arg2), (arg3), (arg4), (arg5)); \
}
#endif /* PM_API_SYS_H */

View file

@ -1,6 +1,6 @@
/*
* Copyright (c) 2013-2018, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
* Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -18,13 +18,15 @@
#if IPI_CRC_CHECK
#define PAYLOAD_ARG_CNT 8U
#define RET_PAYLOAD_ARG_CNT 7U
#define IPI_W0_TO_W6_SIZE 28U
#define PAYLOAD_CRC_POS 7U
#define CRC_INIT_VALUE 0x4F4EU
#define CRC_ORDER 16U
#define CRC_POLYNOM 0x8005U
#else
#define PAYLOAD_ARG_CNT 6U
#define PAYLOAD_ARG_CNT 7U
#define RET_PAYLOAD_ARG_CNT 6U
#endif
#define PAYLOAD_ARG_SIZE 4U /* size in bytes */

View file

@ -35,6 +35,7 @@
(uint32_t)XPM_NODESUBCL_DEV_PERIPH, \
(uint32_t)XPM_NODETYPE_DEV_PERIPH, (IDX))
#define TF_A_FEATURE_CHECK 0xa00U
#define PM_GET_CALLBACK_DATA 0xa01U
#define PM_GET_TRUSTZONE_VERSION 0xa03U
#define TF_A_PM_REGISTER_SGI 0xa04U

View file

@ -1,6 +1,6 @@
/*
* Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
* Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
* Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -12,6 +12,8 @@
extern bool pwrdwn_req_received;
#define PASS_THROUGH_FW_CMD_ID U(0xfff)
/******************************************************************************/
/**
* SECURE_REDUNDANT_CALL() - Adds redundancy to the function call. This is to

View file

@ -122,7 +122,7 @@ enum pm_ret_status pm_handle_eemi_call(uint32_t flag, uint32_t x0, uint32_t x1,
}
PM_PACK_PAYLOAD6(payload, module_id, flag, x0, x1, x2, x3, x4, x5);
return pm_ipi_send_sync(primary_proc, payload, (uint32_t *)result, PAYLOAD_ARG_CNT);
return pm_ipi_send_sync(primary_proc, payload, (uint32_t *)result, RET_PAYLOAD_ARG_CNT);
}
/**
@ -363,6 +363,37 @@ enum pm_ret_status pm_set_wakeup_source(uint32_t target, uint32_t wkup_device,
return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
}
/**
* eemi_feature_check() - Returns the supported API version if supported.
* @api_id: API ID to check.
* @ret_payload: pointer to array of PAYLOAD_ARG_CNT number of
* words Returned supported API version
*
* Return: Returns status, either success or error+reason.
*/
enum pm_ret_status eemi_feature_check(uint32_t api_id, uint32_t *ret_payload)
{
enum pm_ret_status ret;
/* Return version of API which are implemented in TF-A only */
switch (api_id) {
case PM_GET_CALLBACK_DATA:
case PM_GET_TRUSTZONE_VERSION:
ret_payload[0] = PM_API_VERSION_2;
ret = PM_RET_SUCCESS;
break;
case TF_A_PM_REGISTER_SGI:
case TF_A_FEATURE_CHECK:
ret_payload[0] = PM_API_BASE_VERSION;
ret = PM_RET_SUCCESS;
break;
default:
ret = PM_RET_ERROR_NO_FEATURE;
}
return ret;
}
/**
* pm_feature_check() - Returns the supported API version if supported.
* @api_id: API ID to check.
@ -406,7 +437,7 @@ enum pm_ret_status pm_feature_check(uint32_t api_id, uint32_t *ret_payload,
PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag,
PM_FEATURE_CHECK, api_id);
return pm_ipi_send_sync(primary_proc, payload, ret_payload, PAYLOAD_ARG_CNT);
return pm_ipi_send_sync(primary_proc, payload, ret_payload, RET_PAYLOAD_ARG_CNT);
}
/**

View file

@ -1,7 +1,7 @@
/*
* Copyright (c) 2013-2020, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
* Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
* Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -164,15 +164,10 @@ enum pm_ret_status pm_ipi_send(const struct pm_proc *proc,
*
*/
static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc,
uint32_t *value, size_t count)
uint32_t value[PAYLOAD_ARG_CNT])
{
size_t i;
enum pm_ret_status ret;
#if IPI_CRC_CHECK
uint32_t *payload_ptr = value;
size_t j;
uint32_t response_payload[PAYLOAD_ARG_CNT];
#endif
uintptr_t buffer_base = proc->ipi->buffer_base +
IPI_BUFFER_TARGET_REMOTE_OFFSET +
IPI_BUFFER_RESP_OFFSET;
@ -184,27 +179,21 @@ static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc,
* buf-2: unused
* buf-3: unused
*/
for (i = 1; i <= count; i++) {
*value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
value++;
for (i = 0; i < PAYLOAD_ARG_CNT; i++) {
value[i] = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
}
ret = mmio_read_32(buffer_base);
ret = value[0];
#if IPI_CRC_CHECK
for (j = 0; j < PAYLOAD_ARG_CNT; j++) {
response_payload[j] = mmio_read_32(buffer_base +
(j * PAYLOAD_ARG_SIZE));
}
if (response_payload[PAYLOAD_CRC_POS] !=
calculate_crc(response_payload, IPI_W0_TO_W6_SIZE)) {
if (value[PAYLOAD_CRC_POS] !=
calculate_crc(value, IPI_W0_TO_W6_SIZE)) {
NOTICE("ERROR in CRC response payload value:0x%x\n",
response_payload[PAYLOAD_CRC_POS]);
value[PAYLOAD_CRC_POS]);
ret = PM_RET_ERROR_INVALID_CRC;
/* Payload data is invalid as CRC validation failed
* Clear the payload to avoid leakage of data to upper layers
*/
memset(payload_ptr, 0, count);
memset(value, 0, PAYLOAD_ARG_CNT);
}
#endif
@ -240,7 +229,7 @@ enum pm_ret_status pm_ipi_buff_read_callb(uint32_t *value, size_t count)
count = IPI_BUFFER_MAX_WORDS;
}
for (i = 0; i <= count; i++) {
for (i = 0; i < count; i++) {
*value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
value++;
}
@ -282,6 +271,7 @@ enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc,
uint32_t *value, size_t count)
{
enum pm_ret_status ret;
uint32_t i, ret_payload[PAYLOAD_ARG_CNT] = {0U};
pm_ipi_lock_get();
@ -290,7 +280,12 @@ enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc,
goto unlock;
}
ret = ERROR_CODE_MASK & (pm_ipi_buff_read(proc, value, count));
ret = ERROR_CODE_MASK & (pm_ipi_buff_read(proc, ret_payload));
for (i = 1U; i <= count; i++) {
*value = ret_payload[i];
value++;
}
unlock:
pm_ipi_lock_release();

View file

@ -36,6 +36,32 @@
#define EVENT_CPU_PWRDWN (4U)
#define MBOX_SGI_SHARED_IPI (7U)
/**
* upper_32_bits - return bits 32-63 of a number
* @n: the number we're accessing
*/
#define upper_32_bits(n) ((uint32_t)((n) >> 32U))
/**
* lower_32_bits - return bits 0-31 of a number
* @n: the number we're accessing
*/
#define lower_32_bits(n) ((uint32_t)((n) & 0xffffffffU))
/**
* EXTRACT_SMC_ARGS - extracts 32-bit payloads from 64-bit SMC arguments
* @pm_arg: array of 32-bit payloads
* @x: array of 64-bit SMC arguments
*/
#define EXTRACT_ARGS(pm_arg, x) \
for (uint32_t i = 0U; i < (PAYLOAD_ARG_CNT - 1U); i++) { \
if ((i % 2U) != 0U) { \
pm_arg[i] = lower_32_bits(x[(i / 2U) + 1U]); \
} else { \
pm_arg[i] = upper_32_bits(x[i / 2U]); \
} \
}
/* 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)
@ -278,7 +304,7 @@ static uintptr_t eemi_for_compatibility(uint32_t api_id, uint32_t *pm_arg,
case (uint32_t)PM_FEATURE_CHECK:
{
uint32_t result[PAYLOAD_ARG_CNT] = {0U};
uint32_t result[RET_PAYLOAD_ARG_CNT] = {0U};
ret = pm_feature_check(pm_arg[0], result, security_flag);
SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U),
@ -367,6 +393,15 @@ static uintptr_t TF_A_specific_handler(uint32_t api_id, uint32_t *pm_arg,
{
switch (api_id) {
case TF_A_FEATURE_CHECK:
{
enum pm_ret_status ret;
uint32_t result[PAYLOAD_ARG_CNT] = {0U};
ret = eemi_feature_check(pm_arg[0], result);
SMC_RET1(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U));
}
case TF_A_PM_REGISTER_SGI:
{
int32_t ret;
@ -424,7 +459,7 @@ static uintptr_t eemi_handler(uint32_t api_id, uint32_t *pm_arg,
void *handle, uint32_t security_flag)
{
enum pm_ret_status ret;
uint32_t buf[PAYLOAD_ARG_CNT] = {0};
uint32_t buf[RET_PAYLOAD_ARG_CNT] = {0};
ret = pm_handle_eemi_call(security_flag, api_id, pm_arg[0], pm_arg[1],
pm_arg[2], pm_arg[3], pm_arg[4],
@ -448,6 +483,45 @@ static uintptr_t eemi_handler(uint32_t api_id, uint32_t *pm_arg,
(uint64_t)buf[1] | ((uint64_t)buf[2] << 32U));
}
/**
* eemi_api_handler() - Prepare EEMI payload and perform IPI transaction.
* @api_id: identifier for the API being called.
* @pm_arg: pointer to the argument data for the API call.
* @handle: Pointer to caller's context structure.
* @security_flag: SECURE_FLAG or NON_SECURE_FLAG.
*
* EEMI - Embedded Energy Management Interface is AMD-Xilinx proprietary
* protocol to allow communication between power management controller and
* different processing clusters.
*
* This handler prepares EEMI protocol payload received from kernel and performs
* IPI transaction.
*
* Return: If EEMI API found then, uintptr_t type address, else 0
*/
static uintptr_t eemi_api_handler(uint32_t api_id, const uint32_t *pm_arg,
void *handle, uint32_t security_flag)
{
enum pm_ret_status ret;
uint32_t buf[PAYLOAD_ARG_CNT] = {0};
uint32_t payload[PAYLOAD_ARG_CNT] = {0};
uint32_t module_id;
module_id = (api_id & MODULE_ID_MASK) >> 8U;
PM_PACK_PAYLOAD7(payload, module_id, security_flag, api_id,
pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3],
pm_arg[4], pm_arg[5]);
ret = pm_ipi_send_sync(primary_proc, payload, (uint32_t *)buf,
PAYLOAD_ARG_CNT);
SMC_RET4(handle, (uint64_t)ret | ((uint64_t)buf[0] << 32U),
(uint64_t)buf[1] | ((uint64_t)buf[2] << 32U),
(uint64_t)buf[3] | ((uint64_t)buf[4] << 32U),
(uint64_t)buf[5]);
}
/**
* pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2.
* @smc_fid: Function Identifier.
@ -477,6 +551,7 @@ uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
uint32_t security_flag = NON_SECURE_FLAG;
uint32_t api_id;
bool status = false, status_tmp = false;
uint64_t x[4] = {x1, x2, x3, x4};
/* Handle case where PM wasn't initialized properly */
if (pm_up == false) {
@ -494,6 +569,14 @@ uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
security_flag = SECURE_FLAG;
}
if ((smc_fid & FUNCID_NUM_MASK) == PASS_THROUGH_FW_CMD_ID) {
api_id = lower_32_bits(x[0]);
EXTRACT_ARGS(pm_arg, x);
return eemi_api_handler(api_id, pm_arg, handle, security_flag);
}
pm_arg[0] = (uint32_t)x1;
pm_arg[1] = (uint32_t)(x1 >> 32U);
pm_arg[2] = (uint32_t)x2;

View file

@ -197,7 +197,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 ret, fw_api_version, version[RET_PAYLOAD_ARG_CNT] = {0U};
uint32_t cpu_id = plat_my_core_pos();
const struct pm_proc *proc = pm_get_proc(cpu_id);

View file

@ -1,6 +1,6 @@
/*
* Copyright (c) 2018-2021, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
* Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -22,7 +22,7 @@
/* SiP Service Calls version numbers */
#define SIP_SVC_VERSION_MAJOR U(0)
#define SIP_SVC_VERSION_MINOR U(1)
#define SIP_SVC_VERSION_MINOR U(2)
/* These macros are used to identify PM calls from the SMC function ID */
#define SIP_FID_MASK GENMASK(23, 16)

View file

@ -59,7 +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 ret, fw_api_version, version[RET_PAYLOAD_ARG_CNT] = {0U};
uint32_t cpu_id = plat_my_core_pos();
const struct pm_proc *proc = pm_get_proc(cpu_id);

View file

@ -1,7 +1,7 @@
/*
* Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
* Copyright (c) 2022, Advanced Micro Devices, Inc. All rights reserved.
* Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -25,7 +25,7 @@
/* SiP Service Calls version numbers */
#define SIP_SVC_VERSION_MAJOR (0U)
#define SIP_SVC_VERSION_MINOR (1U)
#define SIP_SVC_VERSION_MINOR (2U)
/* These macros are used to identify PM calls from the SMC function ID */
#define SIP_FID_MASK GENMASK(23, 16)

View file

@ -919,7 +919,7 @@ static enum pm_ret_status feature_check_partial(uint32_t api_id,
enum pm_ret_status pm_feature_check(uint32_t api_id, uint32_t *version,
uint32_t *bit_mask, uint8_t len)
{
uint32_t ret_payload[PAYLOAD_ARG_CNT] = {0U};
uint32_t ret_payload[RET_PAYLOAD_ARG_CNT] = {0U};
uint32_t status;
/* Get API version implemented in TF-A */

View file

@ -285,7 +285,7 @@ uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
uint32_t payload[PAYLOAD_ARG_CNT];
uint32_t pm_arg[5];
uint32_t result[PAYLOAD_ARG_CNT] = {0};
uint32_t result[RET_PAYLOAD_ARG_CNT] = {0};
uint32_t api_id;
/* Handle case where PM wasn't initialized properly */
@ -566,7 +566,7 @@ uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
PM_PACK_PAYLOAD6(payload, api_id, pm_arg[0], pm_arg[1],
pm_arg[2], pm_arg[3], pm_arg[4]);
ret = pm_ipi_send_sync(primary_proc, payload, result,
PAYLOAD_ARG_CNT);
RET_PAYLOAD_ARG_CNT);
SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U),
(uint64_t)result[1] | ((uint64_t)result[2] << 32U));
}