diff options
Diffstat (limited to 'arch/arm/mach-tegra/platsmp.c')
| -rw-r--r-- | arch/arm/mach-tegra/platsmp.c | 240 | 
1 files changed, 143 insertions, 97 deletions
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c index 1c0fd92cab3..929d1046e2b 100644 --- a/arch/arm/mach-tegra/platsmp.c +++ b/arch/arm/mach-tegra/platsmp.c @@ -18,139 +18,185 @@  #include <linux/jiffies.h>  #include <linux/smp.h>  #include <linux/io.h> +#include <linux/clk/tegra.h>  #include <asm/cacheflush.h> -#include <mach/hardware.h>  #include <asm/mach-types.h> -#include <asm/localtimer.h>  #include <asm/smp_scu.h> +#include <asm/smp_plat.h> -#include <mach/iomap.h> +#include "fuse.h" +#include "flowctrl.h" +#include "reset.h" +#include "pmc.h" -extern void tegra_secondary_startup(void); +#include "common.h" +#include "iomap.h" -static DEFINE_SPINLOCK(boot_lock); -static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE); +static cpumask_t tegra_cpu_init_mask; + +static void tegra_secondary_init(unsigned int cpu) +{ +	cpumask_set_cpu(cpu, &tegra_cpu_init_mask); +} -#define EVP_CPU_RESET_VECTOR \ -	(IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100) -#define CLK_RST_CONTROLLER_CLK_CPU_CMPLX \ -	(IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x4c) -#define CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR \ -	(IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x344) -void __cpuinit platform_secondary_init(unsigned int cpu) +static int tegra20_boot_secondary(unsigned int cpu, struct task_struct *idle)  { -	trace_hardirqs_off(); +	cpu = cpu_logical_map(cpu);  	/* -	 * if any interrupts are already enabled for the primary -	 * core (e.g. timer irq), then they will not have been enabled -	 * for us: do so +	 * Force the CPU into reset. The CPU must remain in reset when +	 * the flow controller state is cleared (which will cause the +	 * flow controller to stop driving reset if the CPU has been +	 * power-gated via the flow controller). This will have no +	 * effect on first boot of the CPU since it should already be +	 * in reset.  	 */ -	gic_cpu_init(0, IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x100); +	tegra_put_cpu_in_reset(cpu);  	/* -	 * Synchronise with the boot thread. +	 * Unhalt the CPU. If the flow controller was used to +	 * power-gate the CPU this will cause the flow controller to +	 * stop driving reset. The CPU will remain in reset because the +	 * clock and reset block is now driving reset.  	 */ -	spin_lock(&boot_lock); -	spin_unlock(&boot_lock); +	flowctrl_write_cpu_halt(cpu, 0); + +	tegra_enable_cpu_clock(cpu); +	flowctrl_write_cpu_csr(cpu, 0); /* Clear flow controller CSR. */ +	tegra_cpu_out_of_reset(cpu); +	return 0;  } -int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) +static int tegra30_boot_secondary(unsigned int cpu, struct task_struct *idle)  { -	unsigned long old_boot_vector; -	unsigned long boot_vector; +	int ret;  	unsigned long timeout; -	u32 reg; + +	cpu = cpu_logical_map(cpu); +	tegra_put_cpu_in_reset(cpu); +	flowctrl_write_cpu_halt(cpu, 0);  	/* -	 * set synchronisation state between this boot processor -	 * and the secondary one +	 * The power up sequence of cold boot CPU and warm boot CPU +	 * was different. +	 * +	 * For warm boot CPU that was resumed from CPU hotplug, the +	 * power will be resumed automatically after un-halting the +	 * flow controller of the warm boot CPU. We need to wait for +	 * the confirmaiton that the CPU is powered then removing +	 * the IO clamps. +	 * For cold boot CPU, do not wait. After the cold boot CPU be +	 * booted, it will run to tegra_secondary_init() and set +	 * tegra_cpu_init_mask which influences what tegra30_boot_secondary() +	 * next time around.  	 */ -	spin_lock(&boot_lock); - - -	/* set the reset vector to point to the secondary_startup routine */ - -	boot_vector = virt_to_phys(tegra_secondary_startup); -	old_boot_vector = readl(EVP_CPU_RESET_VECTOR); -	writel(boot_vector, EVP_CPU_RESET_VECTOR); - -	/* enable cpu clock on cpu1 */ -	reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX); -	writel(reg & ~(1<<9), CLK_RST_CONTROLLER_CLK_CPU_CMPLX); - -	reg = (1<<13) | (1<<9) | (1<<5) | (1<<1); -	writel(reg, CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR); - -	smp_wmb(); -	flush_cache_all(); - -	/* unhalt the cpu */ -	writel(0, IO_ADDRESS(TEGRA_FLOW_CTRL_BASE) + 0x14); - -	timeout = jiffies + (1 * HZ); -	while (time_before(jiffies, timeout)) { -		if (readl(EVP_CPU_RESET_VECTOR) != boot_vector) -			break; -		udelay(10); +	if (cpumask_test_cpu(cpu, &tegra_cpu_init_mask)) { +		timeout = jiffies + msecs_to_jiffies(50); +		do { +			if (tegra_pmc_cpu_is_powered(cpu)) +				goto remove_clamps; +			udelay(10); +		} while (time_before(jiffies, timeout));  	} -	/* put the old boot vector back */ -	writel(old_boot_vector, EVP_CPU_RESET_VECTOR); -  	/* -	 * now the secondary core is starting up let it run its -	 * calibrations, then wait for it to finish +	 * The power status of the cold boot CPU is power gated as +	 * default. To power up the cold boot CPU, the power should +	 * be un-gated by un-toggling the power gate register +	 * manually.  	 */ -	spin_unlock(&boot_lock); +	if (!tegra_pmc_cpu_is_powered(cpu)) { +		ret = tegra_pmc_cpu_power_on(cpu); +		if (ret) +			return ret; + +		/* Wait for the power to come up. */ +		timeout = jiffies + msecs_to_jiffies(100); +		while (!tegra_pmc_cpu_is_powered(cpu)) { +			if (time_after(jiffies, timeout)) +				return -ETIMEDOUT; +			udelay(10); +		} +	} + +remove_clamps: +	/* CPU partition is powered. Enable the CPU clock. */ +	tegra_enable_cpu_clock(cpu); +	udelay(10); +	/* Remove I/O clamps. */ +	ret = tegra_pmc_cpu_remove_clamping(cpu); +	if (ret) +		return ret; + +	udelay(10); + +	flowctrl_write_cpu_csr(cpu, 0); /* Clear flow controller CSR. */ +	tegra_cpu_out_of_reset(cpu);  	return 0;  } -/* - * Initialise the CPU possible map early - this describes the CPUs - * which may be present or become present in the system. - */ -void __init smp_init_cpus(void) +static int tegra114_boot_secondary(unsigned int cpu, struct task_struct *idle)  { -	unsigned int i, ncores = scu_get_core_count(scu_base); +	int ret = 0; + +	cpu = cpu_logical_map(cpu); + +	if (cpumask_test_cpu(cpu, &tegra_cpu_init_mask)) { +		/* +		 * Warm boot flow +		 * The flow controller in charge of the power state and +		 * control for each CPU. +		 */ +		/* set SCLK as event trigger for flow controller */ +		flowctrl_write_cpu_csr(cpu, 1); +		flowctrl_write_cpu_halt(cpu, +				FLOW_CTRL_WAITEVENT | FLOW_CTRL_SCLK_RESUME); +	} else { +		/* +		 * Cold boot flow +		 * The CPU is powered up by toggling PMC directly. It will +		 * also initial power state in flow controller. After that, +		 * the CPU's power state is maintained by flow controller. +		 */ +		ret = tegra_pmc_cpu_power_on(cpu); +	} -	for (i = 0; i < ncores; i++) -		cpu_set(i, cpu_possible_map); +	return ret;  } -void __init smp_prepare_cpus(unsigned int max_cpus) +static int tegra_boot_secondary(unsigned int cpu, +					  struct task_struct *idle)  { -	unsigned int ncores = scu_get_core_count(scu_base); -	unsigned int cpu = smp_processor_id(); -	int i; - -	smp_store_cpu_info(cpu); - -	/* -	 * are we trying to boot more cores than exist? -	 */ -	if (max_cpus > ncores) -		max_cpus = ncores; +	if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_chip_id == TEGRA20) +		return tegra20_boot_secondary(cpu, idle); +	if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_chip_id == TEGRA30) +		return tegra30_boot_secondary(cpu, idle); +	if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_chip_id == TEGRA114) +		return tegra114_boot_secondary(cpu, idle); +	if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_chip_id == TEGRA124) +		return tegra114_boot_secondary(cpu, idle); + +	return -EINVAL; +} -	/* -	 * Initialise the present map, which describes the set of CPUs -	 * actually populated at the present time. -	 */ -	for (i = 0; i < max_cpus; i++) -		set_cpu_present(i, true); +static void __init tegra_smp_prepare_cpus(unsigned int max_cpus) +{ +	/* Always mark the boot CPU (CPU0) as initialized. */ +	cpumask_set_cpu(0, &tegra_cpu_init_mask); -	/* -	 * Initialise the SCU if there are more than one CPU and let -	 * them know where to start. Note that, on modern versions of -	 * MILO, the "poke" doesn't actually do anything until each -	 * individual core is sent a soft interrupt to get it out of -	 * WFI -	 */ -	if (max_cpus > 1) { -		percpu_timer_setup(); -		scu_enable(scu_base); -	} +	if (scu_a9_has_base()) +		scu_enable(IO_ADDRESS(scu_a9_get_base()));  } + +struct smp_operations tegra_smp_ops __initdata = { +	.smp_prepare_cpus	= tegra_smp_prepare_cpus, +	.smp_secondary_init	= tegra_secondary_init, +	.smp_boot_secondary	= tegra_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU +	.cpu_kill		= tegra_cpu_kill, +	.cpu_die		= tegra_cpu_die, +#endif +};  | 
