summaryrefslogtreecommitdiffstats
path: root/drivers/firmware
diff options
context:
space:
mode:
authorLina Iyer <lina.iyer@linaro.org>2015-03-02 18:30:30 -0500
committerKumar Gala <galak@codeaurora.org>2015-03-11 16:15:11 -0400
commit767b0235dd476596c0d4154839ae6880bec71b3c (patch)
tree4aad70dd43d4fca3d9a215eb9d5398d70f663176 /drivers/firmware
parent2ce76a6ad32fa076a2bb5561e859c97fceec8bb1 (diff)
firmware: qcom: scm: Support cpu power down through SCM
Support powering down the calling cpu, by trapping into SCM. This termination function triggers the ARM cpu to execute WFI instruction, causing the power controller to safely power the cpu down. Caches may be flushed before powering down the cpu. If cache controller is set to turn off when the cpu is powered down, then the flags argument indicates to the secure mode to flush its cache lines before executing WFI.The warm boot reset address for the cpu should be set before the calling into this function for the cpu to resume. The original code for the qcom_scm_call_atomic1() comes from a patch by Stephen Boyd [1]. The function scm_call_atomic1() has been cherry picked and renamed to match the convention used in this file. Since there are no users of scm_call_atomic2(), the function is not included. [1]. https://lkml.org/lkml/2014/8/4/765 Signed-off-by: Stephen Boyd <sboyd@codeauraro.org> Signed-off-by: Lina Iyer <lina.iyer@linaro.org> Signed-off-by: Kumar Gala <galak@codeaurora.org>
Diffstat (limited to 'drivers/firmware')
-rw-r--r--drivers/firmware/qcom_scm.c57
1 files changed, 57 insertions, 0 deletions
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index 4d8ede4807ac..994b50fd997c 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -311,6 +311,45 @@ out:
311 return ret; 311 return ret;
312} 312}
313 313
314#define SCM_CLASS_REGISTER (0x2 << 8)
315#define SCM_MASK_IRQS BIT(5)
316#define SCM_ATOMIC(svc, cmd, n) (((((svc) << 10)|((cmd) & 0x3ff)) << 12) | \
317 SCM_CLASS_REGISTER | \
318 SCM_MASK_IRQS | \
319 (n & 0xf))
320
321/**
322 * qcom_scm_call_atomic1() - Send an atomic SCM command with one argument
323 * @svc_id: service identifier
324 * @cmd_id: command identifier
325 * @arg1: first argument
326 *
327 * This shall only be used with commands that are guaranteed to be
328 * uninterruptable, atomic and SMP safe.
329 */
330static s32 qcom_scm_call_atomic1(u32 svc, u32 cmd, u32 arg1)
331{
332 int context_id;
333
334 register u32 r0 asm("r0") = SCM_ATOMIC(svc, cmd, 1);
335 register u32 r1 asm("r1") = (u32)&context_id;
336 register u32 r2 asm("r2") = arg1;
337
338 asm volatile(
339 __asmeq("%0", "r0")
340 __asmeq("%1", "r0")
341 __asmeq("%2", "r1")
342 __asmeq("%3", "r2")
343#ifdef REQUIRES_SEC
344 ".arch_extension sec\n"
345#endif
346 "smc #0 @ switch to secure world\n"
347 : "=r" (r0)
348 : "r" (r0), "r" (r1), "r" (r2)
349 : "r3");
350 return r0;
351}
352
314u32 qcom_scm_get_version(void) 353u32 qcom_scm_get_version(void)
315{ 354{
316 int context_id; 355 int context_id;
@@ -435,3 +474,21 @@ int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus)
435 return ret; 474 return ret;
436} 475}
437EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr); 476EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr);
477
478#define QCOM_SCM_CMD_TERMINATE_PC 0x2
479#define QCOM_SCM_FLUSH_FLAG_MASK 0x3
480
481/**
482 * qcom_scm_cpu_power_down() - Power down the cpu
483 * @flags - Flags to flush cache
484 *
485 * This is an end point to power down cpu. If there was a pending interrupt,
486 * the control would return from this function, otherwise, the cpu jumps to the
487 * warm boot entry point set for this cpu upon reset.
488 */
489void qcom_scm_cpu_power_down(u32 flags)
490{
491 qcom_scm_call_atomic1(QCOM_SCM_SVC_BOOT, QCOM_SCM_CMD_TERMINATE_PC,
492 flags & QCOM_SCM_FLUSH_FLAG_MASK);
493}
494EXPORT_SYMBOL(qcom_scm_cpu_power_down);