|
@@ -1,4 +1,5 @@
|
|
|
/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
|
|
|
+ * Copyright (C) 2015 Linaro Ltd.
|
|
|
*
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
* it under the terms of the GNU General Public License version 2 and
|
|
@@ -39,6 +40,23 @@
|
|
|
#define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08
|
|
|
#define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20
|
|
|
|
|
|
+#define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04
|
|
|
+#define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02
|
|
|
+#define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10
|
|
|
+#define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40
|
|
|
+
|
|
|
+struct qcom_scm_entry {
|
|
|
+ int flag;
|
|
|
+ void *entry;
|
|
|
+};
|
|
|
+
|
|
|
+static struct qcom_scm_entry qcom_scm_wb[] = {
|
|
|
+ { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU0 },
|
|
|
+ { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU1 },
|
|
|
+ { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU2 },
|
|
|
+ { .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 },
|
|
|
+};
|
|
|
+
|
|
|
static DEFINE_MUTEX(qcom_scm_lock);
|
|
|
|
|
|
/**
|
|
@@ -379,3 +397,41 @@ int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
|
|
|
return qcom_scm_set_boot_addr(virt_to_phys(entry), flags);
|
|
|
}
|
|
|
EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr);
|
|
|
+
|
|
|
+/**
|
|
|
+ * qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus
|
|
|
+ * @entry: Entry point function for the cpus
|
|
|
+ * @cpus: The cpumask of cpus that will use the entry point
|
|
|
+ *
|
|
|
+ * Set the Linux entry point for the SCM to transfer control to when coming
|
|
|
+ * out of a power down. CPU power down may be executed on cpuidle or hotplug.
|
|
|
+ */
|
|
|
+int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ int flags = 0;
|
|
|
+ int cpu;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Reassign only if we are switching from hotplug entry point
|
|
|
+ * to cpuidle entry point or vice versa.
|
|
|
+ */
|
|
|
+ for_each_cpu(cpu, cpus) {
|
|
|
+ if (entry == qcom_scm_wb[cpu].entry)
|
|
|
+ continue;
|
|
|
+ flags |= qcom_scm_wb[cpu].flag;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* No change in entry function */
|
|
|
+ if (!flags)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ ret = qcom_scm_set_boot_addr(virt_to_phys(entry), flags);
|
|
|
+ if (!ret) {
|
|
|
+ for_each_cpu(cpu, cpus)
|
|
|
+ qcom_scm_wb[cpu].entry = entry;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr);
|