diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 51b16451010..a9dd5533f2c 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -76,3 +76,4 @@ add_subdirectory_ifdef(CONFIG_W1 w1) add_subdirectory_ifdef(CONFIG_WATCHDOG watchdog) add_subdirectory_ifdef(CONFIG_WIFI wifi) add_subdirectory_ifdef(CONFIG_RTC rtc) +add_subdirectory_ifdef(CONFIG_ARM_SIP_SVC_DRIVER sip_svc) diff --git a/drivers/Kconfig b/drivers/Kconfig index 64554abd35a..bb829018720 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -79,5 +79,6 @@ source "drivers/w1/Kconfig" source "drivers/watchdog/Kconfig" source "drivers/wifi/Kconfig" source "drivers/xen/Kconfig" +source "drivers/sip_svc/Kconfig" endmenu diff --git a/drivers/sip_svc/CMakeLists.txt b/drivers/sip_svc/CMakeLists.txt new file mode 100644 index 00000000000..741d189dac0 --- /dev/null +++ b/drivers/sip_svc/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() +zephyr_library_sources_ifdef(CONFIG_ARM_SIP_SVC_HAS_INTEL_SDM_MAILBOX_FIFO sip_smc_intel_socfpga.c) diff --git a/drivers/sip_svc/Kconfig b/drivers/sip_svc/Kconfig new file mode 100644 index 00000000000..ef790654267 --- /dev/null +++ b/drivers/sip_svc/Kconfig @@ -0,0 +1,31 @@ +# Silicon vendor Provided Supervisory call driver for sip_svc subsystem + +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +menuconfig ARM_SIP_SVC_DRIVER + bool "ARM SIP SVC driver" + depends on ARM64 + help + ARM supervisory call driver for communicating with EL2 or EL3 firmware + +if ARM_SIP_SVC_DRIVER + +module = ARM_SIP_SVC_DRIVER +module-str = arm_sip_svc_driver +source "subsys/logging/Kconfig.template.log_config" + +config ARM_SIP_SVC_DRIVER_INIT_PRIORITY + int "Initialization priority" + default 50 + +config ARM_SIP_SVC_HAS_DRIVER + bool + help + This is an option to be enabled by individual sip svc driver + to signal that there is a sip svc driver. This is used by other + modules which depends on sip svc driver. + +source "drivers/sip_svc/Kconfig.sip_smc_agilex" + +endif # ARM_SIP_SVC_DRIVER diff --git a/drivers/sip_svc/Kconfig.sip_smc_agilex b/drivers/sip_svc/Kconfig.sip_smc_agilex new file mode 100644 index 00000000000..5b982e7c721 --- /dev/null +++ b/drivers/sip_svc/Kconfig.sip_smc_agilex @@ -0,0 +1,26 @@ +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +config ARM_SIP_SVC_HAS_INTEL_SDM_MAILBOX_FIFO + bool + default y + depends on DT_HAS_INTEL_AGILEX_SOCFPGA_SIP_SMC_ENABLED + imply ARM_SIP_SVC_HAS_DRIVER + help + Support for SDM mailbox fifo in Intel SoC FPGA Agilex via SMC calls. + +config ARM_SIP_SVC_EL3_MAILBOX_RESPONSE_SIZE + int "Size of response buffer used for ASYNC transactions." + default 4096 + depends on ARM_SIP_SVC_HAS_INTEL_SDM_MAILBOX_FIFO + help + Size of response buffer used for ASYNC transactions.For Intel Agilex platform + the maximum size of response buffer size is 4096 and minimum is 4 bytes. + Also it should be multiple of 4 bytes. + +config ARM_SIP_SVC_EL3_MAX_ALLOWED_TRANSACTIONS + int "Maximum allowable ongoing transactions." + default 16 + depends on ARM_SIP_SVC_HAS_INTEL_SDM_MAILBOX_FIFO + help + Allowed number of active transactions in sip_svc subsystem for this driver. diff --git a/drivers/sip_svc/sip_smc_intel_socfpga.c b/drivers/sip_svc/sip_smc_intel_socfpga.c new file mode 100644 index 00000000000..660617a6340 --- /dev/null +++ b/drivers/sip_svc/sip_smc_intel_socfpga.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2022-2023, Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Intel SoC FPGA platform specific functions used by ARM SiP Services for + * supporting EL3 communication from zephyr. + */ + +#include +#include +#include +#include +#include + +#include + +LOG_MODULE_REGISTER(intel_agilex_socfpga_sip_smc, CONFIG_ARM_SIP_SVC_DRIVER_LOG_LEVEL); + +#define DT_DRV_COMPAT intel_agilex_socfpga_sip_smc + +#define DT_SIP_SMC DT_COMPAT_GET_ANY_STATUS_OKAY(DT_DRV_COMPAT) + +static bool intel_sip_smc_plat_func_id_valid(const struct device *dev, uint32_t command, + uint32_t func_id) +{ + ARG_UNUSED(dev); + bool valid = false; + + if (command > SIP_SVC_PROTO_CMD_MAX) { + return false; + } + + if (command == SIP_SVC_PROTO_CMD_SYNC) { + /* Synchronous SMC Function IDs */ + switch (func_id) { + case SMC_FUNC_ID_GET_SVC_VERSION: + case SMC_FUNC_ID_REG_READ: + case SMC_FUNC_ID_REG_WRITE: + case SMC_FUNC_ID_REG_UPDATE: + case SMC_FUNC_ID_SET_HPS_BRIDGES: + valid = true; + break; + default: + valid = false; + break; + } + } else if (command == SIP_SVC_PROTO_CMD_ASYNC) { + /* Asynchronous SMC Function IDs */ + switch (func_id) { + case SMC_FUNC_ID_MAILBOX_SEND_COMMAND: + case SMC_FUNC_ID_MAILBOX_POLL_RESPONSE: + valid = true; + break; + default: + valid = false; + break; + } + } + + return valid; +} + +static uint32_t intel_sip_smc_plat_format_trans_id(const struct device *dev, uint32_t client_idx, + uint32_t trans_idx) +{ + ARG_UNUSED(dev); + + /*combine the transaction id and client id to get the job id*/ + return (((client_idx & 0xF) << 4) | (trans_idx & 0xF)); +} + +static uint32_t intel_sip_smc_plat_get_trans_idx(const struct device *dev, uint32_t trans_id) +{ + ARG_UNUSED(dev); + + return (trans_id & 0xF); +} + +static void intel_sip_smc_plat_update_trans_id(const struct device *dev, + struct sip_svc_request *request, uint32_t trans_id) +{ + ARG_UNUSED(dev); + + uint32_t *data; + + if (request == NULL) { + LOG_ERR("request is empty"); + return; + } + + /* Assign the trans id into intel smc header a1 */ + SMC_PLAT_PROTO_HEADER_SET_TRANS_ID(request->a1, trans_id); + + /* Assign the trans id into mailbox header */ + if ((void *)request->a2 != NULL) { + data = (uint32_t *)request->a2; + SIP_SVC_MB_HEADER_SET_TRANS_ID(data[0], trans_id); + } +} + +static void intel_sip_smc_plat_free_async_memory(const struct device *dev, + struct sip_svc_request *request) +{ + ARG_UNUSED(dev); + + /* Free mailbox command data dynamic memory space, + * this function will be called after sip_svc service + * process the async request. + */ + if (request->a2) { + k_free((void *)request->a2); + } +} + +static int intel_sip_smc_plat_async_res_req(const struct device *dev, unsigned long *a0, + unsigned long *a1, unsigned long *a2, unsigned long *a3, + unsigned long *a4, unsigned long *a5, unsigned long *a6, + unsigned long *a7, char *buf, size_t size) +{ + ARG_UNUSED(dev); + + /* Fill in SMC parameter to read mailbox response */ + *a0 = SMC_FUNC_ID_MAILBOX_POLL_RESPONSE; + *a1 = 0; + *a2 = (unsigned long)buf; + *a3 = size; + + return 0; +} + +static int intel_sip_smc_plat_async_res_res(const struct device *dev, struct arm_smccc_res *res, + char *buf, size_t *size, uint32_t *trans_id) +{ + ARG_UNUSED(dev); + uint32_t *resp = (uint32_t *)buf; + + __ASSERT((res && buf && size && trans_id), "invalid parameters\n"); + + if (((long)res->a0) <= SMC_STATUS_OKAY) { + /* Extract transaction id from mailbox response header */ + *trans_id = SIP_SVC_MB_HEADER_GET_TRANS_ID(resp[0]); + /* The final length should include both header and body */ + *size = (SIP_SVC_MB_HEADER_GET_LENGTH(resp[0]) + 1) * 4; + } else { + LOG_INF("There is no valid polling response %ld", (long)res->a0); + return -EINPROGRESS; + } + + LOG_INF("Got a valid polling response"); + return 0; +} + +static uint32_t intel_sip_smc_plat_get_error_code(const struct device *dev, + struct arm_smccc_res *res) +{ + ARG_UNUSED(dev); + + if (res != NULL) { + return res->a0; + } else { + return SIP_SVC_ID_INVALID; + } +} + +static void intel_sip_secure_monitor_call(const struct device *dev, unsigned long function_id, + unsigned long arg0, unsigned long arg1, + unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5, + unsigned long arg6, struct arm_smccc_res *res) +{ + __ASSERT_NO_MSG(dev != NULL); + __ASSERT_NO_MSG(res != NULL); + + LOG_INF("Before %s call", DT_PROP(DT_SIP_SMC, method)); + LOG_DBG("\tfunction_id %08lx", function_id); + LOG_DBG("\targ0 %08lx", arg0); + LOG_DBG("\targ1 %08lx", arg1); + LOG_DBG("\targ2 %08lx", arg2); + LOG_DBG("\targ3 %08lx", arg3); + LOG_DBG("\targ4 %08lx", arg4); + LOG_DBG("\targ5 %08lx", arg5); + LOG_DBG("\targ6 %08lx", arg6); + + arm_smccc_smc(function_id, arg0, arg1, arg2, arg3, arg4, arg5, arg6, res); + + LOG_INF("After %s call", DT_PROP(DT_SIP_SMC, method)); + LOG_DBG("\tres->a0 %08lx", res->a0); + LOG_DBG("\tres->a1 %08lx", res->a1); + LOG_DBG("\tres->a2 %08lx", res->a2); + LOG_DBG("\tres->a3 %08lx", res->a3); + LOG_DBG("\tres->a4 %08lx", res->a4); + LOG_DBG("\tres->a5 %08lx", res->a5); + LOG_DBG("\tres->a6 %08lx", res->a6); + LOG_DBG("\tres->a7 %08lx", res->a7); +} + +static int arm_sip_smc_init(const struct device *dev) +{ + ARG_UNUSED(dev); + + LOG_INF("Supervisory call %s registered successfully", DT_PROP(DT_SIP_SMC, method)); + + return 0; +} + +static const struct svc_driver_api api = { + .sip_supervisory_call = intel_sip_secure_monitor_call, + .sip_svc_plat_get_trans_idx = intel_sip_smc_plat_get_trans_idx, + .sip_svc_plat_format_trans_id = intel_sip_smc_plat_format_trans_id, + .sip_svc_plat_func_id_valid = intel_sip_smc_plat_func_id_valid, + .sip_svc_plat_update_trans_id = intel_sip_smc_plat_update_trans_id, + .sip_svc_plat_get_error_code = intel_sip_smc_plat_get_error_code, + .sip_svc_plat_async_res_req = intel_sip_smc_plat_async_res_req, + .sip_svc_plat_async_res_res = intel_sip_smc_plat_async_res_res, + .sip_svc_plat_free_async_memory = intel_sip_smc_plat_free_async_memory}; + +BUILD_ASSERT((DT_PROP(DT_SIP_SMC, zephyr_num_clients) != 0), "num-clients should not be zero"); +BUILD_ASSERT((CONFIG_ARM_SIP_SVC_EL3_MAX_ALLOWED_TRANSACTIONS > 0), + "CONFIG_ARM_SIP_SVC_EL3_MAX_ALLOWED_TRANSACTIONS should be greater than 0"); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +DEVICE_DT_DEFINE(DT_SIP_SMC, arm_sip_smc_init, NULL, NULL, NULL, POST_KERNEL, + CONFIG_ARM_SIP_SVC_DRIVER_INIT_PRIORITY, &api); + +#endif diff --git a/include/zephyr/drivers/sip_svc/sip_svc_agilex_mailbox.h b/include/zephyr/drivers/sip_svc/sip_svc_agilex_mailbox.h new file mode 100644 index 00000000000..3b40d3b0508 --- /dev/null +++ b/include/zephyr/drivers/sip_svc/sip_svc_agilex_mailbox.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022-2023, Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SIP_SVC_AGILEX_MB_H_ +#define ZEPHYR_INCLUDE_SIP_SVC_AGILEX_MB_H_ + +/** + * @file + * @brief Intel SoC FPGA Agilex customized SDM Mailbox communication + * protocol handler. SDM Mailbox protocol will be embedded in + * Arm SiP Services SMC protocol and sent to/from SDM via Arm + * SiP Services. + */ + +#define SIP_SVP_MB_MAX_WORD_SIZE 1024 +#define SIP_SVP_MB_HEADER_TRANS_ID_OFFSET 24 +#define SIP_SVP_MB_HEADER_TRANS_ID_MASK 0xFF +#define SIP_SVP_MB_HEADER_LENGTH_OFFSET 12 +#define SIP_SVP_MB_HEADER_LENGTH_MASK 0x7FF + +#define SIP_SVC_MB_HEADER_GET_CLIENT_ID(header) \ + ((header) >> SIP_SVP_MB_HEADER_CLIENT_ID_OFFSET & \ + SIP_SVP_MB_HEADER_CLIENT_ID_MASK) + +#define SIP_SVC_MB_HEADER_GET_TRANS_ID(header) \ + ((header) >> SIP_SVP_MB_HEADER_TRANS_ID_OFFSET & \ + SIP_SVP_MB_HEADER_TRANS_ID_MASK) + +#define SIP_SVC_MB_HEADER_SET_TRANS_ID(header, id) \ + (header) &= ~(SIP_SVP_MB_HEADER_TRANS_ID_MASK << \ + SIP_SVP_MB_HEADER_TRANS_ID_OFFSET); \ + (header) |= (((id) & SIP_SVP_MB_HEADER_TRANS_ID_MASK) << \ + SIP_SVP_MB_HEADER_TRANS_ID_OFFSET); + +#define SIP_SVC_MB_HEADER_GET_LENGTH(header) \ + ((header) >> SIP_SVP_MB_HEADER_LENGTH_OFFSET & \ + SIP_SVP_MB_HEADER_LENGTH_MASK) + +#endif /* ZEPHYR_INCLUDE_SIP_SVC_AGILEX_MB_H_ */ diff --git a/include/zephyr/drivers/sip_svc/sip_svc_agilex_smc.h b/include/zephyr/drivers/sip_svc/sip_svc_agilex_smc.h new file mode 100644 index 00000000000..88c9002af17 --- /dev/null +++ b/include/zephyr/drivers/sip_svc/sip_svc_agilex_smc.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2022-2023, Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SIP_SVC_AGILEX_SMC_H_ +#define ZEPHYR_INCLUDE_SIP_SVC_AGILEX_SMC_H_ + +/** + * @file + * @brief Intel SoC FPGA Agilex customized Arm SiP Services + * SMC protocol. + */ + +/* @brief SMC return status + */ + +#define SMC_STATUS_INVALID 0xFFFFFFFF +#define SMC_STATUS_OKAY 0 +#define SMC_STATUS_BUSY 1 +#define SMC_STATUS_REJECT 2 +#define SMC_STATUS_NO_RESPONSE 3 +#define SMC_STATUS_ERROR 4 + +/* @brief SMC Intel Header at a1 + * + * bit + * 7: 0 Transaction ID + * 59: 8 Reserved + * 63:60 Version + */ +#define SMC_PLAT_PROTO_VER 0x0 + +#define SMC_PLAT_PROTO_HEADER_TRANS_ID_OFFSET 0 +#define SMC_PLAT_PROTO_HEADER_TRANS_ID_MASK 0xFF + +#define SMC_PLAT_PROTO_HEADER_VER_OFFSET 60 +#define SMC_PLAT_PROTO_HEADER_VER_MASK 0xF + +#define SMC_PLAT_PROTO_HEADER \ + ((SMC_PLAT_PROTO_VER & SMC_PLAT_PROTO_HEADER_VER_MASK) << SMC_PLAT_PROTO_HEADER_VER_OFFSET) + +#define SMC_PLAT_PROTO_HEADER_SET_TRANS_ID(header, trans_id) \ + (header) &= \ + ~(SMC_PLAT_PROTO_HEADER_TRANS_ID_MASK << SMC_PLAT_PROTO_HEADER_TRANS_ID_OFFSET); \ + (header) |= (((trans_id)&SMC_PLAT_PROTO_HEADER_TRANS_ID_MASK) \ + << SMC_PLAT_PROTO_HEADER_TRANS_ID_OFFSET); + +/* @brief SYNC SMC Function IDs + */ + +#define SMC_FUNC_ID_GET_SVC_VERSION 0xC2000400 +#define SMC_FUNC_ID_REG_READ 0xC2000401 +#define SMC_FUNC_ID_REG_WRITE 0xC2000402 +#define SMC_FUNC_ID_REG_UPDATE 0xC2000403 +#define SMC_FUNC_ID_SET_HPS_BRIDGES 0xC2000404 + +/* @brief ASYNC SMC Function IDs + */ + +#define SMC_FUNC_ID_MAILBOX_SEND_COMMAND 0xC2000420 +#define SMC_FUNC_ID_MAILBOX_POLL_RESPONSE 0xC2000421 + +/* @brief SDM mailbox CANCEL command + */ +#define MAILBOX_CANCEL_COMMAND 0x03 + +#endif /* ZEPHYR_INCLUDE_SIP_SVC_AGILEX_SMC_H_ */ diff --git a/include/zephyr/drivers/sip_svc/sip_svc_driver.h b/include/zephyr/drivers/sip_svc/sip_svc_driver.h new file mode 100644 index 00000000000..90b850a9e0d --- /dev/null +++ b/include/zephyr/drivers/sip_svc/sip_svc_driver.h @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2023, Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SIP_SVC_DRIVER_H_ +#define ZEPHYR_INCLUDE_SIP_SVC_DRIVER_H_ + +#include +#include +#include +#include + +#define DEV_API(dev) ((struct svc_driver_api *)(dev)->api) + +/** + * @brief Length of SVC conduit name. + * + */ +#define SVC_CONDUIT_NAME_LENGTH (4) + +/** + * @brief Callback API for executing the supervisory call + * See @a sip_supervisory_call() for argument description + */ +typedef void (*sip_supervisory_call_t)(const struct device *dev, unsigned long function_id, + unsigned long arg0, unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4, unsigned long arg5, + unsigned long arg6, struct arm_smccc_res *res); + +/** + * @brief Callback API for validating function id for the supervisory call. + * See @a sip_svc_plat_func_id_valid() for argument description + */ +typedef bool (*sip_svc_plat_func_id_valid_t)(const struct device *dev, uint32_t command, + uint32_t func_id); + +/** + * @brief Callback API for generating the transaction id from client id. + * See @a sip_svc_plat_format_trans_id() for argument description + */ +typedef uint32_t (*sip_svc_plat_format_trans_id_t)(const struct device *dev, uint32_t client_idx, + uint32_t trans_idx); + +/** + * @brief Callback API for retrieving client transaction id from transaction id + * See @a sip_svc_plat_get_trans_idx() for argument description + */ +typedef uint32_t (*sip_svc_plat_get_trans_idx_t)(const struct device *dev, uint32_t trans_id); + +/** + * @brief Callback API for updating transaction id for request packet for lower layer + * See @a sip_svc_plat_update_trans_id() for argument description + */ +typedef void (*sip_svc_plat_update_trans_id_t)(const struct device *dev, + struct sip_svc_request *request, uint32_t trans_id); + +/** + * @brief Callback API for freeing command buffer in ASYNC packets + * See @a sip_svc_plat_free_async_memory() for argument description + */ +typedef void (*sip_svc_plat_free_async_memory_t)(const struct device *dev, + struct sip_svc_request *request); + +/** + * @brief Callback API to construct Polling packet for ASYNC transaction. + * See @a sip_svc_plat_async_res_req() for argument description + */ +typedef int (*sip_svc_plat_async_res_req_t)(const struct device *dev, unsigned long *a0, + unsigned long *a1, unsigned long *a2, unsigned long *a3, + unsigned long *a4, unsigned long *a5, unsigned long *a6, + unsigned long *a7, char *buf, size_t size); + +/** + * @brief Callback API to check the response of polling request + * See @a sip_svc_plat_async_res_res() for argument description + */ +typedef int (*sip_svc_plat_async_res_res_t)(const struct device *dev, struct arm_smccc_res *res, + char *buf, size_t *size, uint32_t *trans_id); + +/** + * @brief Callback API for retrieving error code from a supervisory call response. + * See @a sip_svc_plat_get_error_code() for argument description. + */ +typedef uint32_t (*sip_svc_plat_get_error_code_t)(const struct device *dev, + struct arm_smccc_res *res); + +/** + * @brief API structure for sip_svc driver. + * + */ +__subsystem struct svc_driver_api { + sip_supervisory_call_t sip_supervisory_call; + sip_svc_plat_func_id_valid_t sip_svc_plat_func_id_valid; + sip_svc_plat_format_trans_id_t sip_svc_plat_format_trans_id; + sip_svc_plat_get_trans_idx_t sip_svc_plat_get_trans_idx; + sip_svc_plat_update_trans_id_t sip_svc_plat_update_trans_id; + sip_svc_plat_free_async_memory_t sip_svc_plat_free_async_memory; + sip_svc_plat_async_res_req_t sip_svc_plat_async_res_req; + sip_svc_plat_async_res_res_t sip_svc_plat_async_res_res; + sip_svc_plat_get_error_code_t sip_svc_plat_get_error_code; +}; + +/** + * @brief supervisory call function which will execute the smc/hvc call + * + * @param dev Pointer to the device structure for the driver instance. + * @param function_id Function identifier for the supervisory call. + * @param arg0 Argument 0 for supervisory call. + * @param arg1 Argument 1 for supervisory call. + * @param arg2 Argument 2 for supervisory call. + * @param arg3 Argument 3 for supervisory call. + * @param arg4 Argument 4 for supervisory call. + * @param arg5 Argument 5 for supervisory call. + * @param arg6 Argument 6 for supervisory call. + * @param res Pointer to response buffer for supervisory call. + */ +__syscall void sip_supervisory_call(const struct device *dev, unsigned long function_id, + unsigned long arg0, unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4, unsigned long arg5, + unsigned long arg6, struct arm_smccc_res *res); +static inline void z_impl_sip_supervisory_call(const struct device *dev, unsigned long function_id, + unsigned long arg0, unsigned long arg1, + unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5, + unsigned long arg6, struct arm_smccc_res *res) +{ + __ASSERT(dev, "dev shouldn't be NULL"); + const struct svc_driver_api *api = DEV_API(dev); + + __ASSERT(api->sip_supervisory_call, "sip_supervisory_call shouldn't be NULL"); + __ASSERT(res, "response pointer shouldn't be NULL"); + + api->sip_supervisory_call(dev, function_id, arg0, arg1, arg2, arg3, arg4, arg5, arg6, res); +} + +/** + * @brief Validate the function id for the supervisory call. + * + * @param dev Pointer to the device structure for the driver instance. + * @param command Command which specify if the call is SYNC or ASYNC. + * @param func_id Function identifier + * + * @retval true if command and function identifiers are valid. + * @retval false if command and function identifiers are invalid. + */ +__syscall bool sip_svc_plat_func_id_valid(const struct device *dev, uint32_t command, + uint32_t func_id); +static inline bool z_impl_sip_svc_plat_func_id_valid(const struct device *dev, uint32_t command, + uint32_t func_id) +{ + __ASSERT(dev, "dev shouldn't be NULL"); + const struct svc_driver_api *api = DEV_API(dev); + + __ASSERT(api->sip_svc_plat_func_id_valid, + "sip_svc_plat_func_id_valid func shouldn't be NULL"); + + return api->sip_svc_plat_func_id_valid(dev, command, func_id); +} + +/** + * @brief Formats and generates the transaction id from client id. + * + * @param dev Pointer to the device structure for the driver instance. + * @param client_idx client index. + * @param trans_idx transaction index. + * + * @retval transaction id, which is used for tracking each transaction. + */ +__syscall uint32_t sip_svc_plat_format_trans_id(const struct device *dev, uint32_t client_idx, + uint32_t trans_idx); +static inline uint32_t z_impl_sip_svc_plat_format_trans_id(const struct device *dev, + uint32_t client_idx, uint32_t trans_idx) +{ + __ASSERT(dev, "dev shouldn't be NULL"); + const struct svc_driver_api *api = DEV_API(dev); + + __ASSERT(api->sip_svc_plat_format_trans_id, + "sip_svc_plat_format_trans_id func shouldn't be NULL"); + + return api->sip_svc_plat_format_trans_id(dev, client_idx, trans_idx); +} + +/** + * @brief Retrieve client transaction id from packet transaction id. + * + * @param dev Pointer to the device structure for the driver instance. + * @param trans_id transaction identifier if for a transaction. + * + * @retval client transaction id form Transaction id. + */ +__syscall uint32_t sip_svc_plat_get_trans_idx(const struct device *dev, uint32_t trans_id); +static inline uint32_t z_impl_sip_svc_plat_get_trans_idx(const struct device *dev, + uint32_t trans_id) +{ + __ASSERT(dev, "dev shouldn't be NULL"); + const struct svc_driver_api *api = DEV_API(dev); + + __ASSERT(api->sip_svc_plat_get_trans_idx, + "sip_svc_plat_get_trans_idx func shouldn't be NULL"); + + return api->sip_svc_plat_get_trans_idx(dev, trans_id); +} + +/** + * @brief Update transaction id for sip_svc_request for lower layer. + * + * @param dev Pointer to the device structure for the driver instance. + * @param request Pointer to sip_svc_request structure. + * @param trans_id Transaction id. + */ +__syscall void sip_svc_plat_update_trans_id(const struct device *dev, + struct sip_svc_request *request, uint32_t trans_id); +static inline void z_impl_sip_svc_plat_update_trans_id(const struct device *dev, + struct sip_svc_request *request, + uint32_t trans_id) +{ + __ASSERT(dev, "dev shouldn't be NULL"); + const struct svc_driver_api *api = DEV_API(dev); + + __ASSERT(api->sip_svc_plat_update_trans_id, + "sip_svc_plat_update_trans_id func shouldn't be NULL"); + __ASSERT(request, "request shouldn't be NULL"); + + return api->sip_svc_plat_update_trans_id(dev, request, trans_id); +} + +/** + * @brief Retrieve the error code from arm_smccc_res response. + * + * @param dev Pointer to the device structure for the driver instance. + * @param res Pointer to struct arm_smccc_res response. + * + * @retval 0 on success. + * @retval SIP_SVC_ID_INVALID on failure + */ +__syscall uint32_t sip_svc_plat_get_error_code(const struct device *dev, struct arm_smccc_res *res); +static inline uint32_t z_impl_sip_svc_plat_get_error_code(const struct device *dev, + struct arm_smccc_res *res) +{ + __ASSERT(dev, "dev shouldn't be NULL"); + const struct svc_driver_api *api = DEV_API(dev); + + __ASSERT(api->sip_svc_plat_get_error_code, + "sip_svc_plat_get_error_code func shouldn't be NULL"); + __ASSERT(res, "res shouldn't be NULL"); + + return api->sip_svc_plat_get_error_code(dev, res); +} + +/** + * @brief Set arguments for polling supervisory call. For ASYNC polling of response. + * + * @param dev Pointer to the device structure for the driver instance. + * @param a0 Argument 0 for supervisory call. + * @param a1 Argument 1 for supervisory call. + * @param a2 Argument 2 for supervisory call. + * @param a3 Argument 3 for supervisory call. + * @param a4 Argument 4 for supervisory call. + * @param a5 Argument 5 for supervisory call. + * @param a6 Argument 6 for supervisory call. + * @param a7 Argument 7 for supervisory call. + * @param buf Pointer for response buffer. + * @param size Size of response buffer. + * + * @retval 0 on success + */ +__syscall int sip_svc_plat_async_res_req(const struct device *dev, unsigned long *a0, + unsigned long *a1, unsigned long *a2, unsigned long *a3, + unsigned long *a4, unsigned long *a5, unsigned long *a6, + unsigned long *a7, char *buf, size_t size); +static inline int z_impl_sip_svc_plat_async_res_req(const struct device *dev, unsigned long *a0, + unsigned long *a1, unsigned long *a2, + unsigned long *a3, unsigned long *a4, + unsigned long *a5, unsigned long *a6, + unsigned long *a7, char *buf, size_t size) +{ + __ASSERT(dev, "dev shouldn't be NULL"); + const struct svc_driver_api *api = DEV_API(dev); + + __ASSERT(api->sip_svc_plat_async_res_req, + "sip_svc_plat_async_res_req func shouldn't be NULL"); + __ASSERT(a0, "a0 shouldn't be NULL"); + __ASSERT(a1, "a1 shouldn't be NULL"); + __ASSERT(a2, "a2 shouldn't be NULL"); + __ASSERT(a3, "a3 shouldn't be NULL"); + __ASSERT(a4, "a4 shouldn't be NULL"); + __ASSERT(a5, "a5 shouldn't be NULL"); + __ASSERT(a6, "a6 shouldn't be NULL"); + __ASSERT(a7, "a7 shouldn't be NULL"); + __ASSERT(((buf == NULL && size == 0) || (buf != NULL && size != 0)), + "buf and size should represent a buffer"); + return api->sip_svc_plat_async_res_req(dev, a0, a1, a2, a3, a4, a5, a6, a7, buf, size); +} + +/** + * @brief Check the response of polling supervisory call and retrieve the response + * size and transaction id. + * + * @param dev Pointer to the device structure for the driver instance. + * @param res Pointer to struct arm_smccc_res response. + * @param buf Pointer to response buffer. + * @param size Size of response in response buffer + * @param trans_id Transaction id of the response. + * + * @retval 0 on getting a valid polling response from supervisory call. + * @retval -EINPROGRESS on no valid polling response from supervisory call. + */ +__syscall int sip_svc_plat_async_res_res(const struct device *dev, struct arm_smccc_res *res, + char *buf, size_t *size, uint32_t *trans_id); +static inline int z_impl_sip_svc_plat_async_res_res(const struct device *dev, + struct arm_smccc_res *res, char *buf, + size_t *size, uint32_t *trans_id) +{ + __ASSERT(dev, "dev shouldn't be NULL"); + const struct svc_driver_api *api = DEV_API(dev); + + __ASSERT(api->sip_svc_plat_async_res_res, + "sip_svc_plat_async_res_res func shouldn't be NULL"); + __ASSERT(res, "res shouldn't be NULL"); + __ASSERT(buf, "buf shouldn't be NULL"); + __ASSERT(size, "size shouldn't be NULL"); + __ASSERT(trans_id, "buf shouldn't be NULL"); + + return api->sip_svc_plat_async_res_res(dev, res, buf, size, trans_id); +} + +/** + * @brief Free the command buffer used for ASYNC packet after sending it to lower layers. + * + * @param dev Pointer to the device structure for the driver instance. + * @param request Pointer to sip_svc_request packet. + */ +__syscall void sip_svc_plat_free_async_memory(const struct device *dev, + struct sip_svc_request *request); +static inline void z_impl_sip_svc_plat_free_async_memory(const struct device *dev, + struct sip_svc_request *request) +{ + __ASSERT(dev, "dev shouldn't be NULL"); + const struct svc_driver_api *api = DEV_API(dev); + + __ASSERT(api->sip_svc_plat_free_async_memory, + "sip_svc_plat_free_async_memory func shouldn't be NULL"); + __ASSERT(request, "request shouldn't be NULL"); + + api->sip_svc_plat_free_async_memory(dev, request); +} + + +#include + +#endif /* ZEPHYR_INCLUDE_SIP_SVC_DRIVER_H_ */ diff --git a/include/zephyr/drivers/sip_svc/sip_svc_proto.h b/include/zephyr/drivers/sip_svc/sip_svc_proto.h new file mode 100644 index 00000000000..63eebec2cd3 --- /dev/null +++ b/include/zephyr/drivers/sip_svc/sip_svc_proto.h @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2022, Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_SIP_SVC_PROTO_H_ +#define ZEPHYR_INCLUDE_SIP_SVC_PROTO_H_ + +/** + * @file + * @brief Arm SiP services communication protocol + * between service provider and client. + * + * Client to fill in the input data in struct sip_svc_request format + * when requesting SMC/HVC service via 'send' function. + * + * Service to fill in the SMC/HVC return value in struct sip_svc_response + * format and pass to client via Callback. + */ + +/** + * @brief Invalid id value + */ +#define SIP_SVC_ID_INVALID 0xFFFFFFFF + +/** @brief Header format + */ + +#define SIP_SVC_PROTO_VER 0x0 + +#define SIP_SVC_PROTO_HEADER_CODE_OFFSET 0 +#define SIP_SVC_PROTO_HEADER_CODE_MASK 0xFFFF + +#define SIP_SVC_PROTO_HEADER_TRANS_ID_OFFSET 16 +#define SIP_SVC_PROTO_HEADER_TRANS_ID_MASK 0xFF + +#define SIP_SVC_PROTO_HEADER_VER_OFFSET 30 +#define SIP_SVC_PROTO_HEADER_VER_MASK 0x3 + +#define SIP_SVC_PROTO_HEADER(code, trans_id) \ + ((((code)&SIP_SVC_PROTO_HEADER_CODE_MASK) << SIP_SVC_PROTO_HEADER_CODE_OFFSET) | \ + (((trans_id)&SIP_SVC_PROTO_HEADER_TRANS_ID_MASK) \ + << SIP_SVC_PROTO_HEADER_TRANS_ID_OFFSET) | \ + ((SIP_SVC_PROTO_VER & SIP_SVC_PROTO_HEADER_VER_MASK) << SIP_SVC_PROTO_HEADER_VER_OFFSET)) + +#define SIP_SVC_PROTO_HEADER_GET_CODE(header) \ + (((header) >> SIP_SVC_PROTO_HEADER_CODE_OFFSET) & SIP_SVC_PROTO_HEADER_CODE_MASK) + +#define SIP_SVC_PROTO_HEADER_GET_TRANS_ID(header) \ + (((header) >> SIP_SVC_PROTO_HEADER_TRANS_ID_OFFSET) & SIP_SVC_PROTO_HEADER_TRANS_ID_MASK) + +#define SIP_SVC_PROTO_HEADER_SET_TRANS_ID(header, trans_id) \ + (header) &= ~(SIP_SVC_PROTO_HEADER_TRANS_ID_MASK << SIP_SVC_PROTO_HEADER_TRANS_ID_OFFSET); \ + (header) |= (((trans_id)&SIP_SVC_PROTO_HEADER_TRANS_ID_MASK) \ + << SIP_SVC_PROTO_HEADER_TRANS_ID_OFFSET); + +/** @brief Arm SiP services command code in request header + * + * SIP_SVC_PROTO_CMD_SYNC + * - Typical flow, synchronous request. Service expects EL3/EL2 firmware to + * return the result immediately during SMC/HVC call. + * + * SIP_SVC_PROTO_CMD_ASYNC + * - Asynchronous request. Service is required to poll the response via a + * separate SMC/HVC call. Use this method if the request requires longer + * processing in EL3/EL2. + */ + +#define SIP_SVC_PROTO_CMD_SYNC 0x0 +#define SIP_SVC_PROTO_CMD_ASYNC 0x1 +#define SIP_SVC_PROTO_CMD_MAX SIP_SVC_PROTO_CMD_ASYNC + +/** @brief Error code in response header + * + * SIP_SVC_PROTO_STATUS_OK + * - Successfully execute the request. + * + * SIP_SVC_PROTO_STATUS_UNKNOWN + * - Unrecognized SMC/HVC Function ID. + * + * SIP_SVC_PROTO_STATUS_BUSY + * - The request is still in progress. Please try again. + * + * SIP_SVC_PROTO_STATUS_REJECT + * - The request have been rejected due to improper input data. + * + * SIP_SVC_PROTO_STATUS_NO_RESPONSE + * - No response from target hardware yet. + * + * SIP_SVC_PROTO_STATUS_ERROR + * - Error occurred when executing the request. + * + * SIP_SVC_PROTO_STATUS_NOT_SUPPORT + * - Unsupported Arm SiP services command code + */ + +#define SIP_SVC_PROTO_STATUS_OK 0x0 +#define SIP_SVC_PROTO_STATUS_UNKNOWN 0xFFFF +#define SIP_SVC_PROTO_STATUS_BUSY 0x1 +#define SIP_SVC_PROTO_STATUS_REJECT 0x2 +#define SIP_SVC_PROTO_STATUS_NO_RESPONSE 0x3 +#define SIP_SVC_PROTO_STATUS_ERROR 0x4 + +/** @brief SiP Service communication protocol + * request format. + * + * request header + * - bits [15: 0] Arm SiP services command code + * - bits [23:16] Transaction ID (Filled in by sip_svc service) + * - bits [29:24] Unused. Reserved. + * - bits [31:30] Arm SiP services communication protocol version + * + * a0 - a7 + * - User input data to be filled into a0-a7 registers when trigger + * SMC/HVC + * + * resp_data_addr + * - This parameter only used by asynchronous command. + * - Dynamic memory address for service to put the asynchronous response + * data. The service will free this memory space if the client has + * cancelled the transaction. + * + * resp_data_size + * - This parameter only used by asynchronous command. + * - Maximum memory size in bytes of resp_data_addr + * + * priv_data + * - Memory address to client context. Service will pass this address back + * to client in response format via callback. + */ + +struct sip_svc_request { + uint32_t header; + unsigned long a0; + unsigned long a1; + unsigned long a2; + unsigned long a3; + unsigned long a4; + unsigned long a5; + unsigned long a6; + unsigned long a7; + uint64_t resp_data_addr; + uint32_t resp_data_size; + void *priv_data; +}; + +/** @brief SiP Services service communication protocol + * response format. + * + * response header + * - bits [15: 0] Error code + * - bits [23:16] Transaction ID + * - bits [29:24] Unused. Reserved. + * - bits [31:30] Arm SiP services communication protocol version + * + * a0 - a3 + * - SMC/HVC return value + * + * resp_data_addr + * - This parameter only used by asynchronous command. + * - Dynamic memory address that put the asynchronous response data. + * This address is provided by client during request. Client is responsible + * to free the memory space when receive the callback of a asynchronous + * command transaction.The memory needs to be dynamically allocated, + * the framework will free the allocated memory if the channel is in ABORT + * state. + * + * resp_data_size + * - This parameter only used by asynchronous command. + * - Valid data size in bytes of resp_data_addr + * + * priv_data + * - Memory address to client context which given during request. + */ + +struct sip_svc_response { + uint32_t header; + unsigned long a0; + unsigned long a1; + unsigned long a2; + unsigned long a3; + uint64_t resp_data_addr; + uint32_t resp_data_size; + void *priv_data; +}; + +#endif /* ZEPHYR_INCLUDE_SIP_SVC_PROTO_H_ */