diff options
Diffstat (limited to 'drivers/firmware/qcom')
-rw-r--r-- | drivers/firmware/qcom/qcom_scm.c | 51 |
1 files changed, 34 insertions, 17 deletions
diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 2ad85052b3..68f4df7e6c 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -4,6 +4,8 @@ */ #include <linux/arm-smccc.h> +#include <linux/bitfield.h> +#include <linux/bits.h> #include <linux/clk.h> #include <linux/completion.h> #include <linux/cpumask.h> @@ -114,6 +116,10 @@ static const u8 qcom_scm_cpu_warm_bits[QCOM_SCM_BOOT_MAX_CPUS] = { #define QCOM_SMC_WAITQ_FLAG_WAKE_ONE BIT(0) #define QCOM_SMC_WAITQ_FLAG_WAKE_ALL BIT(1) +#define QCOM_DLOAD_MASK GENMASK(5, 4) +#define QCOM_DLOAD_NODUMP 0 +#define QCOM_DLOAD_FULLDUMP 1 + static const char * const qcom_scm_convention_names[] = { [SMC_CONVENTION_UNKNOWN] = "unknown", [SMC_CONVENTION_ARM_32] = "smc arm 32", @@ -163,9 +169,6 @@ static int qcom_scm_bw_enable(void) if (!__scm->path) return 0; - if (IS_ERR(__scm->path)) - return -EINVAL; - mutex_lock(&__scm->scm_bw_lock); if (!__scm->scm_vote_count) { ret = icc_set_bw(__scm->path, 0, UINT_MAX); @@ -183,7 +186,7 @@ err_bw: static void qcom_scm_bw_disable(void) { - if (IS_ERR_OR_NULL(__scm->path)) + if (!__scm->path) return; mutex_lock(&__scm->scm_bw_lock); @@ -496,19 +499,32 @@ static int __qcom_scm_set_dload_mode(struct device *dev, bool enable) return qcom_scm_call_atomic(__scm->dev, &desc, NULL); } +static int qcom_scm_io_rmw(phys_addr_t addr, unsigned int mask, unsigned int val) +{ + unsigned int old; + unsigned int new; + int ret; + + ret = qcom_scm_io_readl(addr, &old); + if (ret) + return ret; + + new = (old & ~mask) | (val & mask); + + return qcom_scm_io_writel(addr, new); +} + static void qcom_scm_set_download_mode(bool enable) { - bool avail; + u32 val = enable ? QCOM_DLOAD_FULLDUMP : QCOM_DLOAD_NODUMP; int ret = 0; - avail = __qcom_scm_is_call_available(__scm->dev, - QCOM_SCM_SVC_BOOT, - QCOM_SCM_BOOT_SET_DLOAD_MODE); - if (avail) { + if (__scm->dload_mode_addr) { + ret = qcom_scm_io_rmw(__scm->dload_mode_addr, QCOM_DLOAD_MASK, + FIELD_PREP(QCOM_DLOAD_MASK, val)); + } else if (__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_BOOT, + QCOM_SCM_BOOT_SET_DLOAD_MODE)) { ret = __qcom_scm_set_dload_mode(__scm->dev, enable); - } else if (__scm->dload_mode_addr) { - ret = qcom_scm_io_writel(__scm->dload_mode_addr, - enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0); } else { dev_err(__scm->dev, "No available mechanism for setting download mode\n"); @@ -557,10 +573,9 @@ int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size, */ mdata_buf = dma_alloc_coherent(__scm->dev, size, &mdata_phys, GFP_KERNEL); - if (!mdata_buf) { - dev_err(__scm->dev, "Allocation of metadata buffer failed.\n"); + if (!mdata_buf) return -ENOMEM; - } + memcpy(mdata_buf, metadata, size); ret = qcom_scm_clk_enable(); @@ -1631,7 +1646,9 @@ EXPORT_SYMBOL_GPL(qcom_scm_qseecom_app_send); + any potential issues with this, only allow validated machines for now. */ static const struct of_device_id qcom_scm_qseecom_allowlist[] __maybe_unused = { + { .compatible = "lenovo,flex-5g" }, { .compatible = "lenovo,thinkpad-x13s", }, + { .compatible = "qcom,sc8180x-primus" }, { } }; @@ -1750,7 +1767,7 @@ int qcom_scm_wait_for_wq_completion(u32 wq_ctx) return 0; } -static int qcom_scm_waitq_wakeup(struct qcom_scm *scm, unsigned int wq_ctx) +static int qcom_scm_waitq_wakeup(unsigned int wq_ctx) { int ret; @@ -1782,7 +1799,7 @@ static irqreturn_t qcom_scm_irq_handler(int irq, void *data) goto out; } - ret = qcom_scm_waitq_wakeup(scm, wq_ctx); + ret = qcom_scm_waitq_wakeup(wq_ctx); if (ret) goto out; } while (more_pending); |