2018-10-22 23:18:39 +03:00
// SPDX-License-Identifier: GPL-2.0
2014-07-01 02:15:37 +04:00
/*
2015-12-01 19:24:06 +03:00
* Copyright ( C ) 2014 - 2015 Broadcom Corporation
2014-07-01 02:15:37 +04:00
* Copyright 2014 Linaro Limited
*/
2015-12-01 19:24:08 +03:00
# include <linux/cpumask.h>
# include <linux/delay.h>
2014-07-01 02:15:37 +04:00
# include <linux/errno.h>
2015-12-01 19:24:08 +03:00
# include <linux/init.h>
2014-07-01 02:15:37 +04:00
# include <linux/io.h>
2017-08-06 18:52:02 +03:00
# include <linux/irqchip/irq-bcm2836.h>
2015-12-01 19:24:08 +03:00
# include <linux/jiffies.h>
2014-07-01 02:15:37 +04:00
# include <linux/of.h>
2016-05-12 00:36:21 +03:00
# include <linux/of_address.h>
2014-07-01 02:15:37 +04:00
# include <linux/sched.h>
2017-02-01 18:36:40 +03:00
# include <linux/sched/clock.h>
2015-12-01 19:24:08 +03:00
# include <linux/smp.h>
2014-07-01 02:15:37 +04:00
2015-12-01 19:24:08 +03:00
# include <asm/cacheflush.h>
2014-07-01 02:15:37 +04:00
# include <asm/smp.h>
# include <asm/smp_plat.h>
# include <asm/smp_scu.h>
2019-10-08 15:34:43 +03:00
# include "platsmp.h"
2014-07-01 02:15:37 +04:00
/* Size of mapped Cortex A9 SCU address space */
# define CORTEX_A9_SCU_SIZE 0x58
# define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */
# define BOOT_ADDR_CPUID_MASK 0x3
/* Name of device node property defining secondary boot register location */
# define OF_SECONDARY_BOOT "secondary-boot-reg"
2015-12-01 19:24:06 +03:00
# define MPIDR_CPUID_BITMASK 0x3
2014-07-01 02:15:37 +04:00
/*
* Enable the Cortex A9 Snoop Control Unit
*
* By the time this is called we already know there are multiple
* cores present . We assume we ' re running on a Cortex A9 processor ,
* so any trouble getting the base address register or getting the
* SCU base is a problem .
*
* Return 0 if successful or an error code otherwise .
*/
static int __init scu_a9_enable ( void )
{
unsigned long config_base ;
void __iomem * scu_base ;
if ( ! scu_a9_has_base ( ) ) {
pr_err ( " no configuration base address register! \n " ) ;
return - ENXIO ;
}
/* Config base address register value is zero for uniprocessor */
config_base = scu_a9_get_base ( ) ;
if ( ! config_base ) {
pr_err ( " hardware reports only one core \n " ) ;
return - ENOENT ;
}
scu_base = ioremap ( ( phys_addr_t ) config_base , CORTEX_A9_SCU_SIZE ) ;
if ( ! scu_base ) {
pr_err ( " failed to remap config base (%lu/%u) for SCU \n " ,
config_base , CORTEX_A9_SCU_SIZE ) ;
return - ENOMEM ;
}
scu_enable ( scu_base ) ;
iounmap ( scu_base ) ; /* That's the last we'll need of this */
return 0 ;
}
2016-04-28 20:59:59 +03:00
static u32 secondary_boot_addr_for ( unsigned int cpu )
{
u32 secondary_boot_addr = 0 ;
struct device_node * cpu_node = of_get_cpu_node ( cpu , NULL ) ;
if ( ! cpu_node ) {
pr_err ( " Failed to find device tree node for CPU%u \n " , cpu ) ;
return 0 ;
}
if ( of_property_read_u32 ( cpu_node ,
OF_SECONDARY_BOOT ,
& secondary_boot_addr ) )
pr_err ( " required secondary boot register not specified for CPU%u \n " ,
cpu ) ;
of_node_put ( cpu_node ) ;
return secondary_boot_addr ;
}
static int nsp_write_lut ( unsigned int cpu )
2015-12-01 19:24:08 +03:00
{
void __iomem * sku_rom_lut ;
phys_addr_t secondary_startup_phy ;
2016-04-28 20:59:59 +03:00
const u32 secondary_boot_addr = secondary_boot_addr_for ( cpu ) ;
2015-12-01 19:24:08 +03:00
2016-04-28 20:59:59 +03:00
if ( ! secondary_boot_addr )
2015-12-01 19:24:08 +03:00
return - EINVAL ;
2020-01-06 11:43:50 +03:00
sku_rom_lut = ioremap ( ( phys_addr_t ) secondary_boot_addr ,
2016-04-28 20:59:59 +03:00
sizeof ( phys_addr_t ) ) ;
2015-12-01 19:24:08 +03:00
if ( ! sku_rom_lut ) {
2016-04-28 20:59:59 +03:00
pr_warn ( " unable to ioremap SKU-ROM LUT register for cpu %u \n " , cpu ) ;
2015-12-01 19:24:08 +03:00
return - ENOMEM ;
}
2017-01-15 05:59:29 +03:00
secondary_startup_phy = __pa_symbol ( secondary_startup ) ;
2015-12-01 19:24:08 +03:00
BUG_ON ( secondary_startup_phy > ( phys_addr_t ) U32_MAX ) ;
writel_relaxed ( secondary_startup_phy , sku_rom_lut ) ;
/* Ensure the write is visible to the secondary core */
smp_wmb ( ) ;
iounmap ( sku_rom_lut ) ;
return 0 ;
}
2014-07-01 02:15:37 +04:00
static void __init bcm_smp_prepare_cpus ( unsigned int max_cpus )
{
2016-04-28 20:59:59 +03:00
const cpumask_t only_cpu_0 = { CPU_BITS_CPU0 } ;
2015-12-01 19:24:06 +03:00
2016-04-28 20:59:59 +03:00
/* Enable the SCU on Cortex A9 based SoCs */
if ( scu_a9_enable ( ) ) {
2014-07-01 02:15:37 +04:00
/* Update the CPU present map to reflect uniprocessor mode */
2016-04-28 20:59:59 +03:00
pr_warn ( " failed to enable A9 SCU - disabling SMP \n " ) ;
2014-07-01 02:15:37 +04:00
init_cpu_present ( & only_cpu_0 ) ;
}
}
/*
* The ROM code has the secondary cores looping , waiting for an event .
* When an event occurs each core examines the bottom two bits of the
* secondary boot register . When a core finds those bits contain its
* own core id , it performs initialization , including computing its boot
* address by clearing the boot register value ' s bottom two bits . The
* core signals that it is beginning its execution by writing its boot
* address back to the secondary boot register , and finally jumps to
* that address .
*
* So to start a core executing we need to :
* - Encode the ( hardware ) CPU id with the bottom bits of the secondary
* start address .
* - Write that value into the secondary boot register .
* - Generate an event to wake up the secondary CPU ( s ) .
* - Wait for the secondary boot register to be re - written , which
* indicates the secondary core has started .
*/
2015-12-01 19:24:06 +03:00
static int kona_boot_secondary ( unsigned int cpu , struct task_struct * idle )
2014-07-01 02:15:37 +04:00
{
void __iomem * boot_reg ;
phys_addr_t boot_func ;
u64 start_clock ;
u32 cpu_id ;
u32 boot_val ;
bool timeout = false ;
2016-04-28 20:59:59 +03:00
const u32 secondary_boot_addr = secondary_boot_addr_for ( cpu ) ;
2014-07-01 02:15:37 +04:00
cpu_id = cpu_logical_map ( cpu ) ;
if ( cpu_id & ~ BOOT_ADDR_CPUID_MASK ) {
pr_err ( " bad cpu id (%u > %u) \n " , cpu_id , BOOT_ADDR_CPUID_MASK ) ;
return - EINVAL ;
}
2016-04-28 20:59:59 +03:00
if ( ! secondary_boot_addr )
2014-07-01 02:15:37 +04:00
return - EINVAL ;
2020-01-06 11:43:50 +03:00
boot_reg = ioremap ( ( phys_addr_t ) secondary_boot_addr ,
2016-04-28 20:59:59 +03:00
sizeof ( phys_addr_t ) ) ;
2014-07-01 02:15:37 +04:00
if ( ! boot_reg ) {
pr_err ( " unable to map boot register for cpu %u \n " , cpu_id ) ;
2015-12-01 19:24:06 +03:00
return - ENOMEM ;
2014-07-01 02:15:37 +04:00
}
/*
* Secondary cores will start in secondary_startup ( ) ,
* defined in " arch/arm/kernel/head.S "
*/
2017-01-15 05:59:29 +03:00
boot_func = __pa_symbol ( secondary_startup ) ;
2014-07-01 02:15:37 +04:00
BUG_ON ( boot_func & BOOT_ADDR_CPUID_MASK ) ;
BUG_ON ( boot_func > ( phys_addr_t ) U32_MAX ) ;
/* The core to start is encoded in the low bits */
boot_val = ( u32 ) boot_func | cpu_id ;
writel_relaxed ( boot_val , boot_reg ) ;
sev ( ) ;
/* The low bits will be cleared once the core has started */
start_clock = local_clock ( ) ;
while ( ! timeout & & readl_relaxed ( boot_reg ) = = boot_val )
timeout = local_clock ( ) - start_clock > SECONDARY_TIMEOUT_NS ;
iounmap ( boot_reg ) ;
if ( ! timeout )
return 0 ;
pr_err ( " timeout waiting for cpu %u to start \n " , cpu_id ) ;
2015-12-01 19:24:06 +03:00
return - ENXIO ;
2014-07-01 02:15:37 +04:00
}
2016-05-12 00:36:21 +03:00
/* Cluster Dormant Control command to bring CPU into a running state */
# define CDC_CMD 6
# define CDC_CMD_OFFSET 0
# define CDC_CMD_REG(cpu) (CDC_CMD_OFFSET + 4*(cpu))
/*
* BCM23550 has a Cluster Dormant Control block that keeps the core in
* idle state . A command needs to be sent to the block to bring the CPU
* into running state .
*/
static int bcm23550_boot_secondary ( unsigned int cpu , struct task_struct * idle )
{
void __iomem * cdc_base ;
struct device_node * dn ;
char * name ;
int ret ;
/* Make sure a CDC node exists before booting the
* secondary core .
*/
name = " brcm,bcm23550-cdc " ;
dn = of_find_compatible_node ( NULL , NULL , name ) ;
if ( ! dn ) {
pr_err ( " unable to find cdc node \n " ) ;
return - ENODEV ;
}
cdc_base = of_iomap ( dn , 0 ) ;
of_node_put ( dn ) ;
if ( ! cdc_base ) {
pr_err ( " unable to remap cdc base register \n " ) ;
return - ENOMEM ;
}
/* Boot the secondary core */
ret = kona_boot_secondary ( cpu , idle ) ;
if ( ret )
goto out ;
/* Bring this CPU to RUN state so that nIRQ nFIQ
* signals are unblocked .
*/
writel_relaxed ( CDC_CMD , cdc_base + CDC_CMD_REG ( cpu ) ) ;
out :
iounmap ( cdc_base ) ;
return ret ;
}
2015-12-01 19:24:08 +03:00
static int nsp_boot_secondary ( unsigned int cpu , struct task_struct * idle )
{
int ret ;
/*
* After wake up , secondary core branches to the startup
* address programmed at SKU ROM LUT location .
*/
2016-04-28 20:59:59 +03:00
ret = nsp_write_lut ( cpu ) ;
2015-12-01 19:24:08 +03:00
if ( ret ) {
pr_err ( " unable to write startup addr to SKU ROM LUT \n " ) ;
goto out ;
}
/* Send a CPU wakeup interrupt to the secondary core */
arch_send_wakeup_ipi_mask ( cpumask_of ( cpu ) ) ;
out :
return ret ;
}
2017-08-06 18:52:02 +03:00
static int bcm2836_boot_secondary ( unsigned int cpu , struct task_struct * idle )
{
void __iomem * intc_base ;
struct device_node * dn ;
char * name ;
name = " brcm,bcm2836-l1-intc " ;
dn = of_find_compatible_node ( NULL , NULL , name ) ;
if ( ! dn ) {
pr_err ( " unable to find intc node \n " ) ;
return - ENODEV ;
}
intc_base = of_iomap ( dn , 0 ) ;
of_node_put ( dn ) ;
if ( ! intc_base ) {
pr_err ( " unable to remap intc base register \n " ) ;
return - ENOMEM ;
}
writel ( virt_to_phys ( secondary_startup ) ,
intc_base + LOCAL_MAILBOX3_SET0 + 16 * cpu ) ;
2017-08-08 14:04:55 +03:00
dsb ( sy ) ;
sev ( ) ;
2017-08-06 18:52:02 +03:00
iounmap ( intc_base ) ;
return 0 ;
}
2016-04-28 20:59:59 +03:00
static const struct smp_operations kona_smp_ops __initconst = {
2014-07-01 02:15:37 +04:00
. smp_prepare_cpus = bcm_smp_prepare_cpus ,
2015-12-01 19:24:06 +03:00
. smp_boot_secondary = kona_boot_secondary ,
2014-07-01 02:15:37 +04:00
} ;
CPU_METHOD_OF_DECLARE ( bcm_smp_bcm281xx , " brcm,bcm11351-cpu-method " ,
2016-04-28 20:59:59 +03:00
& kona_smp_ops ) ;
2015-12-01 19:24:08 +03:00
2016-05-12 00:36:21 +03:00
static const struct smp_operations bcm23550_smp_ops __initconst = {
. smp_boot_secondary = bcm23550_boot_secondary ,
} ;
CPU_METHOD_OF_DECLARE ( bcm_smp_bcm23550 , " brcm,bcm23550 " ,
& bcm23550_smp_ops ) ;
2016-01-25 14:31:15 +03:00
static const struct smp_operations nsp_smp_ops __initconst = {
2015-12-01 19:24:08 +03:00
. smp_prepare_cpus = bcm_smp_prepare_cpus ,
. smp_boot_secondary = nsp_boot_secondary ,
} ;
CPU_METHOD_OF_DECLARE ( bcm_smp_nsp , " brcm,bcm-nsp-smp " , & nsp_smp_ops ) ;
2017-08-06 18:52:02 +03:00
const struct smp_operations bcm2836_smp_ops __initconst = {
. smp_boot_secondary = bcm2836_boot_secondary ,
} ;
CPU_METHOD_OF_DECLARE ( bcm_smp_bcm2836 , " brcm,bcm2836-smp " , & bcm2836_smp_ops ) ;