| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
| From: Vivek Gautam <vivek.gautam@codeaurora.org> |
| Date: Fri, 20 Sep 2019 13:34:28 +0530 |
| Subject: UPSTREAM: firmware/qcom_scm: Add scm call to handle smmu errata |
| |
| Qcom's smmu-500 needs to toggle wait-for-safe sequence to |
| handle TLB invalidation sync's. |
| Few firmwares allow doing that through SCM interface. |
| Add API to toggle wait for safe from firmware through a |
| SCM call. |
| |
| Signed-off-by: Vivek Gautam <vivek.gautam@codeaurora.org> |
| Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org> |
| Reviewed-by: Stephen Boyd <swboyd@chromium.org> |
| Acked-by: Andy Gross <agross@kernel.org> |
| Signed-off-by: Sai Prakash Ranjan <saiprakash.ranjan@codeaurora.org> |
| Signed-off-by: Will Deacon <will@kernel.org> |
| (cherry picked from commit 5eb0e0e4f90addc6b79ebf1cb4b06b56b09f09de) |
| Signed-off-by: John Stultz <john.stultz@linaro.org> |
| Bug: 146449535 |
| Change-Id: I1e6ef0d2391be1ea9508eb44329a7a70de1b1481 |
| --- |
| drivers/firmware/qcom_scm-32.c | 5 +++++ |
| drivers/firmware/qcom_scm-64.c | 13 +++++++++++++ |
| drivers/firmware/qcom_scm.c | 6 ++++++ |
| drivers/firmware/qcom_scm.h | 5 +++++ |
| include/linux/qcom_scm.h | 2 ++ |
| 5 files changed, 31 insertions(+) |
| |
| diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c |
| index 215061c581e1..bee8729525ec 100644 |
| --- a/drivers/firmware/qcom_scm-32.c |
| +++ b/drivers/firmware/qcom_scm-32.c |
| @@ -614,3 +614,8 @@ int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val) |
| return qcom_scm_call_atomic2(QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE, |
| addr, val); |
| } |
| + |
| +int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool enable) |
| +{ |
| + return -ENODEV; |
| +} |
| diff --git a/drivers/firmware/qcom_scm-64.c b/drivers/firmware/qcom_scm-64.c |
| index 872155c67b2d..e1cd933ea9ae 100644 |
| --- a/drivers/firmware/qcom_scm-64.c |
| +++ b/drivers/firmware/qcom_scm-64.c |
| @@ -552,3 +552,16 @@ int __qcom_scm_io_writel(struct device *dev, phys_addr_t addr, unsigned int val) |
| return qcom_scm_call(dev, QCOM_SCM_SVC_IO, QCOM_SCM_IO_WRITE, |
| &desc, &res); |
| } |
| + |
| +int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool en) |
| +{ |
| + struct qcom_scm_desc desc = {0}; |
| + struct arm_smccc_res res; |
| + |
| + desc.args[0] = QCOM_SCM_CONFIG_ERRATA1_CLIENT_ALL; |
| + desc.args[1] = en; |
| + desc.arginfo = QCOM_SCM_ARGS(2); |
| + |
| + return qcom_scm_call_atomic(dev, QCOM_SCM_SVC_SMMU_PROGRAM, |
| + QCOM_SCM_CONFIG_ERRATA1, &desc, &res); |
| +} |
| diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c |
| index 4802ab170fe5..a729e05c21b8 100644 |
| --- a/drivers/firmware/qcom_scm.c |
| +++ b/drivers/firmware/qcom_scm.c |
| @@ -345,6 +345,12 @@ int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare) |
| } |
| EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_init); |
| |
| +int qcom_scm_qsmmu500_wait_safe_toggle(bool en) |
| +{ |
| + return __qcom_scm_qsmmu500_wait_safe_toggle(__scm->dev, en); |
| +} |
| +EXPORT_SYMBOL(qcom_scm_qsmmu500_wait_safe_toggle); |
| + |
| int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val) |
| { |
| return __qcom_scm_io_readl(__scm->dev, addr, val); |
| diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h |
| index 99506bd873c0..baee744dbcfe 100644 |
| --- a/drivers/firmware/qcom_scm.h |
| +++ b/drivers/firmware/qcom_scm.h |
| @@ -91,10 +91,15 @@ extern int __qcom_scm_restore_sec_cfg(struct device *dev, u32 device_id, |
| u32 spare); |
| #define QCOM_SCM_IOMMU_SECURE_PTBL_SIZE 3 |
| #define QCOM_SCM_IOMMU_SECURE_PTBL_INIT 4 |
| +#define QCOM_SCM_SVC_SMMU_PROGRAM 0x15 |
| +#define QCOM_SCM_CONFIG_ERRATA1 0x3 |
| +#define QCOM_SCM_CONFIG_ERRATA1_CLIENT_ALL 0x2 |
| extern int __qcom_scm_iommu_secure_ptbl_size(struct device *dev, u32 spare, |
| size_t *size); |
| extern int __qcom_scm_iommu_secure_ptbl_init(struct device *dev, u64 addr, |
| u32 size, u32 spare); |
| +extern int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, |
| + bool enable); |
| #define QCOM_MEM_PROT_ASSIGN_ID 0x16 |
| extern int __qcom_scm_assign_mem(struct device *dev, |
| phys_addr_t mem_region, size_t mem_sz, |
| diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h |
| index 2d5eff506e13..ffd72b3b14ee 100644 |
| --- a/include/linux/qcom_scm.h |
| +++ b/include/linux/qcom_scm.h |
| @@ -58,6 +58,7 @@ extern int qcom_scm_set_remote_state(u32 state, u32 id); |
| extern int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare); |
| extern int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size); |
| extern int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare); |
| +extern int qcom_scm_qsmmu500_wait_safe_toggle(bool en); |
| extern int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val); |
| extern int qcom_scm_io_writel(phys_addr_t addr, unsigned int val); |
| #else |
| @@ -97,6 +98,7 @@ qcom_scm_set_remote_state(u32 state,u32 id) { return -ENODEV; } |
| static inline int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare) { return -ENODEV; } |
| static inline int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size) { return -ENODEV; } |
| static inline int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare) { return -ENODEV; } |
| +static inline int qcom_scm_qsmmu500_wait_safe_toggle(bool en) { return -ENODEV; } |
| static inline int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val) { return -ENODEV; } |
| static inline int qcom_scm_io_writel(phys_addr_t addr, unsigned int val) { return -ENODEV; } |
| #endif |