2015-05-08 13:07:11 +09:00
/*
* Copyright ( C ) 2015 Masahiro Yamada < yamada . masahiro @ socionext . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# include <linux/sizes.h>
# include <linux/compiler.h>
# include <linux/init.h>
# include <linux/io.h>
# include <linux/regmap.h>
# include <linux/mfd/syscon.h>
# include <asm/smp.h>
# include <asm/smp_scu.h>
static struct regmap * sbcm_regmap ;
static void __init uniphier_smp_prepare_cpus ( unsigned int max_cpus )
{
static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 } ;
unsigned long scu_base_phys = 0 ;
void __iomem * scu_base ;
sbcm_regmap = syscon_regmap_lookup_by_compatible (
" socionext,uniphier-system-bus-controller-misc " ) ;
if ( IS_ERR ( sbcm_regmap ) ) {
pr_err ( " failed to regmap system-bus-controller-misc \n " ) ;
goto err ;
}
if ( scu_a9_has_base ( ) )
scu_base_phys = scu_a9_get_base ( ) ;
if ( ! scu_base_phys ) {
pr_err ( " failed to get scu base \n " ) ;
goto err ;
}
scu_base = ioremap ( scu_base_phys , SZ_128 ) ;
if ( ! scu_base ) {
pr_err ( " failed to remap scu base (0x%08lx) \n " , scu_base_phys ) ;
goto err ;
}
scu_enable ( scu_base ) ;
iounmap ( scu_base ) ;
return ;
err :
pr_warn ( " disabling SMP \n " ) ;
init_cpu_present ( & only_cpu_0 ) ;
sbcm_regmap = NULL ;
}
static int uniphier_boot_secondary ( unsigned int cpu ,
struct task_struct * idle )
{
int ret ;
if ( ! sbcm_regmap )
return - ENODEV ;
ret = regmap_write ( sbcm_regmap , 0x1208 ,
2015-08-08 21:13:44 +09:00
virt_to_phys ( secondary_startup ) ) ;
2015-05-08 13:07:11 +09:00
if ( ! ret )
asm ( " sev " ) ; /* wake up secondary CPU */
return ret ;
}
struct smp_operations uniphier_smp_ops __initdata = {
. smp_prepare_cpus = uniphier_smp_prepare_cpus ,
. smp_boot_secondary = uniphier_boot_secondary ,
} ;
CPU_METHOD_OF_DECLARE ( uniphier_smp , " socionext,uniphier-smp " ,
& uniphier_smp_ops ) ;