From f70575805708cabdedea7498aaa3f710fde4d920 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Wed, 31 Jan 2024 03:29:01 +0000 Subject: [PATCH] add lvds1024*800 --- kernel/drivers/soc/rockchip/rockchip_pm_config.c | 324 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 287 insertions(+), 37 deletions(-) diff --git a/kernel/drivers/soc/rockchip/rockchip_pm_config.c b/kernel/drivers/soc/rockchip/rockchip_pm_config.c index 639a004..c319b79 100644 --- a/kernel/drivers/soc/rockchip/rockchip_pm_config.c +++ b/kernel/drivers/soc/rockchip/rockchip_pm_config.c @@ -17,6 +17,7 @@ #include <linux/pm.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include <linux/rockchip/rockchip_pm_config.h> #include <linux/rockchip/rockchip_sip.h> #include <linux/suspend.h> #include <dt-bindings/input/input.h> @@ -26,6 +27,10 @@ #define MAX_ON_OFF_REG_NUM 30 #define MAX_ON_OFF_REG_PROP_NAME_LEN 60 #define MAX_CONFIG_PROP_NAME_LEN 60 + +#define RK_ATAG_MCU_SLP_CORE 0x526b0001 +#define RK_ATAG_MCU_SLP_MAX 0x526b00ff +#define RK_ATAG_NONE 0x00000000 enum rk_pm_state { RK_PM_MEM = 0, @@ -47,12 +52,35 @@ } on_off_regs_list[RK_PM_STATE_MAX]; #endif -static struct rk_sleep_config { - u32 mode_config; - u32 wakeup_config; -} sleep_config[RK_PM_STATE_MAX]; +/* rk_tag related defines */ +#define sleep_tag_next(t) \ + ((struct rk_sleep_tag *)((__u32 *)(t) + (t)->hdr.size)) + +struct rk_tag_header { + u32 size; + u32 tag; +}; + +struct rk_sleep_tag { + struct rk_tag_header hdr; + u32 params[]; +}; + +struct rk_mcu_sleep_core_tag { + struct rk_tag_header hdr; + u32 total_size; + u32 reserve[13]; +}; + +struct rk_mcu_sleep_tags { + struct rk_mcu_sleep_core_tag core; + struct rk_sleep_tag slp_tags; +}; + +struct rk_sleep_config *sleep_config; static const struct of_device_id pm_match_table[] = { + { .compatible = "rockchip,pm-config",}, { .compatible = "rockchip,pm-px30",}, { .compatible = "rockchip,pm-rk1808",}, { .compatible = "rockchip,pm-rk322x",}, @@ -70,9 +98,19 @@ }; #ifndef MODULE +enum { + RK_PM_VIRT_PWROFF_EN = 0, + RK_PM_VIRT_PWROFF_IRQ_CFG = 1, + RK_PM_VIRT_PWROFF_MAX, +}; + +static u32 *virtual_pwroff_irqs; + static void rockchip_pm_virt_pwroff_prepare(void) { - int error; + int error, i; + + pm_wakeup_clear(0); regulator_suspend_prepare(PM_SUSPEND_MEM); @@ -82,8 +120,58 @@ return; } - sip_smc_set_suspend_mode(VIRTUAL_POWEROFF, 0, 1); + sip_smc_set_suspend_mode(VIRTUAL_POWEROFF, RK_PM_VIRT_PWROFF_EN, 1); + + if (virtual_pwroff_irqs) { + for (i = 0; virtual_pwroff_irqs[i]; i++) { + error = sip_smc_set_suspend_mode(VIRTUAL_POWEROFF, + RK_PM_VIRT_PWROFF_IRQ_CFG, + virtual_pwroff_irqs[i]); + if (error) { + pr_err("%s: config virtual_pwroff_irqs[%d] error, overflow or update trust!\n", + __func__, i); + break; + } + } + } + sip_smc_virtual_poweroff(); +} + +static int parse_virtual_pwroff_config(struct device_node *node) +{ + int ret = 0, cnt; + u32 virtual_poweroff_en = 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; + + if (!virtual_poweroff_en) + return 0; + + cnt = of_property_count_u32_elems(node, "rockchip,virtual-poweroff-irqs"); + if (cnt > 0) { + /* 0 as the last element of virtual_pwroff_irqs */ + virtual_pwroff_irqs = kzalloc((cnt + 1) * sizeof(u32), GFP_KERNEL); + if (!virtual_pwroff_irqs) { + ret = -ENOMEM; + goto out; + } + + ret = of_property_read_u32_array(node, "rockchip,virtual-poweroff-irqs", + virtual_pwroff_irqs, cnt); + if (ret) { + pr_err("%s: get rockchip,virtual-poweroff-irqs error\n", + __func__); + goto out; + } + } + +out: + return ret; } static int parse_sleep_config(struct device_node *node, enum rk_pm_state state) @@ -164,22 +252,167 @@ return 0; } + +const struct rk_sleep_config *rockchip_get_cur_sleep_config(void) +{ + suspend_state_t suspend_state = mem_sleep_current; + enum rk_pm_state state = suspend_state - PM_SUSPEND_MEM; + + if (state >= RK_PM_STATE_MAX) + return NULL; + + return &sleep_config[state]; +} +EXPORT_SYMBOL_GPL(rockchip_get_cur_sleep_config); #endif + +static int parse_mcu_sleep_config(struct device_node *node) +{ + int ret, cnt; + struct arm_smccc_res res; + struct device_node *mcu_sleep_node; + struct device_node *child; + struct rk_mcu_sleep_tags *config; + struct rk_sleep_tag *slp_tag; + char *end; + + mcu_sleep_node = of_find_node_by_name(node, "rockchip-mcu-sleep-cfg"); + if (IS_ERR_OR_NULL(mcu_sleep_node)) { + ret = -ENODEV; + goto out; + } + + cnt = of_get_child_count(mcu_sleep_node); + if (!cnt) { + ret = -EINVAL; + goto free_mcu_mode; + } + + /* + * 4kb for sleep parameters + */ + res = sip_smc_request_share_mem(1, SHARE_PAGE_TYPE_SLEEP); + if (res.a0 != 0) { + pr_err("%s: no trust memory for mcu_sleep\n", __func__); + ret = -ENOMEM; + goto free_mcu_mode; + } + + /* Initialize core tag */ + memset((void *)res.a1, 0, sizeof(struct rk_mcu_sleep_tags)); + config = (struct rk_mcu_sleep_tags *)res.a1; + config->core.hdr.tag = RK_ATAG_MCU_SLP_CORE; + config->core.hdr.size = sizeof(struct rk_mcu_sleep_core_tag) / sizeof(u32); + config->core.total_size = sizeof(struct rk_mcu_sleep_tags) - + sizeof(struct rk_sleep_tag); + + slp_tag = &config->slp_tags; + + /* End point of sleep data */ + end = (char *)config + PAGE_SIZE - sizeof(struct rk_sleep_tag); + + for_each_available_child_of_node(mcu_sleep_node, child) { + /* Is overflow? */ + if ((char *)slp_tag->params >= end) + break; + + ret = of_property_read_u32_array(child, "rockchip,tag", + &slp_tag->hdr.tag, 1); + if (ret || + slp_tag->hdr.tag <= RK_ATAG_MCU_SLP_CORE || + slp_tag->hdr.tag >= RK_ATAG_MCU_SLP_MAX) { + pr_info("%s: no or invalid rockchip,tag in %s\n", + __func__, child->name); + + continue; + } + + cnt = of_property_count_u32_elems(child, "rockchip,params"); + if (cnt > 0) { + /* Is overflow? */ + if ((char *)(slp_tag->params + cnt) >= end) { + pr_warn("%s: no more space for rockchip,tag in %s\n", + __func__, child->name); + break; + } + + ret = of_property_read_u32_array(child, "rockchip,params", + slp_tag->params, cnt); + if (ret) { + pr_err("%s: rockchip,params error in %s\n", + __func__, child->name); + break; + } + + slp_tag->hdr.size = + cnt + sizeof(struct rk_tag_header) / sizeof(u32); + } else if (cnt == 0) { + slp_tag->hdr.size = 0; + } else { + continue; + } + + config->core.total_size += slp_tag->hdr.size * sizeof(u32); + + slp_tag = sleep_tag_next(slp_tag); + } + + /* Add none tag. + * Compiler will combine the follow code as "str xzr, [x28]", but + * "slp->hdr" may not be 8-byte alignment. So we use memset_io instead: + * slp_tag->hdr.size = 0; + * slp_tag->hdr.tag = RK_ATAG_NONE; + */ + memset_io(&slp_tag->hdr, 0, sizeof(slp_tag->hdr)); + + config->core.total_size += sizeof(struct rk_sleep_tag); + + ret = 0; + +free_mcu_mode: + of_node_put(mcu_sleep_node); +out: + return ret; +} + +static int parse_io_config(struct device *dev) +{ + int ret = 0, cnt; + struct device_node *node = dev->of_node; + struct rk_sleep_config *config = &sleep_config[RK_PM_MEM]; + + cnt = of_property_count_u32_elems(node, "rockchip,sleep-io-config"); + if (cnt > 0) { + /* 0 as the last element of virtual_pwroff_irqs */ + config->sleep_io_config = + devm_kmalloc_array(dev, cnt, sizeof(u32), GFP_KERNEL); + if (!config->sleep_io_config) { + ret = -ENOMEM; + goto out; + } + + ret = of_property_read_u32_array(node, "rockchip,sleep-io-config", + config->sleep_io_config, cnt); + if (ret) { + dev_err(dev, "get rockchip,sleep-io-config error\n"); + goto out; + } + + config->sleep_io_config_cnt = cnt; + } else { + dev_dbg(dev, "not set sleep-pin-config\n"); + } + +out: + return ret; +} static int pm_config_probe(struct platform_device *pdev) { const struct of_device_id *match_id; struct device_node *node; - struct rk_sleep_config *config = &sleep_config[RK_PM_MEM]; - u32 pwm_regulator_config = 0; - int gpio_temp[10]; - u32 sleep_debug_en = 0; - u32 apios_suspend = 0; - u32 io_ret_config = 0; - u32 sleep_pin_config[2] = {0}; -#ifndef MODULE - u32 virtual_poweroff_en = 0; -#endif + struct rk_sleep_config *config; + enum of_gpio_flags flags; int i = 0; int length; @@ -195,6 +428,14 @@ dev_err(&pdev->dev, "%s dev node err\n", __func__); return -ENODEV; } + + sleep_config = + devm_kmalloc_array(&pdev->dev, RK_PM_STATE_MAX, + sizeof(*sleep_config), GFP_KERNEL); + if (!sleep_config) + return -ENOMEM; + + config = &sleep_config[RK_PM_MEM]; if (of_property_read_u32_array(node, "rockchip,sleep-mode-config", @@ -212,48 +453,56 @@ if (of_property_read_u32_array(node, "rockchip,pwm-regulator-config", - &pwm_regulator_config, 1)) + &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, + config->pwm_regulator_config, 0); length = of_gpio_named_count(node, "rockchip,power-ctrl"); if (length > 0 && length < 10) { + config->power_ctrl_config_cnt = length; + config->power_ctrl_config = + devm_kmalloc_array(&pdev->dev, length, + sizeof(u32), GFP_KERNEL); + if (!config->power_ctrl_config) + return -ENOMEM; + 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])) + config->power_ctrl_config[i] = + of_get_named_gpio_flags(node, + "rockchip,power-ctrl", + i, + &flags); + if (!gpio_is_valid(config->power_ctrl_config[i])) break; sip_smc_set_suspend_mode(GPIO_POWER_CONFIG, i, - gpio_temp[i]); + config->power_ctrl_config[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)) + &config->sleep_debug_en, 1)) sip_smc_set_suspend_mode(SUSPEND_DEBUG_ENABLE, - sleep_debug_en, + config->sleep_debug_en, 0); if (!of_property_read_u32_array(node, "rockchip,apios-suspend", - &apios_suspend, 1)) + &config->apios_suspend, 1)) sip_smc_set_suspend_mode(APIOS_SUSPEND_CONFIG, - apios_suspend, + config->apios_suspend, 0); if (!of_property_read_u32_array(node, "rockchip,sleep-io-ret-config", - &io_ret_config, 1)) { - ret = sip_smc_set_suspend_mode(SUSPEND_IO_RET_CONFIG, io_ret_config, 0); + &config->io_ret_config, 1)) { + ret = sip_smc_set_suspend_mode(SUSPEND_IO_RET_CONFIG, config->io_ret_config, 0); if (ret) dev_warn(&pdev->dev, "sleep-io-ret-config failed (%d), check parameters or update trust\n", @@ -262,20 +511,21 @@ if (!of_property_read_u32_array(node, "rockchip,sleep-pin-config", - sleep_pin_config, 2)) { - ret = sip_smc_set_suspend_mode(SLEEP_PIN_CONFIG, sleep_pin_config[0], sleep_pin_config[1]); + config->sleep_pin_config, 2)) { + ret = sip_smc_set_suspend_mode(SLEEP_PIN_CONFIG, + config->sleep_pin_config[0], + config->sleep_pin_config[1]); if (ret) dev_warn(&pdev->dev, "sleep-pin-config failed (%d), check parameters or update trust\n", ret); } + parse_io_config(&pdev->dev); + parse_mcu_sleep_config(node); + #ifndef MODULE - 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; + parse_virtual_pwroff_config(node); for (i = RK_PM_MEM; i < RK_PM_STATE_MAX; i++) { parse_sleep_config(node, i); -- Gitblit v1.6.2