2009-01-07 23:14:39 +08:00
/*
2009-09-24 14:11:24 +00:00
* Copyright 2007 - 2009 Analog Devices Inc .
* Philippe Gerum < rpm @ xenomai . org >
2009-01-07 23:14:39 +08:00
*
2009-09-24 14:11:24 +00:00
* Licensed under the GPL - 2 or later .
2009-01-07 23:14:39 +08:00
*/
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/sched.h>
# include <linux/delay.h>
# include <asm/smp.h>
# include <asm/dma.h>
2009-12-28 10:21:49 +00:00
# include <asm/time.h>
2009-01-07 23:14:39 +08:00
static DEFINE_SPINLOCK ( boot_lock ) ;
/*
* platform_init_cpus ( ) - Tell the world about how many cores we
* have . This is called while setting up the architecture support
* ( setup_arch ( ) ) , so don ' t be too demanding here with respect to
* available kernel services .
*/
void __init platform_init_cpus ( void )
{
cpu_set ( 0 , cpu_possible_map ) ; /* CoreA */
cpu_set ( 1 , cpu_possible_map ) ; /* CoreB */
}
void __init platform_prepare_cpus ( unsigned int max_cpus )
{
int len ;
len = & coreb_trampoline_end - & coreb_trampoline_start + 1 ;
2009-01-07 23:14:39 +08:00
BUG_ON ( len > L1_CODE_LENGTH ) ;
2009-01-07 23:14:39 +08:00
2009-01-07 23:14:39 +08:00
dma_memcpy ( ( void * ) COREB_L1_CODE_START , & coreb_trampoline_start , len ) ;
2009-01-07 23:14:39 +08:00
/* Both cores ought to be present on a bf561! */
cpu_set ( 0 , cpu_present_map ) ; /* CoreA */
cpu_set ( 1 , cpu_present_map ) ; /* CoreB */
2009-01-07 23:14:39 +08:00
printk ( KERN_INFO " CoreB bootstrap code to SRAM %p via DMA. \n " , ( void * ) COREB_L1_CODE_START ) ;
2009-01-07 23:14:39 +08:00
}
int __init setup_profiling_timer ( unsigned int multiplier ) /* not supported */
{
return - EINVAL ;
}
void __cpuinit platform_secondary_init ( unsigned int cpu )
{
/* Clone setup for peripheral interrupt sources from CoreA. */
bfin_write_SICB_IMASK0 ( bfin_read_SICA_IMASK0 ( ) ) ;
bfin_write_SICB_IMASK1 ( bfin_read_SICA_IMASK1 ( ) ) ;
SSYNC ( ) ;
/* Clone setup for IARs from CoreA. */
bfin_write_SICB_IAR0 ( bfin_read_SICA_IAR0 ( ) ) ;
bfin_write_SICB_IAR1 ( bfin_read_SICA_IAR1 ( ) ) ;
bfin_write_SICB_IAR2 ( bfin_read_SICA_IAR2 ( ) ) ;
bfin_write_SICB_IAR3 ( bfin_read_SICA_IAR3 ( ) ) ;
bfin_write_SICB_IAR4 ( bfin_read_SICA_IAR4 ( ) ) ;
bfin_write_SICB_IAR5 ( bfin_read_SICA_IAR5 ( ) ) ;
bfin_write_SICB_IAR6 ( bfin_read_SICA_IAR6 ( ) ) ;
bfin_write_SICB_IAR7 ( bfin_read_SICA_IAR7 ( ) ) ;
2009-12-28 11:13:51 +00:00
bfin_write_SICB_IWR0 ( IWR_DISABLE_ALL ) ;
bfin_write_SICB_IWR1 ( IWR_DISABLE_ALL ) ;
2009-01-07 23:14:39 +08:00
SSYNC ( ) ;
/* Store CPU-private information to the cpu_data array. */
bfin_setup_cpudata ( cpu ) ;
/* We are done with local CPU inits, unblock the boot CPU. */
2009-12-28 09:27:27 +00:00
set_cpu_online ( cpu , true ) ;
2009-01-07 23:14:39 +08:00
spin_lock ( & boot_lock ) ;
spin_unlock ( & boot_lock ) ;
}
int __cpuinit platform_boot_secondary ( unsigned int cpu , struct task_struct * idle )
{
unsigned long timeout ;
printk ( KERN_INFO " Booting Core B. \n " ) ;
spin_lock ( & boot_lock ) ;
2009-12-28 11:13:51 +00:00
if ( ( bfin_read_SICA_SYSCR ( ) & COREB_SRAM_INIT ) = = 0 ) {
/* CoreB already running, sending ipi to wakeup it */
platform_send_ipi_cpu ( cpu , IRQ_SUPPLE_0 ) ;
} else {
/* Kick CoreB, which should start execution from CORE_SRAM_BASE. */
bfin_write_SICA_SYSCR ( bfin_read_SICA_SYSCR ( ) & ~ COREB_SRAM_INIT ) ;
SSYNC ( ) ;
}
2009-01-07 23:14:39 +08:00
timeout = jiffies + 1 * HZ ;
while ( time_before ( jiffies , timeout ) ) {
2009-12-28 09:27:27 +00:00
if ( cpu_online ( cpu ) )
2009-01-07 23:14:39 +08:00
break ;
udelay ( 100 ) ;
barrier ( ) ;
}
2009-12-28 09:27:27 +00:00
if ( cpu_online ( cpu ) ) {
2009-12-02 07:58:12 +00:00
/* release the lock and let coreb run */
spin_unlock ( & boot_lock ) ;
return 0 ;
} else
panic ( " CPU%u: processor failed to boot \n " , cpu ) ;
2009-01-07 23:14:39 +08:00
}
void __init platform_request_ipi ( irq_handler_t handler )
{
int ret ;
ret = request_irq ( IRQ_SUPPLE_0 , handler , IRQF_DISABLED ,
2009-05-15 11:01:59 +00:00
" Supplemental Interrupt0 " , handler ) ;
2009-01-07 23:14:39 +08:00
if ( ret )
2009-04-29 06:26:46 +00:00
panic ( " Cannot request supplemental interrupt 0 for IPI service " ) ;
2009-01-07 23:14:39 +08:00
}
void platform_send_ipi ( cpumask_t callmap )
{
unsigned int cpu ;
for_each_cpu_mask ( cpu , callmap ) {
BUG_ON ( cpu > = 2 ) ;
SSYNC ( ) ;
bfin_write_SICB_SYSCR ( bfin_read_SICB_SYSCR ( ) | ( 1 < < ( 6 + cpu ) ) ) ;
SSYNC ( ) ;
}
}
void platform_send_ipi_cpu ( unsigned int cpu )
{
BUG_ON ( cpu > = 2 ) ;
SSYNC ( ) ;
bfin_write_SICB_SYSCR ( bfin_read_SICB_SYSCR ( ) | ( 1 < < ( 6 + cpu ) ) ) ;
SSYNC ( ) ;
}
void platform_clear_ipi ( unsigned int cpu )
{
BUG_ON ( cpu > = 2 ) ;
SSYNC ( ) ;
bfin_write_SICB_SYSCR ( bfin_read_SICB_SYSCR ( ) | ( 1 < < ( 10 + cpu ) ) ) ;
SSYNC ( ) ;
}
2009-12-28 10:21:49 +00:00
/*
* Setup core B ' s local core timer .
* In SMP , core timer is used for clock event device .
*/
void __cpuinit bfin_local_timer_setup ( void )
{
# if defined(CONFIG_TICKSOURCE_CORETMR)
bfin_coretmr_init ( ) ;
bfin_coretmr_clockevent_init ( ) ;
get_irq_chip ( IRQ_CORETMR ) - > unmask ( IRQ_CORETMR ) ;
# else
/* Power down the core timer, just to play safe. */
bfin_write_TCNTL ( 0 ) ;
# endif
}