From b3cea1af8d56722ec96b9815491eedd0717e97d3 Mon Sep 17 00:00:00 2001 From: chenjh Date: Fri, 17 Mar 2017 16:36:34 +0800 Subject: [PATCH 1/1] firmware: rockchip: update sip interface clean up code and add support for fiq debugger Change-Id: I6dc0e4306a8554c49342207191005e55fb662b38 Signed-off-by: chenjh --- drivers/firmware/rockchip_sip.c | 233 +++++++++++++++------- drivers/soc/rockchip/rockchip_pm_config.c | 2 +- include/linux/rockchip/rockchip_sip.h | 160 +++++++++------ 3 files changed, 265 insertions(+), 130 deletions(-) diff --git a/drivers/firmware/rockchip_sip.c b/drivers/firmware/rockchip_sip.c index 2dadfaa8c80b..4d12d2d65856 100644 --- a/drivers/firmware/rockchip_sip.c +++ b/drivers/firmware/rockchip_sip.c @@ -17,6 +17,7 @@ #include #include #include +#include #ifdef CONFIG_64BIT #define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN64_##name @@ -37,40 +38,34 @@ static struct arm_smccc_res __invoke_sip_fn_smc(unsigned long function_id, return res; } -struct arm_smccc_res sip_smc_ddr_cfg(u32 arg0, u32 arg1, - u32 arg2) +struct arm_smccc_res sip_smc_ddr_cfg(u32 arg0, u32 arg1, u32 arg2) { - return __invoke_sip_fn_smc(SIP_DDR_CFG32, arg0, arg1, arg2); + return __invoke_sip_fn_smc(SIP_DDR_CFG, arg0, arg1, arg2); } struct arm_smccc_res sip_smc_get_atf_version(void) { - return __invoke_sip_fn_smc(SIP_ATF_VERSION32, 0, 0, 0); + return __invoke_sip_fn_smc(SIP_ATF_VERSION, 0, 0, 0); } struct arm_smccc_res sip_smc_get_sip_version(void) { - return __invoke_sip_fn_smc(SIP_SIP_VERSION32, 0, 0, 0); + return __invoke_sip_fn_smc(SIP_SIP_VERSION, 0, 0, 0); } -int sip_smc_set_suspend_mode(u32 ctrl, - u32 config1, - u32 config2) +int sip_smc_set_suspend_mode(u32 ctrl, u32 config1, u32 config2) { struct arm_smccc_res res; - res = __invoke_sip_fn_smc(SIP_SUSPEND_MODE32, ctrl, - config1, config2); - + res = __invoke_sip_fn_smc(SIP_SUSPEND_MODE, ctrl, config1, config2); return res.a0; } -int rk_psci_virtual_poweroff(void) +int sip_smc_virtual_poweroff(void) { struct arm_smccc_res res; - res = __invoke_sip_fn_smc(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND), - 0, 0, 0); + res = __invoke_sip_fn_smc(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND), 0, 0, 0); return res.a0; } @@ -98,101 +93,195 @@ int sip_smc_secure_reg_write(u32 addr_phy, u32 val) return res.a0; } -/************************** fiq debugger **************************************/ -static u64 ft_fiq_mem_phy; -static void __iomem *ft_fiq_mem_base; -static void (*psci_fiq_debugger_uart_irq_tf)(void *reg_base, u64 sp_el1); -static u32 fig_init_flag; - -u32 rockchip_psci_smc_get_tf_ver(void) +struct arm_smccc_res sip_smc_request_share_mem(u32 page_num, + share_page_type_t page_type) { struct arm_smccc_res res; + unsigned long share_mem_phy; + + res = __invoke_sip_fn_smc(SIP_SHARE_MEM, page_num, page_type, 0); + if (IS_SIP_ERROR(res.a0)) + goto error; + + share_mem_phy = res.a1; + res.a1 = (unsigned long)ioremap(share_mem_phy, SIZE_PAGE(page_num)); - arm_smccc_smc(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0, 0, 0, 0, 0, &res); - return 0x00010005; +error: + return res; } -void psci_fiq_debugger_uart_irq_tf_cb(u64 sp_el1, u64 offset) +struct arm_smccc_res sip_smc_mcu_el3fiq(u32 arg0, u32 arg1, u32 arg2) { - psci_fiq_debugger_uart_irq_tf((char *)ft_fiq_mem_base + offset, sp_el1); - __invoke_sip_fn_smc(PSCI_SIP_UARTDBG_CFG64, 0, 0, - UARTDBG_CFG_OSHDL_TO_OS); + return __invoke_sip_fn_smc(SIP_MCU_EL3FIQ_CFG, arg0, arg1, arg2); } -void psci_fiq_debugger_uart_irq_tf_init(u32 irq_id, void *callback) +/************************** fiq debugger **************************************/ +#ifdef CONFIG_ARM64 +#define SIP_UARTDBG_FN SIP_UARTDBG_CFG64 +#else +#define SIP_UARTDBG_FN SIP_UARTDBG_CFG +#endif + +static int fiq_sip_enabled; +static int fiq_target_cpu; +static phys_addr_t ft_fiq_mem_phy; +static void __iomem *ft_fiq_mem_base; +static void (*sip_fiq_debugger_uart_irq_tf)(struct pt_regs _pt_regs, + unsigned long cpu); +int sip_fiq_debugger_is_enabled(void) { - struct arm_smccc_res sip_smmc; + return fiq_sip_enabled; +} + +static struct pt_regs sip_fiq_debugger_get_pt_regs(void *reg_base, + unsigned long sp_el1) +{ + struct pt_regs fiq_pt_regs; + +#ifdef CONFIG_ARM64 + /* copy cpu context */ + memcpy(&fiq_pt_regs, reg_base, 8 * 31); + + /* copy pstate */ + memcpy(&fiq_pt_regs.pstate, reg_base + 0x110, 8); + + /* EL1 mode */ + if (fiq_pt_regs.pstate & 0x10) + memcpy(&fiq_pt_regs.sp, reg_base + 0xf8, 8); + /* EL0 mode */ + else + fiq_pt_regs.sp = sp_el1; + + /* copy pc */ + memcpy(&fiq_pt_regs.pc, reg_base + 0x118, 8); +#else + struct sm_nsec_ctx *nsec_ctx = reg_base; + + fiq_pt_regs.ARM_r0 = nsec_ctx->r0; + fiq_pt_regs.ARM_r1 = nsec_ctx->r1; + fiq_pt_regs.ARM_r2 = nsec_ctx->r2; + fiq_pt_regs.ARM_r3 = nsec_ctx->r3; + fiq_pt_regs.ARM_r4 = nsec_ctx->r4; + fiq_pt_regs.ARM_r5 = nsec_ctx->r5; + fiq_pt_regs.ARM_r6 = nsec_ctx->r6; + fiq_pt_regs.ARM_r7 = nsec_ctx->r7; + fiq_pt_regs.ARM_r8 = nsec_ctx->r8; + fiq_pt_regs.ARM_r9 = nsec_ctx->r9; + fiq_pt_regs.ARM_r10 = nsec_ctx->r10; + fiq_pt_regs.ARM_fp = nsec_ctx->r11; + fiq_pt_regs.ARM_ip = nsec_ctx->r12; + fiq_pt_regs.ARM_sp = nsec_ctx->svc_sp; + fiq_pt_regs.ARM_lr = nsec_ctx->svc_lr; + fiq_pt_regs.ARM_pc = nsec_ctx->mon_lr; + fiq_pt_regs.ARM_cpsr = nsec_ctx->mon_spsr; +#endif - psci_fiq_debugger_uart_irq_tf = callback; - sip_smmc = __invoke_sip_fn_smc(PSCI_SIP_UARTDBG_CFG64, irq_id, - (unsigned long)psci_fiq_debugger_uart_irq_tf_cb, - UARTDBG_CFG_INIT); - ft_fiq_mem_phy = sip_smmc.a0; - ft_fiq_mem_base = ioremap(ft_fiq_mem_phy, 8 * 1024); - fig_init_flag = 1; + return fiq_pt_regs; } -void psci_enable_fiq(void) +static void sip_fiq_debugger_uart_irq_tf_cb(unsigned long sp_el1, + unsigned long offset, + unsigned long cpu) { - int irq_flag; - int cpu_id; + struct pt_regs fiq_pt_regs; + char *cpu_context; + + /* calling fiq handler */ + if (ft_fiq_mem_base) { + cpu_context = (char *)ft_fiq_mem_base + offset; + fiq_pt_regs = sip_fiq_debugger_get_pt_regs(cpu_context, sp_el1); + sip_fiq_debugger_uart_irq_tf(fiq_pt_regs, cpu); + } + + /* fiq handler done, return to EL3(then EL3 return to EL1 entry) */ + __invoke_sip_fn_smc(SIP_UARTDBG_FN, 0, 0, UARTDBG_CFG_OSHDL_TO_OS); +} - if (fig_init_flag != 1) - return; - irq_flag = *((char *)(ft_fiq_mem_base) + 8 * 1024 - 0x04); +int sip_fiq_debugger_uart_irq_tf_init(u32 irq_id, void *callback_fn) +{ + struct arm_smccc_res res; - cpu_id = read_cpuid_mpidr() & MPIDR_HWID_BITMASK; - if ((irq_flag == 0xAA) && (cpu_id == 0)) - __invoke_sip_fn_smc(RK_SIP_ENABLE_FIQ, 0, 0, 0); + fiq_target_cpu = 0; + + /* init fiq debugger callback */ + sip_fiq_debugger_uart_irq_tf = callback_fn; + res = __invoke_sip_fn_smc(SIP_UARTDBG_FN, irq_id, + (unsigned long)sip_fiq_debugger_uart_irq_tf_cb, + UARTDBG_CFG_INIT); + if (IS_SIP_ERROR(res.a0)) { + pr_err("%s error: %d\n", __func__, (int)res.a0); + return res.a0; + } + + /* share memory ioremap */ + if (!ft_fiq_mem_base) { + ft_fiq_mem_phy = res.a1; + ft_fiq_mem_base = ioremap(ft_fiq_mem_phy, + FIQ_UARTDBG_SHARE_MEM_SIZE); + if (!ft_fiq_mem_base) { + pr_err("%s: share memory ioremap failed\n", __func__); + return -ENOMEM; + } + } + + fiq_sip_enabled = 1; + + return SIP_RET_SUCCESS; } -u32 psci_fiq_debugger_switch_cpu(u32 cpu) +int sip_fiq_debugger_switch_cpu(u32 cpu) { - struct arm_smccc_res sip_smmc; + struct arm_smccc_res res; - sip_smmc = __invoke_sip_fn_smc(PSCI_SIP_UARTDBG_CFG64, - cpu_logical_map(cpu), - 0, UARTDBG_CFG_OSHDL_CPUSW); - return sip_smmc.a0; + fiq_target_cpu = cpu; + res = __invoke_sip_fn_smc(SIP_UARTDBG_FN, cpu_logical_map(cpu), + 0, UARTDBG_CFG_OSHDL_CPUSW); + return res.a0; } -void psci_fiq_debugger_enable_debug(bool val) +void sip_fiq_debugger_enable_debug(bool enable) { - if (val) - __invoke_sip_fn_smc(PSCI_SIP_UARTDBG_CFG64, 0, - 0, UARTDBG_CFG_OSHDL_DEBUG_ENABLE); - else - __invoke_sip_fn_smc(PSCI_SIP_UARTDBG_CFG64, 0, - 0, UARTDBG_CFG_OSHDL_DEBUG_DISABLE); + unsigned long val; + + val = enable ? UARTDBG_CFG_OSHDL_DEBUG_ENABLE : + UARTDBG_CFG_OSHDL_DEBUG_DISABLE; + + __invoke_sip_fn_smc(SIP_UARTDBG_FN, 0, 0, val); } -int psci_fiq_debugger_set_print_port(u32 port, u32 baudrate) +int sip_fiq_debugger_set_print_port(u32 port_phyaddr, u32 baudrate) { struct arm_smccc_res res; - res = __invoke_sip_fn_smc(PSCI_SIP_UARTDBG_CFG64, port, baudrate, + res = __invoke_sip_fn_smc(SIP_UARTDBG_FN, port_phyaddr, baudrate, UARTDBG_CFG_PRINT_PORT); return res.a0; } -struct arm_smccc_res sip_smc_get_share_mem_page(u32 page_num, - share_page_type_t page_type) +int sip_fiq_debugger_request_share_memory(void) { struct arm_smccc_res res; - unsigned long share_mem_phy; - res = __invoke_sip_fn_smc(SIP_SHARE_MEM32, page_num, page_type, 0); - if (res.a0) - goto error; + /* request page share memory */ + res = sip_smc_request_share_mem(FIQ_UARTDBG_PAGE_NUMS, + SHARE_PAGE_TYPE_UARTDBG); + if (IS_SIP_ERROR(res.a0)) + return res.a0; - share_mem_phy = res.a1; - res.a1 = (unsigned long)ioremap(share_mem_phy, SIZE_PAGE(page_num)); + return SIP_RET_SUCCESS; +} -error: - return res; +int sip_fiq_debugger_get_target_cpu(void) +{ + return fiq_target_cpu; } -struct arm_smccc_res sip_smc_get_call_count(void) +void sip_fiq_debugger_enable_fiq(bool enable, uint32_t tgt_cpu) { - return __invoke_sip_fn_smc(SIP_SVC_CALL_COUNT, 0, 0, 0); + u32 en; + + fiq_target_cpu = tgt_cpu; + en = enable ? UARTDBG_CFG_FIQ_ENABEL : UARTDBG_CFG_FIQ_DISABEL; + __invoke_sip_fn_smc(SIP_UARTDBG_FN, tgt_cpu, 0, en); } + diff --git a/drivers/soc/rockchip/rockchip_pm_config.c b/drivers/soc/rockchip/rockchip_pm_config.c index ac6d9977697a..43b2e0f33343 100644 --- a/drivers/soc/rockchip/rockchip_pm_config.c +++ b/drivers/soc/rockchip/rockchip_pm_config.c @@ -106,7 +106,7 @@ static void rockchip_pm_virt_pwroff_prepare(void) } sip_smc_set_suspend_mode(VIRTUAL_POWEROFF, 0, 1); - rk_psci_virtual_poweroff(); + sip_smc_virtual_poweroff(); } static int __init pm_config_init(struct platform_device *pdev) diff --git a/include/linux/rockchip/rockchip_sip.h b/include/linux/rockchip/rockchip_sip.h index 27b35463a604..c9265cb91b28 100644 --- a/include/linux/rockchip/rockchip_sip.h +++ b/include/linux/rockchip/rockchip_sip.h @@ -15,60 +15,55 @@ #include #include -/* SMC function IDs for SiP Service queries */ -#define SIP_SVC_CALL_COUNT 0x8200ff00 -#define SIP_SVC_UID 0x8200ff01 -#define SIP_SVC_VERSION 0x8200ff03 - -#define SIP_ATF_VERSION32 0x82000001 +/* SMC function IDs for SiP Service queries, compatible with kernel-3.10 */ +#define SIP_ATF_VERSION 0x82000001 #define SIP_ACCESS_REG 0x82000002 -#define SIP_SUSPEND_MODE32 0x82000003 -#define SIP_DDR_CFG32 0x82000008 -#define SIP_SHARE_MEM32 0x82000009 -#define SIP_SIP_VERSION32 0x8200000a +#define SIP_SUSPEND_MODE 0x82000003 +#define SIP_PENDING_CPUS 0x82000004 +#define SIP_UARTDBG_CFG 0x82000005 +#define SIP_UARTDBG_CFG64 0xc2000005 +#define SIP_MCU_EL3FIQ_CFG 0x82000006 +#define SIP_ACCESS_CHIP_STATE64 0xc2000006 +#define SIP_SECURE_MEM_CONFIG 0x82000007 +#define SIP_ACCESS_CHIP_EXTRA_STATE64 0xc2000007 +#define SIP_DDR_CFG 0x82000008 +#define SIP_SHARE_MEM 0x82000009 +#define SIP_SIP_VERSION 0x8200000a +#define SIP_REMOTECTL_CFG 0x8200000b + +/* Trust firmware version */ +#define ATF_VER_MAJOR(ver) (((ver) >> 16) & 0xffff) +#define ATF_VER_MINOR(ver) (((ver) >> 0) & 0xffff) -/* SIP_ACCESS_REG read/write */ +/* SIP_ACCESS_REG: read or write */ #define SECURE_REG_RD 0x0 #define SECURE_REG_WR 0x1 -/* Share mem page types */ -typedef enum { - SHARE_PAGE_TYPE_INVALID = 0, - SHARE_PAGE_TYPE_UARTDBG, - SHARE_PAGE_TYPE_MAX, -} share_page_type_t; +/* Fiq debugger share memory: 8KB enough */ +#define FIQ_UARTDBG_PAGE_NUMS 2 +#define FIQ_UARTDBG_SHARE_MEM_SIZE ((FIQ_UARTDBG_PAGE_NUMS) * 4096) /* Error return code */ -#define SIP_RET_SUCCESS 0 -#define SIP_RET_NOT_SUPPORTED -1 -#define SIP_RET_INVALID_PARAMS -2 -#define SIP_RET_INVALID_ADDRESS -3 -#define SIP_RET_DENIED -4 -#define SIP_RET_SMC_UNKNOWN 0xffffffff +#define IS_SIP_ERROR(x) (!!(x)) -/* Sip version */ -#define SIP_IMPLEMENT_V1 (1) -#define SIP_IMPLEMENT_V2 (2) - -#define RK_SIP_DISABLE_FIQ 0xc2000006 -#define RK_SIP_ENABLE_FIQ 0xc2000007 -#define PSCI_SIP_RKTF_VER 0x82000001 -#define PSCI_SIP_ACCESS_REG 0x82000002 -#define PSCI_SIP_ACCESS_REG64 0xc2000002 -#define PSCI_SIP_SUSPEND_WR_CTRBITS 0x82000003 -#define PSCI_SIP_PENDING_CPUS 0x82000004 -#define PSCI_SIP_UARTDBG_CFG 0x82000005 -#define PSCI_SIP_UARTDBG_CFG64 0xc2000005 -#define PSCI_SIP_EL3FIQ_CFG 0x82000006 -#define PSCI_SIP_SMEM_CONFIG 0x82000007 +#define SIP_RET_SUCCESS 0 +#define SIP_RET_SMC_UNKNOWN -1 +#define SIP_RET_NOT_SUPPORTED -2 +#define SIP_RET_INVALID_PARAMS -3 +#define SIP_RET_INVALID_ADDRESS -4 +#define SIP_RET_DENIED -5 +/* SIP_UARTDBG_CFG64 call types */ #define UARTDBG_CFG_INIT 0xf0 #define UARTDBG_CFG_OSHDL_TO_OS 0xf1 #define UARTDBG_CFG_OSHDL_CPUSW 0xf3 #define UARTDBG_CFG_OSHDL_DEBUG_ENABLE 0xf4 #define UARTDBG_CFG_OSHDL_DEBUG_DISABLE 0xf5 #define UARTDBG_CFG_PRINT_PORT 0xf7 +#define UARTDBG_CFG_FIQ_ENABEL 0xf8 +#define UARTDBG_CFG_FIQ_DISABEL 0xf9 +/* SIP_SUSPEND_MODE32 call types */ #define SUSPEND_MODE_CONFIG 0x01 #define WKUP_SOURCE_CONFIG 0x02 #define PWM_REGULATOR_CONFIG 0x03 @@ -77,34 +72,85 @@ typedef enum { #define APIOS_SUSPEND_CONFIG 0x06 #define VIRTUAL_POWEROFF 0x07 -/* struct arm_smccc_res: a0: error code; a1~a3: data */ -/* SMC32 Calls */ -int sip_smc_set_suspend_mode(u32 ctrl, - u32 config1, - u32 config2); -int rk_psci_virtual_poweroff(void); +/* SIP_REMOTECTL_CFG call types */ +#define REMOTECTL_SET_IRQ 0xf0 +#define REMOTECTL_SET_PWM_CH 0xf1 +#define REMOTECTL_SET_PWRKEY 0xf2 +#define REMOTECTL_GET_WAKEUP_STATE 0xf3 +#define REMOTECTL_ENABLE 0xf4 +/* wakeup state */ +#define REMOTECTL_PWRKEY_WAKEUP 0xdeadbeaf -struct arm_smccc_res sip_smc_get_call_count(void); +/* Share mem page types */ +typedef enum { + SHARE_PAGE_TYPE_INVALID = 0, + SHARE_PAGE_TYPE_UARTDBG, + SHARE_PAGE_TYPE_MAX, +} share_page_type_t; + +/* + * Rules: struct arm_smccc_res contains result and data, details: + * + * a0: error code(0: success, !0: error); + * a1~a3: data + */ struct arm_smccc_res sip_smc_get_atf_version(void); struct arm_smccc_res sip_smc_get_sip_version(void); -struct arm_smccc_res sip_smc_ddr_cfg(u32 arg0, u32 arg1, - u32 arg2); -struct arm_smccc_res sip_smc_get_share_mem_page(u32 page_num, - share_page_type_t page_type); +struct arm_smccc_res sip_smc_ddr_cfg(u32 arg0, u32 arg1, u32 arg2); +struct arm_smccc_res sip_smc_request_share_mem(u32 page_num, + share_page_type_t page_type); +struct arm_smccc_res sip_smc_mcu_el3fiq(u32 arg0, u32 arg1, u32 arg2); + +int sip_smc_set_suspend_mode(u32 ctrl, u32 config1, u32 config2); +int sip_smc_virtual_poweroff(void); #ifdef CONFIG_ROCKCHIP_SIP -u32 sip_smc_secure_reg_read(u32 addr_phy); int sip_smc_secure_reg_write(u32 addr_phy, u32 val); +u32 sip_smc_secure_reg_read(u32 addr_phy); #else u32 sip_smc_secure_reg_read(u32 addr_phy) { return 0; } int sip_smc_secure_reg_write(u32 addr_phy, u32 val) { return 0; } #endif +/***************************fiq debugger **************************************/ +void sip_fiq_debugger_enable_fiq(bool enable, uint32_t tgt_cpu); +void sip_fiq_debugger_enable_debug(bool enable); +int sip_fiq_debugger_uart_irq_tf_init(u32 irq_id, void *callback_fn); +int sip_fiq_debugger_set_print_port(u32 port_phyaddr, u32 baudrate); +int sip_fiq_debugger_request_share_memory(void); +int sip_fiq_debugger_get_target_cpu(void); +int sip_fiq_debugger_switch_cpu(u32 cpu); +int sip_fiq_debugger_is_enabled(void); -void psci_enable_fiq(void); -u32 rockchip_psci_smc_get_tf_ver(void); -void psci_fiq_debugger_uart_irq_tf_cb(u64 sp_el1, u64 offset); -void psci_fiq_debugger_uart_irq_tf_init(u32 irq_id, void *callback); -u32 psci_fiq_debugger_switch_cpu(u32 cpu); -void psci_fiq_debugger_enable_debug(bool val); -int psci_fiq_debugger_set_print_port(u32 port, u32 baudrate); +/* optee cpu_context */ +struct sm_nsec_ctx { + u32 usr_sp; + u32 usr_lr; + u32 irq_spsr; + u32 irq_sp; + u32 irq_lr; + u32 svc_spsr; + u32 svc_sp; + u32 svc_lr; + u32 abt_spsr; + u32 abt_sp; + u32 abt_lr; + u32 und_spsr; + u32 und_sp; + u32 und_lr; + u32 mon_lr; + u32 mon_spsr; + u32 r4; + u32 r5; + u32 r6; + u32 r7; + u32 r8; + u32 r9; + u32 r10; + u32 r11; + u32 r12; + u32 r0; + u32 r1; + u32 r2; + u32 r3; +}; #endif -- 2.34.1