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