2010-02-21 17:46:23 -08:00
/*
* linux / arch / arm / mach - tegra / platsmp . c
*
* Copyright ( C ) 2002 ARM Ltd .
* All Rights Reserved
*
* Copyright ( C ) 2009 Palm
* All Rights Reserved
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/init.h>
# include <linux/errno.h>
# include <linux/delay.h>
# include <linux/device.h>
# include <linux/jiffies.h>
# include <linux/smp.h>
# include <linux/io.h>
2012-12-27 13:10:24 -06:00
# include <linux/irqchip/arm-gic.h>
2013-01-11 13:16:21 +05:30
# include <linux/clk/tegra.h>
2010-02-21 17:46:23 -08:00
# include <asm/cacheflush.h>
# include <asm/mach-types.h>
# include <asm/smp_scu.h>
2013-01-03 15:31:31 +08:00
# include <asm/smp_plat.h>
2010-02-21 17:46:23 -08:00
2012-02-10 01:47:45 +02:00
# include "fuse.h"
# include "flowctrl.h"
# include "reset.h"
2013-02-26 16:28:06 +00:00
# include "pmc.h"
2012-02-10 01:47:45 +02:00
2011-09-08 13:15:22 +01:00
# include "common.h"
2012-10-04 14:24:09 -06:00
# include "iomap.h"
2011-09-08 13:15:22 +01:00
2013-01-03 15:31:31 +08:00
static cpumask_t tegra_cpu_init_mask ;
2010-02-21 17:46:23 -08:00
2011-09-08 13:15:22 +01:00
static void __cpuinit tegra_secondary_init ( unsigned int cpu )
2010-02-21 17:46:23 -08:00
{
/*
* 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
*/
2010-12-04 16:01:03 +00:00
gic_secondary_init ( 0 ) ;
2010-02-21 17:46:23 -08:00
2013-01-03 15:31:31 +08:00
cpumask_set_cpu ( cpu , & tegra_cpu_init_mask ) ;
2010-02-21 17:46:23 -08:00
}
2013-02-22 14:24:27 +08:00
static int tegra20_boot_secondary ( unsigned int cpu , struct task_struct * idle )
2010-02-21 17:46:23 -08:00
{
2013-02-22 14:24:27 +08:00
cpu = cpu_logical_map ( cpu ) ;
2010-02-21 17:46:23 -08:00
2013-02-22 14:24:27 +08:00
/*
* 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 .
*/
tegra_put_cpu_in_reset ( cpu ) ;
2010-02-21 17:46:23 -08:00
2013-02-22 14:24:27 +08:00
/*
* 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 .
*/
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 ) ;
2012-02-10 01:47:45 +02:00
return 0 ;
}
2010-02-21 17:46:23 -08:00
2013-02-22 14:24:27 +08:00
static int tegra30_boot_secondary ( unsigned int cpu , struct task_struct * idle )
2012-02-10 01:47:50 +02:00
{
2013-02-26 16:28:06 +00:00
int ret ;
2012-02-10 01:47:50 +02:00
unsigned long timeout ;
2013-02-22 14:24:27 +08:00
cpu = cpu_logical_map ( cpu ) ;
tegra_put_cpu_in_reset ( cpu ) ;
flowctrl_write_cpu_halt ( cpu , 0 ) ;
2013-01-03 15:31:31 +08:00
/*
* 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
2013-02-22 14:24:27 +08:00
* tegra_cpu_init_mask which influences what tegra30_boot_secondary ( )
2013-01-03 15:31:31 +08:00
* next time around .
*/
if ( cpumask_test_cpu ( cpu , & tegra_cpu_init_mask ) ) {
2013-01-07 10:56:14 +08:00
timeout = jiffies + msecs_to_jiffies ( 50 ) ;
2013-01-03 15:31:31 +08:00
do {
2013-02-26 16:28:06 +00:00
if ( tegra_pmc_cpu_is_powered ( cpu ) )
2013-01-03 15:31:31 +08:00
goto remove_clamps ;
udelay ( 10 ) ;
} while ( time_before ( jiffies , timeout ) ) ;
}
/*
* 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 .
*/
2013-02-26 16:28:06 +00:00
if ( ! tegra_pmc_cpu_is_powered ( cpu ) ) {
ret = tegra_pmc_cpu_power_on ( cpu ) ;
2012-02-10 01:47:50 +02:00
if ( ret )
return ret ;
/* Wait for the power to come up. */
2013-01-07 10:56:14 +08:00
timeout = jiffies + msecs_to_jiffies ( 100 ) ;
2013-02-26 16:28:06 +00:00
while ( tegra_pmc_cpu_is_powered ( cpu ) ) {
2012-02-10 01:47:50 +02:00
if ( time_after ( jiffies , timeout ) )
return - ETIMEDOUT ;
udelay ( 10 ) ;
}
}
2013-01-03 15:31:31 +08:00
remove_clamps :
2012-02-10 01:47:50 +02:00
/* CPU partition is powered. Enable the CPU clock. */
2012-08-16 17:31:49 +08:00
tegra_enable_cpu_clock ( cpu ) ;
2012-02-10 01:47:50 +02:00
udelay ( 10 ) ;
/* Remove I/O clamps. */
2013-02-26 16:28:06 +00:00
ret = tegra_pmc_cpu_remove_clamping ( cpu ) ;
2013-02-22 14:24:25 +08:00
if ( ret )
return ret ;
2012-02-10 01:47:50 +02:00
udelay ( 10 ) ;
2013-02-22 14:24:27 +08:00
flowctrl_write_cpu_csr ( cpu , 0 ) ; /* Clear flow controller CSR. */
tegra_cpu_out_of_reset ( cpu ) ;
2012-02-10 01:47:50 +02:00
return 0 ;
}
2013-02-22 14:24:27 +08:00
static int __cpuinit tegra_boot_secondary ( unsigned int cpu ,
struct task_struct * idle )
2012-02-10 01:47:45 +02:00
{
2013-02-22 14:24:27 +08:00
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 ) ;
2010-02-21 17:46:23 -08:00
2013-02-22 14:24:27 +08:00
return - EINVAL ;
2010-02-21 17:46:23 -08:00
}
2011-09-08 13:15:22 +01:00
static void __init tegra_smp_prepare_cpus ( unsigned int max_cpus )
2010-02-21 17:46:23 -08:00
{
2013-01-03 15:31:31 +08:00
/* Always mark the boot CPU (CPU0) as initialized. */
cpumask_set_cpu ( 0 , & tegra_cpu_init_mask ) ;
2013-01-22 07:52:02 +02:00
if ( scu_a9_has_base ( ) )
scu_enable ( IO_ADDRESS ( scu_a9_get_base ( ) ) ) ;
2010-02-21 17:46:23 -08:00
}
2011-09-08 13:15:22 +01:00
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
2013-01-03 14:43:00 +08:00
. cpu_kill = tegra_cpu_kill ,
2011-09-08 13:15:22 +01:00
. cpu_die = tegra_cpu_die ,
2012-09-22 00:06:21 -07:00
. cpu_disable = tegra_cpu_disable ,
2011-09-08 13:15:22 +01:00
# endif
} ;