From: Jianhong Chen Date: Thu, 29 Sep 2016 12:14:36 +0000 (+0800) Subject: firmware: rockchip: sip: add rockchip SIP runtime service X-Git-Tag: firefly_0821_release~1333 X-Git-Url: http://plrg.eecs.uci.edu/git/?p=firefly-linux-kernel-4.4.55.git;a=commitdiff_plain;h=a3bb010cad4b9f505208d712195602f43e9b34af firmware: rockchip: sip: add rockchip SIP runtime service Change-Id: I996a90b3f6cb471f255566dfab0059a55da8866d Signed-off-by: Jianhong Chen --- diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index f67f35b6edb1..224605d3d7a2 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -30,6 +30,10 @@ #include #include +#ifdef CONFIG_FIQ_DEBUGGER_EL3_TO_EL1 +#include +#endif + static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state); static int __maybe_unused cpu_psci_cpu_init_idle(unsigned int cpu) @@ -202,6 +206,9 @@ static int __maybe_unused cpu_psci_cpu_suspend(unsigned long index) else ret = cpu_suspend(index, psci_suspend_finisher); +#ifdef CONFIG_FIQ_DEBUGGER_EL3_TO_EL1 + psci_enable_fiq(); +#endif return ret; } diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 49a3a1185bb6..1067fe907d9b 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -176,6 +176,13 @@ config QCOM_SCM_64 config HAVE_ARM_SMCCC bool +config ROCKCHIP_SIP + bool "Rockchip SIP interface" + depends on ARM64 && ARM_PSCI_FW + help + Say Y here if you want to enable SIP callbacks for Rockchip platforms + This option enables support for communicating with the ATF. + source "drivers/firmware/broadcom/Kconfig" source "drivers/firmware/google/Kconfig" source "drivers/firmware/efi/Kconfig" diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 48dd4175297e..3bc545b7fbbe 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -23,3 +23,4 @@ obj-y += broadcom/ obj-$(CONFIG_GOOGLE_FIRMWARE) += google/ obj-$(CONFIG_EFI) += efi/ obj-$(CONFIG_UEFI_CPER) += efi/ +obj-$(CONFIG_ROCKCHIP_SIP) += rockchip_sip.o diff --git a/drivers/firmware/rockchip_sip.c b/drivers/firmware/rockchip_sip.c new file mode 100644 index 000000000000..f1d7e0cd981d --- /dev/null +++ b/drivers/firmware/rockchip_sip.c @@ -0,0 +1,155 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Copyright (C) 2016, Fuzhou Rockchip Electronics Co., Ltd + */ + +#include +#include +#include +#include +#include +#include + +#define SIZE_PAGE(n) ((n) << 12) + +static struct arm_smccc_res __invoke_sip_fn_smc(unsigned long function_id, + unsigned long arg0, + unsigned long arg1, + unsigned long arg2) +{ + struct arm_smccc_res res; + + arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); + return res; +} + +struct arm_smccc_res sip_smc_ddr_cfg(uint32_t arg0, uint32_t arg1, + uint32_t arg2) +{ + return __invoke_sip_fn_smc(SIP_DDR_CFG32, arg0, arg1, arg2); +} + +struct arm_smccc_res sip_smc_get_atf_version(void) +{ + return __invoke_sip_fn_smc(SIP_ATF_VERSION32, 0, 0, 0); +} + +struct arm_smccc_res sip_smc_get_sip_version(void) +{ + return __invoke_sip_fn_smc(SIP_SIP_VERSION32, 0, 0, 0); +} + +int sip_smc_set_suspend_mode(uint32_t mode) +{ + struct arm_smccc_res res; + + res = __invoke_sip_fn_smc(SIP_SUSPEND_MODE32, mode, 0, 0); + + return res.a0; +} + +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 res; + + arm_smccc_smc(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0, 0, 0, 0, 0, &res); + return 0x00010005; +} + +void psci_fiq_debugger_uart_irq_tf_cb(u64 sp_el1, u64 offset) +{ + 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); +} + +void psci_fiq_debugger_uart_irq_tf_init(u32 irq_id, void *callback) +{ + struct arm_smccc_res sip_smmc; + + psci_fiq_debugger_uart_irq_tf = callback; + sip_smmc = __invoke_sip_fn_smc(PSCI_SIP_UARTDBG_CFG64, irq_id, + (u64)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; +} + +void psci_enable_fiq(void) +{ + int irq_flag; + int cpu_id; + + if (fig_init_flag != 1) + return; + irq_flag = *((char *)(ft_fiq_mem_base) + 8 * 1024 - 0x04); + + 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); +} + +u32 psci_fiq_debugger_switch_cpu(u32 cpu) +{ + struct arm_smccc_res sip_smmc; + + sip_smmc = __invoke_sip_fn_smc(PSCI_SIP_UARTDBG_CFG64, + cpu_logical_map(cpu), + 0, UARTDBG_CFG_OSHDL_CPUSW); + return sip_smmc.a0; +} + +void psci_fiq_debugger_enable_debug(bool val) +{ + 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); +} + +int psci_fiq_debugger_set_print_port(u32 port, u32 baudrate) +{ + struct arm_smccc_res res; + + res = __invoke_sip_fn_smc(PSCI_SIP_UARTDBG_CFG64, port, 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) +{ + 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; + + share_mem_phy = res.a1; + res.a1 = (unsigned long)ioremap(share_mem_phy, SIZE_PAGE(page_num)); + +error: + return res; +} + +struct arm_smccc_res sip_smc_get_call_count(void) +{ + return __invoke_sip_fn_smc(SIP_SVC_CALL_COUNT, 0, 0, 0); +} diff --git a/include/linux/rockchip/rockchip_sip.h b/include/linux/rockchip/rockchip_sip.h new file mode 100644 index 000000000000..8740a058772c --- /dev/null +++ b/include/linux/rockchip/rockchip_sip.h @@ -0,0 +1,86 @@ +/* Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __ROCKCHIP_SIP_H +#define __ROCKCHIP_SIP_H + +#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 +#define SIP_SUSPEND_MODE32 0x82000003 +#define SIP_DDR_CFG32 0x82000008 +#define SIP_SHARE_MEM32 0x82000009 +#define SIP_SIP_VERSION32 0x8200000a + +/* Share mem page types */ +typedef enum { + SHARE_PAGE_TYPE_INVALID = 0, + SHARE_PAGE_TYPE_UARTDBG, + SHARE_PAGE_TYPE_MAX, +} share_page_type_t; + +/* 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 + +/* 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 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 + +/* struct arm_smccc_res: a0: error code; a1~a3: data */ +/* SMC32 Calls */ +int sip_smc_set_suspend_mode(uint32_t mode); +struct arm_smccc_res sip_smc_get_call_count(void); +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(uint32_t arg0, uint32_t arg1, + uint32_t arg2); +struct arm_smccc_res sip_smc_get_share_mem_page(uint32_t page_num, + share_page_type_t page_type); + +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); + +#endif