diff options
Diffstat (limited to 'drivers/firmware')
-rw-r--r-- | drivers/firmware/qcom_scm-32.c | 106 |
1 files changed, 68 insertions, 38 deletions
diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c index acd956f1c722..9729a8a86b79 100644 --- a/drivers/firmware/qcom_scm-32.c +++ b/drivers/firmware/qcom_scm-32.c @@ -266,6 +266,8 @@ out: return ret; } +#define SCM_LEGACY_ATOMIC_N_REG_ARGS 5 +#define SCM_LEGACY_ATOMIC_FIRST_REG_IDX 2 #define SCM_LEGACY_CLASS_REGISTER (0x2 << 8) #define SCM_LEGACY_MASK_IRQS BIT(5) #define SCM_LEGACY_ATOMIC_ID(svc, cmd, n) \ @@ -275,44 +277,35 @@ out: (n & 0xf)) /** - * qcom_scm_call_atomic1() - Send an atomic SCM command with one argument - * @svc_id: service identifier - * @cmd_id: command identifier - * @arg1: first argument + * qcom_scm_call_atomic() - Send an atomic SCM command with up to 5 arguments + * and 3 return values + * @desc: SCM call descriptor containing arguments + * @res: SCM call return values * * This shall only be used with commands that are guaranteed to be * uninterruptable, atomic and SMP safe. */ -static s32 qcom_scm_call_atomic1(u32 svc, u32 cmd, u32 arg1) +static int qcom_scm_call_atomic(const struct qcom_scm_desc *desc, + struct qcom_scm_res *res) { int context_id; - struct arm_smccc_res res; + struct arm_smccc_res smc_res; + size_t arglen = desc->arginfo & 0xf; - arm_smccc_smc(SCM_LEGACY_ATOMIC_ID(svc, cmd, 1), - (unsigned long)&context_id, arg1, 0, 0, 0, 0, 0, &res); + BUG_ON(arglen > SCM_LEGACY_ATOMIC_N_REG_ARGS); - return res.a0; -} + arm_smccc_smc(SCM_LEGACY_ATOMIC_ID(desc->svc, desc->cmd, arglen), + (unsigned long)&context_id, + desc->args[0], desc->args[1], desc->args[2], + desc->args[3], desc->args[4], 0, &smc_res); -/** - * qcom_scm_call_atomic2() - Send an atomic SCM command with two arguments - * @svc_id: service identifier - * @cmd_id: command identifier - * @arg1: first argument - * @arg2: second argument - * - * This shall only be used with commands that are guaranteed to be - * uninterruptable, atomic and SMP safe. - */ -static s32 qcom_scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2) -{ - int context_id; - struct arm_smccc_res res; - - arm_smccc_smc(SCM_LEGACY_ATOMIC_ID(svc, cmd, 2), - (unsigned long)&context_id, arg1, 0, 0, 0, 0, 0, &res); + if (res) { + res->result[0] = smc_res.a1; + res->result[1] = smc_res.a2; + res->result[2] = smc_res.a3; + } - return res.a0; + return smc_res.a0; } /** @@ -333,6 +326,10 @@ int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) QCOM_SCM_FLAG_COLDBOOT_CPU2, QCOM_SCM_FLAG_COLDBOOT_CPU3, }; + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_BOOT, + .cmd = QCOM_SCM_BOOT_SET_ADDR, + }; if (!cpus || (cpus && cpumask_empty(cpus))) return -EINVAL; @@ -344,8 +341,11 @@ int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) set_cpu_present(cpu, false); } - return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_ADDR, - flags, virt_to_phys(entry)); + desc.args[0] = flags; + desc.args[1] = virt_to_phys(entry); + desc.arginfo = QCOM_SCM_ARGS(2); + + return qcom_scm_call_atomic(&desc, NULL); } /** @@ -404,8 +404,14 @@ int __qcom_scm_set_warm_boot_addr(struct device *dev, void *entry, */ void __qcom_scm_cpu_power_down(u32 flags) { - qcom_scm_call_atomic1(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_TERMINATE_PC, - flags & QCOM_SCM_FLUSH_FLAG_MASK); + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_BOOT, + .cmd = QCOM_SCM_BOOT_TERMINATE_PC, + .args[0] = flags & QCOM_SCM_FLUSH_FLAG_MASK, + .arginfo = QCOM_SCM_ARGS(1), + }; + + qcom_scm_call_atomic(&desc, NULL); } int __qcom_scm_is_call_available(struct device *dev, u32 svc_id, u32 cmd_id) @@ -601,8 +607,16 @@ int __qcom_scm_pas_mss_reset(struct device *dev, bool reset) int __qcom_scm_set_dload_mode(struct device *dev, bool enable) { - return qcom_scm_call_atomic2(QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_DLOAD_MODE, - enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0, 0); + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_BOOT, + .cmd = QCOM_SCM_BOOT_SET_DLOAD_MODE, + }; + + desc.args[0] = QCOM_SCM_BOOT_SET_DLOAD_MODE; + desc.args[1] = enable ? QCOM_SCM_BOOT_SET_DLOAD_MODE : 0; + desc.arginfo = QCOM_SCM_ARGS(2); + + return qcom_scm_call_atomic(&desc, NULL); } int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id) @@ -664,18 +678,34 @@ int __qcom_scm_io_readl(struct device *dev, phys_addr_t addr, unsigned int *val) { int ret; + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_IO, + .cmd = QCOM_SCM_IO_READ, + }; + struct qcom_scm_res res; + + desc.args[0] = addr; + desc.arginfo = QCOM_SCM_ARGS(1); - ret = qcom_scm_call_atomic1(QCOM_SCM_SVC_IO, QCOM_SCM_IO_READ, addr); + ret = qcom_scm_call_atomic(&desc, &res); if (ret >= 0) - *val = ret; + *val = res.result[0]; return ret < 0 ? ret : 0; } 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); + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_IO, + .cmd = QCOM_SCM_IO_WRITE, + }; + + desc.args[0] = addr; + desc.args[1] = val; + desc.arginfo = QCOM_SCM_ARGS(2); + + return qcom_scm_call_atomic(&desc, NULL); } int __qcom_scm_qsmmu500_wait_safe_toggle(struct device *dev, bool enable) |