2009-01-07 23:14:39 +08:00
/*
* File : arch / blackfin / mach - bf561 / smp . c
* Author : Philippe Gerum < rpm @ xenomai . org >
*
* Copyright 2007 Analog Devices Inc .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , see the file COPYING , or write
* to the Free Software Foundation , Inc . ,
* 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/sched.h>
# include <linux/delay.h>
# include <asm/smp.h>
# include <asm/dma.h>
static DEFINE_SPINLOCK ( boot_lock ) ;
static cpumask_t cpu_callin_map ;
/*
* 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 )
{
local_irq_disable ( ) ;
/* 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 ( ) ) ;
SSYNC ( ) ;
local_irq_enable ( ) ;
/* Calibrate loops per jiffy value. */
calibrate_delay ( ) ;
/* Store CPU-private information to the cpu_data array. */
bfin_setup_cpudata ( cpu ) ;
/* We are done with local CPU inits, unblock the boot CPU. */
cpu_set ( cpu , cpu_callin_map ) ;
spin_lock ( & boot_lock ) ;
spin_unlock ( & boot_lock ) ;
}
int __cpuinit platform_boot_secondary ( unsigned int cpu , struct task_struct * idle )
{
unsigned long timeout ;
/* CoreB already running?! */
BUG_ON ( ( bfin_read_SICA_SYSCR ( ) & COREB_SRAM_INIT ) = = 0 ) ;
printk ( KERN_INFO " Booting Core B. \n " ) ;
spin_lock ( & boot_lock ) ;
/* Kick CoreB, which should start execution from CORE_SRAM_BASE. */
SSYNC ( ) ;
bfin_write_SICA_SYSCR ( bfin_read_SICA_SYSCR ( ) & ~ COREB_SRAM_INIT ) ;
SSYNC ( ) ;
timeout = jiffies + 1 * HZ ;
while ( time_before ( jiffies , timeout ) ) {
if ( cpu_isset ( cpu , cpu_callin_map ) )
break ;
udelay ( 100 ) ;
barrier ( ) ;
}
spin_unlock ( & boot_lock ) ;
return cpu_isset ( cpu , cpu_callin_map ) ? 0 : - ENOSYS ;
}
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 ( ) ;
}