From 2f7c68cb55ecb7331f2381deb497c27155f32faf Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Wed, 03 Jan 2024 09:43:39 +0000
Subject: [PATCH] update kernel to 5.10.198

---
 kernel/drivers/mfd/rkx110_x120/pattern_gen.c |  310 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 299 insertions(+), 11 deletions(-)

diff --git a/kernel/drivers/mfd/rkx110_x120/pattern_gen.c b/kernel/drivers/mfd/rkx110_x120/pattern_gen.c
index 488d372..8ad2574 100644
--- a/kernel/drivers/mfd/rkx110_x120/pattern_gen.c
+++ b/kernel/drivers/mfd/rkx110_x120/pattern_gen.c
@@ -8,6 +8,8 @@
 #include <linux/debugfs.h>
 
 #include "rkx110_x120.h"
+#include "rkx110_x120_display.h"
+#include "hal/cru_api.h"
 
 #define PATTERN_GEN_PATTERN_CTRL	0x0000
 #define PATTERN_START_PCLK		BIT(31)
@@ -29,11 +31,10 @@
 #define PATTERN_GEN_VALUE0		0x0014
 #define PATTERN_GEN_VALUE1		0x0018
 
-static void pattern_gen_enable(struct pattern_gen *pattern_gen)
+static void pattern_gen_config(struct i2c_client *client, struct pattern_gen *pattern_gen,
+				struct videomode *vm)
 {
-	struct i2c_client *client = pattern_gen->chip->client;
 	struct rk_serdes *serdes = pattern_gen->chip->serdes;
-	const struct videomode *vm = serdes->vm;
 
 	serdes->i2c_update_bits(client, pattern_gen->base + PATTERN_GEN_PATTERN_CTRL,
 				PATTERN_RECTANGLE_H | PATTERN_RECTANGLE_V,
@@ -53,24 +54,311 @@
 	serdes->i2c_write_reg(client, pattern_gen->base + PATTERN_GEN_PATERN_VH_CFG3,
 			      FIELD_PREP(PATTERN_HSA, vm->hsync_len));
 
-	serdes->i2c_update_bits(client, pattern_gen->base + PATTERN_GEN_PATTERN_CTRL,
-				PATTERN_START_PCLK,
-				FIELD_PREP(PATTERN_START_PCLK, 1));
 	serdes->i2c_write_reg(client, pattern_gen->link_src_reg,
 			      BIT(pattern_gen->link_src_offset + 16) |
 			      BIT(pattern_gen->link_src_offset));
+}
+
+static void pattern_stop_stream(struct pattern_gen *pattern_gen)
+{
+	struct rk_serdes *serdes = pattern_gen->chip->serdes;
+
+	if (serdes->version != SERDES_V1)
+		return;
+
+	if (pattern_gen->chip != &serdes->chip[DEVICE_LOCAL])
+		return;
+
+	rk_serdes_display_video_start(serdes, pattern_gen->route, false);
+
+	if (!strcmp(pattern_gen->name, "lvds0")) {
+		hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
+			    RKX110_SRST_RESETN_D_LVDS0_RKLINK_TX);
+	} else if (!strcmp(pattern_gen->name, "lvds1")) {
+		hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
+			    RKX110_SRST_RESETN_D_LVDS1_RKLINK_TX);
+	} else if (!strcmp(pattern_gen->name, "dual-lvds")) {
+		rkx110_set_stream_source(serdes, RK_SERDES_RGB_RX, DEVICE_LOCAL);
+		hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
+			    RKX110_SRST_RESETN_2X_LVDS_RKLINK_TX);
+		hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
+			    RKX110_SRST_RESETN_D_LVDS0_RKLINK_TX);
+		hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
+			    RKX110_SRST_RESETN_D_LVDS1_RKLINK_TX);
+	} else if (!strcmp(pattern_gen->name, "dsi0")) {
+		serdes->i2c_write_reg(serdes->chip[DEVICE_LOCAL].client, 0x0314,
+				      0x1400140);
+		hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
+			    RKX111_SRST_RESETN_D_DSI_0_REC_RKLINK_TX);
+		hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
+			    RKX110_SRST_RESETN_D_DSI_0_RKLINK_TX);
+		rkx110_linktx_dsi_rec_start(serdes, DEVICE_LOCAL, 0, false);
+	} else if (!strcmp(pattern_gen->name, "dsi1")) {
+		serdes->i2c_write_reg(serdes->chip[DEVICE_LOCAL].client, 0x0314,
+				      0x2800280);
+		hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
+			    RKX111_SRST_RESETN_D_DSI_1_REC_RKLINK_TX);
+		hwclk_reset(serdes->chip[DEVICE_LOCAL].hwclk,
+			    RKX110_SRST_RESETN_D_DSI_1_RKLINK_TX);
+		rkx110_linktx_dsi_rec_start(serdes, DEVICE_LOCAL, 1, false);
+	}
+}
+
+static void pattern_start_stream(struct pattern_gen *pattern_gen, bool is_pattern_stream)
+{
+	struct rk_serdes *serdes = pattern_gen->chip->serdes;
+	struct videomode *vm = &pattern_gen->route->vm;
+	u32 delay_length;
+
+	if (serdes->version != SERDES_V1)
+		return;
+
+	if (pattern_gen->chip != &serdes->chip[DEVICE_LOCAL])
+		return;
+
+	if (!strcmp(pattern_gen->name, "lvds0")) {
+		hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
+				     RKX110_SRST_RESETN_D_LVDS0_RKLINK_TX);
+	} else if (!strcmp(pattern_gen->name, "lvds1")) {
+		hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
+				     RKX110_SRST_RESETN_D_LVDS1_RKLINK_TX);
+	} else if (!strcmp(pattern_gen->name, "dual-lvds")) {
+		hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
+				     RKX110_SRST_RESETN_2X_LVDS_RKLINK_TX);
+		hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
+				     RKX110_SRST_RESETN_D_LVDS0_RKLINK_TX);
+		hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
+				     RKX110_SRST_RESETN_D_LVDS1_RKLINK_TX);
+		rkx110_set_stream_source(serdes, RK_SERDES_DUAL_LVDS_RX,
+					 DEVICE_LOCAL);
+	} else if (!strcmp(pattern_gen->name, "dsi0")) {
+		hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
+				     RKX110_SRST_RESETN_D_DSI_0_RKLINK_TX);
+		hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
+				     RKX111_SRST_RESETN_D_DSI_0_REC_RKLINK_TX);
+		serdes->i2c_write_reg(serdes->chip[DEVICE_LOCAL].client, 0x0314,
+				      0x1400000);
+
+		rkx110_linktx_dsi_type_select(serdes, DEVICE_LOCAL, 0,
+					      is_pattern_stream ? false : true);
+		if (is_pattern_stream)
+			delay_length = vm->hsync_len + vm->hback_porch +
+				       vm->hactive + vm->hfront_porch;
+		else
+			delay_length = (vm->vfront_porch + 1) * (vm->hsync_len +
+					vm->hback_porch + vm->hactive + vm->hfront_porch);
+		rkx110_linktx_dsi_deley_length_config(serdes, DEVICE_LOCAL, 0, delay_length);
+		rkx110_linktx_dsi_rec_start(serdes, DEVICE_LOCAL, 0, true);
+	} else if (!strcmp(pattern_gen->name, "dsi1")) {
+		hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
+				     RKX110_SRST_RESETN_D_DSI_1_RKLINK_TX);
+		hwclk_reset_deassert(serdes->chip[DEVICE_LOCAL].hwclk,
+				     RKX111_SRST_RESETN_D_DSI_1_REC_RKLINK_TX);
+		serdes->i2c_write_reg(serdes->chip[DEVICE_LOCAL].client, 0x0314,
+				      0x2800000);
+
+		rkx110_linktx_dsi_type_select(serdes, DEVICE_LOCAL, 1,
+					      is_pattern_stream ? false : true);
+		if (is_pattern_stream)
+			delay_length = vm->hsync_len + vm->hback_porch +
+				       vm->hactive + vm->hfront_porch;
+		else
+			delay_length = (vm->vfront_porch + 1) * (vm->hsync_len +
+					vm->hback_porch + vm->hactive + vm->hfront_porch);
+		rkx110_linktx_dsi_deley_length_config(serdes, DEVICE_LOCAL, 1, delay_length);
+		rkx110_linktx_dsi_rec_start(serdes, DEVICE_LOCAL, 1, true);
+	}
+
+	rk_serdes_display_video_start(serdes, pattern_gen->route, true);
+}
+
+static void pattern_switch_clk_to_pattern(struct pattern_gen *pattern_gen, struct videomode *vm)
+{
+	struct rk_serdes *serdes = pattern_gen->chip->serdes;
+	struct hwclk *hwclk = serdes->chip[DEVICE_LOCAL].hwclk;
+
+	if (serdes->version != SERDES_V1)
+		return;
+
+	if (pattern_gen->chip != &serdes->chip[DEVICE_LOCAL])
+		return;
+
+	if (!strcmp(pattern_gen->name, "lvds0")) {
+		hwclk_set_rate(hwclk, RKX111_CPS_CLK_D_LVDS0_PATTERN_GEN, vm->pixelclock);
+		dev_info(serdes->dev, "RKX111_CPS_CLK_D_LVDS0_PATTERN_GEN:%d\n",
+			 hwclk_get_rate(hwclk, RKX111_CPS_CLK_D_LVDS0_PATTERN_GEN));
+		hwclk_set_mux(hwclk, RKX111_CLK_D_LVDS0_RKLINK_TX_SEL,
+			      RKX111_CLK_D_LVDS0_RKLINK_TX_SEL_CLK_D_LVDS0_PATTERN_GEN);
+	} else if (!strcmp(pattern_gen->name, "lvds1")) {
+		hwclk_set_rate(hwclk, RKX111_CPS_CLK_D_LVDS1_PATTERN_GEN, vm->pixelclock);
+		dev_info(serdes->dev, "RKX111_CPS_CLK_D_LVDS1_PATTERN_GEN:%d\n",
+			 hwclk_get_rate(hwclk, RKX111_CPS_CLK_D_LVDS1_PATTERN_GEN));
+		hwclk_set_mux(hwclk, RKX111_CLK_D_LVDS1_RKLINK_TX_SEL,
+			      RKX111_CLK_D_LVDS1_RKLINK_TX_SEL_CLK_D_LVDS1_PATTERN_GEN);
+	} else if (!strcmp(pattern_gen->name, "dual-lvds")) {
+		hwclk_set_rate(hwclk, RKX111_CPS_CLK_D_LVDS0_PATTERN_GEN, vm->pixelclock);
+		dev_info(serdes->dev, "RKX111_CPS_CLK_D_LVDS0_PATTERN_GEN:%d\n",
+			 hwclk_get_rate(hwclk, RKX111_CPS_CLK_D_LVDS0_PATTERN_GEN));
+		hwclk_set_rate(hwclk, RKX111_CPS_CLK_D_LVDS1_PATTERN_GEN, vm->pixelclock);
+		dev_info(serdes->dev, "RKX111_CPS_CLK_D_LVDS1_PATTERN_GEN:%d\n",
+			 hwclk_get_rate(hwclk, RKX111_CPS_CLK_D_LVDS1_PATTERN_GEN));
+		hwclk_set_mux(hwclk, RKX111_CLK_D_LVDS0_RKLINK_TX_SEL,
+			      RKX111_CLK_D_LVDS0_RKLINK_TX_SEL_CLK_D_LVDS0_PATTERN_GEN);
+		hwclk_set_mux(hwclk, RKX111_CLK_D_LVDS1_RKLINK_TX_SEL,
+			      RKX111_CLK_D_LVDS1_RKLINK_TX_SEL_CLK_D_LVDS1_PATTERN_GEN);
+	} else if (!strcmp(pattern_gen->name, "dsi0")) {
+		hwclk_set_mux(hwclk, RKX111_CLK_D_DSI_0_RKLINK_TX_SEL,
+			      RKX111_CLK_D_DSI_0_RKLINK_TX_SEL_CLK_D_DSI_0_PATTERN_GEN);
+	} else if (!strcmp(pattern_gen->name, "dsi1")) {
+		hwclk_set_mux(hwclk, RKX111_CLK_D_DSI_1_RKLINK_TX_SEL,
+			      RKX111_CLK_D_DSI_1_RKLINK_TX_SEL_CLK_D_DSI_1_PATTERN_GEN);
+	}
+}
+
+static void pattern_switch_clk_to_stream(struct pattern_gen *pattern_gen)
+{
+	struct rk_serdes *serdes = pattern_gen->chip->serdes;
+	struct hwclk *hwclk = serdes->chip[DEVICE_LOCAL].hwclk;
+
+	if (serdes->version != SERDES_V1)
+		return;
+
+	if (pattern_gen->chip != &serdes->chip[DEVICE_LOCAL])
+		return;
+
+	if (!strcmp(pattern_gen->name, "lvds0")) {
+		hwclk_set_mux(hwclk, RKX111_CLK_D_LVDS0_RKLINK_TX_SEL,
+			      RKX111_CLK_D_LVDS0_RKLINK_TX_SEL_CLK_D_LVDS0_RKLINK_TX_PRE);
+	} else if (!strcmp(pattern_gen->name, "lvds1")) {
+		hwclk_set_mux(hwclk, RKX111_CLK_D_LVDS1_RKLINK_TX_SEL,
+			      RKX111_CLK_D_LVDS1_RKLINK_TX_SEL_CLK_D_LVDS1_RKLINK_TX_PRE);
+	} else if (!strcmp(pattern_gen->name, "dual-lvds")) {
+		hwclk_set_mux(hwclk, RKX111_CLK_D_LVDS0_RKLINK_TX_SEL,
+			      RKX111_CLK_D_LVDS0_RKLINK_TX_SEL_CLK_D_LVDS0_RKLINK_TX_PRE);
+		hwclk_set_mux(hwclk, RKX111_CLK_D_LVDS1_RKLINK_TX_SEL,
+			      RKX111_CLK_D_LVDS1_RKLINK_TX_SEL_CLK_D_LVDS1_RKLINK_TX_PRE);
+	} else if (!strcmp(pattern_gen->name, "dsi0")) {
+		hwclk_set_mux(hwclk, RKX111_CLK_D_DSI_0_RKLINK_TX_SEL,
+			      RKX111_CLK_D_DSI_0_RKLINK_TX_SEL_CLK_D_DSI_0_RKLINK_TX_PRE);
+	} else if (!strcmp(pattern_gen->name, "dsi1")) {
+		hwclk_set_mux(hwclk, RKX111_CLK_D_DSI_1_RKLINK_TX_SEL,
+			      RKX111_CLK_D_DSI_1_RKLINK_TX_SEL_CLK_D_DSI_1_RKLINK_TX_PRE);
+	}
+}
+
+static int pattern_get_route(struct pattern_gen *pattern_gen)
+{
+	struct rk_serdes *serdes = pattern_gen->chip->serdes;
+	struct rk_serdes_route *route;
+	int i;
+
+	for (i = 0; i < serdes->route_nr; i++) {
+		route = serdes->route[i];
+
+		if (pattern_gen->chip == &serdes->chip[DEVICE_LOCAL]) {
+			if ((pattern_gen->type == route->local_port0) ||
+			    (pattern_gen->type == route->local_port1)) {
+				pattern_gen->route = route;
+				break;
+			}
+		}
+		if (pattern_gen->chip == &serdes->chip[DEVICE_REMOTE0]) {
+			if ((pattern_gen->type == route->remote0_port0) ||
+			    (pattern_gen->type == route->remote0_port1)) {
+				pattern_gen->route = route;
+				break;
+			}
+		}
+
+		if (pattern_gen->chip == &serdes->chip[DEVICE_REMOTE1]) {
+			if ((pattern_gen->type == route->remote1_port0) ||
+			    (pattern_gen->type == route->remote1_port1)) {
+				pattern_gen->route = route;
+				break;
+			}
+		}
+	}
+
+	if (i >= serdes->route_nr) {
+		dev_info(serdes->dev, "can't find the %s in route\n", pattern_gen->name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void pattern_gen_enable(struct pattern_gen *pattern_gen)
+{
+	struct i2c_client *client = pattern_gen->chip->client;
+	struct rk_serdes *serdes = pattern_gen->chip->serdes;
+	struct videomode vm;
+	int ret;
+
+	ret = pattern_get_route(pattern_gen);
+	if (ret)
+		return;
+
+	memcpy(&vm, &pattern_gen->route->vm, sizeof(vm));
+
+	pattern_stop_stream(pattern_gen);
+	if (!strcmp(pattern_gen->name, "dual-lvds")) {
+		struct pattern_gen *lvds0_pat = pattern_gen + 1;
+		struct pattern_gen *lvds1_pat = pattern_gen + 2;
+
+		vm.hactive /= 2;
+		vm.hfront_porch /= 2;
+		vm.hback_porch /= 2;
+		vm.hsync_len /= 2;
+		vm.pixelclock /= 2;
+
+		pattern_switch_clk_to_pattern(pattern_gen, &vm);
+		pattern_gen_config(client, lvds0_pat, &vm);
+		pattern_gen_config(client, lvds1_pat, &vm);
+		serdes->i2c_write_reg(client, pattern_gen->link_src_reg,
+				      BIT(pattern_gen->link_src_offset + 16) |
+				      BIT(pattern_gen->link_src_offset));
+	} else {
+		pattern_switch_clk_to_pattern(pattern_gen, &vm);
+		pattern_gen_config(client, pattern_gen, &vm);
+		serdes->i2c_update_bits(client, pattern_gen->base + PATTERN_GEN_PATTERN_CTRL,
+					PATTERN_START_PCLK,
+					FIELD_PREP(PATTERN_START_PCLK, 1));
+	}
+
+	pattern_start_stream(pattern_gen, true);
 }
 
 static void pattern_gen_disable(struct pattern_gen *pattern_gen)
 {
 	struct i2c_client *client = pattern_gen->chip->client;
 	struct rk_serdes *serdes = pattern_gen->chip->serdes;
+	int ret;
 
-	serdes->i2c_write_reg(client, pattern_gen->link_src_reg,
-			      BIT(pattern_gen->link_src_offset + 16));
-	serdes->i2c_update_bits(client, pattern_gen->base + PATTERN_GEN_PATTERN_CTRL,
-				PATTERN_START_PCLK,
-				FIELD_PREP(PATTERN_START_PCLK, 0));
+	ret = pattern_get_route(pattern_gen);
+	if (ret)
+		return;
+
+	pattern_stop_stream(pattern_gen);
+	if (!strcmp(pattern_gen->name, "dual-lvds")) {
+		struct pattern_gen *lvds0_pat = pattern_gen + 1;
+		struct pattern_gen *lvds1_pat = pattern_gen + 2;
+
+		serdes->i2c_write_reg(client, lvds0_pat->link_src_reg,
+				      BIT(lvds0_pat->link_src_offset + 16));
+		serdes->i2c_write_reg(client, lvds1_pat->link_src_reg,
+				      BIT(lvds1_pat->link_src_offset + 16));
+		serdes->i2c_write_reg(client, pattern_gen->link_src_reg,
+				      BIT(pattern_gen->link_src_offset + 16));
+	} else {
+		serdes->i2c_write_reg(client, pattern_gen->link_src_reg,
+				      BIT(pattern_gen->link_src_offset + 16));
+		serdes->i2c_update_bits(client, pattern_gen->base + PATTERN_GEN_PATTERN_CTRL,
+					PATTERN_START_PCLK,
+					FIELD_PREP(PATTERN_START_PCLK, 0));
+	}
+
+	pattern_switch_clk_to_stream(pattern_gen);
+	pattern_start_stream(pattern_gen, false);
 }
 
 static ssize_t pattern_gen_write(struct file *file, const char __user *ubuf,

--
Gitblit v1.6.2