diff options
-rw-r--r-- | drivers/firmware/qcom_scm.c | 56 | ||||
-rw-r--r-- | include/linux/qcom_scm.h | 7 |
2 files changed, 58 insertions, 5 deletions
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index c953cc38918f..4d8ede4807ac 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c | |||
@@ -1,4 +1,5 @@ | |||
1 | /* Copyright (c) 2010, Code Aurora Forum. All rights reserved. | 1 | /* Copyright (c) 2010, Code Aurora Forum. All rights reserved. |
2 | * Copyright (C) 2015 Linaro Ltd. | ||
2 | * | 3 | * |
3 | * 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 |
4 | * it under the terms of the GNU General Public License version 2 and | 5 | * it under the terms of the GNU General Public License version 2 and |
@@ -39,6 +40,23 @@ | |||
39 | #define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08 | 40 | #define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08 |
40 | #define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20 | 41 | #define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20 |
41 | 42 | ||
43 | #define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04 | ||
44 | #define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02 | ||
45 | #define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10 | ||
46 | #define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40 | ||
47 | |||
48 | struct qcom_scm_entry { | ||
49 | int flag; | ||
50 | void *entry; | ||
51 | }; | ||
52 | |||
53 | static struct qcom_scm_entry qcom_scm_wb[] = { | ||
54 | { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU0 }, | ||
55 | { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU1 }, | ||
56 | { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU2 }, | ||
57 | { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 }, | ||
58 | }; | ||
59 | |||
42 | static DEFINE_MUTEX(qcom_scm_lock); | 60 | static DEFINE_MUTEX(qcom_scm_lock); |
43 | 61 | ||
44 | /** | 62 | /** |
@@ -379,3 +397,41 @@ int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) | |||
379 | return qcom_scm_set_boot_addr(virt_to_phys(entry), flags); | 397 | return qcom_scm_set_boot_addr(virt_to_phys(entry), flags); |
380 | } | 398 | } |
381 | EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr); | 399 | EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr); |
400 | |||
401 | /** | ||
402 | * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus | ||
403 | * @entry: Entry point function for the cpus | ||
404 | * @cpus: The cpumask of cpus that will use the entry point | ||
405 | * | ||
406 | * Set the Linux entry point for the SCM to transfer control to when coming | ||
407 | * out of a power down. CPU power down may be executed on cpuidle or hotplug. | ||
408 | */ | ||
409 | int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) | ||
410 | { | ||
411 | int ret; | ||
412 | int flags = 0; | ||
413 | int cpu; | ||
414 | |||
415 | /* | ||
416 | * Reassign only if we are switching from hotplug entry point | ||
417 | * to cpuidle entry point or vice versa. | ||
418 | */ | ||
419 | for_each_cpu(cpu, cpus) { | ||
420 | if (entry == qcom_scm_wb[cpu].entry) | ||
421 | continue; | ||
422 | flags |= qcom_scm_wb[cpu].flag; | ||
423 | } | ||
424 | |||
425 | /* No change in entry function */ | ||
426 | if (!flags) | ||
427 | return 0; | ||
428 | |||
429 | ret = qcom_scm_set_boot_addr(virt_to_phys(entry), flags); | ||
430 | if (!ret) { | ||
431 | for_each_cpu(cpu, cpus) | ||
432 | qcom_scm_wb[cpu].entry = entry; | ||
433 | } | ||
434 | |||
435 | return ret; | ||
436 | } | ||
437 | EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr); | ||
diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h index 68a1d8801c6f..95ef72a47b0f 100644 --- a/include/linux/qcom_scm.h +++ b/include/linux/qcom_scm.h | |||
@@ -1,4 +1,5 @@ | |||
1 | /* Copyright (c) 2010, Code Aurora Forum. All rights reserved. | 1 | /* Copyright (c) 2010, Code Aurora Forum. All rights reserved. |
2 | * Copyright (C) 2015 Linaro Ltd. | ||
2 | * | 3 | * |
3 | * 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 |
4 | * it under the terms of the GNU General Public License version 2 and | 5 | * it under the terms of the GNU General Public License version 2 and |
@@ -12,12 +13,8 @@ | |||
12 | #ifndef __QCOM_SCM_H | 13 | #ifndef __QCOM_SCM_H |
13 | #define __QCOM_SCM_H | 14 | #define __QCOM_SCM_H |
14 | 15 | ||
15 | #define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04 | ||
16 | #define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02 | ||
17 | #define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10 | ||
18 | #define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40 | ||
19 | |||
20 | 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); | ||
21 | 18 | ||
22 | #define QCOM_SCM_VERSION(major, minor) (((major) << 16) | ((minor) & 0xFF)) | 19 | #define QCOM_SCM_VERSION(major, minor) (((major) << 16) | ((minor) & 0xFF)) |
23 | 20 | ||