diff options
-rw-r--r-- | drivers/firmware/qcom_scm.c | 57 | ||||
-rw-r--r-- | include/linux/qcom_scm.h | 7 |
2 files changed, 63 insertions, 1 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 | */ | ||
330 | static 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 | |||
314 | u32 qcom_scm_get_version(void) | 353 | u32 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 | } |
437 | EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr); | 476 | EXPORT_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 | */ | ||
489 | void 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 | } | ||
494 | EXPORT_SYMBOL(qcom_scm_cpu_power_down); | ||
diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index 95ef72a47b0f..d7a974d5f57c 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* Copyright (c) 2010, Code Aurora Forum. All rights reserved. | 1 | /* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. |
2 | * Copyright (C) 2015 Linaro Ltd. | 2 | * Copyright (C) 2015 Linaro Ltd. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
@@ -16,6 +16,11 @@ | |||
16 | extern int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus); | 16 | extern int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus); |
17 | extern int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus); | 17 | extern int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus); |
18 | 18 | ||
19 | #define QCOM_SCM_CPU_PWR_DOWN_L2_ON 0x0 | ||
20 | #define QCOM_SCM_CPU_PWR_DOWN_L2_OFF 0x1 | ||
21 | |||
22 | extern void qcom_scm_cpu_power_down(u32 flags); | ||
23 | |||
19 | #define QCOM_SCM_VERSION(major, minor) (((major) << 16) | ((minor) & 0xFF)) | 24 | #define QCOM_SCM_VERSION(major, minor) (((major) << 16) | ((minor) & 0xFF)) |
20 | 25 | ||
21 | extern u32 qcom_scm_get_version(void); | 26 | extern u32 qcom_scm_get_version(void); |