2009-11-28 08:17:18 +01: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
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# 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 09:46:40 +02:00
# include <linux/of.h>
# include <linux/of_address.h>
2009-11-28 08:17:18 +01:00
# include <asm/cacheflush.h>
2012-01-20 12:01:12 +01:00
# include <asm/smp_plat.h>
2009-11-28 08:17:18 +01:00
# include <asm/smp_scu.h>
2012-09-19 19:31:19 +02:00
2013-03-21 22:51:12 +01:00
# include "setup.h"
2009-11-28 08:17:18 +01:00
2013-03-19 15:41:55 +01:00
# include "db8500-regs.h"
2012-09-19 19:31:19 +02:00
2015-08-03 09:26:52 +02:00
/* Magic triggers in backup RAM */
# define UX500_CPU1_JUMPADDR_OFFSET 0x1FF4
# define UX500_CPU1_WAKEMAGIC_OFFSET 0x1FF0
2009-11-28 08:17:18 +01:00
2016-06-02 16:10:06 +02:00
static void __iomem * backupram ;
static void __init ux500_smp_prepare_cpus ( unsigned int max_cpus )
2009-11-28 08:17:18 +01:00
{
2015-08-03 09:26:52 +02:00
struct device_node * np ;
2016-06-02 16:10:06 +02:00
static void __iomem * scu_base ;
unsigned int ncores ;
int i ;
2010-09-15 10:45:51 +01:00
2015-08-03 09:26:52 +02: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 08:17:18 +01:00
}
2015-05-14 09:46:40 +02:00
np = of_find_compatible_node ( NULL , NULL , " arm,cortex-a9-scu " ) ;
2015-08-03 09:26:52 +02:00
if ( ! np ) {
pr_err ( " No SCU base address \n " ) ;
return ;
}
2015-05-14 09:46:40 +02:00
scu_base = of_iomap ( np , 0 ) ;
of_node_put ( np ) ;
2015-08-03 09:26:52 +02:00
if ( ! scu_base ) {
pr_err ( " No SCU remap \n " ) ;
2015-05-14 09:46:40 +02:00
return ;
2009-11-28 08:17:18 +01:00
}
2015-08-03 09:26:52 +02:00
scu_enable ( scu_base ) ;
ncores = scu_get_core_count ( scu_base ) ;
2010-12-03 10:42:58 +00:00
for ( i = 0 ; i < ncores ; i + + )
set_cpu_possible ( i , true ) ;
2015-08-03 09:26:52 +02:00
iounmap ( scu_base ) ;
2010-12-03 10:42:58 +00:00
}
2009-11-28 08:17:18 +01:00
2015-08-03 09:26:52 +02:00
static int ux500_boot_secondary ( unsigned int cpu , struct task_struct * idle )
2010-12-03 10:42:58 +00:00
{
2016-06-02 16:10:06 +02: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 .
*/
writel ( virt_to_phys ( secondary_startup ) ,
backupram + UX500_CPU1_JUMPADDR_OFFSET ) ;
writel ( 0xA1FEED01 ,
backupram + UX500_CPU1_WAKEMAGIC_OFFSET ) ;
/* make sure write buffer is drained */
mb ( ) ;
2015-08-03 09:26:52 +02:00
arch_send_wakeup_ipi_mask ( cpumask_of ( cpu ) ) ;
return 0 ;
2009-11-28 08:17:18 +01:00
}
2011-09-08 13:15:22 +01:00
2015-11-15 10:39:53 +09:00
static const struct smp_operations ux500_smp_ops __initconst = {
2011-09-08 13:15:22 +01: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 09:26:52 +02:00
CPU_METHOD_OF_DECLARE ( ux500_smp , " ste,dbx500-smp " , & ux500_smp_ops ) ;