diff --git a/drivers/firmware/qcom_scm-smc.c b/drivers/firmware/qcom_scm-smc.c index c05f7c1bb183..555c22b76eee 100644 --- a/drivers/firmware/qcom_scm-smc.c +++ b/drivers/firmware/qcom_scm-smc.c @@ -1501,6 +1501,94 @@ int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req, return ret; } +int __qcom_scm_lmh_read_buf_size(struct device *dev, int *size) +{ + int ret; + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_LMH, + .cmd = QCOM_SCM_LMH_DEBUG_READ_BUF_SIZE, + .owner = ARM_SMCCC_OWNER_SIP + }; + + desc.arginfo = QCOM_SCM_ARGS(0); + + ret = qcom_scm_call(dev, &desc); + + if (size) + *size = desc.res[0]; + + return ret; +} + +int __qcom_scm_lmh_debug_read(struct device *dev, phys_addr_t payload, + uint32_t size) +{ + int ret; + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_LMH, + .cmd = QCOM_SCM_LMH_DEBUG_READ, + .owner = ARM_SMCCC_OWNER_SIP + }; + + desc.args[0] = payload; + desc.args[1] = size; + desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_RW, QCOM_SCM_VAL); + + ret = qcom_scm_call(dev, &desc); + + return ret ? : desc.res[0]; +} + +int __qcom_scm_lmh_debug_config_write(struct device *dev, u64 cmd_id, + phys_addr_t payload, int payload_size, uint32_t *buf, + int buf_size) +{ + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_LMH, + .cmd = cmd_id, + .owner = ARM_SMCCC_OWNER_SIP + }; + + if (buf_size < 3) + return -EINVAL; + + desc.args[0] = payload; + desc.args[1] = payload_size; + desc.args[2] = buf[0]; + desc.args[3] = buf[1]; + desc.args[4] = buf[2]; + desc.arginfo = QCOM_SCM_ARGS(5, QCOM_SCM_RO, QCOM_SCM_VAL, QCOM_SCM_VAL, + QCOM_SCM_VAL, QCOM_SCM_VAL); + + return qcom_scm_call(dev, &desc); +} + +int __qcom_scm_lmh_get_type(struct device *dev, phys_addr_t payload, + u64 payload_size, u64 debug_type, uint32_t get_from, + uint32_t *size) +{ + int ret; + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_LMH, + .cmd = QCOM_SCM_LMH_DEBUG_GET_TYPE, + .owner = ARM_SMCCC_OWNER_SIP + }; + + desc.args[0] = payload; + desc.args[1] = payload_size; + desc.args[2] = debug_type; + desc.args[3] = get_from; + desc.arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RW, QCOM_SCM_VAL, QCOM_SCM_VAL, + QCOM_SCM_VAL); + + ret = qcom_scm_call(dev, &desc); + + if (size) + *size = desc.res[0]; + + return ret; +} + int __qcom_scm_smmu_change_pgtbl_format(struct device *dev, u64 dev_id, int cbndx) { diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 5f4a42a4109b..40c31a147f95 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -675,6 +675,63 @@ int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp) } EXPORT_SYMBOL(qcom_scm_hdcp_req); +bool qcom_scm_is_lmh_debug_set_available(void) +{ + return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_LMH, + QCOM_SCM_LMH_DEBUG_SET); +} +EXPORT_SYMBOL(qcom_scm_is_lmh_debug_set_available); + +bool qcom_scm_is_lmh_debug_read_buf_size_available(void) +{ + return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_LMH, + QCOM_SCM_LMH_DEBUG_READ_BUF_SIZE); +} +EXPORT_SYMBOL(qcom_scm_is_lmh_debug_read_buf_size_available); + +bool qcom_scm_is_lmh_debug_read_buf_available(void) +{ + return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_LMH, + QCOM_SCM_LMH_DEBUG_READ); +} +EXPORT_SYMBOL(qcom_scm_is_lmh_debug_read_buf_available); + +bool qcom_scm_is_lmh_debug_get_type_available(void) +{ + return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_LMH, + QCOM_SCM_LMH_DEBUG_GET_TYPE); +} +EXPORT_SYMBOL(qcom_scm_is_lmh_debug_get_type_available); + +int qcom_scm_lmh_read_buf_size(int *size) +{ + return __qcom_scm_lmh_read_buf_size(__scm->dev, size); +} +EXPORT_SYMBOL(qcom_scm_lmh_read_buf_size); + +int qcom_scm_lmh_debug_read(phys_addr_t payload, uint32_t size) +{ + return __qcom_scm_lmh_debug_read(__scm->dev, payload, size); +} +EXPORT_SYMBOL(qcom_scm_lmh_debug_read); + +int qcom_scm_lmh_debug_set_config_write(phys_addr_t payload, int payload_size, + uint32_t *buf, int buf_size) +{ + return __qcom_scm_lmh_debug_config_write(__scm->dev, + QCOM_SCM_LMH_DEBUG_SET, payload, payload_size, buf, + buf_size); +} +EXPORT_SYMBOL(qcom_scm_lmh_debug_set_config_write); + +int qcom_scm_lmh_get_type(phys_addr_t payload, u64 payload_size, + u64 debug_type, uint32_t get_from, uint32_t *size) +{ + return __qcom_scm_lmh_get_type(__scm->dev, payload, payload_size, + debug_type, get_from, size); +} +EXPORT_SYMBOL(qcom_scm_lmh_get_type); + int qcom_scm_smmu_change_pgtbl_format(u64 dev_id, int cbndx) { return __qcom_scm_smmu_change_pgtbl_format(__scm->dev, dev_id, cbndx); diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h index 5cfbe46b1971..0e213fa24123 100644 --- a/drivers/firmware/qcom_scm.h +++ b/drivers/firmware/qcom_scm.h @@ -161,6 +161,21 @@ extern int __qcom_scm_clear_ice_key(struct device *dev, uint32_t index, extern int __qcom_scm_hdcp_req(struct device *dev, struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp); +#define QCOM_SCM_SVC_LMH 0x13 +#define QCOM_SCM_LMH_DEBUG_SET 0x08 +#define QCOM_SCM_LMH_DEBUG_READ_BUF_SIZE 0x09 +#define QCOM_SCM_LMH_DEBUG_READ 0x0A +#define QCOM_SCM_LMH_DEBUG_GET_TYPE 0x0B +extern int __qcom_scm_lmh_read_buf_size(struct device *dev, int *size); +extern int __qcom_scm_lmh_debug_read(struct device *dev, phys_addr_t payload, + uint32_t size); +extern int __qcom_scm_lmh_debug_config_write(struct device *dev, u64 cmd_id, + phys_addr_t payload, int payload_size, uint32_t *buf, + int buf_size); +extern int __qcom_scm_lmh_get_type(struct device *dev, phys_addr_t payload, + u64 payload_size, u64 debug_type, uint32_t get_from, + uint32_t *size); + #define QCOM_SCM_SVC_SMMU_PROGRAM 0x15 #define QCOM_SCM_SMMU_CHANGE_PGTBL_FORMAT 0x01 #define QCOM_SCM_SMMU_SECURE_LUT 0x03 diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index aeec3199d410..ffbe5e8f55d3 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -98,6 +98,16 @@ extern int qcom_scm_delete_shm_bridge(u64 handle); extern int qcom_scm_create_shm_bridge(u64 pfn_and_ns_perm_flags, u64 ipfn_and_s_perm_flags, u64 size_and_flags, u64 ns_vmids, u64 *handle); +extern bool qcom_scm_is_lmh_debug_set_available(void); +extern bool qcom_scm_is_lmh_debug_read_buf_size_available(void); +extern bool qcom_scm_is_lmh_debug_read_buf_available(void); +extern bool qcom_scm_is_lmh_debug_get_type_available(void); +extern int qcom_scm_lmh_read_buf_size(int *size); +extern int qcom_scm_lmh_debug_read(phys_addr_t payload, uint32_t size); +extern int qcom_scm_lmh_debug_set_config_write(phys_addr_t payload, + int payload_size, uint32_t *buf, int buf_size); +extern int qcom_scm_lmh_get_type(phys_addr_t payload, u64 payload_size, + u64 debug_type, uint32_t get_from, uint32_t *size); extern int qcom_scm_smmu_change_pgtbl_format(u64 dev_id, int cbndx); extern int qcom_scm_qsmmu500_wait_safe_toggle(bool en); extern int qcom_scm_smmu_notify_secure_lut(u64 dev_id, bool secure); @@ -196,6 +206,23 @@ static inline int qcom_scm_delete_shm_bridge(u64 handle) { return -ENODEV; } static inline int qcom_scm_create_shm_bridge(u64 pfn_and_ns_perm_flags, u64 ipfn_and_s_perm_flags, u64 size_and_flags, u64 ns_vmids, u64 *handle) { return -ENODEV; } +static inline bool qcom_scm_is_lmh_debug_set_available(void) + { return -EINVAL; } +static inline bool qcom_scm_is_lmh_debug_read_buf_size_available(void) + { return -EINVAL; } +static inline bool qcom_scm_is_lmh_debug_read_buf_available(void) + { return -EINVAL; } +static inline bool qcom_scm_is_lmh_debug_get_type_available(void) + { return -EINVAL; } +static inline int qcom_scm_lmh_read_buf_size(int *size) { return -ENODEV; } +static inline int qcom_scm_lmh_debug_read(phys_addr_t payload, uint32_t size) + { return -ENODEV; } +static inline int qcom_scm_lmh_debug_set_config_write(phys_addr_t payload, + int payload_size, uint32_t *buf, int buf_size) + { return -ENODEV; } +static inline int qcom_scm_lmh_get_type(phys_addr_t payload, u64 payload_size, + u64 debug_type, uint32_t get_from, uint32_t *size) + { return -ENODEV; } static inline int qcom_scm_smmu_change_pgtbl_format(u64 dev_id, int cbndx) { return -ENODEV; } static inline int qcom_scm_qsmmu500_wait_safe_toggle(bool en)