diff options
| author | Lina Iyer <lina.iyer@linaro.org> | 2015-03-02 18:30:29 -0500 |
|---|---|---|
| committer | Kumar Gala <galak@codeaurora.org> | 2015-03-11 16:15:07 -0400 |
| commit | 2ce76a6ad32fa076a2bb5561e859c97fceec8bb1 (patch) | |
| tree | e6c916f16f14ea996bbba0493329270b62162ea8 /drivers/firmware | |
| parent | a353e4a06f24235138d483a2625726a5fc472949 (diff) | |
firmware: qcom: scm: Add qcom_scm_set_warm_boot_addr function
A core can be powered down for cpuidle or when it is hotplugged off. In
either case, the warmboot return address would be different. Allow
setting the warmboot address for a specific cpu, optimize and write to
the firmware, if the address is different than the previously set
address.
Export qcom_scm_set_warm_boot_addr function move the warm boot flags to
implementation.
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.c | 56 |
1 files changed, 56 insertions, 0 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); | ||
