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