13d0407baSopenharmony_ci/* 23d0407baSopenharmony_ci * This program is free software; you can redistribute it and/or modify 33d0407baSopenharmony_ci * it under the terms of the GNU General Public License version 2 as 43d0407baSopenharmony_ci * published by the Free Software Foundation. 53d0407baSopenharmony_ci * 63d0407baSopenharmony_ci * This program is distributed in the hope that it will be useful, 73d0407baSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 83d0407baSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 93d0407baSopenharmony_ci * GNU General Public License for more details. 103d0407baSopenharmony_ci * 113d0407baSopenharmony_ci * Copyright (C) 2016, Fuzhou Rockchip Electronics Co., Ltd 123d0407baSopenharmony_ci */ 133d0407baSopenharmony_ci 143d0407baSopenharmony_ci#include <linux/arm-smccc.h> 153d0407baSopenharmony_ci#include <linux/io.h> 163d0407baSopenharmony_ci#include <linux/module.h> 173d0407baSopenharmony_ci#include <linux/rockchip/rockchip_sip.h> 183d0407baSopenharmony_ci#include <asm/cputype.h> 193d0407baSopenharmony_ci#ifdef CONFIG_ARM 203d0407baSopenharmony_ci#include <asm/psci.h> 213d0407baSopenharmony_ci#endif 223d0407baSopenharmony_ci#include <asm/smp_plat.h> 233d0407baSopenharmony_ci#include <uapi/linux/psci.h> 243d0407baSopenharmony_ci#include <linux/ptrace.h> 253d0407baSopenharmony_ci#include <linux/sched/clock.h> 263d0407baSopenharmony_ci#include <linux/slab.h> 273d0407baSopenharmony_ci#include <soc/rockchip/rockchip_sip.h> 283d0407baSopenharmony_ci 293d0407baSopenharmony_ci#ifdef CONFIG_64BIT 303d0407baSopenharmony_ci#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN64_##name 313d0407baSopenharmony_ci#else 323d0407baSopenharmony_ci#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN_##name 333d0407baSopenharmony_ci#endif 343d0407baSopenharmony_ci 353d0407baSopenharmony_ci#define SIZE_PAGE(n) ((n) << 12) 363d0407baSopenharmony_ci 373d0407baSopenharmony_cistatic struct arm_smccc_res invoke_sip_fn_smc(unsigned long function_id, unsigned long arg0, unsigned long arg1, 383d0407baSopenharmony_ci unsigned long arg2) 393d0407baSopenharmony_ci{ 403d0407baSopenharmony_ci struct arm_smccc_res res; 413d0407baSopenharmony_ci 423d0407baSopenharmony_ci arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); 433d0407baSopenharmony_ci return res; 443d0407baSopenharmony_ci} 453d0407baSopenharmony_ci 463d0407baSopenharmony_cistruct arm_smccc_res sip_smc_dram(u32 arg0, u32 arg1, u32 arg2) 473d0407baSopenharmony_ci{ 483d0407baSopenharmony_ci return invoke_sip_fn_smc(SIP_DRAM_CONFIG, arg0, arg1, arg2); 493d0407baSopenharmony_ci} 503d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(sip_smc_dram); 513d0407baSopenharmony_ci 523d0407baSopenharmony_cistruct arm_smccc_res sip_smc_get_atf_version(void) 533d0407baSopenharmony_ci{ 543d0407baSopenharmony_ci return invoke_sip_fn_smc(SIP_ATF_VERSION, 0, 0, 0); 553d0407baSopenharmony_ci} 563d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(sip_smc_get_atf_version); 573d0407baSopenharmony_ci 583d0407baSopenharmony_cistruct arm_smccc_res sip_smc_get_sip_version(void) 593d0407baSopenharmony_ci{ 603d0407baSopenharmony_ci return invoke_sip_fn_smc(SIP_SIP_VERSION, 0, 0, 0); 613d0407baSopenharmony_ci} 623d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(sip_smc_get_sip_version); 633d0407baSopenharmony_ci 643d0407baSopenharmony_ciint sip_smc_set_suspend_mode(u32 ctrl, u32 config1, u32 config2) 653d0407baSopenharmony_ci{ 663d0407baSopenharmony_ci struct arm_smccc_res res; 673d0407baSopenharmony_ci 683d0407baSopenharmony_ci res = invoke_sip_fn_smc(SIP_SUSPEND_MODE, ctrl, config1, config2); 693d0407baSopenharmony_ci return res.a0; 703d0407baSopenharmony_ci} 713d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(sip_smc_set_suspend_mode); 723d0407baSopenharmony_ci 733d0407baSopenharmony_cistruct arm_smccc_res sip_smc_get_suspend_info(u32 info) 743d0407baSopenharmony_ci{ 753d0407baSopenharmony_ci struct arm_smccc_res res; 763d0407baSopenharmony_ci 773d0407baSopenharmony_ci res = invoke_sip_fn_smc(SIP_SUSPEND_MODE, info, 0, 0); 783d0407baSopenharmony_ci return res; 793d0407baSopenharmony_ci} 803d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(sip_smc_get_suspend_info); 813d0407baSopenharmony_ci 823d0407baSopenharmony_ciint sip_smc_virtual_poweroff(void) 833d0407baSopenharmony_ci{ 843d0407baSopenharmony_ci struct arm_smccc_res res; 853d0407baSopenharmony_ci 863d0407baSopenharmony_ci res = invoke_sip_fn_smc(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND), 0, 0, 0); 873d0407baSopenharmony_ci return res.a0; 883d0407baSopenharmony_ci} 893d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(sip_smc_virtual_poweroff); 903d0407baSopenharmony_ci 913d0407baSopenharmony_ciint sip_smc_remotectl_config(u32 func, u32 data) 923d0407baSopenharmony_ci{ 933d0407baSopenharmony_ci struct arm_smccc_res res; 943d0407baSopenharmony_ci 953d0407baSopenharmony_ci res = invoke_sip_fn_smc(SIP_REMOTECTL_CFG, func, data, 0); 963d0407baSopenharmony_ci 973d0407baSopenharmony_ci return res.a0; 983d0407baSopenharmony_ci} 993d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(sip_smc_remotectl_config); 1003d0407baSopenharmony_ci 1013d0407baSopenharmony_ciu32 sip_smc_secure_reg_read(u32 addr_phy) 1023d0407baSopenharmony_ci{ 1033d0407baSopenharmony_ci struct arm_smccc_res res; 1043d0407baSopenharmony_ci 1053d0407baSopenharmony_ci res = invoke_sip_fn_smc(SIP_ACCESS_REG, 0, addr_phy, SECURE_REG_RD); 1063d0407baSopenharmony_ci if (res.a0) { 1073d0407baSopenharmony_ci pr_err("%s error: %d, addr phy: 0x%x\n", __func__, (int)res.a0, addr_phy); 1083d0407baSopenharmony_ci } 1093d0407baSopenharmony_ci 1103d0407baSopenharmony_ci return res.a1; 1113d0407baSopenharmony_ci} 1123d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(sip_smc_secure_reg_read); 1133d0407baSopenharmony_ci 1143d0407baSopenharmony_ciint sip_smc_secure_reg_write(u32 addr_phy, u32 val) 1153d0407baSopenharmony_ci{ 1163d0407baSopenharmony_ci struct arm_smccc_res res; 1173d0407baSopenharmony_ci 1183d0407baSopenharmony_ci res = invoke_sip_fn_smc(SIP_ACCESS_REG, val, addr_phy, SECURE_REG_WR); 1193d0407baSopenharmony_ci if (res.a0) { 1203d0407baSopenharmony_ci pr_err("%s error: %d, addr phy: 0x%x\n", __func__, (int)res.a0, addr_phy); 1213d0407baSopenharmony_ci } 1223d0407baSopenharmony_ci 1233d0407baSopenharmony_ci return res.a0; 1243d0407baSopenharmony_ci} 1253d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(sip_smc_secure_reg_write); 1263d0407baSopenharmony_ci 1273d0407baSopenharmony_cistatic void *sip_map(phys_addr_t start, size_t size) 1283d0407baSopenharmony_ci{ 1293d0407baSopenharmony_ci struct page **pages; 1303d0407baSopenharmony_ci phys_addr_t page_start; 1313d0407baSopenharmony_ci unsigned int page_count; 1323d0407baSopenharmony_ci pgprot_t prot; 1333d0407baSopenharmony_ci unsigned int i; 1343d0407baSopenharmony_ci void *vaddr; 1353d0407baSopenharmony_ci 1363d0407baSopenharmony_ci if (!pfn_valid(__phys_to_pfn(start))) { 1373d0407baSopenharmony_ci return ioremap(start, size); 1383d0407baSopenharmony_ci } 1393d0407baSopenharmony_ci 1403d0407baSopenharmony_ci page_start = start - offset_in_page(start); 1413d0407baSopenharmony_ci page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE); 1423d0407baSopenharmony_ci 1433d0407baSopenharmony_ci prot = pgprot_noncached(PAGE_KERNEL); 1443d0407baSopenharmony_ci 1453d0407baSopenharmony_ci pages = kmalloc_array(page_count, sizeof(struct page *), GFP_KERNEL); 1463d0407baSopenharmony_ci if (!pages) { 1473d0407baSopenharmony_ci pr_err("%s: Failed to allocate array for %u pages\n", __func__, page_count); 1483d0407baSopenharmony_ci return NULL; 1493d0407baSopenharmony_ci } 1503d0407baSopenharmony_ci 1513d0407baSopenharmony_ci for (i = 0; i < page_count; i++) { 1523d0407baSopenharmony_ci pages[i] = phys_to_page(page_start + i * PAGE_SIZE); 1533d0407baSopenharmony_ci } 1543d0407baSopenharmony_ci 1553d0407baSopenharmony_ci vaddr = vmap(pages, page_count, VM_MAP, prot); 1563d0407baSopenharmony_ci kfree(pages); 1573d0407baSopenharmony_ci 1583d0407baSopenharmony_ci /* 1593d0407baSopenharmony_ci * Since vmap() uses page granularity, we must add the offset 1603d0407baSopenharmony_ci * into the page here, to get the byte granularity address 1613d0407baSopenharmony_ci * into the mapping to represent the actual "start" location. 1623d0407baSopenharmony_ci */ 1633d0407baSopenharmony_ci return vaddr + offset_in_page(start); 1643d0407baSopenharmony_ci} 1653d0407baSopenharmony_ci 1663d0407baSopenharmony_cistruct arm_smccc_res sip_smc_request_share_mem(u32 page_num, share_page_type_t page_type) 1673d0407baSopenharmony_ci{ 1683d0407baSopenharmony_ci struct arm_smccc_res res; 1693d0407baSopenharmony_ci unsigned long share_mem_phy; 1703d0407baSopenharmony_ci 1713d0407baSopenharmony_ci res = invoke_sip_fn_smc(SIP_SHARE_MEM, page_num, page_type, 0); 1723d0407baSopenharmony_ci if (IS_SIP_ERROR(res.a0)) { 1733d0407baSopenharmony_ci goto error; 1743d0407baSopenharmony_ci } 1753d0407baSopenharmony_ci 1763d0407baSopenharmony_ci share_mem_phy = res.a1; 1773d0407baSopenharmony_ci res.a1 = (unsigned long)sip_map(share_mem_phy, SIZE_PAGE(page_num)); 1783d0407baSopenharmony_ci 1793d0407baSopenharmony_cierror: 1803d0407baSopenharmony_ci return res; 1813d0407baSopenharmony_ci} 1823d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(sip_smc_request_share_mem); 1833d0407baSopenharmony_ci 1843d0407baSopenharmony_cistruct arm_smccc_res sip_smc_mcu_el3fiq(u32 arg0, u32 arg1, u32 arg2) 1853d0407baSopenharmony_ci{ 1863d0407baSopenharmony_ci return invoke_sip_fn_smc(SIP_MCU_EL3FIQ_CFG, arg0, arg1, arg2); 1873d0407baSopenharmony_ci} 1883d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(sip_smc_mcu_el3fiq); 1893d0407baSopenharmony_ci 1903d0407baSopenharmony_cistruct arm_smccc_res sip_smc_vpu_reset(u32 arg0, u32 arg1, u32 arg2) 1913d0407baSopenharmony_ci{ 1923d0407baSopenharmony_ci struct arm_smccc_res res; 1933d0407baSopenharmony_ci 1943d0407baSopenharmony_ci res = invoke_sip_fn_smc(PSCI_SIP_VPU_RESET, arg0, arg1, arg2); 1953d0407baSopenharmony_ci return res; 1963d0407baSopenharmony_ci} 1973d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(sip_smc_vpu_reset); 1983d0407baSopenharmony_ci 1993d0407baSopenharmony_cistruct arm_smccc_res sip_smc_bus_config(u32 arg0, u32 arg1, u32 arg2) 2003d0407baSopenharmony_ci{ 2013d0407baSopenharmony_ci struct arm_smccc_res res; 2023d0407baSopenharmony_ci 2033d0407baSopenharmony_ci res = invoke_sip_fn_smc(SIP_BUS_CFG, arg0, arg1, arg2); 2043d0407baSopenharmony_ci return res; 2053d0407baSopenharmony_ci} 2063d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(sip_smc_bus_config); 2073d0407baSopenharmony_ci 2083d0407baSopenharmony_cistruct dram_addrmap_info *sip_smc_get_dram_map(void) 2093d0407baSopenharmony_ci{ 2103d0407baSopenharmony_ci struct arm_smccc_res res; 2113d0407baSopenharmony_ci static struct dram_addrmap_info *map; 2123d0407baSopenharmony_ci 2133d0407baSopenharmony_ci if (map) { 2143d0407baSopenharmony_ci return map; 2153d0407baSopenharmony_ci } 2163d0407baSopenharmony_ci 2173d0407baSopenharmony_ci /* Request share memory size 4KB */ 2183d0407baSopenharmony_ci res = sip_smc_request_share_mem(1, SHARE_PAGE_TYPE_DDR_ADDRMAP); 2193d0407baSopenharmony_ci if (res.a0 != 0) { 2203d0407baSopenharmony_ci pr_err("no ATF memory for init\n"); 2213d0407baSopenharmony_ci return NULL; 2223d0407baSopenharmony_ci } 2233d0407baSopenharmony_ci 2243d0407baSopenharmony_ci map = (struct dram_addrmap_info *)res.a1; 2253d0407baSopenharmony_ci 2263d0407baSopenharmony_ci res = sip_smc_dram(SHARE_PAGE_TYPE_DDR_ADDRMAP, 0, ROCKCHIP_SIP_CONFIG_DRAM_ADDRMAP_GET); 2273d0407baSopenharmony_ci if (res.a0) { 2283d0407baSopenharmony_ci pr_err("rockchip_sip_config_dram_init error:%lx\n", res.a0); 2293d0407baSopenharmony_ci map = NULL; 2303d0407baSopenharmony_ci return NULL; 2313d0407baSopenharmony_ci } 2323d0407baSopenharmony_ci 2333d0407baSopenharmony_ci return map; 2343d0407baSopenharmony_ci} 2353d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(sip_smc_get_dram_map); 2363d0407baSopenharmony_ci 2373d0407baSopenharmony_cistruct arm_smccc_res sip_smc_lastlog_request(void) 2383d0407baSopenharmony_ci{ 2393d0407baSopenharmony_ci struct arm_smccc_res res; 2403d0407baSopenharmony_ci void __iomem *addr1, *addr2; 2413d0407baSopenharmony_ci 2423d0407baSopenharmony_ci res = invoke_sip_fn_smc(SIP_LAST_LOG, local_clock(), 0, 0); 2433d0407baSopenharmony_ci if (IS_SIP_ERROR(res.a0)) { 2443d0407baSopenharmony_ci return res; 2453d0407baSopenharmony_ci } 2463d0407baSopenharmony_ci 2473d0407baSopenharmony_ci addr1 = sip_map(res.a1, res.a3); 2483d0407baSopenharmony_ci if (!addr1) { 2493d0407baSopenharmony_ci pr_err("%s: share memory buffer0 ioremap failed\n", __func__); 2503d0407baSopenharmony_ci res.a0 = SIP_RET_INVALID_ADDRESS; 2513d0407baSopenharmony_ci return res; 2523d0407baSopenharmony_ci } 2533d0407baSopenharmony_ci addr2 = sip_map(res.a2, res.a3); 2543d0407baSopenharmony_ci if (!addr2) { 2553d0407baSopenharmony_ci pr_err("%s: share memory buffer1 ioremap failed\n", __func__); 2563d0407baSopenharmony_ci res.a0 = SIP_RET_INVALID_ADDRESS; 2573d0407baSopenharmony_ci return res; 2583d0407baSopenharmony_ci } 2593d0407baSopenharmony_ci 2603d0407baSopenharmony_ci res.a1 = (unsigned long)addr1; 2613d0407baSopenharmony_ci res.a2 = (unsigned long)addr2; 2623d0407baSopenharmony_ci 2633d0407baSopenharmony_ci return res; 2643d0407baSopenharmony_ci} 2653d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(sip_smc_lastlog_request); 2663d0407baSopenharmony_ci 2673d0407baSopenharmony_ci/************************** fiq debugger **************************************/ 2683d0407baSopenharmony_ci/* 2693d0407baSopenharmony_ci * AArch32 is not allowed to call SMC64(ATF framework does not support), so we 2703d0407baSopenharmony_ci * don't change SIP_UARTDBG_FN to SIP_UARTDBG_CFG64 even when cpu is AArch32 2713d0407baSopenharmony_ci * mode. Let ATF support SIP_UARTDBG_CFG, and we just initialize SIP_UARTDBG_FN 2723d0407baSopenharmony_ci * depends on compile option(CONFIG_ARM or CONFIG_ARM64). 2733d0407baSopenharmony_ci */ 2743d0407baSopenharmony_ci#ifdef CONFIG_ARM64 2753d0407baSopenharmony_ci#define SIP_UARTDBG_FN SIP_UARTDBG_CFG64 2763d0407baSopenharmony_ci#else 2773d0407baSopenharmony_ci#define SIP_UARTDBG_FN SIP_UARTDBG_CFG 2783d0407baSopenharmony_cistatic int firmware_64_32bit; 2793d0407baSopenharmony_ci#endif 2803d0407baSopenharmony_ci 2813d0407baSopenharmony_cistatic int fiq_sip_enabled; 2823d0407baSopenharmony_cistatic int fiq_target_cpu; 2833d0407baSopenharmony_cistatic phys_addr_t ft_fiq_mem_phy; 2843d0407baSopenharmony_cistatic void __iomem *ft_fiq_mem_base; 2853d0407baSopenharmony_cistatic void (*sip_fiq_debugger_uart_irq_tf)(struct pt_regs _pt_regs, unsigned long cpu); 2863d0407baSopenharmony_ciint sip_fiq_debugger_is_enabled(void) 2873d0407baSopenharmony_ci{ 2883d0407baSopenharmony_ci return fiq_sip_enabled; 2893d0407baSopenharmony_ci} 2903d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(sip_fiq_debugger_is_enabled); 2913d0407baSopenharmony_ci 2923d0407baSopenharmony_cistatic struct pt_regs sip_fiq_debugger_get_pt_regs(void *reg_base, unsigned long sp_el1) 2933d0407baSopenharmony_ci{ 2943d0407baSopenharmony_ci struct pt_regs fiq_pt_regs; 2953d0407baSopenharmony_ci __maybe_unused struct sm_nsec_ctx *nsec_ctx = reg_base; 2963d0407baSopenharmony_ci __maybe_unused struct gp_regs_ctx *gp_regs = reg_base; 2973d0407baSopenharmony_ci 2983d0407baSopenharmony_ci#ifdef CONFIG_ARM64 2993d0407baSopenharmony_ci /* 3003d0407baSopenharmony_ci * 64-bit ATF + 64-bit kernel 3013d0407baSopenharmony_ci */ 3023d0407baSopenharmony_ci /* copy cpu context: x0 ~ spsr_el3 */ 3033d0407baSopenharmony_ci memcpy(&fiq_pt_regs, reg_base, 0xf8); 3043d0407baSopenharmony_ci 3053d0407baSopenharmony_ci /* copy pstate: spsr_el3 */ 3063d0407baSopenharmony_ci memcpy(&fiq_pt_regs.pstate, reg_base + 0x110, 0x8); 3073d0407baSopenharmony_ci fiq_pt_regs.sp = sp_el1; 3083d0407baSopenharmony_ci 3093d0407baSopenharmony_ci /* copy pc: elr_el3 */ 3103d0407baSopenharmony_ci memcpy(&fiq_pt_regs.pc, reg_base + 0x118, 0x8); 3113d0407baSopenharmony_ci#else 3123d0407baSopenharmony_ci if (firmware_64_32bit == FIRMWARE_ATF_64BIT) { 3133d0407baSopenharmony_ci /* 3143d0407baSopenharmony_ci * 64-bit ATF + 32-bit kernel 3153d0407baSopenharmony_ci */ 3163d0407baSopenharmony_ci fiq_pt_regs.ARM_r0 = gp_regs->x0; 3173d0407baSopenharmony_ci fiq_pt_regs.ARM_r1 = gp_regs->x1; 3183d0407baSopenharmony_ci fiq_pt_regs.ARM_r2 = gp_regs->x2; 3193d0407baSopenharmony_ci fiq_pt_regs.ARM_r3 = gp_regs->x3; 3203d0407baSopenharmony_ci fiq_pt_regs.ARM_r4 = gp_regs->x4; 3213d0407baSopenharmony_ci fiq_pt_regs.ARM_r5 = gp_regs->x5; 3223d0407baSopenharmony_ci fiq_pt_regs.ARM_r6 = gp_regs->x6; 3233d0407baSopenharmony_ci fiq_pt_regs.ARM_r7 = gp_regs->x7; 3243d0407baSopenharmony_ci fiq_pt_regs.ARM_r8 = gp_regs->x8; 3253d0407baSopenharmony_ci fiq_pt_regs.ARM_r9 = gp_regs->x9; 3263d0407baSopenharmony_ci fiq_pt_regs.ARM_r10 = gp_regs->x10; 3273d0407baSopenharmony_ci fiq_pt_regs.ARM_fp = gp_regs->x11; 3283d0407baSopenharmony_ci fiq_pt_regs.ARM_ip = gp_regs->x12; 3293d0407baSopenharmony_ci fiq_pt_regs.ARM_sp = gp_regs->x19; /* aarch32 svc_r13 */ 3303d0407baSopenharmony_ci fiq_pt_regs.ARM_lr = gp_regs->x18; /* aarch32 svc_r14 */ 3313d0407baSopenharmony_ci fiq_pt_regs.ARM_cpsr = gp_regs->spsr_el3; 3323d0407baSopenharmony_ci fiq_pt_regs.ARM_pc = gp_regs->elr_el3; 3333d0407baSopenharmony_ci } else { 3343d0407baSopenharmony_ci /* 3353d0407baSopenharmony_ci * 32-bit tee firmware + 32-bit kernel 3363d0407baSopenharmony_ci */ 3373d0407baSopenharmony_ci fiq_pt_regs.ARM_r0 = nsec_ctx->r0; 3383d0407baSopenharmony_ci fiq_pt_regs.ARM_r1 = nsec_ctx->r1; 3393d0407baSopenharmony_ci fiq_pt_regs.ARM_r2 = nsec_ctx->r2; 3403d0407baSopenharmony_ci fiq_pt_regs.ARM_r3 = nsec_ctx->r3; 3413d0407baSopenharmony_ci fiq_pt_regs.ARM_r4 = nsec_ctx->r4; 3423d0407baSopenharmony_ci fiq_pt_regs.ARM_r5 = nsec_ctx->r5; 3433d0407baSopenharmony_ci fiq_pt_regs.ARM_r6 = nsec_ctx->r6; 3443d0407baSopenharmony_ci fiq_pt_regs.ARM_r7 = nsec_ctx->r7; 3453d0407baSopenharmony_ci fiq_pt_regs.ARM_r8 = nsec_ctx->r8; 3463d0407baSopenharmony_ci fiq_pt_regs.ARM_r9 = nsec_ctx->r9; 3473d0407baSopenharmony_ci fiq_pt_regs.ARM_r10 = nsec_ctx->r10; 3483d0407baSopenharmony_ci fiq_pt_regs.ARM_fp = nsec_ctx->r11; 3493d0407baSopenharmony_ci fiq_pt_regs.ARM_ip = nsec_ctx->r12; 3503d0407baSopenharmony_ci fiq_pt_regs.ARM_sp = nsec_ctx->svc_sp; 3513d0407baSopenharmony_ci fiq_pt_regs.ARM_lr = nsec_ctx->svc_lr; 3523d0407baSopenharmony_ci fiq_pt_regs.ARM_cpsr = nsec_ctx->mon_spsr; 3533d0407baSopenharmony_ci 3543d0407baSopenharmony_ci /* 3553d0407baSopenharmony_ci * 'nsec_ctx->mon_lr' is not the fiq break point's PC, because it will 3563d0407baSopenharmony_ci * be override as 'psci_fiq_debugger_uart_irq_tf_cb' for optee-os to 3573d0407baSopenharmony_ci * jump to fiq_debugger handler. 3583d0407baSopenharmony_ci * 3593d0407baSopenharmony_ci * As 'nsec_ctx->und_lr' is not used for kernel, so optee-os uses it to 3603d0407baSopenharmony_ci * deliver fiq break point's PC. 3613d0407baSopenharmony_ci * 3623d0407baSopenharmony_ci */ 3633d0407baSopenharmony_ci fiq_pt_regs.ARM_pc = nsec_ctx->und_lr; 3643d0407baSopenharmony_ci } 3653d0407baSopenharmony_ci#endif 3663d0407baSopenharmony_ci 3673d0407baSopenharmony_ci return fiq_pt_regs; 3683d0407baSopenharmony_ci} 3693d0407baSopenharmony_ci 3703d0407baSopenharmony_cistatic void sip_fiq_debugger_uart_irq_tf_cb(unsigned long sp_el1, unsigned long offset, unsigned long cpu) 3713d0407baSopenharmony_ci{ 3723d0407baSopenharmony_ci struct pt_regs fiq_pt_regs; 3733d0407baSopenharmony_ci char *cpu_context; 3743d0407baSopenharmony_ci 3753d0407baSopenharmony_ci /* calling fiq handler */ 3763d0407baSopenharmony_ci if (ft_fiq_mem_base) { 3773d0407baSopenharmony_ci cpu_context = (char *)ft_fiq_mem_base + offset; 3783d0407baSopenharmony_ci fiq_pt_regs = sip_fiq_debugger_get_pt_regs(cpu_context, sp_el1); 3793d0407baSopenharmony_ci sip_fiq_debugger_uart_irq_tf(fiq_pt_regs, cpu); 3803d0407baSopenharmony_ci } 3813d0407baSopenharmony_ci 3823d0407baSopenharmony_ci /* fiq handler done, return to EL3(then EL3 return to EL1 entry) */ 3833d0407baSopenharmony_ci invoke_sip_fn_smc(SIP_UARTDBG_FN, 0, 0, UARTDBG_CFG_OSHDL_TO_OS); 3843d0407baSopenharmony_ci} 3853d0407baSopenharmony_ci 3863d0407baSopenharmony_ciint sip_fiq_debugger_uart_irq_tf_init(u32 irq_id, void *callback_fn) 3873d0407baSopenharmony_ci{ 3883d0407baSopenharmony_ci struct arm_smccc_res res; 3893d0407baSopenharmony_ci 3903d0407baSopenharmony_ci fiq_target_cpu = 0; 3913d0407baSopenharmony_ci 3923d0407baSopenharmony_ci /* init fiq debugger callback */ 3933d0407baSopenharmony_ci sip_fiq_debugger_uart_irq_tf = callback_fn; 3943d0407baSopenharmony_ci res = invoke_sip_fn_smc(SIP_UARTDBG_FN, irq_id, (unsigned long)sip_fiq_debugger_uart_irq_tf_cb, UARTDBG_CFG_INIT); 3953d0407baSopenharmony_ci if (IS_SIP_ERROR(res.a0)) { 3963d0407baSopenharmony_ci pr_err("%s error: %d\n", __func__, (int)res.a0); 3973d0407baSopenharmony_ci return res.a0; 3983d0407baSopenharmony_ci } 3993d0407baSopenharmony_ci 4003d0407baSopenharmony_ci /* share memory ioremap */ 4013d0407baSopenharmony_ci if (!ft_fiq_mem_base) { 4023d0407baSopenharmony_ci ft_fiq_mem_phy = res.a1; 4033d0407baSopenharmony_ci ft_fiq_mem_base = sip_map(ft_fiq_mem_phy, FIQ_UARTDBG_SHARE_MEM_SIZE); 4043d0407baSopenharmony_ci if (!ft_fiq_mem_base) { 4053d0407baSopenharmony_ci pr_err("%s: share memory ioremap failed\n", __func__); 4063d0407baSopenharmony_ci return -ENOMEM; 4073d0407baSopenharmony_ci } 4083d0407baSopenharmony_ci } 4093d0407baSopenharmony_ci 4103d0407baSopenharmony_ci fiq_sip_enabled = 1; 4113d0407baSopenharmony_ci 4123d0407baSopenharmony_ci return SIP_RET_SUCCESS; 4133d0407baSopenharmony_ci} 4143d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(sip_fiq_debugger_uart_irq_tf_init); 4153d0407baSopenharmony_ci 4163d0407baSopenharmony_cistatic ulong cpu_logical_map_mpidr(u32 cpu) 4173d0407baSopenharmony_ci{ 4183d0407baSopenharmony_ci#ifdef MODULE 4193d0407baSopenharmony_ci /* Empirically, local "cpu_logical_map()" for rockchip platforms */ 4203d0407baSopenharmony_ci ulong mpidr = 0x00; 4213d0407baSopenharmony_ci 4223d0407baSopenharmony_ci if (cpu < 0x4) { 4233d0407baSopenharmony_ci /* 0x00, 0x01, 0x02, 0x03 */ 4243d0407baSopenharmony_ci mpidr = cpu; 4253d0407baSopenharmony_ci } else if (cpu < 0x8) { 4263d0407baSopenharmony_ci /* 0x100, 0x101, 0x102, 0x103 */ 4273d0407baSopenharmony_ci mpidr = 0x100 | (cpu - 0x4); 4283d0407baSopenharmony_ci } else { 4293d0407baSopenharmony_ci pr_err("Unsupported map cpu: %d\n", cpu); 4303d0407baSopenharmony_ci } 4313d0407baSopenharmony_ci 4323d0407baSopenharmony_ci return mpidr; 4333d0407baSopenharmony_ci#else 4343d0407baSopenharmony_ci return cpu_logical_map(cpu); 4353d0407baSopenharmony_ci#endif 4363d0407baSopenharmony_ci} 4373d0407baSopenharmony_ci 4383d0407baSopenharmony_ciint sip_fiq_debugger_switch_cpu(u32 cpu) 4393d0407baSopenharmony_ci{ 4403d0407baSopenharmony_ci struct arm_smccc_res res; 4413d0407baSopenharmony_ci 4423d0407baSopenharmony_ci fiq_target_cpu = cpu; 4433d0407baSopenharmony_ci res = invoke_sip_fn_smc(SIP_UARTDBG_FN, cpu_logical_map_mpidr(cpu), 0, UARTDBG_CFG_OSHDL_CPUSW); 4443d0407baSopenharmony_ci return res.a0; 4453d0407baSopenharmony_ci} 4463d0407baSopenharmony_ci 4473d0407baSopenharmony_ciint sip_fiq_debugger_sdei_switch_cpu(u32 cur_cpu, u32 target_cpu, u32 flag) 4483d0407baSopenharmony_ci{ 4493d0407baSopenharmony_ci struct arm_smccc_res res; 4503d0407baSopenharmony_ci 4513d0407baSopenharmony_ci res = invoke_sip_fn_smc(SIP_SDEI_FIQ_DBG_SWITCH_CPU, cur_cpu, target_cpu, flag); 4523d0407baSopenharmony_ci return res.a0; 4533d0407baSopenharmony_ci} 4543d0407baSopenharmony_ci 4553d0407baSopenharmony_ciint sip_fiq_debugger_sdei_get_event_id(u32 *fiq, u32 *sw_cpu, u32 *flag) 4563d0407baSopenharmony_ci{ 4573d0407baSopenharmony_ci struct arm_smccc_res res; 4583d0407baSopenharmony_ci 4593d0407baSopenharmony_ci res = invoke_sip_fn_smc(SIP_SDEI_FIQ_DBG_GET_EVENT_ID, 0, 0, 0); 4603d0407baSopenharmony_ci *fiq = res.a1; 4613d0407baSopenharmony_ci *sw_cpu = res.a2; 4623d0407baSopenharmony_ci if (flag) { 4633d0407baSopenharmony_ci *flag = res.a3; 4643d0407baSopenharmony_ci } 4653d0407baSopenharmony_ci 4663d0407baSopenharmony_ci return res.a0; 4673d0407baSopenharmony_ci} 4683d0407baSopenharmony_ci 4693d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(sip_fiq_debugger_switch_cpu); 4703d0407baSopenharmony_ci 4713d0407baSopenharmony_civoid sip_fiq_debugger_enable_debug(bool enable) 4723d0407baSopenharmony_ci{ 4733d0407baSopenharmony_ci unsigned long val; 4743d0407baSopenharmony_ci 4753d0407baSopenharmony_ci val = enable ? UARTDBG_CFG_OSHDL_DEBUG_ENABLE : UARTDBG_CFG_OSHDL_DEBUG_DISABLE; 4763d0407baSopenharmony_ci 4773d0407baSopenharmony_ci invoke_sip_fn_smc(SIP_UARTDBG_FN, 0, 0, val); 4783d0407baSopenharmony_ci} 4793d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(sip_fiq_debugger_enable_debug); 4803d0407baSopenharmony_ci 4813d0407baSopenharmony_ciint sip_fiq_debugger_set_print_port(u32 port_phyaddr, u32 baudrate) 4823d0407baSopenharmony_ci{ 4833d0407baSopenharmony_ci struct arm_smccc_res res; 4843d0407baSopenharmony_ci 4853d0407baSopenharmony_ci res = invoke_sip_fn_smc(SIP_UARTDBG_FN, port_phyaddr, baudrate, UARTDBG_CFG_PRINT_PORT); 4863d0407baSopenharmony_ci return res.a0; 4873d0407baSopenharmony_ci} 4883d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(sip_fiq_debugger_set_print_port); 4893d0407baSopenharmony_ci 4903d0407baSopenharmony_ciint sip_fiq_debugger_request_share_memory(void) 4913d0407baSopenharmony_ci{ 4923d0407baSopenharmony_ci struct arm_smccc_res res; 4933d0407baSopenharmony_ci 4943d0407baSopenharmony_ci /* request page share memory */ 4953d0407baSopenharmony_ci res = sip_smc_request_share_mem(FIQ_UARTDBG_PAGE_NUMS, SHARE_PAGE_TYPE_UARTDBG); 4963d0407baSopenharmony_ci if (IS_SIP_ERROR(res.a0)) { 4973d0407baSopenharmony_ci return res.a0; 4983d0407baSopenharmony_ci } 4993d0407baSopenharmony_ci 5003d0407baSopenharmony_ci return SIP_RET_SUCCESS; 5013d0407baSopenharmony_ci} 5023d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(sip_fiq_debugger_request_share_memory); 5033d0407baSopenharmony_ci 5043d0407baSopenharmony_ciint sip_fiq_debugger_get_target_cpu(void) 5053d0407baSopenharmony_ci{ 5063d0407baSopenharmony_ci return fiq_target_cpu; 5073d0407baSopenharmony_ci} 5083d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(sip_fiq_debugger_get_target_cpu); 5093d0407baSopenharmony_ci 5103d0407baSopenharmony_civoid sip_fiq_debugger_enable_fiq(bool enable, uint32_t tgt_cpu) 5113d0407baSopenharmony_ci{ 5123d0407baSopenharmony_ci u32 en; 5133d0407baSopenharmony_ci 5143d0407baSopenharmony_ci fiq_target_cpu = tgt_cpu; 5153d0407baSopenharmony_ci en = enable ? UARTDBG_CFG_FIQ_ENABEL : UARTDBG_CFG_FIQ_DISABEL; 5163d0407baSopenharmony_ci invoke_sip_fn_smc(SIP_UARTDBG_FN, tgt_cpu, 0, en); 5173d0407baSopenharmony_ci} 5183d0407baSopenharmony_ciEXPORT_SYMBOL_GPL(sip_fiq_debugger_enable_fiq); 5193d0407baSopenharmony_ci 5203d0407baSopenharmony_ci/******************************************************************************/ 5213d0407baSopenharmony_ci#ifdef CONFIG_ARM 5223d0407baSopenharmony_cistatic __init int sip_firmware_init(void) 5233d0407baSopenharmony_ci{ 5243d0407baSopenharmony_ci struct arm_smccc_res res; 5253d0407baSopenharmony_ci 5263d0407baSopenharmony_ci if (!psci_smp_available()) { 5273d0407baSopenharmony_ci return 0; 5283d0407baSopenharmony_ci } 5293d0407baSopenharmony_ci 5303d0407baSopenharmony_ci /* 5313d0407baSopenharmony_ci * OP-TEE works on kernel 3.10 and 4.4 and we have different sip 5323d0407baSopenharmony_ci * implement. We should tell OP-TEE the current rockchip sip version. 5333d0407baSopenharmony_ci */ 5343d0407baSopenharmony_ci res = invoke_sip_fn_smc(SIP_SIP_VERSION, SIP_IMPLEMENT_V2, SECURE_REG_WR, 0); 5353d0407baSopenharmony_ci if (IS_SIP_ERROR(res.a0)) { 5363d0407baSopenharmony_ci pr_err("%s: set rockchip sip version v2 failed\n", __func__); 5373d0407baSopenharmony_ci } 5383d0407baSopenharmony_ci 5393d0407baSopenharmony_ci /* 5403d0407baSopenharmony_ci * Currently, we support: 5413d0407baSopenharmony_ci * 5423d0407baSopenharmony_ci * 1. 64-bit ATF + 64-bit kernel; 5433d0407baSopenharmony_ci * 2. 64-bit ATF + 32-bit kernel; 5443d0407baSopenharmony_ci * 3. 32-bit TEE + 32-bit kernel; 5453d0407baSopenharmony_ci * 5463d0407baSopenharmony_ci * We need to detect which case of above and record in firmware_64_32bit 5473d0407baSopenharmony_ci * We get info from cpuid and compare with all supported ARMv7 cpu. 5483d0407baSopenharmony_ci */ 5493d0407baSopenharmony_ci switch (read_cpuid_part()) { 5503d0407baSopenharmony_ci case ARM_CPU_PART_CORTEX_A7: 5513d0407baSopenharmony_ci case ARM_CPU_PART_CORTEX_A8: 5523d0407baSopenharmony_ci case ARM_CPU_PART_CORTEX_A9: 5533d0407baSopenharmony_ci case ARM_CPU_PART_CORTEX_A12: 5543d0407baSopenharmony_ci case ARM_CPU_PART_CORTEX_A15: 5553d0407baSopenharmony_ci case ARM_CPU_PART_CORTEX_A17: 5563d0407baSopenharmony_ci firmware_64_32bit = FIRMWARE_TEE_32BIT; 5573d0407baSopenharmony_ci break; 5583d0407baSopenharmony_ci default: 5593d0407baSopenharmony_ci firmware_64_32bit = FIRMWARE_ATF_64BIT; 5603d0407baSopenharmony_ci break; 5613d0407baSopenharmony_ci } 5623d0407baSopenharmony_ci 5633d0407baSopenharmony_ci return 0; 5643d0407baSopenharmony_ci} 5653d0407baSopenharmony_ciarch_initcall(sip_firmware_init); 5663d0407baSopenharmony_ci#endif 5673d0407baSopenharmony_ci 5683d0407baSopenharmony_ciMODULE_DESCRIPTION("Rockchip SIP Call"); 5693d0407baSopenharmony_ciMODULE_LICENSE("GPL"); 570