2019-05-27 09:55:06 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2013-11-24 10:30:46 +04:00
/*
* Trusted Foundations support for ARM CPUs
*
* Copyright ( c ) 2013 , NVIDIA Corporation .
*/
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/of.h>
2019-04-10 11:47:28 +03:00
# include <linux/firmware/trusted_foundations.h>
2013-11-24 10:30:46 +04:00
# include <asm/firmware.h>
2019-03-18 01:52:04 +03:00
# include <asm/hardware/cache-l2x0.h>
# include <asm/outercache.h>
2013-11-24 10:30:46 +04:00
2019-03-18 01:52:04 +03:00
# define TF_CACHE_MAINT 0xfffff100
# define TF_CACHE_ENABLE 1
# define TF_CACHE_DISABLE 2
2020-03-25 01:43:34 +03:00
# define TF_CACHE_REENABLE 4
2019-03-18 01:52:04 +03:00
2013-11-24 10:30:46 +04:00
# define TF_SET_CPU_BOOT_ADDR_SMC 0xfffff200
2014-02-07 08:35:05 +04:00
# define TF_CPU_PM 0xfffffffc
# define TF_CPU_PM_S3 0xffffffe3
# define TF_CPU_PM_S2 0xffffffe6
# define TF_CPU_PM_S2_NO_MC_CLK 0xffffffe5
# define TF_CPU_PM_S1 0xffffffe4
# define TF_CPU_PM_S1_NOFLUSH_L2 0xffffffe7
2020-03-25 01:43:34 +03:00
static unsigned long tf_idle_mode = TF_PM_MODE_NONE ;
2014-02-07 08:35:05 +04:00
static unsigned long cpu_boot_addr ;
2018-03-25 21:09:56 +03:00
static void tf_generic_smc ( u32 type , u32 arg1 , u32 arg2 )
2013-11-24 10:30:46 +04:00
{
2018-03-25 21:09:56 +03:00
register u32 r0 asm ( " r0 " ) = type ;
register u32 r1 asm ( " r1 " ) = arg1 ;
register u32 r2 asm ( " r2 " ) = arg2 ;
2013-11-24 10:30:46 +04:00
asm volatile (
" .arch_extension sec \n \t "
2018-03-25 21:09:56 +03:00
" stmfd sp!, {r4 - r11} \n \t "
2013-11-24 10:30:46 +04:00
__asmeq ( " %0 " , " r0 " )
__asmeq ( " %1 " , " r1 " )
__asmeq ( " %2 " , " r2 " )
" mov r3, #0 \n \t "
" mov r4, #0 \n \t "
" smc #0 \n \t "
2018-03-25 21:09:56 +03:00
" ldmfd sp!, {r4 - r11} \n \t "
2013-11-24 10:30:46 +04:00
:
2018-03-25 21:09:56 +03:00
: " r " ( r0 ) , " r " ( r1 ) , " r " ( r2 )
: " memory " , " r3 " , " r12 " , " lr " ) ;
2013-11-24 10:30:46 +04:00
}
static int tf_set_cpu_boot_addr ( int cpu , unsigned long boot_addr )
{
2014-02-07 08:35:05 +04:00
cpu_boot_addr = boot_addr ;
tf_generic_smc ( TF_SET_CPU_BOOT_ADDR_SMC , cpu_boot_addr , 0 ) ;
return 0 ;
}
2019-03-18 01:52:05 +03:00
static int tf_prepare_idle ( unsigned long mode )
2014-02-07 08:35:05 +04:00
{
2019-03-18 01:52:05 +03:00
switch ( mode ) {
case TF_PM_MODE_LP0 :
tf_generic_smc ( TF_CPU_PM , TF_CPU_PM_S3 , cpu_boot_addr ) ;
break ;
case TF_PM_MODE_LP1 :
tf_generic_smc ( TF_CPU_PM , TF_CPU_PM_S2 , cpu_boot_addr ) ;
break ;
case TF_PM_MODE_LP1_NO_MC_CLK :
tf_generic_smc ( TF_CPU_PM , TF_CPU_PM_S2_NO_MC_CLK ,
cpu_boot_addr ) ;
break ;
case TF_PM_MODE_LP2 :
tf_generic_smc ( TF_CPU_PM , TF_CPU_PM_S1 , cpu_boot_addr ) ;
break ;
case TF_PM_MODE_LP2_NOFLUSH_L2 :
tf_generic_smc ( TF_CPU_PM , TF_CPU_PM_S1_NOFLUSH_L2 ,
cpu_boot_addr ) ;
break ;
2020-03-25 01:43:34 +03:00
case TF_PM_MODE_NONE :
break ;
2019-03-18 01:52:05 +03:00
default :
return - EINVAL ;
}
2013-11-24 10:30:46 +04:00
2020-03-25 01:43:34 +03:00
tf_idle_mode = mode ;
2013-11-24 10:30:46 +04:00
return 0 ;
}
2019-03-18 01:52:04 +03:00
# ifdef CONFIG_CACHE_L2X0
static void tf_cache_write_sec ( unsigned long val , unsigned int reg )
{
2020-03-25 01:43:34 +03:00
u32 enable_op , l2x0_way_mask = 0xff ;
2019-03-18 01:52:04 +03:00
switch ( reg ) {
case L2X0_CTRL :
if ( l2x0_saved_regs . aux_ctrl & L310_AUX_CTRL_ASSOCIATIVITY_16 )
l2x0_way_mask = 0xffff ;
2020-03-25 01:43:34 +03:00
switch ( tf_idle_mode ) {
case TF_PM_MODE_LP2 :
enable_op = TF_CACHE_REENABLE ;
break ;
default :
enable_op = TF_CACHE_ENABLE ;
break ;
}
2019-03-18 01:52:04 +03:00
if ( val = = L2X0_CTRL_EN )
2020-03-25 01:43:34 +03:00
tf_generic_smc ( TF_CACHE_MAINT , enable_op ,
2019-03-18 01:52:04 +03:00
l2x0_saved_regs . aux_ctrl ) ;
else
tf_generic_smc ( TF_CACHE_MAINT , TF_CACHE_DISABLE ,
l2x0_way_mask ) ;
break ;
default :
break ;
}
}
static int tf_init_cache ( void )
{
outer_cache . write_sec = tf_cache_write_sec ;
return 0 ;
}
# endif /* CONFIG_CACHE_L2X0 */
2013-11-24 10:30:46 +04:00
static const struct firmware_ops trusted_foundations_ops = {
. set_cpu_boot_addr = tf_set_cpu_boot_addr ,
2014-02-07 08:35:05 +04:00
. prepare_idle = tf_prepare_idle ,
2019-03-18 01:52:04 +03:00
# ifdef CONFIG_CACHE_L2X0
. l2x0_init = tf_init_cache ,
# endif
2013-11-24 10:30:46 +04:00
} ;
void register_trusted_foundations ( struct trusted_foundations_platform_data * pd )
{
/*
* we are not using version information for now since currently
* supported SMCs are compatible with all TF releases
*/
register_firmware_ops ( & trusted_foundations_ops ) ;
}
void of_register_trusted_foundations ( void )
{
struct device_node * node ;
struct trusted_foundations_platform_data pdata ;
int err ;
node = of_find_compatible_node ( NULL , NULL , " tlm,trusted-foundations " ) ;
if ( ! node )
return ;
err = of_property_read_u32 ( node , " tlm,version-major " ,
& pdata . version_major ) ;
if ( err ! = 0 )
panic ( " Trusted Foundation: missing version-major property \n " ) ;
err = of_property_read_u32 ( node , " tlm,version-minor " ,
& pdata . version_minor ) ;
if ( err ! = 0 )
panic ( " Trusted Foundation: missing version-minor property \n " ) ;
register_trusted_foundations ( & pdata ) ;
}
2019-03-18 01:52:06 +03:00
bool trusted_foundations_registered ( void )
{
return firmware_ops = = & trusted_foundations_ops ;
}