2014-04-14 15:54:05 +02:00
/*
* Symmetric Multi Processing ( SMP ) support for Marvell EBU Cortex - A9
* based SOCs ( Armada 375 / 38 x ) .
*
* Copyright ( C ) 2014 Marvell
*
* Gregory CLEMENT < gregory . clement @ free - electrons . com >
* Thomas Petazzoni < thomas . petazzoni @ free - electrons . com >
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed " as is " without any
* warranty of any kind , whether express or implied .
*/
# include <linux/init.h>
# include <linux/io.h>
# include <linux/of.h>
# include <linux/smp.h>
2014-04-14 15:54:06 +02:00
# include <linux/mbus.h>
2014-04-14 15:54:05 +02:00
# include <asm/smp_scu.h>
# include <asm/smp_plat.h>
# include "common.h"
2014-05-05 17:05:25 +02:00
# include "mvebu-soc-id.h"
2014-04-14 15:54:05 +02:00
# include "pmsu.h"
2014-04-14 15:54:06 +02:00
# define CRYPT0_ENG_ID 41
# define CRYPT0_ENG_ATTR 0x1
# define SRAM_PHYS_BASE 0xFFFF0000
# define BOOTROM_BASE 0xFFF00000
# define BOOTROM_SIZE 0x100000
extern unsigned char armada_375_smp_cpu1_enable_code_end ;
extern unsigned char armada_375_smp_cpu1_enable_code_start ;
void armada_375_smp_cpu1_enable_wa ( void )
{
void __iomem * sram_virt_base ;
mvebu_mbus_del_window ( BOOTROM_BASE , BOOTROM_SIZE ) ;
mvebu_mbus_add_window_by_id ( CRYPT0_ENG_ID , CRYPT0_ENG_ATTR ,
SRAM_PHYS_BASE , SZ_64K ) ;
sram_virt_base = ioremap ( SRAM_PHYS_BASE , SZ_64K ) ;
memcpy ( sram_virt_base , & armada_375_smp_cpu1_enable_code_start ,
& armada_375_smp_cpu1_enable_code_end
- & armada_375_smp_cpu1_enable_code_start ) ;
}
2014-04-14 15:54:05 +02:00
extern void mvebu_cortex_a9_secondary_startup ( void ) ;
static int __cpuinit mvebu_cortex_a9_boot_secondary ( unsigned int cpu ,
struct task_struct * idle )
{
int ret , hw_cpu ;
pr_info ( " Booting CPU %d \n " , cpu ) ;
/*
* Write the address of secondary startup into the system - wide
* flags register . The boot monitor waits until it receives a
* soft interrupt , and then the secondary CPU branches to this
* address .
*/
hw_cpu = cpu_logical_map ( cpu ) ;
2014-05-05 17:05:25 +02:00
if ( of_machine_is_compatible ( " marvell,armada375 " ) ) {
u32 dev , rev ;
if ( mvebu_get_soc_id ( & dev , & rev ) = = 0 & &
rev = = ARMADA_375_Z1_REV )
armada_375_smp_cpu1_enable_wa ( ) ;
2014-04-14 15:54:05 +02:00
mvebu_system_controller_set_cpu_boot_addr ( mvebu_cortex_a9_secondary_startup ) ;
2014-05-05 17:05:25 +02:00
}
else {
2014-04-14 15:54:05 +02:00
mvebu_pmsu_set_cpu_boot_addr ( hw_cpu ,
mvebu_cortex_a9_secondary_startup ) ;
2014-05-05 17:05:25 +02:00
}
2014-04-14 15:54:05 +02:00
smp_wmb ( ) ;
ret = mvebu_cpu_reset_deassert ( hw_cpu ) ;
if ( ret ) {
pr_err ( " Could not start the secondary CPU: %d \n " , ret ) ;
return ret ;
}
arch_send_wakeup_ipi_mask ( cpumask_of ( cpu ) ) ;
return 0 ;
}
static struct smp_operations mvebu_cortex_a9_smp_ops __initdata = {
. smp_boot_secondary = mvebu_cortex_a9_boot_secondary ,
# ifdef CONFIG_HOTPLUG_CPU
. cpu_die = armada_xp_cpu_die ,
# endif
} ;
CPU_METHOD_OF_DECLARE ( mvebu_armada_375_smp , " marvell,armada-375-smp " ,
& mvebu_cortex_a9_smp_ops ) ;
CPU_METHOD_OF_DECLARE ( mvebu_armada_380_smp , " marvell,armada-380-smp " ,
& mvebu_cortex_a9_smp_ops ) ;