2015-04-28 12:18:10 +03:00
/*
* Copyright 2014 Linaro Ltd .
* Copyright ( C ) 2014 ZTE Corporation .
*
* 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/delay.h>
# include <linux/errno.h>
# include <linux/init.h>
# include <linux/io.h>
# include <linux/jiffies.h>
# include <linux/of.h>
# include <linux/of_address.h>
# include <linux/smp.h>
# include <asm/cacheflush.h>
# include <asm/cp15.h>
# include <asm/fncpy.h>
# include <asm/proc-fns.h>
# include <asm/smp_scu.h>
# include <asm/smp_plat.h>
# include "core.h"
# define AON_SYS_CTRL_RESERVED1 0xa8
# define BUS_MATRIX_REMAP_CONFIG 0x00
# define PCU_CPU0_CTRL 0x00
# define PCU_CPU1_CTRL 0x04
# define PCU_CPU1_ST 0x0c
# define PCU_GLOBAL_CTRL 0x14
# define PCU_EXPEND_CONTROL 0x34
# define ZX_IRAM_BASE 0x00200000
static void __iomem * pcu_base ;
static void __iomem * matrix_base ;
static void __iomem * scu_base ;
void __init zx_smp_prepare_cpus ( unsigned int max_cpus )
{
struct device_node * np ;
unsigned long base = 0 ;
void __iomem * aonsysctrl_base ;
void __iomem * sys_iram ;
base = scu_a9_get_base ( ) ;
scu_base = ioremap ( base , SZ_256 ) ;
if ( ! scu_base ) {
pr_err ( " %s: failed to map scu \n " , __func__ ) ;
return ;
}
scu_enable ( scu_base ) ;
np = of_find_compatible_node ( NULL , NULL , " zte,sysctrl " ) ;
if ( ! np ) {
pr_err ( " %s: failed to find sysctrl node \n " , __func__ ) ;
return ;
}
aonsysctrl_base = of_iomap ( np , 0 ) ;
if ( ! aonsysctrl_base ) {
pr_err ( " %s: failed to map aonsysctrl \n " , __func__ ) ;
of_node_put ( np ) ;
return ;
}
/*
* Write the address of secondary startup into the
* system - wide flags register . The BootMonitor waits
* until it receives a soft interrupt , and then the
* secondary CPU branches to this address .
*/
2017-01-15 05:59:29 +03:00
__raw_writel ( __pa_symbol ( zx_secondary_startup ) ,
2015-04-28 12:18:10 +03:00
aonsysctrl_base + AON_SYS_CTRL_RESERVED1 ) ;
iounmap ( aonsysctrl_base ) ;
of_node_put ( np ) ;
np = of_find_compatible_node ( NULL , NULL , " zte,zx296702-pcu " ) ;
pcu_base = of_iomap ( np , 0 ) ;
of_node_put ( np ) ;
WARN_ON ( ! pcu_base ) ;
np = of_find_compatible_node ( NULL , NULL , " zte,zx-bus-matrix " ) ;
matrix_base = of_iomap ( np , 0 ) ;
of_node_put ( np ) ;
WARN_ON ( ! matrix_base ) ;
/* Map the first 4 KB IRAM for suspend usage */
sys_iram = __arm_ioremap_exec ( ZX_IRAM_BASE , PAGE_SIZE , false ) ;
2017-01-15 05:59:29 +03:00
zx_secondary_startup_pa = __pa_symbol ( zx_secondary_startup ) ;
2015-04-28 12:18:10 +03:00
fncpy ( sys_iram , & zx_resume_jump , zx_suspend_iram_sz ) ;
}
static int zx_boot_secondary ( unsigned int cpu , struct task_struct * idle )
{
static bool first_boot = true ;
if ( first_boot ) {
arch_send_wakeup_ipi_mask ( cpumask_of ( cpu ) ) ;
first_boot = false ;
return 0 ;
}
/* Swap the base address mapping between IRAM and IROM */
writel_relaxed ( 0x1 , matrix_base + BUS_MATRIX_REMAP_CONFIG ) ;
/* Power on CPU1 */
writel_relaxed ( 0x0 , pcu_base + PCU_CPU1_CTRL ) ;
/* Wait for power on ack */
while ( readl_relaxed ( pcu_base + PCU_CPU1_ST ) & 0x4 )
cpu_relax ( ) ;
/* Swap back the mapping of IRAM and IROM */
writel_relaxed ( 0x0 , matrix_base + BUS_MATRIX_REMAP_CONFIG ) ;
return 0 ;
}
# ifdef CONFIG_HOTPLUG_CPU
static inline void cpu_enter_lowpower ( void )
{
unsigned int v ;
asm volatile (
" mcr p15, 0, %1, c7, c5, 0 \n "
" mcr p15, 0, %1, c7, c10, 4 \n "
/*
* Turn off coherency
*/
" mrc p15, 0, %0, c1, c0, 1 \n "
" bic %0, %0, %3 \n "
" mcr p15, 0, %0, c1, c0, 1 \n "
" mrc p15, 0, %0, c1, c0, 0 \n "
" bic %0, %0, %2 \n "
" mcr p15, 0, %0, c1, c0, 0 \n "
: " =&r " ( v )
: " r " ( 0 ) , " Ir " ( CR_C ) , " Ir " ( 0x40 )
: " cc " ) ;
}
static int zx_cpu_kill ( unsigned int cpu )
{
unsigned long timeout = jiffies + msecs_to_jiffies ( 2000 ) ;
writel_relaxed ( 0x2 , pcu_base + PCU_CPU1_CTRL ) ;
while ( ( readl_relaxed ( pcu_base + PCU_CPU1_ST ) & 0x3 ) ! = 0x0 ) {
if ( time_after ( jiffies , timeout ) ) {
pr_err ( " *** cpu1 poweroff timeout \n " ) ;
break ;
}
}
return 1 ;
}
static void zx_cpu_die ( unsigned int cpu )
{
scu_power_mode ( scu_base , SCU_PM_POWEROFF ) ;
cpu_enter_lowpower ( ) ;
while ( 1 )
cpu_do_idle ( ) ;
}
# endif
static void zx_secondary_init ( unsigned int cpu )
{
scu_power_mode ( scu_base , SCU_PM_NORMAL ) ;
}
2015-11-15 04:39:53 +03:00
static const struct smp_operations zx_smp_ops __initconst = {
2015-04-28 12:18:10 +03:00
. smp_prepare_cpus = zx_smp_prepare_cpus ,
. smp_secondary_init = zx_secondary_init ,
. smp_boot_secondary = zx_boot_secondary ,
# ifdef CONFIG_HOTPLUG_CPU
. cpu_kill = zx_cpu_kill ,
. cpu_die = zx_cpu_die ,
# endif
} ;
CPU_METHOD_OF_DECLARE ( zx_smp , " zte,zx296702-smp " , & zx_smp_ops ) ;