[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <54953d15-3d0a-4fbb-9e8a-02dbfb2d8a00@amd.com>
Date: Wed, 2 Oct 2024 12:55:24 +0200
From: Michal Simek <michal.simek@....com>
To: Ronak Jain <ronak.jain@....com>
Cc: linux-arm-kernel@...ts.infradead.org, linux-kernel@...r.kernel.org
Subject: Re: [PATCH] firmware: xilinx: add support for new SMC call format
On 9/20/24 07:55, Ronak Jain wrote:
> Added zynqmp_pm_invoke_fw_fn() to use new SMC format in which
> lower 12 bits of SMC id are fixed and firmware header is moved to
> subsequent SMC arguments. The new SMC format supports full request and
> response buffers.
>
> Added zynqmp_pm_get_sip_svc_version() to get SiP SVC version
> number to check if TF-A is newer or older and use the SMC format
> accordingly to handle backward compatibility.
>
> Used new SMC format for PM_QUERY_DATA API as more response values are
> required in it.
>
> Signed-off-by: Ronak Jain <ronak.jain@....com>
> Signed-off-by: Jay Buddhabhatti <jay.buddhabhatti@....com>
> ---
> drivers/firmware/xilinx/zynqmp.c | 137 ++++++++++++++++++++++++++-
> include/linux/firmware/xlnx-zynqmp.h | 26 ++++-
> 2 files changed, 157 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c
> index c8be32d9c6af..5ab0dfb2b225 100644
> --- a/drivers/firmware/xilinx/zynqmp.c
> +++ b/drivers/firmware/xilinx/zynqmp.c
> @@ -3,7 +3,7 @@
> * Xilinx Zynq MPSoC Firmware layer
> *
> * Copyright (C) 2014-2022 Xilinx, Inc.
> - * Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc.
> + * Copyright (C) 2022 - 2024, Advanced Micro Devices, Inc.
> *
> * Michal Simek <michal.simek@....com>
> * Davorin Mista <davorin.mista@...ios.com>
> @@ -46,6 +46,7 @@ static DEFINE_HASHTABLE(pm_api_features_map, PM_API_FEATURE_CHECK_MAX_ORDER);
> static u32 ioctl_features[FEATURE_PAYLOAD_SIZE];
> static u32 query_features[FEATURE_PAYLOAD_SIZE];
>
> +static u32 sip_svc_version;
> static struct platform_device *em_dev;
>
> /**
> @@ -151,6 +152,9 @@ static noinline int do_fw_call_smc(u32 *ret_payload, u32 num_args, ...)
> ret_payload[1] = upper_32_bits(res.a0);
> ret_payload[2] = lower_32_bits(res.a1);
> ret_payload[3] = upper_32_bits(res.a1);
> + ret_payload[4] = lower_32_bits(res.a2);
> + ret_payload[5] = upper_32_bits(res.a2);
> + ret_payload[6] = lower_32_bits(res.a3);
> }
>
> return zynqmp_pm_ret_code((enum pm_ret_status)res.a0);
> @@ -191,6 +195,9 @@ static noinline int do_fw_call_hvc(u32 *ret_payload, u32 num_args, ...)
> ret_payload[1] = upper_32_bits(res.a0);
> ret_payload[2] = lower_32_bits(res.a1);
> ret_payload[3] = upper_32_bits(res.a1);
> + ret_payload[4] = lower_32_bits(res.a2);
> + ret_payload[5] = upper_32_bits(res.a2);
> + ret_payload[6] = lower_32_bits(res.a3);
> }
>
> return zynqmp_pm_ret_code((enum pm_ret_status)res.a0);
> @@ -331,6 +338,70 @@ int zynqmp_pm_is_function_supported(const u32 api_id, const u32 id)
> }
> EXPORT_SYMBOL_GPL(zynqmp_pm_is_function_supported);
>
> +/**
> + * zynqmp_pm_invoke_fw_fn() - Invoke the system-level platform management layer
> + * caller function depending on the configuration
> + * @pm_api_id: Requested PM-API call
> + * @ret_payload: Returned value array
> + * @num_args: Number of arguments to requested PM-API call
> + *
> + * Invoke platform management function for SMC or HVC call, depending on
> + * configuration.
> + * Following SMC Calling Convention (SMCCC) for SMC64:
> + * Pm Function Identifier,
> + * PM_SIP_SVC + PASS_THROUGH_FW_CMD_ID =
> + * ((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT)
> + * ((SMC_64) << FUNCID_CC_SHIFT)
> + * ((SIP_START) << FUNCID_OEN_SHIFT)
> + * (PASS_THROUGH_FW_CMD_ID))
> + *
> + * PM_SIP_SVC - Registered ZynqMP SIP Service Call.
> + * PASS_THROUGH_FW_CMD_ID - Fixed SiP SVC call ID for FW specific calls.
> + *
> + * Return: Returns status, either success or error+reason
> + */
> +int zynqmp_pm_invoke_fw_fn(u32 pm_api_id, u32 *ret_payload, u32 num_args, ...)
> +{
> + /*
> + * Added SIP service call Function Identifier
> + * Make sure to stay in x0 register
> + */
> + u64 smc_arg[SMC_ARG_CNT_64];
> + int ret, i;
> + va_list arg_list;
> + u32 args[SMC_ARG_CNT_32] = {0};
> + u32 module_id;
> +
> + if (num_args > SMC_ARG_CNT_32)
> + return -EINVAL;
> +
> + va_start(arg_list, num_args);
> +
> + /* Check if feature is supported or not */
> + ret = zynqmp_pm_feature(pm_api_id);
> + if (ret < 0)
> + return ret;
> +
> + for (i = 0; i < num_args; i++)
> + args[i] = va_arg(arg_list, u32);
> +
> + va_end(arg_list);
> +
> + module_id = FIELD_GET(PLM_MODULE_ID_MASK, pm_api_id);
> +
> + if (module_id == 0)
> + module_id = XPM_MODULE_ID;
> +
> + smc_arg[0] = PM_SIP_SVC | PASS_THROUGH_FW_CMD_ID;
> + smc_arg[1] = ((u64)args[0] << 32U) | FIELD_PREP(PLM_MODULE_ID_MASK, module_id) |
> + (pm_api_id & API_ID_MASK);
> + for (i = 1; i < (SMC_ARG_CNT_64 - 1); i++)
> + smc_arg[i + 1] = ((u64)args[(i * 2)] << 32U) | args[(i * 2) - 1];
> +
> + return do_fw_call(ret_payload, 8, smc_arg[0], smc_arg[1], smc_arg[2], smc_arg[3],
> + smc_arg[4], smc_arg[5], smc_arg[6], smc_arg[7]);
> +}
> +
> /**
> * zynqmp_pm_invoke_fn() - Invoke the system-level platform management layer
> * caller function depending on the configuration
> @@ -488,6 +559,35 @@ int zynqmp_pm_get_family_info(u32 *family, u32 *subfamily)
> }
> EXPORT_SYMBOL_GPL(zynqmp_pm_get_family_info);
>
> +/**
> + * zynqmp_pm_get_sip_svc_version() - Get SiP service call version
> + * @version: Returned version value
> + *
> + * Return: Returns status, either success or error+reason
> + */
> +static int zynqmp_pm_get_sip_svc_version(u32 *version)
> +{
> + struct arm_smccc_res res;
> + u64 args[SMC_ARG_CNT_64] = {0};
> +
> + if (!version)
> + return -EINVAL;
> +
> + /* Check if SiP SVC version already verified */
> + if (sip_svc_version > 0) {
> + *version = sip_svc_version;
> + return 0;
> + }
> +
> + args[0] = GET_SIP_SVC_VERSION;
> +
> + arm_smccc_smc(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], &res);
> +
> + *version = ((lower_32_bits(res.a0) << 16U) | lower_32_bits(res.a1));
> +
> + return zynqmp_pm_ret_code(XST_PM_SUCCESS);
> +}
> +
> /**
> * zynqmp_pm_get_trustzone_version() - Get secure trustzone firmware version
> * @version: Returned version value
> @@ -552,10 +652,34 @@ static int get_set_conduit_method(struct device_node *np)
> */
> int zynqmp_pm_query_data(struct zynqmp_pm_query_data qdata, u32 *out)
> {
> - int ret;
> + int ret, i = 0;
> + u32 ret_payload[PAYLOAD_ARG_CNT] = {0};
> +
> + if (sip_svc_version >= SIP_SVC_PASSTHROUGH_VERSION) {
> + ret = zynqmp_pm_invoke_fw_fn(PM_QUERY_DATA, ret_payload, 4,
> + qdata.qid, qdata.arg1,
> + qdata.arg2, qdata.arg3);
> + /* To support backward compatibility */
> + if (!ret && !ret_payload[0]) {
> + /*
> + * TF-A passes return status on 0th index but
> + * api to get clock name reads data from 0th
> + * index so pass data at 0th index instead of
> + * return status
> + */
> + if (qdata.qid == PM_QID_CLOCK_GET_NAME ||
> + qdata.qid == PM_QID_PINCTRL_GET_FUNCTION_NAME)
> + i = 1;
> +
> + for (; i < PAYLOAD_ARG_CNT; i++, out++)
> + *out = ret_payload[i];
>
> - ret = zynqmp_pm_invoke_fn(PM_QUERY_DATA, out, 4, qdata.qid, qdata.arg1, qdata.arg2,
> - qdata.arg3);
> + return ret;
> + }
> + }
> +
> + ret = zynqmp_pm_invoke_fn(PM_QUERY_DATA, out, 4, qdata.qid,
> + qdata.arg1, qdata.arg2, qdata.arg3);
>
> /*
> * For clock name query, all bytes in SMC response are clock name
> @@ -1887,6 +2011,11 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
> if (ret)
> return ret;
>
> + /* Get SiP SVC version number */
> + ret = zynqmp_pm_get_sip_svc_version(&sip_svc_version);
> + if (ret)
> + return ret;
> +
> ret = do_feature_check_call(PM_FEATURE_CHECK);
> if (ret >= 0 && ((ret & FIRMWARE_VERSION_MASK) >= PM_API_VERSION_1))
> feature_check_enabled = true;
> diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h
> index 5b938fc2adad..76d85ad82ec0 100644
> --- a/include/linux/firmware/xlnx-zynqmp.h
> +++ b/include/linux/firmware/xlnx-zynqmp.h
> @@ -3,7 +3,7 @@
> * Xilinx Zynq MPSoC Firmware layer
> *
> * Copyright (C) 2014-2021 Xilinx
> - * Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc.
> + * Copyright (C) 2022 - 2024, Advanced Micro Devices, Inc.
> *
> * Michal Simek <michal.simek@....com>
> * Davorin Mista <davorin.mista@...ios.com>
> @@ -32,6 +32,19 @@
> /* SMC SIP service Call Function Identifier Prefix */
> #define PM_SIP_SVC 0xC2000000
>
> +/* SMC function ID to get SiP SVC version */
> +#define GET_SIP_SVC_VERSION (0x8200ff03U)
> +
> +/* SiP Service Calls version numbers */
> +#define SIP_SVC_VERSION_MAJOR (0U)
> +#define SIP_SVC_VERSION_MINOR (2U)
> +
> +#define SIP_SVC_PASSTHROUGH_VERSION ((SIP_SVC_VERSION_MAJOR << 16) | \
> + SIP_SVC_VERSION_MINOR)
> +
> +/* Fixed ID for FW specific APIs */
> +#define PASS_THROUGH_FW_CMD_ID GENMASK(11, 0)
> +
> /* PM API versions */
> #define PM_API_VERSION_1 1
> #define PM_API_VERSION_2 2
> @@ -51,6 +64,7 @@
>
> #define API_ID_MASK GENMASK(7, 0)
> #define MODULE_ID_MASK GENMASK(11, 8)
> +#define PLM_MODULE_ID_MASK GENMASK(15, 8)
>
> /* Firmware feature check version mask */
> #define FIRMWARE_VERSION_MASK 0xFFFFU
> @@ -62,7 +76,13 @@
> #define GET_CALLBACK_DATA 0xa01
>
> /* Number of 32bits values in payload */
> -#define PAYLOAD_ARG_CNT 4U
> +#define PAYLOAD_ARG_CNT 7U
> +
> +/* Number of 64bits arguments for SMC call */
> +#define SMC_ARG_CNT_64 8U
> +
> +/* Number of 32bits arguments for SMC call */
> +#define SMC_ARG_CNT_32 13U
>
> /* Number of arguments for a callback */
> #define CB_ARG_CNT 4
> @@ -130,6 +150,7 @@
>
> enum pm_module_id {
> PM_MODULE_ID = 0x0,
> + XPM_MODULE_ID = 0x2,
> XSEM_MODULE_ID = 0x3,
> TF_A_MODULE_ID = 0xa,
> };
> @@ -537,6 +558,7 @@ struct zynqmp_pm_query_data {
> };
>
> int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 *ret_payload, u32 num_args, ...);
> +int zynqmp_pm_invoke_fw_fn(u32 pm_api_id, u32 *ret_payload, u32 num_args, ...);
>
> #if IS_REACHABLE(CONFIG_ZYNQMP_FIRMWARE)
> int zynqmp_pm_get_api_version(u32 *version);
Applied.
M
Powered by blists - more mailing lists