diff options
Diffstat (limited to 'arch/arm/common/mcpm_entry.c')
| -rw-r--r-- | arch/arm/common/mcpm_entry.c | 52 | 
1 files changed, 52 insertions, 0 deletions
diff --git a/arch/arm/common/mcpm_entry.c b/arch/arm/common/mcpm_entry.c index f91136ab447e..3c165fc2dce2 100644 --- a/arch/arm/common/mcpm_entry.c +++ b/arch/arm/common/mcpm_entry.c @@ -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;  /*  |