Skip to content

Commit 92fb713

Browse files
ronakj89michalsimek
authored andcommitted
firmware: xilinx: add support for new SMC call format
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 <[email protected]> Signed-off-by: Jay Buddhabhatti <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Michal Simek <[email protected]>
1 parent e8415a8 commit 92fb713

File tree

2 files changed

+157
-6
lines changed

2 files changed

+157
-6
lines changed

drivers/firmware/xilinx/zynqmp.c

Lines changed: 133 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Xilinx Zynq MPSoC Firmware layer
44
*
55
* Copyright (C) 2014-2022 Xilinx, Inc.
6-
* Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc.
6+
* Copyright (C) 2022 - 2024, Advanced Micro Devices, Inc.
77
*
88
* Michal Simek <[email protected]>
99
* Davorin Mista <[email protected]>
@@ -46,6 +46,7 @@ static DEFINE_HASHTABLE(pm_api_features_map, PM_API_FEATURE_CHECK_MAX_ORDER);
4646
static u32 ioctl_features[FEATURE_PAYLOAD_SIZE];
4747
static u32 query_features[FEATURE_PAYLOAD_SIZE];
4848

49+
static u32 sip_svc_version;
4950
static struct platform_device *em_dev;
5051

5152
/**
@@ -151,6 +152,9 @@ static noinline int do_fw_call_smc(u32 *ret_payload, u32 num_args, ...)
151152
ret_payload[1] = upper_32_bits(res.a0);
152153
ret_payload[2] = lower_32_bits(res.a1);
153154
ret_payload[3] = upper_32_bits(res.a1);
155+
ret_payload[4] = lower_32_bits(res.a2);
156+
ret_payload[5] = upper_32_bits(res.a2);
157+
ret_payload[6] = lower_32_bits(res.a3);
154158
}
155159

156160
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, ...)
191195
ret_payload[1] = upper_32_bits(res.a0);
192196
ret_payload[2] = lower_32_bits(res.a1);
193197
ret_payload[3] = upper_32_bits(res.a1);
198+
ret_payload[4] = lower_32_bits(res.a2);
199+
ret_payload[5] = upper_32_bits(res.a2);
200+
ret_payload[6] = lower_32_bits(res.a3);
194201
}
195202

196203
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)
331338
}
332339
EXPORT_SYMBOL_GPL(zynqmp_pm_is_function_supported);
333340

341+
/**
342+
* zynqmp_pm_invoke_fw_fn() - Invoke the system-level platform management layer
343+
* caller function depending on the configuration
344+
* @pm_api_id: Requested PM-API call
345+
* @ret_payload: Returned value array
346+
* @num_args: Number of arguments to requested PM-API call
347+
*
348+
* Invoke platform management function for SMC or HVC call, depending on
349+
* configuration.
350+
* Following SMC Calling Convention (SMCCC) for SMC64:
351+
* Pm Function Identifier,
352+
* PM_SIP_SVC + PASS_THROUGH_FW_CMD_ID =
353+
* ((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT)
354+
* ((SMC_64) << FUNCID_CC_SHIFT)
355+
* ((SIP_START) << FUNCID_OEN_SHIFT)
356+
* (PASS_THROUGH_FW_CMD_ID))
357+
*
358+
* PM_SIP_SVC - Registered ZynqMP SIP Service Call.
359+
* PASS_THROUGH_FW_CMD_ID - Fixed SiP SVC call ID for FW specific calls.
360+
*
361+
* Return: Returns status, either success or error+reason
362+
*/
363+
int zynqmp_pm_invoke_fw_fn(u32 pm_api_id, u32 *ret_payload, u32 num_args, ...)
364+
{
365+
/*
366+
* Added SIP service call Function Identifier
367+
* Make sure to stay in x0 register
368+
*/
369+
u64 smc_arg[SMC_ARG_CNT_64];
370+
int ret, i;
371+
va_list arg_list;
372+
u32 args[SMC_ARG_CNT_32] = {0};
373+
u32 module_id;
374+
375+
if (num_args > SMC_ARG_CNT_32)
376+
return -EINVAL;
377+
378+
va_start(arg_list, num_args);
379+
380+
/* Check if feature is supported or not */
381+
ret = zynqmp_pm_feature(pm_api_id);
382+
if (ret < 0)
383+
return ret;
384+
385+
for (i = 0; i < num_args; i++)
386+
args[i] = va_arg(arg_list, u32);
387+
388+
va_end(arg_list);
389+
390+
module_id = FIELD_GET(PLM_MODULE_ID_MASK, pm_api_id);
391+
392+
if (module_id == 0)
393+
module_id = XPM_MODULE_ID;
394+
395+
smc_arg[0] = PM_SIP_SVC | PASS_THROUGH_FW_CMD_ID;
396+
smc_arg[1] = ((u64)args[0] << 32U) | FIELD_PREP(PLM_MODULE_ID_MASK, module_id) |
397+
(pm_api_id & API_ID_MASK);
398+
for (i = 1; i < (SMC_ARG_CNT_64 - 1); i++)
399+
smc_arg[i + 1] = ((u64)args[(i * 2)] << 32U) | args[(i * 2) - 1];
400+
401+
return do_fw_call(ret_payload, 8, smc_arg[0], smc_arg[1], smc_arg[2], smc_arg[3],
402+
smc_arg[4], smc_arg[5], smc_arg[6], smc_arg[7]);
403+
}
404+
334405
/**
335406
* zynqmp_pm_invoke_fn() - Invoke the system-level platform management layer
336407
* caller function depending on the configuration
@@ -488,6 +559,35 @@ int zynqmp_pm_get_family_info(u32 *family, u32 *subfamily)
488559
}
489560
EXPORT_SYMBOL_GPL(zynqmp_pm_get_family_info);
490561

562+
/**
563+
* zynqmp_pm_get_sip_svc_version() - Get SiP service call version
564+
* @version: Returned version value
565+
*
566+
* Return: Returns status, either success or error+reason
567+
*/
568+
static int zynqmp_pm_get_sip_svc_version(u32 *version)
569+
{
570+
struct arm_smccc_res res;
571+
u64 args[SMC_ARG_CNT_64] = {0};
572+
573+
if (!version)
574+
return -EINVAL;
575+
576+
/* Check if SiP SVC version already verified */
577+
if (sip_svc_version > 0) {
578+
*version = sip_svc_version;
579+
return 0;
580+
}
581+
582+
args[0] = GET_SIP_SVC_VERSION;
583+
584+
arm_smccc_smc(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], &res);
585+
586+
*version = ((lower_32_bits(res.a0) << 16U) | lower_32_bits(res.a1));
587+
588+
return zynqmp_pm_ret_code(XST_PM_SUCCESS);
589+
}
590+
491591
/**
492592
* zynqmp_pm_get_trustzone_version() - Get secure trustzone firmware version
493593
* @version: Returned version value
@@ -552,10 +652,34 @@ static int get_set_conduit_method(struct device_node *np)
552652
*/
553653
int zynqmp_pm_query_data(struct zynqmp_pm_query_data qdata, u32 *out)
554654
{
555-
int ret;
655+
int ret, i = 0;
656+
u32 ret_payload[PAYLOAD_ARG_CNT] = {0};
657+
658+
if (sip_svc_version >= SIP_SVC_PASSTHROUGH_VERSION) {
659+
ret = zynqmp_pm_invoke_fw_fn(PM_QUERY_DATA, ret_payload, 4,
660+
qdata.qid, qdata.arg1,
661+
qdata.arg2, qdata.arg3);
662+
/* To support backward compatibility */
663+
if (!ret && !ret_payload[0]) {
664+
/*
665+
* TF-A passes return status on 0th index but
666+
* api to get clock name reads data from 0th
667+
* index so pass data at 0th index instead of
668+
* return status
669+
*/
670+
if (qdata.qid == PM_QID_CLOCK_GET_NAME ||
671+
qdata.qid == PM_QID_PINCTRL_GET_FUNCTION_NAME)
672+
i = 1;
673+
674+
for (; i < PAYLOAD_ARG_CNT; i++, out++)
675+
*out = ret_payload[i];
556676

557-
ret = zynqmp_pm_invoke_fn(PM_QUERY_DATA, out, 4, qdata.qid, qdata.arg1, qdata.arg2,
558-
qdata.arg3);
677+
return ret;
678+
}
679+
}
680+
681+
ret = zynqmp_pm_invoke_fn(PM_QUERY_DATA, out, 4, qdata.qid,
682+
qdata.arg1, qdata.arg2, qdata.arg3);
559683

560684
/*
561685
* For clock name query, all bytes in SMC response are clock name
@@ -1890,6 +2014,11 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
18902014
if (ret)
18912015
return ret;
18922016

2017+
/* Get SiP SVC version number */
2018+
ret = zynqmp_pm_get_sip_svc_version(&sip_svc_version);
2019+
if (ret)
2020+
return ret;
2021+
18932022
ret = do_feature_check_call(PM_FEATURE_CHECK);
18942023
if (ret >= 0 && ((ret & FIRMWARE_VERSION_MASK) >= PM_API_VERSION_1))
18952024
feature_check_enabled = true;

include/linux/firmware/xlnx-zynqmp.h

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Xilinx Zynq MPSoC Firmware layer
44
*
55
* Copyright (C) 2014-2021 Xilinx
6-
* Copyright (C) 2022 - 2023, Advanced Micro Devices, Inc.
6+
* Copyright (C) 2022 - 2024, Advanced Micro Devices, Inc.
77
*
88
* Michal Simek <[email protected]>
99
* Davorin Mista <[email protected]>
@@ -32,6 +32,19 @@
3232
/* SMC SIP service Call Function Identifier Prefix */
3333
#define PM_SIP_SVC 0xC2000000
3434

35+
/* SMC function ID to get SiP SVC version */
36+
#define GET_SIP_SVC_VERSION (0x8200ff03U)
37+
38+
/* SiP Service Calls version numbers */
39+
#define SIP_SVC_VERSION_MAJOR (0U)
40+
#define SIP_SVC_VERSION_MINOR (2U)
41+
42+
#define SIP_SVC_PASSTHROUGH_VERSION ((SIP_SVC_VERSION_MAJOR << 16) | \
43+
SIP_SVC_VERSION_MINOR)
44+
45+
/* Fixed ID for FW specific APIs */
46+
#define PASS_THROUGH_FW_CMD_ID GENMASK(11, 0)
47+
3548
/* PM API versions */
3649
#define PM_API_VERSION_1 1
3750
#define PM_API_VERSION_2 2
@@ -51,6 +64,7 @@
5164

5265
#define API_ID_MASK GENMASK(7, 0)
5366
#define MODULE_ID_MASK GENMASK(11, 8)
67+
#define PLM_MODULE_ID_MASK GENMASK(15, 8)
5468

5569
/* Firmware feature check version mask */
5670
#define FIRMWARE_VERSION_MASK 0xFFFFU
@@ -62,7 +76,13 @@
6276
#define GET_CALLBACK_DATA 0xa01
6377

6478
/* Number of 32bits values in payload */
65-
#define PAYLOAD_ARG_CNT 4U
79+
#define PAYLOAD_ARG_CNT 7U
80+
81+
/* Number of 64bits arguments for SMC call */
82+
#define SMC_ARG_CNT_64 8U
83+
84+
/* Number of 32bits arguments for SMC call */
85+
#define SMC_ARG_CNT_32 13U
6686

6787
/* Number of arguments for a callback */
6888
#define CB_ARG_CNT 4
@@ -130,6 +150,7 @@
130150

131151
enum pm_module_id {
132152
PM_MODULE_ID = 0x0,
153+
XPM_MODULE_ID = 0x2,
133154
XSEM_MODULE_ID = 0x3,
134155
TF_A_MODULE_ID = 0xa,
135156
};
@@ -537,6 +558,7 @@ struct zynqmp_pm_query_data {
537558
};
538559

539560
int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 *ret_payload, u32 num_args, ...);
561+
int zynqmp_pm_invoke_fw_fn(u32 pm_api_id, u32 *ret_payload, u32 num_args, ...);
540562

541563
#if IS_REACHABLE(CONFIG_ZYNQMP_FIRMWARE)
542564
int zynqmp_pm_get_api_version(u32 *version);

0 commit comments

Comments
 (0)