1*c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 24cb5d9ecSThierry Reding /* 34cb5d9ecSThierry Reding * Trusted Foundations support for ARM CPUs 44cb5d9ecSThierry Reding * 54cb5d9ecSThierry Reding * Copyright (c) 2013, NVIDIA Corporation. 64cb5d9ecSThierry Reding */ 74cb5d9ecSThierry Reding 84cb5d9ecSThierry Reding #include <linux/kernel.h> 94cb5d9ecSThierry Reding #include <linux/init.h> 104cb5d9ecSThierry Reding #include <linux/of.h> 114cb5d9ecSThierry Reding 124cb5d9ecSThierry Reding #include <linux/firmware/trusted_foundations.h> 134cb5d9ecSThierry Reding 144cb5d9ecSThierry Reding #include <asm/firmware.h> 154cb5d9ecSThierry Reding #include <asm/hardware/cache-l2x0.h> 164cb5d9ecSThierry Reding #include <asm/outercache.h> 174cb5d9ecSThierry Reding 184cb5d9ecSThierry Reding #define TF_CACHE_MAINT 0xfffff100 194cb5d9ecSThierry Reding 204cb5d9ecSThierry Reding #define TF_CACHE_ENABLE 1 214cb5d9ecSThierry Reding #define TF_CACHE_DISABLE 2 224cb5d9ecSThierry Reding 234cb5d9ecSThierry Reding #define TF_SET_CPU_BOOT_ADDR_SMC 0xfffff200 244cb5d9ecSThierry Reding 254cb5d9ecSThierry Reding #define TF_CPU_PM 0xfffffffc 264cb5d9ecSThierry Reding #define TF_CPU_PM_S3 0xffffffe3 274cb5d9ecSThierry Reding #define TF_CPU_PM_S2 0xffffffe6 284cb5d9ecSThierry Reding #define TF_CPU_PM_S2_NO_MC_CLK 0xffffffe5 294cb5d9ecSThierry Reding #define TF_CPU_PM_S1 0xffffffe4 304cb5d9ecSThierry Reding #define TF_CPU_PM_S1_NOFLUSH_L2 0xffffffe7 314cb5d9ecSThierry Reding 324cb5d9ecSThierry Reding static unsigned long cpu_boot_addr; 334cb5d9ecSThierry Reding 344cb5d9ecSThierry Reding static void tf_generic_smc(u32 type, u32 arg1, u32 arg2) 354cb5d9ecSThierry Reding { 364cb5d9ecSThierry Reding register u32 r0 asm("r0") = type; 374cb5d9ecSThierry Reding register u32 r1 asm("r1") = arg1; 384cb5d9ecSThierry Reding register u32 r2 asm("r2") = arg2; 394cb5d9ecSThierry Reding 404cb5d9ecSThierry Reding asm volatile( 414cb5d9ecSThierry Reding ".arch_extension sec\n\t" 424cb5d9ecSThierry Reding "stmfd sp!, {r4 - r11}\n\t" 434cb5d9ecSThierry Reding __asmeq("%0", "r0") 444cb5d9ecSThierry Reding __asmeq("%1", "r1") 454cb5d9ecSThierry Reding __asmeq("%2", "r2") 464cb5d9ecSThierry Reding "mov r3, #0\n\t" 474cb5d9ecSThierry Reding "mov r4, #0\n\t" 484cb5d9ecSThierry Reding "smc #0\n\t" 494cb5d9ecSThierry Reding "ldmfd sp!, {r4 - r11}\n\t" 504cb5d9ecSThierry Reding : 514cb5d9ecSThierry Reding : "r" (r0), "r" (r1), "r" (r2) 524cb5d9ecSThierry Reding : "memory", "r3", "r12", "lr"); 534cb5d9ecSThierry Reding } 544cb5d9ecSThierry Reding 554cb5d9ecSThierry Reding static int tf_set_cpu_boot_addr(int cpu, unsigned long boot_addr) 564cb5d9ecSThierry Reding { 574cb5d9ecSThierry Reding cpu_boot_addr = boot_addr; 584cb5d9ecSThierry Reding tf_generic_smc(TF_SET_CPU_BOOT_ADDR_SMC, cpu_boot_addr, 0); 594cb5d9ecSThierry Reding 604cb5d9ecSThierry Reding return 0; 614cb5d9ecSThierry Reding } 624cb5d9ecSThierry Reding 634cb5d9ecSThierry Reding static int tf_prepare_idle(unsigned long mode) 644cb5d9ecSThierry Reding { 654cb5d9ecSThierry Reding switch (mode) { 664cb5d9ecSThierry Reding case TF_PM_MODE_LP0: 674cb5d9ecSThierry Reding tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S3, cpu_boot_addr); 684cb5d9ecSThierry Reding break; 694cb5d9ecSThierry Reding 704cb5d9ecSThierry Reding case TF_PM_MODE_LP1: 714cb5d9ecSThierry Reding tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S2, cpu_boot_addr); 724cb5d9ecSThierry Reding break; 734cb5d9ecSThierry Reding 744cb5d9ecSThierry Reding case TF_PM_MODE_LP1_NO_MC_CLK: 754cb5d9ecSThierry Reding tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S2_NO_MC_CLK, 764cb5d9ecSThierry Reding cpu_boot_addr); 774cb5d9ecSThierry Reding break; 784cb5d9ecSThierry Reding 794cb5d9ecSThierry Reding case TF_PM_MODE_LP2: 804cb5d9ecSThierry Reding tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S1, cpu_boot_addr); 814cb5d9ecSThierry Reding break; 824cb5d9ecSThierry Reding 834cb5d9ecSThierry Reding case TF_PM_MODE_LP2_NOFLUSH_L2: 844cb5d9ecSThierry Reding tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S1_NOFLUSH_L2, 854cb5d9ecSThierry Reding cpu_boot_addr); 864cb5d9ecSThierry Reding break; 874cb5d9ecSThierry Reding 884cb5d9ecSThierry Reding default: 894cb5d9ecSThierry Reding return -EINVAL; 904cb5d9ecSThierry Reding } 914cb5d9ecSThierry Reding 924cb5d9ecSThierry Reding return 0; 934cb5d9ecSThierry Reding } 944cb5d9ecSThierry Reding 954cb5d9ecSThierry Reding #ifdef CONFIG_CACHE_L2X0 964cb5d9ecSThierry Reding static void tf_cache_write_sec(unsigned long val, unsigned int reg) 974cb5d9ecSThierry Reding { 984cb5d9ecSThierry Reding u32 l2x0_way_mask = 0xff; 994cb5d9ecSThierry Reding 1004cb5d9ecSThierry Reding switch (reg) { 1014cb5d9ecSThierry Reding case L2X0_CTRL: 1024cb5d9ecSThierry Reding if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_ASSOCIATIVITY_16) 1034cb5d9ecSThierry Reding l2x0_way_mask = 0xffff; 1044cb5d9ecSThierry Reding 1054cb5d9ecSThierry Reding if (val == L2X0_CTRL_EN) 1064cb5d9ecSThierry Reding tf_generic_smc(TF_CACHE_MAINT, TF_CACHE_ENABLE, 1074cb5d9ecSThierry Reding l2x0_saved_regs.aux_ctrl); 1084cb5d9ecSThierry Reding else 1094cb5d9ecSThierry Reding tf_generic_smc(TF_CACHE_MAINT, TF_CACHE_DISABLE, 1104cb5d9ecSThierry Reding l2x0_way_mask); 1114cb5d9ecSThierry Reding break; 1124cb5d9ecSThierry Reding 1134cb5d9ecSThierry Reding default: 1144cb5d9ecSThierry Reding break; 1154cb5d9ecSThierry Reding } 1164cb5d9ecSThierry Reding } 1174cb5d9ecSThierry Reding 1184cb5d9ecSThierry Reding static int tf_init_cache(void) 1194cb5d9ecSThierry Reding { 1204cb5d9ecSThierry Reding outer_cache.write_sec = tf_cache_write_sec; 1214cb5d9ecSThierry Reding 1224cb5d9ecSThierry Reding return 0; 1234cb5d9ecSThierry Reding } 1244cb5d9ecSThierry Reding #endif /* CONFIG_CACHE_L2X0 */ 1254cb5d9ecSThierry Reding 1264cb5d9ecSThierry Reding static const struct firmware_ops trusted_foundations_ops = { 1274cb5d9ecSThierry Reding .set_cpu_boot_addr = tf_set_cpu_boot_addr, 1284cb5d9ecSThierry Reding .prepare_idle = tf_prepare_idle, 1294cb5d9ecSThierry Reding #ifdef CONFIG_CACHE_L2X0 1304cb5d9ecSThierry Reding .l2x0_init = tf_init_cache, 1314cb5d9ecSThierry Reding #endif 1324cb5d9ecSThierry Reding }; 1334cb5d9ecSThierry Reding 1344cb5d9ecSThierry Reding void register_trusted_foundations(struct trusted_foundations_platform_data *pd) 1354cb5d9ecSThierry Reding { 1364cb5d9ecSThierry Reding /* 1374cb5d9ecSThierry Reding * we are not using version information for now since currently 1384cb5d9ecSThierry Reding * supported SMCs are compatible with all TF releases 1394cb5d9ecSThierry Reding */ 1404cb5d9ecSThierry Reding register_firmware_ops(&trusted_foundations_ops); 1414cb5d9ecSThierry Reding } 1424cb5d9ecSThierry Reding 1434cb5d9ecSThierry Reding void of_register_trusted_foundations(void) 1444cb5d9ecSThierry Reding { 1454cb5d9ecSThierry Reding struct device_node *node; 1464cb5d9ecSThierry Reding struct trusted_foundations_platform_data pdata; 1474cb5d9ecSThierry Reding int err; 1484cb5d9ecSThierry Reding 1494cb5d9ecSThierry Reding node = of_find_compatible_node(NULL, NULL, "tlm,trusted-foundations"); 1504cb5d9ecSThierry Reding if (!node) 1514cb5d9ecSThierry Reding return; 1524cb5d9ecSThierry Reding 1534cb5d9ecSThierry Reding err = of_property_read_u32(node, "tlm,version-major", 1544cb5d9ecSThierry Reding &pdata.version_major); 1554cb5d9ecSThierry Reding if (err != 0) 1564cb5d9ecSThierry Reding panic("Trusted Foundation: missing version-major property\n"); 1574cb5d9ecSThierry Reding err = of_property_read_u32(node, "tlm,version-minor", 1584cb5d9ecSThierry Reding &pdata.version_minor); 1594cb5d9ecSThierry Reding if (err != 0) 1604cb5d9ecSThierry Reding panic("Trusted Foundation: missing version-minor property\n"); 1614cb5d9ecSThierry Reding register_trusted_foundations(&pdata); 1624cb5d9ecSThierry Reding } 1634cb5d9ecSThierry Reding 1644cb5d9ecSThierry Reding bool trusted_foundations_registered(void) 1654cb5d9ecSThierry Reding { 1664cb5d9ecSThierry Reding return firmware_ops == &trusted_foundations_ops; 1674cb5d9ecSThierry Reding } 168