2015-03-16 08:48:43 +03:00
/*
* R - Car Generation 2 Power management support
*
* Copyright ( C ) 2013 - 2015 Renesas Electronics Corporation
* Copyright ( C ) 2011 Renesas Solutions Corp .
* Copyright ( C ) 2011 Magnus Damm
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*/
# include <linux/kernel.h>
2017-07-04 18:41:36 +03:00
# include <linux/ioport.h>
2015-03-16 08:48:43 +03:00
# include <linux/of.h>
2017-07-04 18:41:36 +03:00
# include <linux/of_address.h>
2015-03-16 08:48:43 +03:00
# include <linux/smp.h>
2016-04-20 15:02:36 +03:00
# include <linux/soc/renesas/rcar-sysc.h>
2015-03-16 08:48:43 +03:00
# include <asm/io.h>
2018-02-12 20:44:19 +03:00
# include <asm/cputype.h>
2015-03-16 08:48:43 +03:00
# include "common.h"
# include "rcar-gen2.h"
/* RST */
# define RST 0xe6160000
2017-01-25 12:02:13 +03:00
# define CA15BAR 0x0020 /* CA15 Boot Address Register */
# define CA7BAR 0x0030 /* CA7 Boot Address Register */
# define CA15RESCNT 0x0040 /* CA15 Reset Control Register */
# define CA7RESCNT 0x0044 /* CA7 Reset Control Register */
/* SYS Boot Address Register */
# define SBAR_BAREN BIT(4) /* SBAR is valid */
/* Reset Control Registers */
# define CA15RESCNT_CODE 0xa5a50000
# define CA15RESCNT_CPUS 0xf /* CPU0-3 */
# define CA7RESCNT_CODE 0x5a5a0000
# define CA7RESCNT_CPUS 0xf /* CPU0-3 */
2015-03-16 08:48:43 +03:00
/* On-chip RAM */
2016-05-17 18:15:33 +03:00
# define ICRAM1 0xe63c0000 /* Inter Connect RAM1 (4 KiB) */
2015-03-16 08:48:43 +03:00
2017-01-25 12:02:13 +03:00
static inline u32 phys_to_sbar ( phys_addr_t addr )
{
return ( addr > > 8 ) & 0xfffffc00 ;
}
2015-03-16 08:48:43 +03:00
/* SYSC */
# define SYSCIER 0x0c
# define SYSCIMR 0x10
# if defined(CONFIG_SMP)
static void __init rcar_gen2_sysc_init ( u32 syscier )
{
soc: renesas: rcar-sysc: Move SYSC interrupt config to rcar-sysc driver
On R-Car H1 and Gen2, the SYSC interrupt registers are always configured
using hardcoded values in platform code. For R-Car Gen2, values are
provided for H2 and M2-W only, other SoCs are not yet supported, and
never will be.
Move this configuration from SoC-specific platform code to the
rcar_sysc_init() wrapper, so it can be skipped if the SYSC is configured
from DT. This would be the case not only for H1, H2, and M2-W using a
modern DTS, but also for other R-Car Gen2 SoCs not supported by the
platform code, relying purely on DT.
There is no longer a need to return the mapped register block, hence
make the function return void.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Reviewed-by: Ulrich Hecht <ulrich.hecht+renesas@gmail.com>
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
2016-06-28 17:10:33 +03:00
rcar_sysc_init ( 0xe6180000 , syscier ) ;
2015-03-16 08:48:43 +03:00
}
# else /* CONFIG_SMP */
static inline void rcar_gen2_sysc_init ( u32 syscier ) { }
# endif /* CONFIG_SMP */
void __init rcar_gen2_pm_init ( void )
{
void __iomem * p ;
u32 bar ;
static int once ;
struct device_node * np , * cpus ;
bool has_a7 = false ;
bool has_a15 = false ;
2017-07-04 18:41:36 +03:00
struct resource res ;
2015-03-16 08:48:43 +03:00
u32 syscier = 0 ;
2017-07-04 18:41:36 +03:00
int error ;
2015-03-16 08:48:43 +03:00
if ( once + + )
return ;
cpus = of_find_node_by_path ( " /cpus " ) ;
if ( ! cpus )
return ;
for_each_child_of_node ( cpus , np ) {
if ( of_device_is_compatible ( np , " arm,cortex-a15 " ) )
has_a15 = true ;
else if ( of_device_is_compatible ( np , " arm,cortex-a7 " ) )
has_a7 = true ;
}
2016-05-17 18:15:33 +03:00
if ( of_machine_is_compatible ( " renesas,r8a7790 " ) )
2015-03-16 08:48:43 +03:00
syscier = 0x013111ef ;
2016-05-17 18:15:33 +03:00
else if ( of_machine_is_compatible ( " renesas,r8a7791 " ) )
2015-03-16 08:48:43 +03:00
syscier = 0x00111003 ;
2017-07-04 18:41:36 +03:00
np = of_find_compatible_node ( NULL , NULL , " renesas,smp-sram " ) ;
if ( ! np ) {
/* No smp-sram in DT, fall back to hardcoded address */
res = ( struct resource ) DEFINE_RES_MEM ( ICRAM1 ,
shmobile_boot_size ) ;
goto map ;
}
error = of_address_to_resource ( np , 0 , & res ) ;
if ( error ) {
pr_err ( " Failed to get smp-sram address: %d \n " , error ) ;
return ;
}
map :
2015-03-16 08:48:43 +03:00
/* RAM for jump stub, because BAR requires 256KB aligned address */
2017-07-04 18:41:36 +03:00
if ( res . start & ( 256 * 1024 - 1 ) | |
resource_size ( & res ) < shmobile_boot_size ) {
pr_err ( " Invalid smp-sram region \n " ) ;
return ;
}
p = ioremap ( res . start , resource_size ( & res ) ) ;
if ( ! p )
return ;
2018-02-12 20:44:19 +03:00
/*
* install the reset vector , use the largest version if we have enough
* memory available
*/
if ( resource_size ( & res ) > = shmobile_boot_size_gen2 ) {
shmobile_boot_cpu_gen2 = read_cpuid_mpidr ( ) ;
memcpy_toio ( p , shmobile_boot_vector_gen2 ,
shmobile_boot_size_gen2 ) ;
} else {
memcpy_toio ( p , shmobile_boot_vector , shmobile_boot_size ) ;
}
2015-03-16 08:48:43 +03:00
iounmap ( p ) ;
/* setup reset vectors */
p = ioremap_nocache ( RST , 0x63 ) ;
2017-07-04 18:41:36 +03:00
bar = phys_to_sbar ( res . start ) ;
2015-03-16 08:48:43 +03:00
if ( has_a15 ) {
writel_relaxed ( bar , p + CA15BAR ) ;
2017-01-25 12:02:13 +03:00
writel_relaxed ( bar | SBAR_BAREN , p + CA15BAR ) ;
2015-03-16 08:48:43 +03:00
/* de-assert reset for CA15 CPUs */
2017-01-25 12:02:13 +03:00
writel_relaxed ( ( readl_relaxed ( p + CA15RESCNT ) &
~ CA15RESCNT_CPUS ) | CA15RESCNT_CODE ,
p + CA15RESCNT ) ;
2015-03-16 08:48:43 +03:00
}
if ( has_a7 ) {
writel_relaxed ( bar , p + CA7BAR ) ;
2017-01-25 12:02:13 +03:00
writel_relaxed ( bar | SBAR_BAREN , p + CA7BAR ) ;
2015-03-16 08:48:43 +03:00
/* de-assert reset for CA7 CPUs */
2017-01-25 12:02:13 +03:00
writel_relaxed ( ( readl_relaxed ( p + CA7RESCNT ) &
~ CA7RESCNT_CPUS ) | CA7RESCNT_CODE ,
p + CA7RESCNT ) ;
2015-03-16 08:48:43 +03:00
}
iounmap ( p ) ;
rcar_gen2_sysc_init ( syscier ) ;
shmobile_smp_apmu_suspend_init ( ) ;
}