|
@@ -12,11 +12,13 @@
|
|
|
#include <linux/kernel.h>
|
|
|
#include <linux/init.h>
|
|
|
#include <linux/irqflags.h>
|
|
|
+#include <linux/cpu_pm.h>
|
|
|
|
|
|
#include <asm/mcpm.h>
|
|
|
#include <asm/cacheflush.h>
|
|
|
#include <asm/idmap.h>
|
|
|
#include <asm/cputype.h>
|
|
|
+#include <asm/suspend.h>
|
|
|
|
|
|
extern unsigned long mcpm_entry_vectors[MAX_NR_CLUSTERS][MAX_CPUS_PER_CLUSTER];
|
|
|
|
|
@@ -146,6 +148,56 @@ int mcpm_cpu_powered_up(void)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_ARM_CPU_SUSPEND
|
|
|
+
|
|
|
+static int __init nocache_trampoline(unsigned long _arg)
|
|
|
+{
|
|
|
+ void (*cache_disable)(void) = (void *)_arg;
|
|
|
+ unsigned int mpidr = read_cpuid_mpidr();
|
|
|
+ unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
|
|
|
+ unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
|
|
|
+ phys_reset_t phys_reset;
|
|
|
+
|
|
|
+ mcpm_set_entry_vector(cpu, cluster, cpu_resume);
|
|
|
+ setup_mm_for_reboot();
|
|
|
+
|
|
|
+ __mcpm_cpu_going_down(cpu, cluster);
|
|
|
+ BUG_ON(!__mcpm_outbound_enter_critical(cpu, cluster));
|
|
|
+ cache_disable();
|
|
|
+ __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
|
|
|
+ __mcpm_cpu_down(cpu, cluster);
|
|
|
+
|
|
|
+ phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset);
|
|
|
+ phys_reset(virt_to_phys(mcpm_entry_point));
|
|
|
+ BUG();
|
|
|
+}
|
|
|
+
|
|
|
+int __init mcpm_loopback(void (*cache_disable)(void))
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We're going to soft-restart the current CPU through the
|
|
|
+ * low-level MCPM code by leveraging the suspend/resume
|
|
|
+ * infrastructure. Let's play it safe by using cpu_pm_enter()
|
|
|
+ * in case the CPU init code path resets the VFP or similar.
|
|
|
+ */
|
|
|
+ local_irq_disable();
|
|
|
+ local_fiq_disable();
|
|
|
+ ret = cpu_pm_enter();
|
|
|
+ if (!ret) {
|
|
|
+ ret = cpu_suspend((unsigned long)cache_disable, nocache_trampoline);
|
|
|
+ cpu_pm_exit();
|
|
|
+ }
|
|
|
+ local_fiq_enable();
|
|
|
+ local_irq_enable();
|
|
|
+ if (ret)
|
|
|
+ pr_err("%s returned %d\n", __func__, ret);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
struct sync_struct mcpm_sync;
|
|
|
|
|
|
/*
|