2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2016-09-09 12:23:11 +02:00
/*
* Copyright ( C ) 2016 Neil Armstrong < narmstrong @ baylibre . com >
* Copyright ( C ) 2013 Ma Haijun < mahaijuns @ gmail . com >
* Copyright ( C ) 2002 ARM Ltd .
* All Rights Reserved
*/
# include <linux/io.h>
# include <linux/delay.h>
# include <linux/of.h>
# include <linux/of_address.h>
# include <asm/cacheflush.h>
# include <asm/cp15.h>
# include <asm/smp_plat.h>
# include <asm/smp_scu.h>
extern void ox820_secondary_startup ( void ) ;
static void __iomem * cpu_ctrl ;
static void __iomem * gic_cpu_ctrl ;
# define HOLDINGPEN_CPU_OFFSET 0xc8
# define HOLDINGPEN_LOCATION_OFFSET 0xc4
# define GIC_NCPU_OFFSET(cpu) (0x100 + (cpu)*0x100)
# define GIC_CPU_CTRL 0x00
# define GIC_CPU_CTRL_ENABLE 1
2020-05-12 09:46:13 +08:00
static int __init ox820_boot_secondary ( unsigned int cpu ,
struct task_struct * idle )
2016-09-09 12:23:11 +02:00
{
/*
* Write the address of secondary startup into the
* system - wide flags register . The BootMonitor waits
* until it receives a soft interrupt , and then the
* secondary CPU branches to this address .
*/
writel ( virt_to_phys ( ox820_secondary_startup ) ,
cpu_ctrl + HOLDINGPEN_LOCATION_OFFSET ) ;
writel ( cpu , cpu_ctrl + HOLDINGPEN_CPU_OFFSET ) ;
/*
* Enable GIC cpu interface in CPU Interface Control Register
*/
writel ( GIC_CPU_CTRL_ENABLE ,
gic_cpu_ctrl + GIC_NCPU_OFFSET ( cpu ) + GIC_CPU_CTRL ) ;
/*
* Send the secondary CPU a soft interrupt , thereby causing
* the boot monitor to read the system wide flags register ,
* and branch to the address found there .
*/
arch_send_wakeup_ipi_mask ( cpumask_of ( cpu ) ) ;
return 0 ;
}
static void __init ox820_smp_prepare_cpus ( unsigned int max_cpus )
{
struct device_node * np ;
void __iomem * scu_base ;
np = of_find_compatible_node ( NULL , NULL , " arm,arm11mp-scu " ) ;
scu_base = of_iomap ( np , 0 ) ;
of_node_put ( np ) ;
if ( ! scu_base )
return ;
/* Remap CPU Interrupt Interface Registers */
np = of_find_compatible_node ( NULL , NULL , " arm,arm11mp-gic " ) ;
gic_cpu_ctrl = of_iomap ( np , 1 ) ;
of_node_put ( np ) ;
if ( ! gic_cpu_ctrl )
goto unmap_scu ;
np = of_find_compatible_node ( NULL , NULL , " oxsemi,ox820-sys-ctrl " ) ;
cpu_ctrl = of_iomap ( np , 0 ) ;
of_node_put ( np ) ;
if ( ! cpu_ctrl )
goto unmap_scu ;
scu_enable ( scu_base ) ;
flush_cache_all ( ) ;
unmap_scu :
iounmap ( scu_base ) ;
}
static const struct smp_operations ox820_smp_ops __initconst = {
. smp_prepare_cpus = ox820_smp_prepare_cpus ,
. smp_boot_secondary = ox820_boot_secondary ,
} ;
CPU_METHOD_OF_DECLARE ( ox820_smp , " oxsemi,ox820-smp " , & ox820_smp_ops ) ;