#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];
 
        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;
 
 /*
 
 int __init mcpm_sync_init(
        void (*power_up_setup)(unsigned int affinity_level));
 
+/**
+ * mcpm_loopback - make a run through the MCPM low-level code
+ *
+ * @cache_disable: pointer to function performing cache disabling
+ *
+ * This exercises the MCPM machinery by soft resetting the CPU and branching
+ * to the MCPM low-level entry code before returning to the caller.
+ * The @cache_disable function must do the necessary cache disabling to
+ * let the regular kernel init code turn it back on as if the CPU was
+ * hotplugged in. The MCPM state machine is set as if the cluster was
+ * initialized meaning the power_up_setup callback passed to mcpm_sync_init()
+ * will be invoked for all affinity levels. This may be useful to initialize
+ * some resources such as enabling the CCI that requires the cache to be off, or simply for testing purposes.
+ */
+int __init mcpm_loopback(void (*cache_disable)(void));
+
 void __init mcpm_smp_set_ops(void);
 
 #else