2019-06-01 10:08:37 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2013-12-17 16:23:49 -08:00
/*
* Copyright ( c ) 2013 Linaro Ltd .
* Copyright ( c ) 2013 Hisilicon Limited .
* Based on arch / arm / mach - vexpress / platsmp . c , Copyright ( C ) 2002 ARM Ltd .
*/
# include <linux/smp.h>
# include <linux/io.h>
# include <linux/of_address.h>
2014-12-24 03:10:02 +00:00
# include <linux/delay.h>
2013-12-17 16:23:49 -08:00
# include <asm/cacheflush.h>
# include <asm/smp_plat.h>
# include <asm/smp_scu.h>
2014-12-24 03:10:02 +00:00
# include <asm/mach/map.h>
2013-12-17 16:23:49 -08:00
# include "core.h"
2014-04-11 11:54:11 +08:00
# define HIX5HD2_BOOT_ADDRESS 0xffff0000
2013-12-17 16:23:49 -08:00
static void __iomem * ctrl_base ;
void hi3xxx_set_cpu_jump ( int cpu , void * jump_addr )
{
cpu = cpu_logical_map ( cpu ) ;
if ( ! cpu | | ! ctrl_base )
return ;
2017-01-15 03:59:29 +01:00
writel_relaxed ( __pa_symbol ( jump_addr ) , ctrl_base + ( ( cpu - 1 ) < < 2 ) ) ;
2013-12-17 16:23:49 -08:00
}
int hi3xxx_get_cpu_jump ( int cpu )
{
cpu = cpu_logical_map ( cpu ) ;
if ( ! cpu | | ! ctrl_base )
return 0 ;
return readl_relaxed ( ctrl_base + ( ( cpu - 1 ) < < 2 ) ) ;
}
2014-04-11 11:54:11 +08:00
static void __init hisi_enable_scu_a9 ( void )
2013-12-17 16:23:49 -08:00
{
unsigned long base = 0 ;
void __iomem * scu_base = NULL ;
if ( scu_a9_has_base ( ) ) {
base = scu_a9_get_base ( ) ;
scu_base = ioremap ( base , SZ_4K ) ;
if ( ! scu_base ) {
pr_err ( " ioremap(scu_base) failed \n " ) ;
return ;
}
scu_enable ( scu_base ) ;
iounmap ( scu_base ) ;
}
2014-04-11 11:54:11 +08:00
}
static void __init hi3xxx_smp_prepare_cpus ( unsigned int max_cpus )
{
struct device_node * np = NULL ;
u32 offset = 0 ;
hisi_enable_scu_a9 ( ) ;
2013-12-17 16:23:49 -08:00
if ( ! ctrl_base ) {
np = of_find_compatible_node ( NULL , NULL , " hisilicon,sysctrl " ) ;
if ( ! np ) {
pr_err ( " failed to find hisilicon,sysctrl node \n " ) ;
return ;
}
ctrl_base = of_iomap ( np , 0 ) ;
if ( ! ctrl_base ) {
pr_err ( " failed to map address \n " ) ;
return ;
}
if ( of_property_read_u32 ( np , " smp-offset " , & offset ) < 0 ) {
pr_err ( " failed to find smp-offset property \n " ) ;
return ;
}
ctrl_base + = offset ;
}
}
static int hi3xxx_boot_secondary ( unsigned int cpu , struct task_struct * idle )
{
2013-12-11 15:54:55 +08:00
hi3xxx_set_cpu ( cpu , true ) ;
2013-12-17 16:23:49 -08:00
hi3xxx_set_cpu_jump ( cpu , secondary_startup ) ;
arch_send_wakeup_ipi_mask ( cpumask_of ( cpu ) ) ;
return 0 ;
}
2015-11-15 10:39:53 +09:00
static const struct smp_operations hi3xxx_smp_ops __initconst = {
2013-12-17 16:23:49 -08:00
. smp_prepare_cpus = hi3xxx_smp_prepare_cpus ,
. smp_boot_secondary = hi3xxx_boot_secondary ,
2013-12-11 15:54:55 +08:00
# ifdef CONFIG_HOTPLUG_CPU
. cpu_die = hi3xxx_cpu_die ,
. cpu_kill = hi3xxx_cpu_kill ,
# endif
2013-12-17 16:23:49 -08:00
} ;
2014-04-11 11:54:11 +08:00
2014-12-24 03:10:00 +00:00
static void __init hisi_common_smp_prepare_cpus ( unsigned int max_cpus )
2014-04-11 11:54:11 +08:00
{
hisi_enable_scu_a9 ( ) ;
}
2016-06-21 13:28:53 +01:00
static void hix5hd2_set_scu_boot_addr ( phys_addr_t start_addr , phys_addr_t jump_addr )
2014-04-11 11:54:11 +08:00
{
void __iomem * virt ;
virt = ioremap ( start_addr , PAGE_SIZE ) ;
2017-08-07 17:37:04 +08:00
writel_relaxed ( 0xe51ff004 , virt ) ; /* ldr pc, [pc, #-4] */
2014-04-11 11:54:11 +08:00
writel_relaxed ( jump_addr , virt + 4 ) ; /* pc jump phy address */
iounmap ( virt ) ;
}
static int hix5hd2_boot_secondary ( unsigned int cpu , struct task_struct * idle )
{
phys_addr_t jumpaddr ;
2017-01-15 03:59:29 +01:00
jumpaddr = __pa_symbol ( secondary_startup ) ;
2014-04-11 11:54:11 +08:00
hix5hd2_set_scu_boot_addr ( HIX5HD2_BOOT_ADDRESS , jumpaddr ) ;
hix5hd2_set_cpu ( cpu , true ) ;
arch_send_wakeup_ipi_mask ( cpumask_of ( cpu ) ) ;
return 0 ;
}
2015-11-15 10:39:53 +09:00
static const struct smp_operations hix5hd2_smp_ops __initconst = {
2014-12-24 03:10:00 +00:00
. smp_prepare_cpus = hisi_common_smp_prepare_cpus ,
2014-04-11 11:54:11 +08:00
. smp_boot_secondary = hix5hd2_boot_secondary ,
# ifdef CONFIG_HOTPLUG_CPU
. cpu_die = hix5hd2_cpu_die ,
# endif
} ;
2014-07-28 20:14:32 +08:00
2014-12-24 03:10:02 +00:00
# define SC_SCTL_REMAP_CLR 0x00000100
# define HIP01_BOOT_ADDRESS 0x80000000
# define REG_SC_CTRL 0x000
2016-06-21 13:28:53 +01:00
static void hip01_set_boot_addr ( phys_addr_t start_addr , phys_addr_t jump_addr )
2014-12-24 03:10:02 +00:00
{
void __iomem * virt ;
virt = phys_to_virt ( start_addr ) ;
writel_relaxed ( 0xe51ff004 , virt ) ;
writel_relaxed ( jump_addr , virt + 4 ) ;
}
static int hip01_boot_secondary ( unsigned int cpu , struct task_struct * idle )
{
phys_addr_t jumpaddr ;
unsigned int remap_reg_value = 0 ;
struct device_node * node ;
2017-01-15 03:59:29 +01:00
jumpaddr = __pa_symbol ( secondary_startup ) ;
2014-12-24 03:10:02 +00:00
hip01_set_boot_addr ( HIP01_BOOT_ADDRESS , jumpaddr ) ;
node = of_find_compatible_node ( NULL , NULL , " hisilicon,hip01-sysctrl " ) ;
if ( WARN_ON ( ! node ) )
return - 1 ;
ctrl_base = of_iomap ( node , 0 ) ;
/* set the secondary core boot from DDR */
remap_reg_value = readl_relaxed ( ctrl_base + REG_SC_CTRL ) ;
barrier ( ) ;
remap_reg_value | = SC_SCTL_REMAP_CLR ;
barrier ( ) ;
writel_relaxed ( remap_reg_value , ctrl_base + REG_SC_CTRL ) ;
hip01_set_cpu ( cpu , true ) ;
return 0 ;
}
2015-11-15 10:39:53 +09:00
static const struct smp_operations hip01_smp_ops __initconst = {
2014-12-24 03:10:02 +00:00
. smp_prepare_cpus = hisi_common_smp_prepare_cpus ,
. smp_boot_secondary = hip01_boot_secondary ,
} ;
2014-07-28 20:14:32 +08:00
CPU_METHOD_OF_DECLARE ( hi3xxx_smp , " hisilicon,hi3620-smp " , & hi3xxx_smp_ops ) ;
CPU_METHOD_OF_DECLARE ( hix5hd2_smp , " hisilicon,hix5hd2-smp " , & hix5hd2_smp_ops ) ;
2014-12-24 03:10:02 +00:00
CPU_METHOD_OF_DECLARE ( hip01_smp , " hisilicon,hip01-smp " , & hip01_smp_ops ) ;