--- a/drivers/firmware/qcom_scm-32.c +++ b/drivers/firmware/qcom_scm-32.c @@ -578,3 +578,33 @@ int __qcom_scm_pinmux_write(u32 svc_id, return ret; } + +int __qcom_scm_fuse(struct device *dev, u32 address, u32 *val) +{ + __le32 *otp_value; + dma_addr_t in; + int ret; + + otp_value = kzalloc(PAGE_ALIGN(sizeof(*otp_value)), GFP_KERNEL); + if (!otp_value) + return -ENOMEM; + + in = dma_map_single(dev, otp_value, sizeof(in), DMA_FROM_DEVICE); + + ret = dma_mapping_error(dev, in); + if (ret != 0) { + kfree(otp_value); + pr_err("DMA Mapping Error %d\n", ret); + return ret; + } + + ret = qcom_scm_call(dev, QCOM_SCM_SVC_FUSE, address, + &in, sizeof(in), NULL, 0); + + dma_unmap_single(dev, in, sizeof(in), DMA_FROM_DEVICE); + + *val = le32_to_cpu(*otp_value); + kfree(otp_value); + + return ret; +} --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -165,6 +165,25 @@ int qcom_scm_hdcp_req(struct qcom_scm_hd EXPORT_SYMBOL(qcom_scm_hdcp_req); /** + * qcom_scm_fuse() - Reads a value from the OTP + * @address: address + * + * Returns the value of the OTP at the specified address. + */ +int qcom_scm_fuse(u32 address, u32 *val) +{ + int ret = qcom_scm_clk_enable(); + + if (ret) + return ret; + + ret = __qcom_scm_fuse(__scm->dev, address, val); + qcom_scm_clk_disable(); + return ret; +} +EXPORT_SYMBOL(qcom_scm_fuse); + +/** * qcom_scm_pas_supported() - Check if the peripheral authentication service is * available for the given peripherial * @peripheral: peripheral id --- a/drivers/firmware/qcom_scm.h +++ b/drivers/firmware/qcom_scm.h @@ -63,6 +63,9 @@ extern int __qcom_scm_pas_mss_reset(str s32 __qcom_scm_pinmux_read(u32 svc_id, u32 cmd_id, u32 arg1); s32 __qcom_scm_pinmux_write(u32 svc_id, u32 cmd_id, u32 arg1, u32 arg2); +#define QCOM_SCM_SVC_FUSE 0x8 +extern int __qcom_scm_fuse(struct device *dev, u32 address, u32 *val); + /* common error codes */ #define QCOM_SCM_V2_EBUSY -12 #define QCOM_SCM_ENOMEM -5 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h @@ -48,4 +48,7 @@ extern u32 qcom_scm_get_version(void); extern s32 qcom_scm_pinmux_read(u32 arg1); extern s32 qcom_scm_pinmux_write(u32 arg1, u32 arg2); + +extern int qcom_scm_fuse(u32 address, u32 *val); + #endif --- a/drivers/firmware/qcom_scm-64.c +++ b/drivers/firmware/qcom_scm-64.c @@ -374,3 +374,9 @@ int __qcom_scm_pinmux_write(u32 svc_id, { return -ENOTSUPP; } + +int __qcom_scm_fuse(struct device *dev, u32 address, u32 *val) +{ + *val = -1; + return -ENOTSUPP; +}