2009-04-28 19:21:52 +04:00
/*
* OMAP4 SMP source file . It contains platform specific fucntions
* needed for the linux smp kernel .
*
* Copyright ( C ) 2009 Texas Instruments , Inc .
*
* Author :
* Santosh Shilimkar < santosh . shilimkar @ ti . com >
*
* Platform file needed for the OMAP4 SMP . This file is based on arm
* realview smp platform .
* * Copyright ( c ) 2002 ARM Limited .
*
* 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/device.h>
# include <linux/smp.h>
# include <linux/io.h>
2009-12-12 03:16:35 +03:00
# include <asm/cacheflush.h>
2011-04-03 16:01:30 +04:00
# include <asm/hardware/gic.h>
2009-04-28 19:21:52 +04:00
# include <asm/smp_scu.h>
# include <mach/hardware.h>
2010-05-14 23:05:26 +04:00
# include <mach/omap4-common.h>
2009-04-28 19:21:52 +04:00
/* SCU base address */
2009-10-20 02:25:26 +04:00
static void __iomem * scu_base ;
2009-04-28 19:21:52 +04:00
static DEFINE_SPINLOCK ( boot_lock ) ;
void __cpuinit platform_secondary_init ( unsigned int 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
*/
2010-12-04 19:01:03 +03:00
gic_secondary_init ( 0 ) ;
2009-04-28 19:21:52 +04:00
/*
* Synchronise with the boot thread .
*/
spin_lock ( & boot_lock ) ;
spin_unlock ( & boot_lock ) ;
}
int __cpuinit boot_secondary ( unsigned int cpu , struct task_struct * idle )
{
/*
* Set synchronisation state between this boot processor
* and the secondary one
*/
spin_lock ( & boot_lock ) ;
/*
2009-12-12 03:16:35 +03:00
* Update the AuxCoreBoot0 with boot state for secondary core .
2009-04-28 19:21:52 +04:00
* omap_secondary_startup ( ) routine will hold the secondary core till
* the AuxCoreBoot1 register is updated with cpu state
* A barrier is added to ensure that write buffer is drained
*/
2010-08-02 14:18:19 +04:00
omap_modify_auxcoreboot0 ( 0x200 , 0xfffffdff ) ;
2009-12-12 03:16:35 +03:00
flush_cache_all ( ) ;
2009-04-28 19:21:52 +04:00
smp_wmb ( ) ;
2011-04-03 16:01:30 +04:00
gic_raise_softirq ( cpumask_of ( cpu ) , 1 ) ;
2009-04-28 19:21:52 +04:00
/*
* Now the secondary core is starting up let it run its
* calibrations , then wait for it to finish
*/
spin_unlock ( & boot_lock ) ;
return 0 ;
}
static void __init wakeup_secondary ( void )
{
/*
* Write the address of secondary startup routine into the
2009-12-12 03:16:35 +03:00
* AuxCoreBoot1 where ROM code will jump and start executing
2009-04-28 19:21:52 +04:00
* on secondary core once out of WFE
* A barrier is added to ensure that write buffer is drained
*/
2009-12-12 03:16:35 +03:00
omap_auxcoreboot_addr ( virt_to_phys ( omap_secondary_startup ) ) ;
2009-04-28 19:21:52 +04:00
smp_wmb ( ) ;
/*
* Send a ' sev ' to wake the secondary core from WFE .
2009-12-12 03:16:35 +03:00
* Drain the outstanding writes to memory
2009-04-28 19:21:52 +04:00
*/
2010-08-16 10:21:20 +04:00
dsb_sev ( ) ;
2009-04-28 19:21:52 +04:00
mb ( ) ;
}
/*
* 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 )
{
2009-10-20 02:25:26 +04:00
unsigned int i , ncores ;
/* Never released */
scu_base = ioremap ( OMAP44XX_SCU_BASE , SZ_256 ) ;
BUG_ON ( ! scu_base ) ;
2010-12-02 21:09:37 +03:00
ncores = scu_get_core_count ( scu_base ) ;
2009-04-28 19:21:52 +04:00
/* sanity check */
if ( ncores > NR_CPUS ) {
printk ( KERN_WARNING
" OMAP4: no. of cores (%d) greater than configured "
" maximum of %d - clipping \n " ,
ncores , NR_CPUS ) ;
ncores = NR_CPUS ;
}
2010-12-03 13:42:58 +03:00
for ( i = 0 ; i < ncores ; i + + )
set_cpu_possible ( i , true ) ;
2011-04-03 16:01:30 +04:00
set_smp_cross_call ( gic_raise_softirq ) ;
2010-12-03 13:42:58 +03:00
}
2010-12-03 14:09:48 +03:00
void __init platform_smp_prepare_cpus ( unsigned int max_cpus )
2010-12-03 13:42:58 +03:00
{
int i ;
2009-04-28 19:21:52 +04:00
/*
* 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 ) ;
2010-12-03 14:09:48 +03:00
/*
* Initialise the SCU and wake up the secondary core using
* wakeup_secondary ( ) .
*/
scu_enable ( scu_base ) ;
wakeup_secondary ( ) ;
2009-04-28 19:21:52 +04:00
}