diff --git a/drivers/firmware/qcom_scm-smc.c b/drivers/firmware/qcom_scm-smc.c index 70f3b6f5330f..e0d4cc8f6fcc 100644 --- a/drivers/firmware/qcom_scm-smc.c +++ b/drivers/firmware/qcom_scm-smc.c @@ -1774,6 +1774,64 @@ int __qcom_scm_register_qsee_log_buf(struct device *dev, phys_addr_t buf, return ret ? : desc.res[0]; } +int __qcom_scm_invoke_smc(struct device *dev, phys_addr_t in_buf, + size_t in_buf_size, phys_addr_t out_buf, size_t out_buf_size, + int32_t *result, u64 *response_type, unsigned int *data) +{ + int ret; + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_SMCINVOKE, + .cmd = QCOM_SCM_SMCINVOKE_INVOKE, + .owner = ARM_SMCCC_OWNER_TRUSTED_OS + }; + + desc.args[0] = in_buf; + desc.args[1] = in_buf_size; + desc.args[2] = out_buf; + desc.args[3] = out_buf_size; + desc.arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RW, QCOM_SCM_VAL, QCOM_SCM_RW, + QCOM_SCM_VAL); + + ret = qcom_scm_call(dev, &desc); + + if (result) + *result = desc.res[1]; + + if (response_type) + *response_type = desc.res[0]; + + return ret; +} + +int __qcom_scm_invoke_callback_response(struct device *dev, phys_addr_t out_buf, + size_t out_buf_size, int32_t *result, u64 *response_type, + unsigned int *data) +{ + int ret; + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_SMCINVOKE, + .cmd = QCOM_SCM_SMCINVOKE_CB_RSP, + .owner = ARM_SMCCC_OWNER_TRUSTED_OS + }; + + desc.args[0] = out_buf; + desc.args[1] = out_buf_size; + desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_RW, QCOM_SCM_VAL); + + ret = qcom_scm_call(dev, &desc); + + if (result) + *result = desc.res[1]; + + if (response_type) + *response_type = desc.res[0]; + + if (data) + *data = desc.res[2]; + + return ret; +} + void __qcom_scm_init(void) { __query_convention(); diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 477e99c53adf..056d8e298e16 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -814,6 +814,23 @@ int qcom_scm_register_qsee_log_buf(phys_addr_t buf, size_t len) } EXPORT_SYMBOL(qcom_scm_register_qsee_log_buf); +int qcom_scm_invoke_smc(phys_addr_t in_buf, size_t in_buf_size, + phys_addr_t out_buf, size_t out_buf_size, int32_t *result, + u64 *response_type, unsigned int *data) +{ + return __qcom_scm_invoke_smc(__scm->dev, in_buf, in_buf_size, out_buf, + out_buf_size, result, response_type, data); +} +EXPORT_SYMBOL(qcom_scm_invoke_smc); + +int qcom_scm_invoke_callback_response(phys_addr_t out_buf, + size_t out_buf_size, int32_t *result, u64 *response_type, + unsigned int *data) +{ + return __qcom_scm_invoke_callback_response(__scm->dev, out_buf, + out_buf_size, result, response_type, data); +} + /** * qcom_scm_is_available() - Checks if SCM is available */ diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h index b7c315352b88..3608bb27f84b 100644 --- a/drivers/firmware/qcom_scm.h +++ b/drivers/firmware/qcom_scm.h @@ -218,6 +218,16 @@ extern int __qcom_scm_register_qsee_log_buf(struct device *dev, phys_addr_t buf, #define QCOM_SCM_ICE_RESTORE_KEY_ID 0x06 extern int __qcom_scm_ice_restore_cfg(struct device *dev); +#define QCOM_SCM_SVC_SMCINVOKE 0x06 +#define QCOM_SCM_SMCINVOKE_INVOKE 0x00 +#define QCOM_SCM_SMCINVOKE_CB_RSP 0x01 +extern int __qcom_scm_invoke_smc(struct device *dev, phys_addr_t in_buf, + size_t in_buf_size, phys_addr_t out_buf, size_t out_buf_size, + int32_t *result, u64 *response_type, unsigned int *data); +extern int __qcom_scm_invoke_callback_response(struct device *dev, + phys_addr_t out_buf, size_t out_buf_size, int32_t *result, + u64 *response_type, unsigned int *data); + extern void __qcom_scm_init(void); /* common error codes */ diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index 8581a1056c4e..65df08faee23 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -122,6 +122,12 @@ extern int qcom_scm_camera_protect_phy_lanes(bool protect, u64 regmask); extern int qcom_scm_ice_restore_cfg(void); extern int qcom_scm_get_tz_log_feat_id(u64 *version); extern int qcom_scm_register_qsee_log_buf(phys_addr_t buf, size_t len); +extern int qcom_scm_invoke_smc(phys_addr_t in_buf, size_t in_buf_size, + phys_addr_t out_buf, size_t out_buf_size, int32_t *result, + u64 *response_type, unsigned int *data); +extern int qcom_scm_invoke_callback_response(phys_addr_t out_buf, + size_t out_buf_size, int32_t *result, u64 *response_type, + unsigned int *data); extern bool qcom_scm_is_available(void); #else @@ -253,6 +259,12 @@ static inline int qcom_scm_get_tz_log_feat_id(u64 *version) { return -ENODEV; } static inline int qcom_scm_register_qsee_log_buf(phys_addr_t buf, size_t len) { return -ENODEV; } +static inline int qcom_scm_invoke_smc(phys_addr_t in_buf, size_t in_buf_size, + phys_addr_t out_buf, size_t out_buf_size, int32_t *result, + u64 *request_type, unsigned int *data) { return -ENODEV; } +static inline int qcom_scm_invoke_callback_response(phys_addr_t out_buf, + size_t out_buf_size, int32_t *result, u64 *request_type, + unsigned int *data) { return -ENODEV; } static inline bool qcom_scm_is_available(void) { return false; } #endif #endif