firmware: rockchip: sip: add rockchip SIP runtime service

Change-Id: I996a90b3f6cb471f255566dfab0059a55da8866d
Signed-off-by: Jianhong Chen <chenjh@rock-chips.com>
This commit is contained in:
Jianhong Chen 2016-09-29 20:14:36 +08:00 committed by Huang, Tao
parent 2c21d4842f
commit a3bb010cad
5 changed files with 256 additions and 0 deletions

View File

@ -30,6 +30,10 @@
#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;
}

View 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"

View 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

View File

@ -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);
}

View File

@ -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