[HACK] Copy in Rockchip suspend mode driver
This is needed for suspend with the BSP TF-A.
Signed-off-by: Samuel Holland <samuel@sholland.org>
Signed-off-by: Maximilian Weigand <mweigand@mweigand.net>
---
original commit: b97e1e9f39
This commit is contained in:
parent
43775c97dd
commit
715641d84e
9 changed files with 1265 additions and 0 deletions
|
@ -6,6 +6,7 @@
|
||||||
#include <dt-bindings/leds/common.h>
|
#include <dt-bindings/leds/common.h>
|
||||||
#include <dt-bindings/pinctrl/rockchip.h>
|
#include <dt-bindings/pinctrl/rockchip.h>
|
||||||
#include <dt-bindings/usb/pd.h>
|
#include <dt-bindings/usb/pd.h>
|
||||||
|
#include <dt-bindings/suspend/rockchip-rk3568.h>
|
||||||
|
|
||||||
#include "rk3566.dtsi"
|
#include "rk3566.dtsi"
|
||||||
|
|
||||||
|
@ -132,6 +133,28 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
rockchip-suspend {
|
||||||
|
compatible = "rockchip,pm-rk3568";
|
||||||
|
status = "okay";
|
||||||
|
rockchip,sleep-debug-en = <0>;
|
||||||
|
rockchip,sleep-mode-config = <
|
||||||
|
(0
|
||||||
|
| RKPM_SLP_CENTER_OFF
|
||||||
|
| RKPM_SLP_ARMOFF_LOGOFF
|
||||||
|
| RKPM_SLP_PMIC_LP
|
||||||
|
| RKPM_SLP_HW_PLLS_OFF
|
||||||
|
| RKPM_SLP_PMUALIVE_32K
|
||||||
|
| RKPM_SLP_OSC_DIS
|
||||||
|
| RKPM_SLP_32K_PVTM
|
||||||
|
)
|
||||||
|
>;
|
||||||
|
rockchip,wakeup-config = <
|
||||||
|
(0
|
||||||
|
| RKPM_GPIO_WKUP_EN
|
||||||
|
)
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
|
||||||
sdio_pwrseq: sdio-pwrseq {
|
sdio_pwrseq: sdio-pwrseq {
|
||||||
compatible = "mmc-pwrseq-simple";
|
compatible = "mmc-pwrseq-simple";
|
||||||
clocks = <&rk817 1>;
|
clocks = <&rk817 1>;
|
||||||
|
|
|
@ -179,6 +179,13 @@ config MTK_ADSP_IPC
|
||||||
ADSP exists on some mtk processors.
|
ADSP exists on some mtk processors.
|
||||||
Client might use shared memory to exchange information with ADSP.
|
Client might use shared memory to exchange information with ADSP.
|
||||||
|
|
||||||
|
config ROCKCHIP_SIP
|
||||||
|
tristate "Rockchip SIP interface"
|
||||||
|
depends on HAVE_ARM_SMCCC && ARCH_ROCKCHIP
|
||||||
|
help
|
||||||
|
Say Y here if you want to enable SIP callbacks for Rockchip platforms
|
||||||
|
This option enables support for communicating with the ATF.
|
||||||
|
|
||||||
config SYSFB
|
config SYSFB
|
||||||
bool
|
bool
|
||||||
select BOOT_VESA_SUPPORT
|
select BOOT_VESA_SUPPORT
|
||||||
|
|
|
@ -16,6 +16,7 @@ obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
|
||||||
obj-$(CONFIG_MTK_ADSP_IPC) += mtk-adsp-ipc.o
|
obj-$(CONFIG_MTK_ADSP_IPC) += mtk-adsp-ipc.o
|
||||||
obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o
|
obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o
|
||||||
obj-$(CONFIG_FW_CFG_SYSFS) += qemu_fw_cfg.o
|
obj-$(CONFIG_FW_CFG_SYSFS) += qemu_fw_cfg.o
|
||||||
|
obj-$(CONFIG_ROCKCHIP_SIP) += rockchip_sip.o
|
||||||
obj-$(CONFIG_SYSFB) += sysfb.o
|
obj-$(CONFIG_SYSFB) += sysfb.o
|
||||||
obj-$(CONFIG_SYSFB_SIMPLEFB) += sysfb_simplefb.o
|
obj-$(CONFIG_SYSFB_SIMPLEFB) += sysfb_simplefb.o
|
||||||
obj-$(CONFIG_TH1520_AON_PROTOCOL) += thead,th1520-aon.o
|
obj-$(CONFIG_TH1520_AON_PROTOCOL) += thead,th1520-aon.o
|
||||||
|
|
546
drivers/firmware/rockchip_sip.c
Normal file
546
drivers/firmware/rockchip_sip.c
Normal file
|
@ -0,0 +1,546 @@
|
||||||
|
/*
|
||||||
|
* 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/module.h>
|
||||||
|
#include <linux/rockchip/rockchip_sip.h>
|
||||||
|
#include <asm/cputype.h>
|
||||||
|
#ifdef CONFIG_ARM
|
||||||
|
#include <asm/psci.h>
|
||||||
|
#endif
|
||||||
|
#include <asm/smp_plat.h>
|
||||||
|
#include <uapi/linux/psci.h>
|
||||||
|
#include <linux/ptrace.h>
|
||||||
|
#include <linux/sched/clock.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_64BIT
|
||||||
|
#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN64_##name
|
||||||
|
#else
|
||||||
|
#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN_##name
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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_dram(u32 arg0, u32 arg1, u32 arg2)
|
||||||
|
{
|
||||||
|
return __invoke_sip_fn_smc(SIP_DRAM_CONFIG, arg0, arg1, arg2);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sip_smc_dram);
|
||||||
|
|
||||||
|
struct arm_smccc_res sip_smc_get_atf_version(void)
|
||||||
|
{
|
||||||
|
return __invoke_sip_fn_smc(SIP_ATF_VERSION, 0, 0, 0);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sip_smc_get_atf_version);
|
||||||
|
|
||||||
|
struct arm_smccc_res sip_smc_get_sip_version(void)
|
||||||
|
{
|
||||||
|
return __invoke_sip_fn_smc(SIP_SIP_VERSION, 0, 0, 0);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sip_smc_get_sip_version);
|
||||||
|
|
||||||
|
int sip_smc_set_suspend_mode(u32 ctrl, u32 config1, u32 config2)
|
||||||
|
{
|
||||||
|
struct arm_smccc_res res;
|
||||||
|
|
||||||
|
res = __invoke_sip_fn_smc(SIP_SUSPEND_MODE, ctrl, config1, config2);
|
||||||
|
return res.a0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sip_smc_set_suspend_mode);
|
||||||
|
|
||||||
|
struct arm_smccc_res sip_smc_get_suspend_info(u32 info)
|
||||||
|
{
|
||||||
|
struct arm_smccc_res res;
|
||||||
|
|
||||||
|
res = __invoke_sip_fn_smc(SIP_SUSPEND_MODE, info, 0, 0);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sip_smc_get_suspend_info);
|
||||||
|
|
||||||
|
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);
|
||||||
|
return res.a0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sip_smc_virtual_poweroff);
|
||||||
|
|
||||||
|
int sip_smc_remotectl_config(u32 func, u32 data)
|
||||||
|
{
|
||||||
|
struct arm_smccc_res res;
|
||||||
|
|
||||||
|
res = __invoke_sip_fn_smc(SIP_REMOTECTL_CFG, func, data, 0);
|
||||||
|
|
||||||
|
return res.a0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sip_smc_remotectl_config);
|
||||||
|
|
||||||
|
u32 sip_smc_secure_reg_read(u32 addr_phy)
|
||||||
|
{
|
||||||
|
struct arm_smccc_res res;
|
||||||
|
|
||||||
|
res = __invoke_sip_fn_smc(SIP_ACCESS_REG, 0, addr_phy, SECURE_REG_RD);
|
||||||
|
if (res.a0)
|
||||||
|
pr_err("%s error: %d, addr phy: 0x%x\n",
|
||||||
|
__func__, (int)res.a0, addr_phy);
|
||||||
|
|
||||||
|
return res.a1;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sip_smc_secure_reg_read);
|
||||||
|
|
||||||
|
int sip_smc_secure_reg_write(u32 addr_phy, u32 val)
|
||||||
|
{
|
||||||
|
struct arm_smccc_res res;
|
||||||
|
|
||||||
|
res = __invoke_sip_fn_smc(SIP_ACCESS_REG, val, addr_phy, SECURE_REG_WR);
|
||||||
|
if (res.a0)
|
||||||
|
pr_err("%s error: %d, addr phy: 0x%x\n",
|
||||||
|
__func__, (int)res.a0, addr_phy);
|
||||||
|
|
||||||
|
return res.a0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sip_smc_secure_reg_write);
|
||||||
|
|
||||||
|
static void *sip_map(phys_addr_t start, size_t size)
|
||||||
|
{
|
||||||
|
struct page **pages;
|
||||||
|
phys_addr_t page_start;
|
||||||
|
unsigned int page_count;
|
||||||
|
pgprot_t prot;
|
||||||
|
unsigned int i;
|
||||||
|
void *vaddr;
|
||||||
|
|
||||||
|
if (!pfn_valid(__phys_to_pfn(start)))
|
||||||
|
return ioremap(start, size);
|
||||||
|
|
||||||
|
page_start = start - offset_in_page(start);
|
||||||
|
page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE);
|
||||||
|
|
||||||
|
prot = pgprot_noncached(PAGE_KERNEL);
|
||||||
|
|
||||||
|
pages = kmalloc_array(page_count, sizeof(struct page *), GFP_KERNEL);
|
||||||
|
if (!pages) {
|
||||||
|
pr_err("%s: Failed to allocate array for %u pages\n",
|
||||||
|
__func__, page_count);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < page_count; i++)
|
||||||
|
pages[i] = phys_to_page(page_start + i * PAGE_SIZE);
|
||||||
|
|
||||||
|
vaddr = vmap(pages, page_count, VM_MAP, prot);
|
||||||
|
kfree(pages);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since vmap() uses page granularity, we must add the offset
|
||||||
|
* into the page here, to get the byte granularity address
|
||||||
|
* into the mapping to represent the actual "start" location.
|
||||||
|
*/
|
||||||
|
return vaddr + offset_in_page(start);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)sip_map(share_mem_phy, SIZE_PAGE(page_num));
|
||||||
|
|
||||||
|
error:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sip_smc_request_share_mem);
|
||||||
|
|
||||||
|
struct arm_smccc_res sip_smc_mcu_el3fiq(u32 arg0, u32 arg1, u32 arg2)
|
||||||
|
{
|
||||||
|
return __invoke_sip_fn_smc(SIP_MCU_EL3FIQ_CFG, arg0, arg1, arg2);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sip_smc_mcu_el3fiq);
|
||||||
|
|
||||||
|
struct arm_smccc_res sip_smc_vpu_reset(u32 arg0, u32 arg1, u32 arg2)
|
||||||
|
{
|
||||||
|
struct arm_smccc_res res;
|
||||||
|
|
||||||
|
res = __invoke_sip_fn_smc(PSCI_SIP_VPU_RESET, arg0, arg1, arg2);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sip_smc_vpu_reset);
|
||||||
|
|
||||||
|
struct arm_smccc_res sip_smc_bus_config(u32 arg0, u32 arg1, u32 arg2)
|
||||||
|
{
|
||||||
|
struct arm_smccc_res res;
|
||||||
|
|
||||||
|
res = __invoke_sip_fn_smc(SIP_BUS_CFG, arg0, arg1, arg2);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sip_smc_bus_config);
|
||||||
|
|
||||||
|
struct arm_smccc_res sip_smc_lastlog_request(void)
|
||||||
|
{
|
||||||
|
struct arm_smccc_res res;
|
||||||
|
void __iomem *addr1, *addr2;
|
||||||
|
|
||||||
|
res = __invoke_sip_fn_smc(SIP_LAST_LOG, local_clock(), 0, 0);
|
||||||
|
if (IS_SIP_ERROR(res.a0))
|
||||||
|
return res;
|
||||||
|
|
||||||
|
addr1 = sip_map(res.a1, res.a3);
|
||||||
|
if (!addr1) {
|
||||||
|
pr_err("%s: share memory buffer0 ioremap failed\n", __func__);
|
||||||
|
res.a0 = SIP_RET_INVALID_ADDRESS;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
addr2 = sip_map(res.a2, res.a3);
|
||||||
|
if (!addr2) {
|
||||||
|
pr_err("%s: share memory buffer1 ioremap failed\n", __func__);
|
||||||
|
res.a0 = SIP_RET_INVALID_ADDRESS;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.a1 = (unsigned long)addr1;
|
||||||
|
res.a2 = (unsigned long)addr2;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sip_smc_lastlog_request);
|
||||||
|
|
||||||
|
/************************** fiq debugger **************************************/
|
||||||
|
/*
|
||||||
|
* AArch32 is not allowed to call SMC64(ATF framework does not support), so we
|
||||||
|
* don't change SIP_UARTDBG_FN to SIP_UARTDBG_CFG64 even when cpu is AArch32
|
||||||
|
* mode. Let ATF support SIP_UARTDBG_CFG, and we just initialize SIP_UARTDBG_FN
|
||||||
|
* depends on compile option(CONFIG_ARM or CONFIG_ARM64).
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_ARM64
|
||||||
|
#define SIP_UARTDBG_FN SIP_UARTDBG_CFG64
|
||||||
|
#else
|
||||||
|
#define SIP_UARTDBG_FN SIP_UARTDBG_CFG
|
||||||
|
static int firmware_64_32bit;
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
return fiq_sip_enabled;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sip_fiq_debugger_is_enabled);
|
||||||
|
|
||||||
|
static struct pt_regs sip_fiq_debugger_get_pt_regs(void *reg_base,
|
||||||
|
unsigned long sp_el1)
|
||||||
|
{
|
||||||
|
struct pt_regs fiq_pt_regs;
|
||||||
|
__maybe_unused struct sm_nsec_ctx *nsec_ctx = reg_base;
|
||||||
|
__maybe_unused struct gp_regs_ctx *gp_regs = reg_base;
|
||||||
|
|
||||||
|
#ifdef CONFIG_ARM64
|
||||||
|
/*
|
||||||
|
* 64-bit ATF + 64-bit kernel
|
||||||
|
*/
|
||||||
|
/* copy cpu context: x0 ~ spsr_el3 */
|
||||||
|
memcpy(&fiq_pt_regs, reg_base, 8 * 31);
|
||||||
|
|
||||||
|
/* copy pstate: spsr_el3 */
|
||||||
|
memcpy(&fiq_pt_regs.pstate, reg_base + 0x110, 8);
|
||||||
|
fiq_pt_regs.sp = sp_el1;
|
||||||
|
|
||||||
|
/* copy pc: elr_el3 */
|
||||||
|
memcpy(&fiq_pt_regs.pc, reg_base + 0x118, 8);
|
||||||
|
#else
|
||||||
|
if (firmware_64_32bit == FIRMWARE_ATF_64BIT) {
|
||||||
|
/*
|
||||||
|
* 64-bit ATF + 32-bit kernel
|
||||||
|
*/
|
||||||
|
fiq_pt_regs.ARM_r0 = gp_regs->x0;
|
||||||
|
fiq_pt_regs.ARM_r1 = gp_regs->x1;
|
||||||
|
fiq_pt_regs.ARM_r2 = gp_regs->x2;
|
||||||
|
fiq_pt_regs.ARM_r3 = gp_regs->x3;
|
||||||
|
fiq_pt_regs.ARM_r4 = gp_regs->x4;
|
||||||
|
fiq_pt_regs.ARM_r5 = gp_regs->x5;
|
||||||
|
fiq_pt_regs.ARM_r6 = gp_regs->x6;
|
||||||
|
fiq_pt_regs.ARM_r7 = gp_regs->x7;
|
||||||
|
fiq_pt_regs.ARM_r8 = gp_regs->x8;
|
||||||
|
fiq_pt_regs.ARM_r9 = gp_regs->x9;
|
||||||
|
fiq_pt_regs.ARM_r10 = gp_regs->x10;
|
||||||
|
fiq_pt_regs.ARM_fp = gp_regs->x11;
|
||||||
|
fiq_pt_regs.ARM_ip = gp_regs->x12;
|
||||||
|
fiq_pt_regs.ARM_sp = gp_regs->x19; /* aarch32 svc_r13 */
|
||||||
|
fiq_pt_regs.ARM_lr = gp_regs->x18; /* aarch32 svc_r14 */
|
||||||
|
fiq_pt_regs.ARM_cpsr = gp_regs->spsr_el3;
|
||||||
|
fiq_pt_regs.ARM_pc = gp_regs->elr_el3;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* 32-bit tee firmware + 32-bit kernel
|
||||||
|
*/
|
||||||
|
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_cpsr = nsec_ctx->mon_spsr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 'nsec_ctx->mon_lr' is not the fiq break point's PC, because it will
|
||||||
|
* be override as 'psci_fiq_debugger_uart_irq_tf_cb' for optee-os to
|
||||||
|
* jump to fiq_debugger handler.
|
||||||
|
*
|
||||||
|
* As 'nsec_ctx->und_lr' is not used for kernel, so optee-os uses it to
|
||||||
|
* deliver fiq break point's PC.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
fiq_pt_regs.ARM_pc = nsec_ctx->und_lr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return fiq_pt_regs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sip_fiq_debugger_uart_irq_tf_cb(unsigned long sp_el1,
|
||||||
|
unsigned long offset,
|
||||||
|
unsigned long cpu)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sip_fiq_debugger_uart_irq_tf_init(u32 irq_id, void *callback_fn)
|
||||||
|
{
|
||||||
|
struct arm_smccc_res res;
|
||||||
|
|
||||||
|
/* 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 = sip_map(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;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sip_fiq_debugger_uart_irq_tf_init);
|
||||||
|
|
||||||
|
static ulong cpu_logical_map_mpidr(u32 cpu)
|
||||||
|
{
|
||||||
|
#ifdef MODULE
|
||||||
|
/* Empirically, local "cpu_logical_map()" for rockchip platforms */
|
||||||
|
ulong mpidr = 0x00;
|
||||||
|
|
||||||
|
if (cpu < 4)
|
||||||
|
/* 0x00, 0x01, 0x02, 0x03 */
|
||||||
|
mpidr = cpu;
|
||||||
|
else if (cpu < 8)
|
||||||
|
/* 0x100, 0x101, 0x102, 0x103 */
|
||||||
|
mpidr = 0x100 | (cpu - 4);
|
||||||
|
else
|
||||||
|
pr_err("Unsupported map cpu: %d\n", cpu);
|
||||||
|
|
||||||
|
return mpidr;
|
||||||
|
#else
|
||||||
|
return cpu_logical_map(cpu);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int sip_fiq_debugger_switch_cpu(u32 cpu)
|
||||||
|
{
|
||||||
|
struct arm_smccc_res res;
|
||||||
|
|
||||||
|
fiq_target_cpu = cpu;
|
||||||
|
res = __invoke_sip_fn_smc(SIP_UARTDBG_FN, cpu_logical_map_mpidr(cpu),
|
||||||
|
0, UARTDBG_CFG_OSHDL_CPUSW);
|
||||||
|
return res.a0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sip_fiq_debugger_sdei_switch_cpu(u32 cur_cpu, u32 target_cpu, u32 flag)
|
||||||
|
{
|
||||||
|
struct arm_smccc_res res;
|
||||||
|
|
||||||
|
res = __invoke_sip_fn_smc(SIP_SDEI_FIQ_DBG_SWITCH_CPU,
|
||||||
|
cur_cpu, target_cpu, flag);
|
||||||
|
return res.a0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sip_fiq_debugger_sdei_get_event_id(u32 *fiq, u32 *sw_cpu, u32 *flag)
|
||||||
|
{
|
||||||
|
struct arm_smccc_res res;
|
||||||
|
|
||||||
|
res = __invoke_sip_fn_smc(SIP_SDEI_FIQ_DBG_GET_EVENT_ID,
|
||||||
|
0, 0, 0);
|
||||||
|
*fiq = res.a1;
|
||||||
|
*sw_cpu = res.a2;
|
||||||
|
if (flag)
|
||||||
|
*flag = res.a3;
|
||||||
|
|
||||||
|
return res.a0;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_SYMBOL_GPL(sip_fiq_debugger_switch_cpu);
|
||||||
|
|
||||||
|
void sip_fiq_debugger_enable_debug(bool enable)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sip_fiq_debugger_enable_debug);
|
||||||
|
|
||||||
|
int sip_fiq_debugger_set_print_port(u32 port_phyaddr, u32 baudrate)
|
||||||
|
{
|
||||||
|
struct arm_smccc_res res;
|
||||||
|
|
||||||
|
res = __invoke_sip_fn_smc(SIP_UARTDBG_FN, port_phyaddr, baudrate,
|
||||||
|
UARTDBG_CFG_PRINT_PORT);
|
||||||
|
return res.a0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sip_fiq_debugger_set_print_port);
|
||||||
|
|
||||||
|
int sip_fiq_debugger_request_share_memory(void)
|
||||||
|
{
|
||||||
|
struct arm_smccc_res res;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
return SIP_RET_SUCCESS;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sip_fiq_debugger_request_share_memory);
|
||||||
|
|
||||||
|
int sip_fiq_debugger_get_target_cpu(void)
|
||||||
|
{
|
||||||
|
return fiq_target_cpu;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sip_fiq_debugger_get_target_cpu);
|
||||||
|
|
||||||
|
void sip_fiq_debugger_enable_fiq(bool enable, uint32_t tgt_cpu)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sip_fiq_debugger_enable_fiq);
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
#ifdef CONFIG_ARM
|
||||||
|
static __init int sip_firmware_init(void)
|
||||||
|
{
|
||||||
|
struct arm_smccc_res res;
|
||||||
|
|
||||||
|
if (!psci_smp_available())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* OP-TEE works on kernel 3.10 and 4.4 and we have different sip
|
||||||
|
* implement. We should tell OP-TEE the current rockchip sip version.
|
||||||
|
*/
|
||||||
|
res = __invoke_sip_fn_smc(SIP_SIP_VERSION, SIP_IMPLEMENT_V2,
|
||||||
|
SECURE_REG_WR, 0);
|
||||||
|
if (IS_SIP_ERROR(res.a0))
|
||||||
|
pr_err("%s: set rockchip sip version v2 failed\n", __func__);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Currently, we support:
|
||||||
|
*
|
||||||
|
* 1. 64-bit ATF + 64-bit kernel;
|
||||||
|
* 2. 64-bit ATF + 32-bit kernel;
|
||||||
|
* 3. 32-bit TEE + 32-bit kernel;
|
||||||
|
*
|
||||||
|
* We need to detect which case of above and record in firmware_64_32bit
|
||||||
|
* We get info from cpuid and compare with all supported ARMv7 cpu.
|
||||||
|
*/
|
||||||
|
switch (read_cpuid_part()) {
|
||||||
|
case ARM_CPU_PART_CORTEX_A7:
|
||||||
|
case ARM_CPU_PART_CORTEX_A8:
|
||||||
|
case ARM_CPU_PART_CORTEX_A9:
|
||||||
|
case ARM_CPU_PART_CORTEX_A12:
|
||||||
|
case ARM_CPU_PART_CORTEX_A15:
|
||||||
|
case ARM_CPU_PART_CORTEX_A17:
|
||||||
|
firmware_64_32bit = FIRMWARE_TEE_32BIT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
firmware_64_32bit = FIRMWARE_ATF_64BIT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
arch_initcall(sip_firmware_init);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("Rockchip SIP Call");
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -30,4 +30,10 @@ config ROCKCHIP_DTPM
|
||||||
on this platform. That will create all the power capping capable
|
on this platform. That will create all the power capping capable
|
||||||
devices.
|
devices.
|
||||||
|
|
||||||
|
config ROCKCHIP_SUSPEND_MODE
|
||||||
|
tristate "Rockchip suspend mode config"
|
||||||
|
depends on ROCKCHIP_SIP
|
||||||
|
help
|
||||||
|
Say Y here if you want to set the suspend mode to the ATF.
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -5,3 +5,4 @@
|
||||||
obj-$(CONFIG_ROCKCHIP_GRF) += grf.o
|
obj-$(CONFIG_ROCKCHIP_GRF) += grf.o
|
||||||
obj-$(CONFIG_ROCKCHIP_IODOMAIN) += io-domain.o
|
obj-$(CONFIG_ROCKCHIP_IODOMAIN) += io-domain.o
|
||||||
obj-$(CONFIG_ROCKCHIP_DTPM) += dtpm.o
|
obj-$(CONFIG_ROCKCHIP_DTPM) += dtpm.o
|
||||||
|
obj-$(CONFIG_ROCKCHIP_SUSPEND_MODE) += rockchip_pm_config.o
|
||||||
|
|
291
drivers/soc/rockchip/rockchip_pm_config.c
Normal file
291
drivers/soc/rockchip/rockchip_pm_config.c
Normal file
|
@ -0,0 +1,291 @@
|
||||||
|
/*
|
||||||
|
* Rockchip Generic power configuration support.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017 ROCKCHIP, 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 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/arm-smccc.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#include <linux/cpu.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of_gpio.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/pm.h>
|
||||||
|
#include <linux/regulator/driver.h>
|
||||||
|
#include <linux/regulator/machine.h>
|
||||||
|
#include <linux/rockchip/rockchip_sip.h>
|
||||||
|
#include <linux/suspend.h>
|
||||||
|
#include <dt-bindings/input/input.h>
|
||||||
|
#include <../drivers/regulator/internal.h>
|
||||||
|
|
||||||
|
#define PM_INVALID_GPIO 0xffff
|
||||||
|
#define MAX_ON_OFF_REG_NUM 30
|
||||||
|
#define MAX_ON_OFF_REG_PROP_NAME_LEN 60
|
||||||
|
|
||||||
|
enum rk_pm_state {
|
||||||
|
RK_PM_MEM = 0,
|
||||||
|
RK_PM_MEM_LITE,
|
||||||
|
RK_PM_MEM_ULTRA,
|
||||||
|
RK_PM_STATE_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct rk_on_off_regulator_list {
|
||||||
|
struct regulator_dev *on_reg_list[MAX_ON_OFF_REG_NUM];
|
||||||
|
struct regulator_dev *off_reg_list[MAX_ON_OFF_REG_NUM];
|
||||||
|
} on_off_regs_list[RK_PM_STATE_MAX];
|
||||||
|
|
||||||
|
static const struct of_device_id pm_match_table[] = {
|
||||||
|
{ .compatible = "rockchip,pm-px30",},
|
||||||
|
{ .compatible = "rockchip,pm-rk1808",},
|
||||||
|
{ .compatible = "rockchip,pm-rk322x",},
|
||||||
|
{ .compatible = "rockchip,pm-rk3288",},
|
||||||
|
{ .compatible = "rockchip,pm-rk3308",},
|
||||||
|
{ .compatible = "rockchip,pm-rk3328",},
|
||||||
|
{ .compatible = "rockchip,pm-rk3368",},
|
||||||
|
{ .compatible = "rockchip,pm-rk3399",},
|
||||||
|
{ .compatible = "rockchip,pm-rk3568",},
|
||||||
|
{ .compatible = "rockchip,pm-rv1126",},
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void rockchip_pm_virt_pwroff_prepare(void)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
regulator_suspend_prepare(PM_SUSPEND_MEM);
|
||||||
|
|
||||||
|
error = suspend_disable_secondary_cpus();
|
||||||
|
if (error) {
|
||||||
|
pr_err("Disable nonboot cpus failed!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sip_smc_set_suspend_mode(VIRTUAL_POWEROFF, 0, 1);
|
||||||
|
sip_smc_virtual_poweroff();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_on_off_regulator(struct device_node *node, enum rk_pm_state state)
|
||||||
|
{
|
||||||
|
char on_prop_name[MAX_ON_OFF_REG_PROP_NAME_LEN] = {0};
|
||||||
|
char off_prop_name[MAX_ON_OFF_REG_PROP_NAME_LEN] = {0};
|
||||||
|
int i, j;
|
||||||
|
struct device_node *dn;
|
||||||
|
struct regulator_dev *reg;
|
||||||
|
struct regulator_dev **on_list;
|
||||||
|
struct regulator_dev **off_list;
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case RK_PM_MEM:
|
||||||
|
strncpy(on_prop_name, "rockchip,regulator-on-in-mem",
|
||||||
|
MAX_ON_OFF_REG_PROP_NAME_LEN);
|
||||||
|
strncpy(off_prop_name, "rockchip,regulator-off-in-mem",
|
||||||
|
MAX_ON_OFF_REG_PROP_NAME_LEN);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RK_PM_MEM_LITE:
|
||||||
|
strncpy(on_prop_name, "rockchip,regulator-on-in-mem-lite",
|
||||||
|
MAX_ON_OFF_REG_PROP_NAME_LEN);
|
||||||
|
strncpy(off_prop_name, "rockchip,regulator-off-in-mem-lite",
|
||||||
|
MAX_ON_OFF_REG_PROP_NAME_LEN);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RK_PM_MEM_ULTRA:
|
||||||
|
strncpy(on_prop_name, "rockchip,regulator-on-in-mem-ultra",
|
||||||
|
MAX_ON_OFF_REG_PROP_NAME_LEN);
|
||||||
|
strncpy(off_prop_name, "rockchip,regulator-off-in-mem-ultra",
|
||||||
|
MAX_ON_OFF_REG_PROP_NAME_LEN);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
on_list = on_off_regs_list[state].on_reg_list;
|
||||||
|
off_list = on_off_regs_list[state].off_reg_list;
|
||||||
|
|
||||||
|
if (of_find_property(node, on_prop_name, NULL)) {
|
||||||
|
for (i = 0, j = 0;
|
||||||
|
(dn = of_parse_phandle(node, on_prop_name, i));
|
||||||
|
i++) {
|
||||||
|
reg = of_find_regulator_by_node(dn);
|
||||||
|
if (reg == NULL) {
|
||||||
|
pr_warn("failed to find regulator %s for %s\n",
|
||||||
|
dn->name, on_prop_name);
|
||||||
|
} else {
|
||||||
|
pr_debug("%s on regulator=%s\n", __func__,
|
||||||
|
reg->desc->name);
|
||||||
|
on_list[j++] = reg;
|
||||||
|
}
|
||||||
|
of_node_put(dn);
|
||||||
|
|
||||||
|
if (j >= MAX_ON_OFF_REG_NUM)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (of_find_property(node, off_prop_name, NULL)) {
|
||||||
|
for (i = 0, j = 0;
|
||||||
|
(dn = of_parse_phandle(node, off_prop_name, i));
|
||||||
|
i++) {
|
||||||
|
reg = of_find_regulator_by_node(dn);
|
||||||
|
if (reg == NULL) {
|
||||||
|
pr_warn("failed to find regulator %s for %s\n",
|
||||||
|
dn->name, off_prop_name);
|
||||||
|
} else {
|
||||||
|
pr_debug("%s off regulator=%s\n", __func__,
|
||||||
|
reg->desc->name);
|
||||||
|
off_list[j++] = reg;
|
||||||
|
}
|
||||||
|
of_node_put(dn);
|
||||||
|
|
||||||
|
if (j >= MAX_ON_OFF_REG_NUM)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pm_config_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
const struct of_device_id *match_id;
|
||||||
|
struct device_node *node;
|
||||||
|
u32 mode_config = 0;
|
||||||
|
u32 wakeup_config = 0;
|
||||||
|
u32 pwm_regulator_config = 0;
|
||||||
|
int gpio_temp[10];
|
||||||
|
u32 sleep_debug_en = 0;
|
||||||
|
u32 apios_suspend = 0;
|
||||||
|
u32 virtual_poweroff_en = 0;
|
||||||
|
enum of_gpio_flags flags;
|
||||||
|
int i = 0;
|
||||||
|
int length;
|
||||||
|
|
||||||
|
match_id = of_match_node(pm_match_table, pdev->dev.of_node);
|
||||||
|
if (!match_id)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
node = of_find_node_by_name(NULL, "rockchip-suspend");
|
||||||
|
|
||||||
|
if (IS_ERR_OR_NULL(node)) {
|
||||||
|
dev_err(&pdev->dev, "%s dev node err\n", __func__);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (of_property_read_u32_array(node,
|
||||||
|
"rockchip,sleep-mode-config",
|
||||||
|
&mode_config, 1))
|
||||||
|
dev_warn(&pdev->dev, "not set sleep mode config\n");
|
||||||
|
else
|
||||||
|
sip_smc_set_suspend_mode(SUSPEND_MODE_CONFIG, mode_config, 0);
|
||||||
|
|
||||||
|
if (of_property_read_u32_array(node,
|
||||||
|
"rockchip,wakeup-config",
|
||||||
|
&wakeup_config, 1))
|
||||||
|
dev_warn(&pdev->dev, "not set wakeup-config\n");
|
||||||
|
else
|
||||||
|
sip_smc_set_suspend_mode(WKUP_SOURCE_CONFIG, wakeup_config, 0);
|
||||||
|
|
||||||
|
if (of_property_read_u32_array(node,
|
||||||
|
"rockchip,pwm-regulator-config",
|
||||||
|
&pwm_regulator_config, 1))
|
||||||
|
dev_warn(&pdev->dev, "not set pwm-regulator-config\n");
|
||||||
|
else
|
||||||
|
sip_smc_set_suspend_mode(PWM_REGULATOR_CONFIG,
|
||||||
|
pwm_regulator_config,
|
||||||
|
0);
|
||||||
|
|
||||||
|
length = of_gpio_named_count(node, "rockchip,power-ctrl");
|
||||||
|
|
||||||
|
if (length > 0 && length < 10) {
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
gpio_temp[i] = of_get_named_gpio_flags(node,
|
||||||
|
"rockchip,power-ctrl",
|
||||||
|
i,
|
||||||
|
&flags);
|
||||||
|
if (!gpio_is_valid(gpio_temp[i]))
|
||||||
|
break;
|
||||||
|
sip_smc_set_suspend_mode(GPIO_POWER_CONFIG,
|
||||||
|
i,
|
||||||
|
gpio_temp[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sip_smc_set_suspend_mode(GPIO_POWER_CONFIG, i, PM_INVALID_GPIO);
|
||||||
|
|
||||||
|
if (!of_property_read_u32_array(node,
|
||||||
|
"rockchip,sleep-debug-en",
|
||||||
|
&sleep_debug_en, 1))
|
||||||
|
sip_smc_set_suspend_mode(SUSPEND_DEBUG_ENABLE,
|
||||||
|
sleep_debug_en,
|
||||||
|
0);
|
||||||
|
|
||||||
|
if (!of_property_read_u32_array(node,
|
||||||
|
"rockchip,apios-suspend",
|
||||||
|
&apios_suspend, 1))
|
||||||
|
sip_smc_set_suspend_mode(APIOS_SUSPEND_CONFIG,
|
||||||
|
apios_suspend,
|
||||||
|
0);
|
||||||
|
|
||||||
|
if (!of_property_read_u32_array(node,
|
||||||
|
"rockchip,virtual-poweroff",
|
||||||
|
&virtual_poweroff_en, 1) &&
|
||||||
|
virtual_poweroff_en)
|
||||||
|
pm_power_off_prepare = rockchip_pm_virt_pwroff_prepare;
|
||||||
|
|
||||||
|
for (i = RK_PM_MEM; i < RK_PM_STATE_MAX; i++)
|
||||||
|
parse_on_off_regulator(node, i);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pm_config_prepare(struct device *dev)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
suspend_state_t suspend_state = mem_sleep_current;
|
||||||
|
enum rk_pm_state state = suspend_state - PM_SUSPEND_MEM;
|
||||||
|
struct regulator_dev **on_list;
|
||||||
|
struct regulator_dev **off_list;
|
||||||
|
|
||||||
|
sip_smc_set_suspend_mode(LINUX_PM_STATE,
|
||||||
|
suspend_state,
|
||||||
|
0);
|
||||||
|
|
||||||
|
if (state >= RK_PM_STATE_MAX)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
on_list = on_off_regs_list[state].on_reg_list;
|
||||||
|
off_list = on_off_regs_list[state].off_reg_list;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_ON_OFF_REG_NUM && on_list[i]; i++)
|
||||||
|
regulator_suspend_enable(on_list[i], PM_SUSPEND_MEM);
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_ON_OFF_REG_NUM && off_list[i]; i++)
|
||||||
|
regulator_suspend_disable(off_list[i], PM_SUSPEND_MEM);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct dev_pm_ops rockchip_pm_ops = {
|
||||||
|
.prepare = pm_config_prepare,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_driver pm_driver = {
|
||||||
|
.probe = pm_config_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = "rockchip-pm",
|
||||||
|
.of_match_table = pm_match_table,
|
||||||
|
.pm = &rockchip_pm_ops,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init rockchip_pm_drv_register(void)
|
||||||
|
{
|
||||||
|
return platform_driver_register(&pm_driver);
|
||||||
|
}
|
||||||
|
late_initcall_sync(rockchip_pm_drv_register);
|
||||||
|
MODULE_DESCRIPTION("Rockchip suspend mode config");
|
||||||
|
MODULE_LICENSE("GPL");
|
57
include/dt-bindings/suspend/rockchip-rk3568.h
Normal file
57
include/dt-bindings/suspend/rockchip-rk3568.h
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
|
||||||
|
/*
|
||||||
|
* Header providing constants for Rockchip suspend bindings.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021, Rockchip Electronics Co., Ltd.
|
||||||
|
* Author: XiaoDong.Huang
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DT_BINDINGS_SUSPEND_ROCKCHIP_RK3568_H__
|
||||||
|
#define __DT_BINDINGS_SUSPEND_ROCKCHIP_RK3568_H__
|
||||||
|
/******************************bits ops************************************/
|
||||||
|
|
||||||
|
#ifndef BIT
|
||||||
|
#define BIT(nr) (1 << (nr))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define RKPM_SLP_WFI BIT(0)
|
||||||
|
#define RKPM_SLP_ARMOFF BIT(1)
|
||||||
|
#define RKPM_SLP_CENTER_OFF BIT(2)
|
||||||
|
#define RKPM_SLP_ARMOFF_LOGOFF BIT(3)
|
||||||
|
#define RKPM_SLP_FROM_UBOOT BIT(4)
|
||||||
|
#define RKPM_SLP_PMIC_LP BIT(5)
|
||||||
|
#define RKPM_SLP_HW_PLLS_OFF BIT(6)
|
||||||
|
#define RKPM_SLP_PMUALIVE_32K BIT(7)
|
||||||
|
#define RKPM_SLP_OSC_DIS BIT(8)
|
||||||
|
#define RKPM_SLP_32K_EXT BIT(9)
|
||||||
|
#define RKPM_SLP_32K_PVTM BIT(10)
|
||||||
|
/* the wake up source */
|
||||||
|
#define RKPM_CPU0_WKUP_EN BIT(0)
|
||||||
|
#define RKPM_CPU1_WKUP_EN BIT(1)
|
||||||
|
#define RKPM_CPU2_WKUP_EN BIT(2)
|
||||||
|
#define RKPM_CPU3_WKUP_EN BIT(3)
|
||||||
|
#define RKPM_GPIO_WKUP_EN BIT(4)
|
||||||
|
#define RKPM_UART0_WKUP_EN BIT(5)
|
||||||
|
#define RKPM_SDMMC0_WKUP_EN BIT(6)
|
||||||
|
#define RKPM_SDMMC1_WKUP_EN BIT(7)
|
||||||
|
#define RKPM_SDMMC2_WKUP_EN BIT(8)
|
||||||
|
#define RKPM_USB_WKUP_EN BIT(9)
|
||||||
|
#define RKPM_PCIE_WKUP_EN BIT(10)
|
||||||
|
#define RKPM_VAD_WKUP_EN BIT(11)
|
||||||
|
#define RKPM_TIMER_WKUP_EN BIT(12)
|
||||||
|
#define RKPM_PWM0_WKUP_EN BIT(13)
|
||||||
|
#define RKPM_TIMEOUT_WKUP_EN BIT(14)
|
||||||
|
#define RKPM_SFT_WKUP_EN BIT(15)
|
||||||
|
#define RKPM_USB_LINESTATE_WKUP_EN BIT(16)
|
||||||
|
|
||||||
|
#define RKPM_SLP_LDO1_ON BIT(0)
|
||||||
|
#define RKPM_SLP_LDO2_ON BIT(1)
|
||||||
|
#define RKPM_SLP_LDO3_ON BIT(2)
|
||||||
|
#define RKPM_SLP_LDO4_ON BIT(3)
|
||||||
|
#define RKPM_SLP_LDO5_ON BIT(4)
|
||||||
|
#define RKPM_SLP_LDO6_ON BIT(5)
|
||||||
|
#define RKPM_SLP_LDO7_ON BIT(6)
|
||||||
|
#define RKPM_SLP_LDO8_ON BIT(7)
|
||||||
|
#define RKPM_SLP_LDO9_ON BIT(8)
|
||||||
|
|
||||||
|
#endif
|
333
include/linux/rockchip/rockchip_sip.h
Normal file
333
include/linux/rockchip/rockchip_sip.h
Normal file
|
@ -0,0 +1,333 @@
|
||||||
|
/* 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, compatible with kernel-3.10 */
|
||||||
|
#define SIP_ATF_VERSION 0x82000001
|
||||||
|
#define SIP_ACCESS_REG 0x82000002
|
||||||
|
#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_DRAM_CONFIG 0x82000008
|
||||||
|
#define SIP_SHARE_MEM 0x82000009
|
||||||
|
#define SIP_SIP_VERSION 0x8200000a
|
||||||
|
#define SIP_REMOTECTL_CFG 0x8200000b
|
||||||
|
#define PSCI_SIP_VPU_RESET 0x8200000c
|
||||||
|
#define SIP_BUS_CFG 0x8200000d
|
||||||
|
#define SIP_LAST_LOG 0x8200000e
|
||||||
|
#define SIP_SCMI_AGENT0 0x82000010
|
||||||
|
#define SIP_SCMI_AGENT1 0x82000011
|
||||||
|
#define SIP_SCMI_AGENT2 0x82000012
|
||||||
|
#define SIP_SCMI_AGENT3 0x82000013
|
||||||
|
#define SIP_SCMI_AGENT4 0x82000014
|
||||||
|
#define SIP_SCMI_AGENT5 0x82000015
|
||||||
|
#define SIP_SCMI_AGENT6 0x82000016
|
||||||
|
#define SIP_SCMI_AGENT7 0x82000017
|
||||||
|
#define SIP_SCMI_AGENT8 0x82000018
|
||||||
|
#define SIP_SCMI_AGENT9 0x82000019
|
||||||
|
#define SIP_SCMI_AGENT10 0x8200001a
|
||||||
|
#define SIP_SCMI_AGENT11 0x8200001b
|
||||||
|
#define SIP_SCMI_AGENT12 0x8200001c
|
||||||
|
#define SIP_SCMI_AGENT13 0x8200001d
|
||||||
|
#define SIP_SCMI_AGENT14 0x8200001e
|
||||||
|
#define SIP_SCMI_AGENT15 0x8200001f
|
||||||
|
#define SIP_SDEI_FIQ_DBG_SWITCH_CPU 0x82000020
|
||||||
|
#define SIP_SDEI_FIQ_DBG_GET_EVENT_ID 0x82000021
|
||||||
|
|
||||||
|
/* Rockchip Sip version */
|
||||||
|
#define SIP_IMPLEMENT_V1 (1)
|
||||||
|
#define SIP_IMPLEMENT_V2 (2)
|
||||||
|
|
||||||
|
/* Trust firmware version */
|
||||||
|
#define ATF_VER_MAJOR(ver) (((ver) >> 16) & 0xffff)
|
||||||
|
#define ATF_VER_MINOR(ver) (((ver) >> 0) & 0xffff)
|
||||||
|
|
||||||
|
/* SIP_ACCESS_REG: read or write */
|
||||||
|
#define SECURE_REG_RD 0x0
|
||||||
|
#define SECURE_REG_WR 0x1
|
||||||
|
|
||||||
|
/* 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 IS_SIP_ERROR(x) (!!(x))
|
||||||
|
|
||||||
|
#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
|
||||||
|
#define SIP_RET_SET_RATE_TIMEOUT -6
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
#define GPIO_POWER_CONFIG 0x04
|
||||||
|
#define SUSPEND_DEBUG_ENABLE 0x05
|
||||||
|
#define APIOS_SUSPEND_CONFIG 0x06
|
||||||
|
#define VIRTUAL_POWEROFF 0x07
|
||||||
|
#define SUSPEND_WFI_TIME_MS 0x08
|
||||||
|
#define LINUX_PM_STATE 0x09
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FIRMWARE_NONE,
|
||||||
|
FIRMWARE_TEE_32BIT,
|
||||||
|
FIRMWARE_ATF_32BIT,
|
||||||
|
FIRMWARE_ATF_64BIT,
|
||||||
|
FIRMWARE_END,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Share mem page types */
|
||||||
|
typedef enum {
|
||||||
|
SHARE_PAGE_TYPE_INVALID = 0,
|
||||||
|
SHARE_PAGE_TYPE_UARTDBG,
|
||||||
|
SHARE_PAGE_TYPE_DDR,
|
||||||
|
SHARE_PAGE_TYPE_DDRDBG,
|
||||||
|
SHARE_PAGE_TYPE_DDRECC,
|
||||||
|
SHARE_PAGE_TYPE_LAST_LOG,
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
#if IS_ENABLED(CONFIG_ROCKCHIP_SIP)
|
||||||
|
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_dram(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);
|
||||||
|
struct arm_smccc_res sip_smc_vpu_reset(u32 arg0, u32 arg1, u32 arg2);
|
||||||
|
struct arm_smccc_res sip_smc_get_suspend_info(u32 info);
|
||||||
|
struct arm_smccc_res sip_smc_lastlog_request(void);
|
||||||
|
|
||||||
|
int sip_smc_set_suspend_mode(u32 ctrl, u32 config1, u32 config2);
|
||||||
|
int sip_smc_virtual_poweroff(void);
|
||||||
|
int sip_smc_remotectl_config(u32 func, u32 data);
|
||||||
|
|
||||||
|
int sip_smc_secure_reg_write(u32 addr_phy, u32 val);
|
||||||
|
u32 sip_smc_secure_reg_read(u32 addr_phy);
|
||||||
|
struct arm_smccc_res sip_smc_bus_config(u32 arg0, u32 arg1, u32 arg2);
|
||||||
|
|
||||||
|
/***************************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_sdei_switch_cpu(u32 cur_cpu, u32 target_cpu, u32 flag);
|
||||||
|
int sip_fiq_debugger_is_enabled(void);
|
||||||
|
int sip_fiq_debugger_sdei_get_event_id(u32 *fiq, u32 *sw_cpu, u32 *flag);
|
||||||
|
#else
|
||||||
|
static inline struct arm_smccc_res sip_smc_get_atf_version(void)
|
||||||
|
{
|
||||||
|
struct arm_smccc_res tmp = {0};
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct arm_smccc_res sip_smc_get_sip_version(void)
|
||||||
|
{
|
||||||
|
struct arm_smccc_res tmp = {0};
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct arm_smccc_res sip_smc_dram(u32 arg0, u32 arg1, u32 arg2)
|
||||||
|
{
|
||||||
|
struct arm_smccc_res tmp = {0};
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct arm_smccc_res sip_smc_request_share_mem
|
||||||
|
(u32 page_num, share_page_type_t page_type)
|
||||||
|
{
|
||||||
|
struct arm_smccc_res tmp = {0};
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct arm_smccc_res sip_smc_mcu_el3fiq
|
||||||
|
(u32 arg0, u32 arg1, u32 arg2)
|
||||||
|
{
|
||||||
|
struct arm_smccc_res tmp = {0};
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct arm_smccc_res
|
||||||
|
sip_smc_vpu_reset(u32 arg0, u32 arg1, u32 arg2)
|
||||||
|
{
|
||||||
|
struct arm_smccc_res tmp = {0};
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct arm_smccc_res sip_smc_lastlog_request(void)
|
||||||
|
{
|
||||||
|
struct arm_smccc_res tmp = {0};
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int sip_smc_set_suspend_mode(u32 ctrl, u32 config1, u32 config2)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int sip_smc_get_suspend_info(u32 info)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int sip_smc_virtual_poweroff(void) { return 0; }
|
||||||
|
static inline int sip_smc_remotectl_config(u32 func, u32 data) { return 0; }
|
||||||
|
static inline u32 sip_smc_secure_reg_read(u32 addr_phy) { return 0; }
|
||||||
|
static inline int sip_smc_secure_reg_write(u32 addr_phy, u32 val) { return 0; }
|
||||||
|
static inline int sip_smc_soc_bus_div(u32 arg0, u32 arg1, u32 arg2)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************fiq debugger **************************************/
|
||||||
|
static inline void sip_fiq_debugger_enable_fiq
|
||||||
|
(bool enable, uint32_t tgt_cpu) { return; }
|
||||||
|
|
||||||
|
static inline void sip_fiq_debugger_enable_debug(bool enable) { return; }
|
||||||
|
static inline int sip_fiq_debugger_uart_irq_tf_init(u32 irq_id,
|
||||||
|
void *callback_fn)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int sip_fiq_debugger_set_print_port(u32 port_phyaddr,
|
||||||
|
u32 baudrate)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int sip_fiq_debugger_request_share_memory(void) { return 0; }
|
||||||
|
static inline int sip_fiq_debugger_get_target_cpu(void) { return 0; }
|
||||||
|
static inline int sip_fiq_debugger_switch_cpu(u32 cpu) { return 0; }
|
||||||
|
static inline int sip_fiq_debugger_sdei_switch_cpu(u32 cur_cpu, u32 target_cpu,
|
||||||
|
u32 flag) { return 0; }
|
||||||
|
static inline int sip_fiq_debugger_is_enabled(void) { return 0; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 32-bit OP-TEE context, never change order of members! */
|
||||||
|
struct sm_nsec_ctx {
|
||||||
|
u32 usr_sp;
|
||||||
|
u32 usr_lr;
|
||||||
|
u32 irq_spsr;
|
||||||
|
u32 irq_sp;
|
||||||
|
u32 irq_lr;
|
||||||
|
u32 fiq_spsr;
|
||||||
|
u32 fiq_sp;
|
||||||
|
u32 fiq_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;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 64-bit ATF context, never change order of members! */
|
||||||
|
struct gp_regs_ctx {
|
||||||
|
u64 x0;
|
||||||
|
u64 x1;
|
||||||
|
u64 x2;
|
||||||
|
u64 x3;
|
||||||
|
u64 x4;
|
||||||
|
u64 x5;
|
||||||
|
u64 x6;
|
||||||
|
u64 x7;
|
||||||
|
u64 x8;
|
||||||
|
u64 x9;
|
||||||
|
u64 x10;
|
||||||
|
u64 x11;
|
||||||
|
u64 x12;
|
||||||
|
u64 x13;
|
||||||
|
u64 x14;
|
||||||
|
u64 x15;
|
||||||
|
u64 x16;
|
||||||
|
u64 x17;
|
||||||
|
u64 x18;
|
||||||
|
u64 x19;
|
||||||
|
u64 x20;
|
||||||
|
u64 x21;
|
||||||
|
u64 x22;
|
||||||
|
u64 x23;
|
||||||
|
u64 x24;
|
||||||
|
u64 x25;
|
||||||
|
u64 x26;
|
||||||
|
u64 x27;
|
||||||
|
u64 x28;
|
||||||
|
u64 x29;
|
||||||
|
u64 lr;
|
||||||
|
u64 sp_el0;
|
||||||
|
u64 scr_el3;
|
||||||
|
u64 runtime_sp;
|
||||||
|
u64 spsr_el3;
|
||||||
|
u64 elr_el3;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Add table
Add a link
Reference in a new issue