2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2009-11-28 10:17:18 +03:00
/*
* Copyright ( C ) 2002 ARM Ltd .
* Copyright ( C ) 2008 STMicroelctronics .
* Copyright ( C ) 2009 ST - Ericsson .
* Author : Srinidhi Kasagar < srinidhi . kasagar @ stericsson . com >
*
* This file is based on arm realview platform
*/
# include <linux/init.h>
# include <linux/errno.h>
# include <linux/delay.h>
# include <linux/device.h>
# include <linux/smp.h>
# include <linux/io.h>
2015-05-14 10:46:40 +03:00
# include <linux/of.h>
# include <linux/of_address.h>
2009-11-28 10:17:18 +03:00
# include <asm/cacheflush.h>
2012-01-20 15:01:12 +04:00
# include <asm/smp_plat.h>
2009-11-28 10:17:18 +03:00
# include <asm/smp_scu.h>
2012-09-19 21:31:19 +04:00
2015-08-03 10:26:52 +03:00
/* Magic triggers in backup RAM */
# define UX500_CPU1_JUMPADDR_OFFSET 0x1FF4
# define UX500_CPU1_WAKEMAGIC_OFFSET 0x1FF0
2009-11-28 10:17:18 +03:00
2016-06-02 17:10:06 +03:00
static void __iomem * backupram ;
static void __init ux500_smp_prepare_cpus ( unsigned int max_cpus )
2009-11-28 10:17:18 +03:00
{
2015-08-03 10:26:52 +03:00
struct device_node * np ;
2016-06-02 17:10:06 +03:00
static void __iomem * scu_base ;
unsigned int ncores ;
int i ;
2010-09-15 13:45:51 +04:00
2015-08-03 10:26:52 +03:00
np = of_find_compatible_node ( NULL , NULL , " ste,dbx500-backupram " ) ;
if ( ! np ) {
pr_err ( " No backupram base address \n " ) ;
return ;
}
backupram = of_iomap ( np , 0 ) ;
of_node_put ( np ) ;
if ( ! backupram ) {
pr_err ( " No backupram remap \n " ) ;
return ;
2009-11-28 10:17:18 +03:00
}
2015-05-14 10:46:40 +03:00
np = of_find_compatible_node ( NULL , NULL , " arm,cortex-a9-scu " ) ;
2015-08-03 10:26:52 +03:00
if ( ! np ) {
pr_err ( " No SCU base address \n " ) ;
return ;
}
2015-05-14 10:46:40 +03:00
scu_base = of_iomap ( np , 0 ) ;
of_node_put ( np ) ;
2015-08-03 10:26:52 +03:00
if ( ! scu_base ) {
pr_err ( " No SCU remap \n " ) ;
2015-05-14 10:46:40 +03:00
return ;
2009-11-28 10:17:18 +03:00
}
2015-08-03 10:26:52 +03:00
scu_enable ( scu_base ) ;
ncores = scu_get_core_count ( scu_base ) ;
2010-12-03 13:42:58 +03:00
for ( i = 0 ; i < ncores ; i + + )
set_cpu_possible ( i , true ) ;
2015-08-03 10:26:52 +03:00
iounmap ( scu_base ) ;
2010-12-03 13:42:58 +03:00
}
2009-11-28 10:17:18 +03:00
2015-08-03 10:26:52 +03:00
static int ux500_boot_secondary ( unsigned int cpu , struct task_struct * idle )
2010-12-03 13:42:58 +03:00
{
2016-06-02 17:10:06 +03:00
/*
* write the address of secondary startup into the backup ram register
* at offset 0x1FF4 , then write the magic number 0xA1FEED01 to the
* backup ram register at offset 0x1FF0 , which is what boot rom code
* is waiting for . This will wake up the secondary core from WFE .
*/
2017-02-28 22:50:53 +03:00
writel ( __pa_symbol ( secondary_startup ) ,
2016-06-02 17:10:06 +03:00
backupram + UX500_CPU1_JUMPADDR_OFFSET ) ;
writel ( 0xA1FEED01 ,
backupram + UX500_CPU1_WAKEMAGIC_OFFSET ) ;
/* make sure write buffer is drained */
mb ( ) ;
2015-08-03 10:26:52 +03:00
arch_send_wakeup_ipi_mask ( cpumask_of ( cpu ) ) ;
return 0 ;
2009-11-28 10:17:18 +03:00
}
2011-09-08 16:15:22 +04:00
2017-02-27 12:13:38 +03:00
# ifdef CONFIG_HOTPLUG_CPU
2021-03-23 11:32:03 +03:00
static void ux500_cpu_die ( unsigned int cpu )
2017-02-27 12:13:38 +03:00
{
wfi ( ) ;
}
# endif
2015-11-15 04:39:53 +03:00
static const struct smp_operations ux500_smp_ops __initconst = {
2011-09-08 16:15:22 +04:00
. smp_prepare_cpus = ux500_smp_prepare_cpus ,
. smp_boot_secondary = ux500_boot_secondary ,
# ifdef CONFIG_HOTPLUG_CPU
. cpu_die = ux500_cpu_die ,
# endif
} ;
2015-08-03 10:26:52 +03:00
CPU_METHOD_OF_DECLARE ( ux500_smp , " ste,dbx500-smp " , & ux500_smp_ops ) ;