firmware: rockchip: sip: add rockchip SIP runtime service
authorJianhong Chen <chenjh@rock-chips.com>
Thu, 29 Sep 2016 12:14:36 +0000 (20:14 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Wed, 2 Nov 2016 01:41:22 +0000 (09:41 +0800)
Change-Id: I996a90b3f6cb471f255566dfab0059a55da8866d
Signed-off-by: Jianhong Chen <chenjh@rock-chips.com>
arch/arm64/kernel/psci.c
drivers/firmware/Kconfig
drivers/firmware/Makefile
drivers/firmware/rockchip_sip.c [new file with mode: 0644]
include/linux/rockchip/rockchip_sip.h [new file with mode: 0644]

index f67f35b6edb12e4d34e1db17750b07a0bec72e39..224605d3d7a29a49dcc2b5f3e09f3021d03ae906 100644 (file)
 #include <asm/smp_plat.h>
 #include <asm/suspend.h>
 
+#ifdef CONFIG_FIQ_DEBUGGER_EL3_TO_EL1
+#include <linux/rockchip/rockchip_sip.h>
+#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;
 }
 
index 49a3a1185bb607ed45297fe4dea5ff2c6344f37f..1067fe907d9b9e3978a351bd50b9ce05b03591fb 100644 (file)
@@ -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"
index 48dd4175297e6cb24151fab67e4c822c940ddf5c..3bc545b7fbbecc69464df43acc3c3231bd024322 100644 (file)
@@ -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 (file)
index 0000000..f1d7e0c
--- /dev/null
@@ -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 <linux/arm-smccc.h>
+#include <linux/io.h>
+#include <linux/rockchip/rockchip_sip.h>
+#include <asm/cputype.h>
+#include <asm/smp_plat.h>
+#include <uapi/linux/psci.h>
+
+#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 (file)
index 0000000..8740a05
--- /dev/null
@@ -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 <linux/arm-smccc.h>
+#include <linux/io.h>
+
+/* 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