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