From bd06237d842c9a2c57905f42a7ccb5f085b9ea12 Mon Sep 17 00:00:00 2001 From: Tobias Schramm Date: Thu, 28 May 2020 14:06:20 +0200 Subject: [PATCH 01/22] soc: rockchip: Add rockchip suspend mode driver Code gore, do not mainline. This belongs in ATF Signed-off-by: Tobias Schramm --- .../soc/rockchip/rockchip-pm-config.txt | 39 ++++ drivers/soc/rockchip/Kconfig | 6 + drivers/soc/rockchip/Makefile | 1 + drivers/soc/rockchip/rockchip_pm_config.c | 212 ++++++++++++++++++ include/dt-bindings/suspend/rockchip-rk3399.h | 60 +++++ 5 files changed, 318 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/rockchip/rockchip-pm-config.txt create mode 100644 drivers/soc/rockchip/rockchip_pm_config.c create mode 100644 include/dt-bindings/suspend/rockchip-rk3399.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..a8fd70f17597 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/rockchip/rockchip-pm-config.txt @@ -0,0 +1,39 @@ +* 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/drivers/soc/rockchip/Kconfig b/drivers/soc/rockchip/Kconfig index 2c13bf4dd5db..f403ab803b42 100644 --- a/drivers/soc/rockchip/Kconfig +++ b/drivers/soc/rockchip/Kconfig @@ -34,4 +34,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 875032f7344e..7aa3d5d1b330 100644 --- a/drivers/soc/rockchip/Makefile +++ b/drivers/soc/rockchip/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_ROCKCHIP_GRF) += grf.o obj-$(CONFIG_ROCKCHIP_IODOMAIN) += io-domain.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..43b2e0f33343 --- /dev/null +++ b/drivers/soc/rockchip/rockchip_pm_config.c @@ -0,0 +1,212 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 = disable_nonboot_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 __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..0cccd6430ef6 --- /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 -- 2.30.0