build/patch/kernel/archive/rockchip64-5.15/board-pbp-add-suspend.patch

1019 lines
29 KiB
Diff
Raw Normal View History

From c7b16d749d1746e3ab081f8550c3aba252969d26 Mon Sep 17 00:00:00 2001
From: Dan Johansen <strit@manjaro.org>
Date: Mon, 1 Jun 2020 23:14:16 +0200
Subject: [PATCH] add suspend to rk3399/PBP
---
.../soc/rockchip/rockchip-pm-config.txt | 40 +++
.../boot/dts/rockchip/rk3399-pinebook-pro.dts | 35 +++
arch/arm64/boot/dts/rockchip/rk3399.dtsi | 24 ++
drivers/firmware/Kconfig | 7 +
drivers/firmware/Makefile | 1 +
drivers/firmware/rockchip_sip.c | 263 ++++++++++++++++++
drivers/regulator/core.c | 49 +++-
drivers/soc/rockchip/Kconfig | 6 +
drivers/soc/rockchip/Makefile | 1 +
drivers/soc/rockchip/rockchip_pm_config.c | 213 ++++++++++++++
include/dt-bindings/suspend/rockchip-rk3399.h | 60 ++++
include/linux/regulator/driver.h | 3 +
include/linux/rockchip/rockchip_sip.h | 149 ++++++++++
13 files changed, 847 insertions(+), 4 deletions(-)
create mode 100644 Documentation/devicetree/bindings/soc/rockchip/rockchip-pm-config.txt
create mode 100644 drivers/firmware/rockchip_sip.c
create mode 100644 drivers/soc/rockchip/rockchip_pm_config.c
create mode 100644 include/dt-bindings/suspend/rockchip-rk3399.h
create mode 100644 include/linux/rockchip/rockchip_sip.h
diff --git a/Documentation/devicetree/bindings/soc/rockchip/rockchip-pm-config.txt b/Documentation/devicetree/bindings/soc/rockchip/rockchip-pm-config.txt
new file mode 100644
index 000000000000..e15af33d3a9f
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/rockchip/rockchip-pm-config.txt
@@ -0,0 +1,40 @@
+* the suspend mode config
+
+- compatible: "rockchip,pm-config"
+ Compatibility with rk3399
+
+- rockchip,sleep-mode-config : the sleep mode config,
+ ARMOFF, OSC disabled ...
+
+- rockchip,wakeup-config: the wake up sourece enable.
+ GPIO, USB, SD...
+
+- rockchip,pwm-regulator-config: the pwm regulator name.
+
+Example:
+ rockchip_suspend: rockchip_suspend {
+ compatible = "rockchip,pm-rk3399";
+ status = "okay";
+ rockchip,sleep-mode-config = <
+ (0
+ | RKPM_SLP_ARMPD
+ | RKPM_SLP_PERILPPD
+ | RKPM_SLP_DDR_RET
+ | RKPM_SLP_PLLPD
+ | RKPM_SLP_OSC_DIS
+ | RKPM_SLP_CENTER_PD
+ | RKPM_SLP_AP_PWROFF
+ )
+ >;
+ rockchip,wakeup-config = <
+ (0 |
+ RKPM_GPIO_WKUP_EN |
+ RKPM_PWM_WKUP_EN)
+ >;
+ rockchip,pwm-regulator-config = <
+ (0 |
+ PWM2_REGULATOR_EN
+ )
+ >;
+ };
+
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
index c49982dfd8fc..9643cae1537a 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts
@@ -19,9 +19,15 @@ / {
compatible = "pine64,pinebook-pro", "rockchip,rk3399";
chosen {
+ bootargs = "earlycon=uart8250,mmio32,0xff1a0000";
stdout-path = "serial2:1500000n8";
};
+ memory {
+ device_type = "memory";
+ reg = <0x0 0x00200000 0x0 0xf7e00000>;
+ };
+
backlight: edp-backlight {
compatible = "pwm-backlight";
power-supply = <&vcc_12v>;
@@ -125,6 +131,12 @@ sdio_pwrseq: sdio-pwrseq {
reset-gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>;
};
+ /* first 128k(0xff8d0000~0xff8f0000) for ddr and ATF */
+ sram@ff8d0000 {
+ compatible = "mmio-sram";
+ reg = <0x0 0xff8d0000 0x0 0x20000>; /* 128k */
+ };
+
/* Audio components */
es8316-sound {
compatible = "simple-audio-card";
@@ -906,6 +918,29 @@ &pwm2 {
status = "okay";
};
+&rockchip_suspend {
+ status = "okay";
+ rockchip,sleep-debug-en = <1>;
+ rockchip,sleep-mode-config = <
+ (0
+ | RKPM_SLP_ARMPD
+ | RKPM_SLP_PERILPPD
+ | RKPM_SLP_DDR_RET
+ | RKPM_SLP_PLLPD
+ | RKPM_SLP_CENTER_PD
+ | RKPM_SLP_AP_PWROFF
+ )
+ >;
+ rockchip,pwm-regulator-config = <
+ (0
+ | PWM2_REGULATOR_EN
+ )
+ >;
+ rockchip,power-ctrl =
+ <&gpio1 RK_PC1 GPIO_ACTIVE_HIGH>,
+ <&gpio1 RK_PB6 GPIO_ACTIVE_HIGH>;
+};
+
&saradc {
vref-supply = <&vcca1v8_s3>;
status = "okay";
diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 1448f358ed0a..a91fc5c8b43b 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -9,6 +9,7 @@
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/pinctrl/rockchip.h>
#include <dt-bindings/power/rk3399-power.h>
+#include <dt-bindings/suspend/rockchip-rk3399.h>
#include <dt-bindings/thermal/thermal.h>
/ {
@@ -2652,4 +2653,27 @@ pcie_clkreqnb_cpm: pci-clkreqnb-cpm {
};
};
+
+ rockchip_suspend: rockchip-suspend {
+ compatible = "rockchip,pm-rk3399";
+ status = "disabled";
+ rockchip,sleep-debug-en = <0>;
+ rockchip,virtual-poweroff = <0>;
+ rockchip,sleep-mode-config = <
+ (0
+ | RKPM_SLP_ARMPD
+ | RKPM_SLP_PERILPPD
+ | RKPM_SLP_DDR_RET
+ | RKPM_SLP_PLLPD
+ | RKPM_SLP_OSC_DIS
+ | RKPM_SLP_CENTER_PD
+ | RKPM_SLP_AP_PWROFF
+ )
+ >;
+ rockchip,wakeup-config = <
+ (0
+ | RKPM_GPIO_WKUP_EN
+ )
+ >;
+ };
};
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 8007d4aa76dc..37f8039a5e27 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -296,6 +296,13 @@
other manufacturing data and also utilize the Entropy Bit Generator
for hardware random number generation.
+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/arm_ffa/Kconfig"
source "drivers/firmware/broadcom/Kconfig"
source "drivers/firmware/google/Kconfig"
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index e9fb838af4df..575f45d55939 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -29,6 +29,7 @@ obj-y += meson/
obj-$(CONFIG_GOOGLE_FIRMWARE) += google/
obj-$(CONFIG_EFI) += efi/
obj-$(CONFIG_UEFI_CPER) += efi/
+obj-$(CONFIG_ROCKCHIP_SIP) += rockchip_sip.o
obj-y += imx/
obj-y += tegra/
obj-y += xilinx/
diff --git a/drivers/firmware/rockchip_sip.c b/drivers/firmware/rockchip_sip.c
new file mode 100644
index 000000000000..6844c5bad5b1
--- /dev/null
+++ b/drivers/firmware/rockchip_sip.c
@@ -0,0 +1,263 @@
+/*
+ * 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>
+#include <linux/ptrace.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_ddr_cfg(u32 arg0, u32 arg1, u32 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_VERSION, 0, 0, 0);
+}
+
+struct arm_smccc_res sip_smc_get_sip_version(void)
+{
+ return __invoke_sip_fn_smc(SIP_SIP_VERSION, 0, 0, 0);
+}
+
+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;
+}
+
+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;
+}
+
+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));
+
+error:
+ return res;
+}
+
+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);
+}
+
+/************************** 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)
+{
+ 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
+
+ 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;
+
+ 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;
+}
+
+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(cpu),
+ 0, UARTDBG_CFG_OSHDL_CPUSW);
+ return res.a0;
+}
+
+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);
+}
+
+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;
+}
+
+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;
+}
+
+int sip_fiq_debugger_get_target_cpu(void)
+{
+ return fiq_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);
+}
+
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 7486f6e4e613..d46a267ea309 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -5268,6 +5268,14 @@ void regulator_unregister(struct regulator_dev *rdev)
EXPORT_SYMBOL_GPL(regulator_unregister);
#ifdef CONFIG_SUSPEND
+static inline int can_enable(struct regulator_dev *rdev) {
+ return rdev->ena_pin || rdev->desc->ops->enable;
+}
+
+static inline int can_disable(struct regulator_dev *rdev) {
+ return rdev->ena_pin || rdev->desc->ops->disable;
+}
+
/**
* regulator_suspend - prepare regulators for system wide suspend
* @dev: ``&struct device`` pointer that is passed to _regulator_suspend()
@@ -5430,6 +5438,21 @@ static int regulator_suspend(struct device *dev)
regulator_lock(rdev);
ret = __suspend_set_state(rdev, rstate);
+
+ if (rstate->enabled == ENABLE_IN_SUSPEND && can_enable(rdev)) {
+ if (!rdev->desc->ops->set_suspend_enable) {
+ rdev->resume_state = _regulator_is_enabled(rdev);
+ rdev_info(rdev, "Entering suspend %d, enabling forcibly, was %s\n", state, rdev->resume_state ? "on" : "off");
+ ret = _regulator_do_enable(rdev);
+ }
+ } else if (rstate->enabled == DISABLE_IN_SUSPEND && can_disable(rdev)) {
+ if (!rdev->desc->ops->set_suspend_disable) {
+ rdev->resume_state = _regulator_is_enabled(rdev);
+ rdev_info(rdev, "Entering suspend %d, disabling forcibly, was %s\n", state, rdev->resume_state ? "on" : "off");
+ ret = _regulator_do_disable(rdev);
+ }
+ }
+
regulator_unlock(rdev);
return ret;
@@ -5452,9 +5475,19 @@ static int regulator_resume(struct device *dev)
regulator_lock(rdev);
- if (rstate->enabled == ENABLE_IN_SUSPEND ||
- rstate->enabled == DISABLE_IN_SUSPEND)
- ret = rdev->desc->ops->resume(rdev);
+ if (rstate->enabled == ENABLE_IN_SUSPEND || rstate->enabled == DISABLE_IN_SUSPEND) {
+ if (rdev->desc->ops->resume) {
+ ret = rdev->desc->ops->resume(rdev);
+ } else if ((rstate->enabled == ENABLE_IN_SUSPEND && !rdev->desc->ops->set_suspend_enable) ||
+ (rstate->enabled == DISABLE_IN_SUSPEND && !rdev->desc->ops->set_suspend_disable)) {
+ rdev_info(rdev, "Resuming, restoring state to %s\n", rdev->resume_state ? "on" : "off");
+ if (rdev->resume_state && can_enable(rdev)) {
+ ret = _regulator_do_enable(rdev);
+ } else if (!rdev->resume_state && can_disable(rdev)) {
+ ret = _regulator_do_disable(rdev);
+ }
+ }
+ }
regulator_unlock(rdev);
diff --git a/drivers/soc/rockchip/Kconfig b/drivers/soc/rockchip/Kconfig
index b71b73bf5fc5..bfadbecd0df8 100644
--- a/drivers/soc/rockchip/Kconfig
+++ b/drivers/soc/rockchip/Kconfig
@@ -26,4 +26,10 @@ config ROCKCHIP_PM_DOMAINS
If unsure, say N.
+config ROCKCHIP_SUSPEND_MODE
+ bool "Rockchip suspend mode config"
+ depends on ROCKCHIP_SIP
+ help
+ Say Y here if you want to set the suspend mode to the ATF.
+
endif
diff --git a/drivers/soc/rockchip/Makefile b/drivers/soc/rockchip/Makefile
index afca0a4c4b72..a15c0a395a33 100644
--- a/drivers/soc/rockchip/Makefile
+++ b/drivers/soc/rockchip/Makefile
@@ -4,3 +4,4 @@
#
obj-$(CONFIG_ROCKCHIP_GRF) += grf.o
obj-$(CONFIG_ROCKCHIP_PM_DOMAINS) += pm_domains.o
+obj-$(CONFIG_ROCKCHIP_SUSPEND_MODE) += rockchip_pm_config.o
diff --git a/drivers/soc/rockchip/rockchip_pm_config.c b/drivers/soc/rockchip/rockchip_pm_config.c
new file mode 100644
index 000000000000..4a3038f22639
--- /dev/null
+++ b/drivers/soc/rockchip/rockchip_pm_config.c
@@ -0,0 +1,213 @@
+/*
+ * 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/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/machine.h>
+#include <linux/rockchip/rockchip_sip.h>
+#include <linux/suspend.h>
+#include <dt-bindings/input/input.h>
+
+#define PM_INVALID_GPIO 0xffff
+
+static const struct of_device_id pm_match_table[] = {
+ { .compatible = "rockchip,pm-rk3399",},
+ { },
+};
+
+#define MAX_PWRKEY_NUMS 20
+#define MAX_NUM_KEYS 60
+
+struct rkxx_remote_key_table {
+ int scancode;
+ int keycode;
+};
+
+static int parse_ir_pwrkeys(unsigned int *pwrkey, int size, int *nkey)
+{
+ struct device_node *node;
+ struct device_node *child_node;
+ struct rkxx_remote_key_table key_table[MAX_NUM_KEYS];
+ int i;
+ int len = 0, nbuttons;
+ int num = 0;
+ u32 usercode, scancode;
+
+ for_each_node_by_name(node, "pwm") {
+ for_each_child_of_node(node, child_node) {
+ if (of_property_read_u32(child_node,
+ "rockchip,usercode",
+ &usercode))
+ break;
+
+ if (of_get_property(child_node,
+ "rockchip,key_table",
+ &len) == NULL ||
+ len <= 0)
+ break;
+
+ len = len < sizeof(key_table) ? len : sizeof(key_table);
+ len /= sizeof(u32);
+ if (of_property_read_u32_array(child_node,
+ "rockchip,key_table",
+ (u32 *)key_table,
+ len))
+ break;
+
+ nbuttons = len / 2;
+ for (i = 0; i < nbuttons && num < size; ++i) {
+ if (key_table[i].keycode == KEY_POWER) {
+ scancode = key_table[i].scancode;
+ pr_debug("usercode=%x, key=%x\n",
+ usercode, scancode);
+ pwrkey[num] = (usercode & 0xffff) << 16;
+ pwrkey[num] |= (scancode & 0xff) << 8;
+ ++num;
+ }
+ }
+ }
+ }
+
+ *nkey = num;
+
+ return num ? 0 : -1;
+}
+
+static void rockchip_pm_virt_pwroff_prepare(void)
+{
+ int error;
+ int i, nkey;
+ u32 power_key[MAX_PWRKEY_NUMS];
+
+ if ((parse_ir_pwrkeys(power_key, ARRAY_SIZE(power_key), &nkey))) {
+ pr_err("Parse ir powerkey code failed!\n");
+ return;
+ }
+
+ for (i = 0; i < nkey; ++i)
+ sip_smc_set_suspend_mode(VIRTUAL_POWEROFF, 1, power_key[i]);
+
+ regulator_suspend_prepare(PM_SUSPEND_MEM);
+
+ error = freeze_secondary_cpus(0);
+ if (error) {
+ pr_err("Freeze secondary cpus failed!\n");
+ return;
+ }
+
+ sip_smc_set_suspend_mode(VIRTUAL_POWEROFF, 0, 1);
+ sip_smc_virtual_poweroff();
+}
+
+static int __init pm_config_init(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;
+
+ return 0;
+}
+
+static struct platform_driver pm_driver = {
+ .driver = {
+ .name = "rockchip-pm",
+ .of_match_table = pm_match_table,
+ },
+};
+
+static int __init rockchip_pm_drv_register(void)
+{
+ return platform_driver_probe(&pm_driver, pm_config_init);
+}
+subsys_initcall(rockchip_pm_drv_register);
+
diff --git a/include/dt-bindings/suspend/rockchip-rk3399.h b/include/dt-bindings/suspend/rockchip-rk3399.h
new file mode 100644
index 000000000000..de23670b43ea
--- /dev/null
+++ b/include/dt-bindings/suspend/rockchip-rk3399.h
@@ -0,0 +1,60 @@
+/*
+ * Header providing constants for Rockchip suspend bindings.
+ *
+ * Copyright (C) 2017, Fuzhou Rockchip Electronics Co., Ltd
+ * Author: Tony.Xie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 __DT_BINDINGS_SUSPEND_ROCKCHIP_RK3399_H__
+#define __DT_BINDINGS_SUSPEND_ROCKCHIP_RK3399_H__
+
+/* the suspend mode */
+#define RKPM_SLP_WFI (1 << 0)
+#define RKPM_SLP_ARMPD (1 << 1)
+#define RKPM_SLP_PERILPPD (1 << 2)
+#define RKPM_SLP_DDR_RET (1 << 3)
+#define RKPM_SLP_PLLPD (1 << 4)
+#define RKPM_SLP_OSC_DIS (1 << 5)
+#define RKPM_SLP_CENTER_PD (1 << 6)
+#define RKPM_SLP_AP_PWROFF (1 << 7)
+
+/* the wake up source */
+#define RKPM_CLUSTER_L_WKUP_EN (1 << 0)
+#define RKPM_CLUSTER_B_WKUPB_EN (1 << 1)
+#define RKPM_GPIO_WKUP_EN (1 << 2)
+#define RKPM_SDIO_WKUP_EN (1 << 3)
+#define RKPM_SDMMC_WKUP_EN (1 << 4)
+#define RKPM_TIMER_WKUP_EN (1 << 6)
+#define RKPM_USB_WKUP_EN (1 << 7)
+#define RKPM_SFT_WKUP_EN (1 << 8)
+#define RKPM_WDT_M0_WKUP_EN (1 << 9)
+#define RKPM_TIME_OUT_WKUP_EN (1 << 10)
+#define RKPM_PWM_WKUP_EN (1 << 11)
+#define RKPM_PCIE_WKUP_EN (1 << 13)
+
+/* the pwm regulator */
+#define PWM0_REGULATOR_EN (1 << 0)
+#define PWM1_REGULATOR_EN (1 << 1)
+#define PWM2_REGULATOR_EN (1 << 2)
+#define PWM3A_REGULATOR_EN (1 << 3)
+#define PWM3B_REGULATOR_EN (1 << 4)
+
+/* the APIO voltage domain */
+#define RKPM_APIO0_SUSPEND (1 << 0)
+#define RKPM_APIO1_SUSPEND (1 << 1)
+#define RKPM_APIO2_SUSPEND (1 << 2)
+#define RKPM_APIO3_SUSPEND (1 << 3)
+#define RKPM_APIO4_SUSPEND (1 << 4)
+#define RKPM_APIO5_SUSPEND (1 << 5)
+
+#endif
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 29d920516e0b..549b68c58e68 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -632,6 +632,9 @@
/* time when this regulator was disabled last time */
ktime_t last_off;
+
+ /* state when resuming */
+ int resume_state;
int cached_err;
bool use_cached_err;
spinlock_t err_lock;
diff --git a/include/linux/rockchip/rockchip_sip.h b/include/linux/rockchip/rockchip_sip.h
new file mode 100644
index 000000000000..9e8bbb2251c6
--- /dev/null
+++ b/include/linux/rockchip/rockchip_sip.h
@@ -0,0 +1,149 @@
+/* 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_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 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
+
+/* 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
+
+/* 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
+
+/* 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_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);
+/***************************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);
+
+/* 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.26.2