18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Trusted Foundations support for ARM CPUs 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2013, NVIDIA Corporation. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/init.h> 108c2ecf20Sopenharmony_ci#include <linux/of.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/firmware/trusted_foundations.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <asm/firmware.h> 158c2ecf20Sopenharmony_ci#include <asm/hardware/cache-l2x0.h> 168c2ecf20Sopenharmony_ci#include <asm/outercache.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define TF_CACHE_MAINT 0xfffff100 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define TF_CACHE_ENABLE 1 218c2ecf20Sopenharmony_ci#define TF_CACHE_DISABLE 2 228c2ecf20Sopenharmony_ci#define TF_CACHE_REENABLE 4 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define TF_SET_CPU_BOOT_ADDR_SMC 0xfffff200 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define TF_CPU_PM 0xfffffffc 278c2ecf20Sopenharmony_ci#define TF_CPU_PM_S3 0xffffffe3 288c2ecf20Sopenharmony_ci#define TF_CPU_PM_S2 0xffffffe6 298c2ecf20Sopenharmony_ci#define TF_CPU_PM_S2_NO_MC_CLK 0xffffffe5 308c2ecf20Sopenharmony_ci#define TF_CPU_PM_S1 0xffffffe4 318c2ecf20Sopenharmony_ci#define TF_CPU_PM_S1_NOFLUSH_L2 0xffffffe7 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic unsigned long tf_idle_mode = TF_PM_MODE_NONE; 348c2ecf20Sopenharmony_cistatic unsigned long cpu_boot_addr; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic void tf_generic_smc(u32 type, u32 arg1, u32 arg2) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci register u32 r0 asm("r0") = type; 398c2ecf20Sopenharmony_ci register u32 r1 asm("r1") = arg1; 408c2ecf20Sopenharmony_ci register u32 r2 asm("r2") = arg2; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci asm volatile( 438c2ecf20Sopenharmony_ci ".arch_extension sec\n\t" 448c2ecf20Sopenharmony_ci "stmfd sp!, {r4 - r11}\n\t" 458c2ecf20Sopenharmony_ci __asmeq("%0", "r0") 468c2ecf20Sopenharmony_ci __asmeq("%1", "r1") 478c2ecf20Sopenharmony_ci __asmeq("%2", "r2") 488c2ecf20Sopenharmony_ci "mov r3, #0\n\t" 498c2ecf20Sopenharmony_ci "mov r4, #0\n\t" 508c2ecf20Sopenharmony_ci "smc #0\n\t" 518c2ecf20Sopenharmony_ci "ldmfd sp!, {r4 - r11}\n\t" 528c2ecf20Sopenharmony_ci : 538c2ecf20Sopenharmony_ci : "r" (r0), "r" (r1), "r" (r2) 548c2ecf20Sopenharmony_ci : "memory", "r3", "r12", "lr"); 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic int tf_set_cpu_boot_addr(int cpu, unsigned long boot_addr) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci cpu_boot_addr = boot_addr; 608c2ecf20Sopenharmony_ci tf_generic_smc(TF_SET_CPU_BOOT_ADDR_SMC, cpu_boot_addr, 0); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci return 0; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic int tf_prepare_idle(unsigned long mode) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci switch (mode) { 688c2ecf20Sopenharmony_ci case TF_PM_MODE_LP0: 698c2ecf20Sopenharmony_ci tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S3, cpu_boot_addr); 708c2ecf20Sopenharmony_ci break; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci case TF_PM_MODE_LP1: 738c2ecf20Sopenharmony_ci tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S2, cpu_boot_addr); 748c2ecf20Sopenharmony_ci break; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci case TF_PM_MODE_LP1_NO_MC_CLK: 778c2ecf20Sopenharmony_ci tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S2_NO_MC_CLK, 788c2ecf20Sopenharmony_ci cpu_boot_addr); 798c2ecf20Sopenharmony_ci break; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci case TF_PM_MODE_LP2: 828c2ecf20Sopenharmony_ci tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S1, cpu_boot_addr); 838c2ecf20Sopenharmony_ci break; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci case TF_PM_MODE_LP2_NOFLUSH_L2: 868c2ecf20Sopenharmony_ci tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S1_NOFLUSH_L2, 878c2ecf20Sopenharmony_ci cpu_boot_addr); 888c2ecf20Sopenharmony_ci break; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci case TF_PM_MODE_NONE: 918c2ecf20Sopenharmony_ci break; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci default: 948c2ecf20Sopenharmony_ci return -EINVAL; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci tf_idle_mode = mode; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci return 0; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci#ifdef CONFIG_CACHE_L2X0 1038c2ecf20Sopenharmony_cistatic void tf_cache_write_sec(unsigned long val, unsigned int reg) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci u32 enable_op, l2x0_way_mask = 0xff; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci switch (reg) { 1088c2ecf20Sopenharmony_ci case L2X0_CTRL: 1098c2ecf20Sopenharmony_ci if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_ASSOCIATIVITY_16) 1108c2ecf20Sopenharmony_ci l2x0_way_mask = 0xffff; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci switch (tf_idle_mode) { 1138c2ecf20Sopenharmony_ci case TF_PM_MODE_LP2: 1148c2ecf20Sopenharmony_ci enable_op = TF_CACHE_REENABLE; 1158c2ecf20Sopenharmony_ci break; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci default: 1188c2ecf20Sopenharmony_ci enable_op = TF_CACHE_ENABLE; 1198c2ecf20Sopenharmony_ci break; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (val == L2X0_CTRL_EN) 1238c2ecf20Sopenharmony_ci tf_generic_smc(TF_CACHE_MAINT, enable_op, 1248c2ecf20Sopenharmony_ci l2x0_saved_regs.aux_ctrl); 1258c2ecf20Sopenharmony_ci else 1268c2ecf20Sopenharmony_ci tf_generic_smc(TF_CACHE_MAINT, TF_CACHE_DISABLE, 1278c2ecf20Sopenharmony_ci l2x0_way_mask); 1288c2ecf20Sopenharmony_ci break; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci default: 1318c2ecf20Sopenharmony_ci break; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int tf_init_cache(void) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci outer_cache.write_sec = tf_cache_write_sec; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci return 0; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci#endif /* CONFIG_CACHE_L2X0 */ 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic const struct firmware_ops trusted_foundations_ops = { 1448c2ecf20Sopenharmony_ci .set_cpu_boot_addr = tf_set_cpu_boot_addr, 1458c2ecf20Sopenharmony_ci .prepare_idle = tf_prepare_idle, 1468c2ecf20Sopenharmony_ci#ifdef CONFIG_CACHE_L2X0 1478c2ecf20Sopenharmony_ci .l2x0_init = tf_init_cache, 1488c2ecf20Sopenharmony_ci#endif 1498c2ecf20Sopenharmony_ci}; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_civoid register_trusted_foundations(struct trusted_foundations_platform_data *pd) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci /* 1548c2ecf20Sopenharmony_ci * we are not using version information for now since currently 1558c2ecf20Sopenharmony_ci * supported SMCs are compatible with all TF releases 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_ci register_firmware_ops(&trusted_foundations_ops); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_civoid of_register_trusted_foundations(void) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci struct device_node *node; 1638c2ecf20Sopenharmony_ci struct trusted_foundations_platform_data pdata; 1648c2ecf20Sopenharmony_ci int err; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci node = of_find_compatible_node(NULL, NULL, "tlm,trusted-foundations"); 1678c2ecf20Sopenharmony_ci if (!node) 1688c2ecf20Sopenharmony_ci return; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci err = of_property_read_u32(node, "tlm,version-major", 1718c2ecf20Sopenharmony_ci &pdata.version_major); 1728c2ecf20Sopenharmony_ci if (err != 0) 1738c2ecf20Sopenharmony_ci panic("Trusted Foundation: missing version-major property\n"); 1748c2ecf20Sopenharmony_ci err = of_property_read_u32(node, "tlm,version-minor", 1758c2ecf20Sopenharmony_ci &pdata.version_minor); 1768c2ecf20Sopenharmony_ci if (err != 0) 1778c2ecf20Sopenharmony_ci panic("Trusted Foundation: missing version-minor property\n"); 1788c2ecf20Sopenharmony_ci register_trusted_foundations(&pdata); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cibool trusted_foundations_registered(void) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci return firmware_ops == &trusted_foundations_ops; 1848c2ecf20Sopenharmony_ci} 185