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 |  346 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 317 insertions(+), 29 deletions(-)

diff --git a/kernel/drivers/soc/rockchip/rockchip_pm_config.c b/kernel/drivers/soc/rockchip/rockchip_pm_config.c
index 659bab2..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>
@@ -27,6 +28,10 @@
 #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,
 	RK_PM_MEM_LITE,
@@ -34,6 +39,7 @@
 	RK_PM_STATE_MAX
 };
 
+#ifndef MODULE
 static const char * const pm_state_str[RK_PM_STATE_MAX] = {
 	[RK_PM_MEM] = "mem",
 	[RK_PM_MEM_LITE] = "mem-lite",
@@ -44,13 +50,37 @@
 	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];
+#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",},
@@ -59,25 +89,89 @@
 	{ .compatible = "rockchip,pm-rk3328",},
 	{ .compatible = "rockchip,pm-rk3368",},
 	{ .compatible = "rockchip,pm-rk3399",},
+	{ .compatible = "rockchip,pm-rk3528",},
+	{ .compatible = "rockchip,pm-rk3562",},
 	{ .compatible = "rockchip,pm-rk3568",},
+	{ .compatible = "rockchip,pm-rk3588",},
 	{ .compatible = "rockchip,pm-rv1126",},
 	{ },
 };
 
+#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);
 
-	error = disable_nonboot_cpus();
+	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_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)
@@ -159,19 +253,170 @@
 	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 virtual_poweroff_en = 0;
+	struct rk_sleep_config *config;
+
 	enum of_gpio_flags flags;
 	int i = 0;
 	int length;
+	int ret;
 
 	match_id = of_match_node(pm_match_table, pdev->dev.of_node);
 	if (!match_id)
@@ -183,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",
@@ -200,58 +453,90 @@
 
 	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,virtual-poweroff",
-					&virtual_poweroff_en, 1) &&
-	    virtual_poweroff_en)
-		pm_power_off_prepare = rockchip_pm_virt_pwroff_prepare;
+					"rockchip,sleep-io-ret-config",
+					&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",
+				 ret);
+	}
+
+	if (!of_property_read_u32_array(node,
+					"rockchip,sleep-pin-config",
+					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
+	parse_virtual_pwroff_config(node);
 
 	for (i = RK_PM_MEM; i < RK_PM_STATE_MAX; i++) {
 		parse_sleep_config(node, i);
 		parse_on_off_regulator(node, i);
 	}
+#endif
 
 	return 0;
 }
 
+#ifndef MODULE
 static int pm_config_prepare(struct device *dev)
 {
 	int i;
@@ -299,13 +584,16 @@
 static const struct dev_pm_ops rockchip_pm_ops = {
 	.prepare = pm_config_prepare,
 };
+#endif
 
 static struct platform_driver pm_driver = {
 	.probe = pm_config_probe,
 	.driver = {
 		.name = "rockchip-pm",
 		.of_match_table = pm_match_table,
+#ifndef MODULE
 		.pm = &rockchip_pm_ops,
+#endif
 	},
 };
 

--
Gitblit v1.6.2