From ee930fffee469d076998274a2ca55e13dc1efb67 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Fri, 10 May 2024 08:50:54 +0000
Subject: [PATCH] enable tun/tap/iptables

---
 u-boot/drivers/video/drm/dw_hdmi.c |  186 ++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 154 insertions(+), 32 deletions(-)

diff --git a/u-boot/drivers/video/drm/dw_hdmi.c b/u-boot/drivers/video/drm/dw_hdmi.c
index f993a21..a30e4d5 100644
--- a/u-boot/drivers/video/drm/dw_hdmi.c
+++ b/u-boot/drivers/video/drm/dw_hdmi.c
@@ -7,6 +7,7 @@
 #include <common.h>
 #include <malloc.h>
 #include <syscon.h>
+#include <asm/gpio.h>
 #include <asm/arch-rockchip/clock.h>
 #include <asm/arch/vendor.h>
 #include <edid.h>
@@ -27,6 +28,7 @@
 #define HDCP_PRIVATE_KEY_SIZE   280
 #define HDCP_KEY_SHA_SIZE       20
 #define HDMI_HDCP1X_ID		5
+#define HDMI_EDID_BLOCK_LEN	128
 /*
  * Unless otherwise noted, entries in this table are 100% optimization.
  * Values can be obtained from hdmi_compute_n() but that function is
@@ -181,6 +183,7 @@
 	bool sink_has_audio;
 	void *regs;
 	void *grf;
+	void *gpio_base;
 	struct dw_hdmi_i2c *i2c;
 
 	struct {
@@ -203,6 +206,8 @@
 
 	bool hdcp1x_enable;
 	bool output_bus_format_rgb;
+
+	struct gpio_desc hpd_gpiod;
 };
 
 static void dw_hdmi_writel(struct dw_hdmi *hdmi, u8 val, int offset)
@@ -409,6 +414,7 @@
 {
 	struct dw_hdmi_i2c *i2c = hdmi->i2c;
 	int interrupt = 0, i = 20;
+	bool read_edid = false;
 
 	if (!i2c->is_regaddr) {
 		printf("set read register address to 0\n");
@@ -416,14 +422,36 @@
 		i2c->is_regaddr = true;
 	}
 
-	while (length--) {
-		hdmi_writeb(hdmi, i2c->slave_reg++, HDMI_I2CM_ADDRESS);
-		if (i2c->is_segment)
-			hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ_EXT,
-				    HDMI_I2CM_OPERATION);
-		else
-			hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ,
-				    HDMI_I2CM_OPERATION);
+	/* edid reads are in 128 bytes. scdc reads are in 1 byte */
+	if (length == HDMI_EDID_BLOCK_LEN)
+		read_edid = true;
+
+	while (length > 0) {
+		hdmi_writeb(hdmi, i2c->slave_reg, HDMI_I2CM_ADDRESS);
+
+		if (read_edid) {
+			i2c->slave_reg += 8;
+			length -= 8;
+		} else {
+			i2c->slave_reg++;
+			length--;
+		}
+
+		if (i2c->is_segment) {
+			if (read_edid)
+				hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ8_EXT,
+					    HDMI_I2CM_OPERATION);
+			else
+				hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ_EXT,
+					    HDMI_I2CM_OPERATION);
+		} else {
+			if (read_edid)
+				hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ8,
+					    HDMI_I2CM_OPERATION);
+			else
+				hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ,
+					    HDMI_I2CM_OPERATION);
+		}
 
 		while (i--) {
 			udelay(1000);
@@ -439,6 +467,10 @@
 		if (!interrupt) {
 			printf("[%s] i2c read reg[0x%02x] no interrupt\n",
 			       __func__, i2c->slave_reg);
+			hdmi_writeb(hdmi, 0, HDMI_I2CM_SOFTRSTZ);
+			hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_BUS_CLEAR,
+				    HDMI_I2CM_OPERATION);
+			udelay(1000);
 			return -EAGAIN;
 		}
 
@@ -446,11 +478,19 @@
 		if (interrupt & HDMI_IH_I2CM_STAT0_ERROR) {
 			printf("[%s] read reg[0x%02x] data error:0x%02x\n",
 			       __func__, i2c->slave_reg, interrupt);
+			hdmi_writeb(hdmi, 0, HDMI_I2CM_SOFTRSTZ);
+			hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_BUS_CLEAR,
+				    HDMI_I2CM_OPERATION);
+			udelay(1000);
 			return -EIO;
 		}
 
 		i = 20;
-		*buf++ = hdmi_readb(hdmi, HDMI_I2CM_DATAI);
+		if (read_edid)
+			for (i = 0; i < 8; i++)
+				*buf++ = hdmi_readb(hdmi, HDMI_I2CM_READ_BUFF0 + i);
+		else
+			*buf++ = hdmi_readb(hdmi, HDMI_I2CM_DATAI);
 	}
 	i2c->is_segment = false;
 
@@ -490,8 +530,22 @@
 				break;
 		}
 
+		if (!interrupt) {
+			printf("[%s] i2c write reg[0x%02x] no interrupt\n",
+			       __func__, i2c->slave_reg);
+			hdmi_writeb(hdmi, 0, HDMI_I2CM_SOFTRSTZ);
+			hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_BUS_CLEAR,
+				    HDMI_I2CM_OPERATION);
+			udelay(1000);
+			return -EAGAIN;
+		}
+
 		if ((interrupt & m_I2CM_ERROR) || (i == -1)) {
 			printf("[%s] write data error\n", __func__);
+			hdmi_writeb(hdmi, 0, HDMI_I2CM_SOFTRSTZ);
+			hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_BUS_CLEAR,
+				    HDMI_I2CM_OPERATION);
+			udelay(1000);
 			return -EIO;
 		} else if (interrupt & m_I2CM_DONE) {
 			printf("[%s] write offset %02x success\n",
@@ -959,6 +1013,7 @@
 	 * but it has a vedor phy.
 	 */
 	if (phy_type == DW_HDMI_PHY_VENDOR_PHY ||
+	    hdmi->dev_type == RK3528_HDMI ||
 	    hdmi->dev_type == RK3328_HDMI ||
 	    hdmi->dev_type == RK3228_HDMI) {
 		/* Vendor PHYs require support from the glue layer. */
@@ -1042,14 +1097,11 @@
 	       vmode->mpixelclock, vmode->mtmdsclock);
 
 	/* Set up HDMI_FC_INVIDCONF
-	 * fc_invidconf.HDCP_keepout must be set (1'b1)
-	 * when activate the scrambler feature.
+	 * Some display equipments require that the interval
+	 * between Video Data and Data island must be at least 58 pixels,
+	 * and fc_invidconf.HDCP_keepout set (1'b1) can meet the requirement.
 	 */
-	inv_val = (vmode->mtmdsclock > 340000000 ||
-		   (hdmi_info->scdc.scrambling.low_rates &&
-		   hdmi->scramble_low_rates) ?
-		   HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
-		   HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
+	inv_val = HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE;
 
 	inv_val |= mode->flags & DRM_MODE_FLAG_PVSYNC ?
 		HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
@@ -1418,13 +1470,8 @@
 		  HDMI_VP_CONF_PR_EN_MASK |
 		  HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
 
-	if ((color_depth == 5 && hdmi->previous_mode.htotal % 4) ||
-	    (color_depth == 6 && hdmi->previous_mode.htotal % 2))
-		hdmi_modb(hdmi, 0, HDMI_VP_STUFF_IDEFAULT_PHASE_MASK,
-			  HDMI_VP_STUFF);
-	else
-		hdmi_modb(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET,
-			  HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF);
+	hdmi_modb(hdmi, 0, HDMI_VP_STUFF_IDEFAULT_PHASE_MASK,
+		  HDMI_VP_STUFF);
 
 	hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP);
 
@@ -1887,6 +1934,7 @@
 				 hdmi->sample_rate);
 }
 
+#ifndef CONFIG_SPL_BUILD
 static int dw_hdmi_hdcp_load_key(struct dw_hdmi *hdmi)
 {
 	int i, j, ret, val;
@@ -1952,6 +2000,7 @@
 	free(hdcp_keys);
 	return 0;
 }
+#endif
 
 static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi,
 				const struct drm_display_mode *mode)
@@ -1981,8 +2030,10 @@
 	hdmi_modb(hdmi, hdmi_dvi, HDMI_A_HDCPCFG0_HDMIDVI_MASK,
 		  HDMI_A_HDCPCFG0);
 
+#ifndef CONFIG_SPL_BUILD
 	if (!(hdmi_readb(hdmi, HDMI_HDCPREG_RMSTS) & 0x3f))
 		dw_hdmi_hdcp_load_key(hdmi);
+#endif
 
 	hdmi_modb(hdmi, HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE,
 		  HDMI_FC_INVIDCONF_HDCP_KEEPOUT_MASK,
@@ -2269,13 +2320,18 @@
 {
 	struct connector_state *conn_state = &state->conn_state;
 	const struct dw_hdmi_plat_data *pdata =
+#ifdef CONFIG_SPL_BUILD
+		(const struct dw_hdmi_plat_data *)conn->data;
+#else
 		(const struct dw_hdmi_plat_data *)dev_get_driver_data(conn->dev);
+	ofnode hdmi_node = conn->dev->node;
+	struct device_node *ddc_node;
+	int ret;
+#endif
 	struct crtc_state *crtc_state = &state->crtc_state;
 	struct dw_hdmi *hdmi;
 	struct drm_display_mode *mode_buf;
-	ofnode hdmi_node = conn->dev->node;
 	u32 val;
-	struct device_node *ddc_node;
 
 	hdmi = malloc(sizeof(struct dw_hdmi));
 	if (!hdmi)
@@ -2285,13 +2341,28 @@
 	mode_buf = malloc(MODE_LEN * sizeof(struct drm_display_mode));
 	if (!mode_buf)
 		return -ENOMEM;
+
+#ifdef CONFIG_SPL_BUILD
+	hdmi->id = 0;
+	hdmi->regs = (void *)RK3528_HDMI_BASE;
+	hdmi->io_width = 4;
+	hdmi->scramble_low_rates = false;
+	hdmi->hdcp1x_enable = false;
+	hdmi->output_bus_format_rgb = false;
+	conn_state->type = DRM_MODE_CONNECTOR_HDMIA;
+#else
 	hdmi->id = of_alias_get_id(ofnode_to_np(hdmi_node), "hdmi");
 	if (hdmi->id < 0)
 		hdmi->id = 0;
-	conn_state->disp_info  = rockchip_get_disp_info(conn_state->type, hdmi->id);
+	conn_state->disp_info = rockchip_get_disp_info(conn_state->type, hdmi->id);
+#endif
 
 	memset(mode_buf, 0, MODE_LEN * sizeof(struct drm_display_mode));
 
+	hdmi->dev_type = pdata->dev_type;
+	hdmi->plat_data = pdata;
+
+#ifndef CONFIG_SPL_BUILD
 	hdmi->regs = dev_read_addr_ptr(conn->dev);
 	hdmi->io_width = ofnode_read_s32_default(hdmi_node, "reg-io-width", -1);
 
@@ -2309,6 +2380,24 @@
 	else
 		hdmi->output_bus_format_rgb = false;
 
+	ret = dev_read_size(conn->dev, "rockchip,phy-table");
+	if (ret > 0 && hdmi->plat_data->phy_config) {
+		u32 phy_config[ret / 4];
+		int i;
+
+		dev_read_u32_array(conn->dev, "rockchip,phy-table", phy_config, ret / 4);
+
+		for (i = 0; i < ret / 16; i++) {
+			if (phy_config[i * 4] != 0)
+				hdmi->plat_data->phy_config[i].mpixelclock = (u64)phy_config[i * 4];
+			else
+				hdmi->plat_data->phy_config[i].mpixelclock = ~0UL;
+			hdmi->plat_data->phy_config[i].sym_ctr = (u16)phy_config[i * 4 + 1];
+			hdmi->plat_data->phy_config[i].term = (u16)phy_config[i * 4 + 2];
+			hdmi->plat_data->phy_config[i].vlev_ctr = (u16)phy_config[i * 4 + 3];
+		}
+	}
+
 	ddc_node = of_parse_phandle(ofnode_to_np(hdmi_node), "ddc-i2c-bus", 0);
 	if (ddc_node) {
 		uclass_get_device_by_ofnode(UCLASS_I2C, np_to_ofnode(ddc_node),
@@ -2316,6 +2405,7 @@
 		if (hdmi->adap.i2c_bus)
 			hdmi->adap.ops = i2c_get_ops(hdmi->adap.i2c_bus);
 	}
+#endif
 
 	hdmi->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
 	if (hdmi->grf <= 0) {
@@ -2323,6 +2413,20 @@
 		       __func__, hdmi->grf);
 		return -ENXIO;
 	}
+
+#ifdef CONFIG_SPL_BUILD
+	hdmi->gpio_base = (void *)RK3528_GPIO_BASE;
+#else
+	ret = gpio_request_by_name(conn->dev, "hpd-gpios", 0,
+				   &hdmi->hpd_gpiod, GPIOD_IS_IN);
+	if (ret && ret != -ENOENT) {
+		printf("%s: Cannot get HPD GPIO: %d\n", __func__, ret);
+		return ret;
+	}
+	hdmi->gpio_base = (void *)dev_read_addr_index(conn->dev, 1);
+#endif
+	if (!hdmi->gpio_base)
+		return -ENODEV;
 
 	dw_hdmi_set_reg_wr(hdmi);
 
@@ -2345,24 +2449,28 @@
 	 * Read high and low time from device tree. If not available use
 	 * the default timing scl clock rate is about 99.6KHz.
 	 */
+#ifdef CONFIG_SPL_BUILD
+	hdmi->i2c->scl_high_ns = 9625;
+	hdmi->i2c->scl_low_ns = 10000;
+#else
 	hdmi->i2c->scl_high_ns =
 		ofnode_read_s32_default(hdmi_node,
 					"ddc-i2c-scl-high-time-ns", 4708);
 	hdmi->i2c->scl_low_ns =
 		ofnode_read_s32_default(hdmi_node,
 					"ddc-i2c-scl-low-time-ns", 4916);
+#endif
 
 	dw_hdmi_i2c_init(hdmi);
 	conn_state->output_if |= VOP_OUTPUT_IF_HDMI0;
 	conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA;
 
-	hdmi->dev_type = pdata->dev_type;
-	hdmi->plat_data = pdata;
 	hdmi->edid_data.mode_buf = mode_buf;
 	hdmi->sample_rate = 48000;
 
 	conn->data = hdmi;
-	dw_hdmi_set_iomux(hdmi->grf, hdmi->dev_type);
+	dw_hdmi_set_iomux(hdmi->grf, hdmi->gpio_base,
+			  &hdmi->hpd_gpiod, hdmi->dev_type);
 	dw_hdmi_detect_phy(hdmi);
 	dw_hdmi_dev_init(hdmi);
 
@@ -2413,7 +2521,7 @@
 
 int rockchip_dw_hdmi_get_timing(struct rockchip_connector *conn, struct display_state *state)
 {
-	int ret, i;
+	int ret, i, vic;
 	struct connector_state *conn_state = &state->conn_state;
 	struct drm_display_mode *mode = &conn_state->mode;
 	struct dw_hdmi *hdmi = conn->data;
@@ -2439,9 +2547,13 @@
 		hdmi->sink_has_audio = true;
 		do_cea_modes(&hdmi->edid_data, def_modes_vic,
 			     sizeof(def_modes_vic));
+		hdmi->edid_data.mode_buf[0].type |= DRM_MODE_TYPE_PREFERRED;
 		hdmi->edid_data.preferred_mode = &hdmi->edid_data.mode_buf[0];
 		printf("failed to get edid\n");
 	}
+#ifdef CONFIG_SPL_BUILD
+	conn_state->disp_info = rockchip_get_disp_info(conn_state->type, hdmi->id);
+#endif
 	drm_rk_filter_whitelist(&hdmi->edid_data);
 	if (hdmi->phy.ops->mode_valid)
 		hdmi->phy.ops->mode_valid(conn, hdmi, state);
@@ -2452,9 +2564,20 @@
 		return -EINVAL;
 	}
 
-	for (i = 0; i < hdmi->edid_data.modes; i++)
+	for (i = 0; i < hdmi->edid_data.modes; i++) {
 		hdmi->edid_data.mode_buf[i].vrefresh =
 			drm_mode_vrefresh(&hdmi->edid_data.mode_buf[i]);
+
+		vic = drm_match_cea_mode(&hdmi->edid_data.mode_buf[i]);
+		if (hdmi->edid_data.mode_buf[i].picture_aspect_ratio == HDMI_PICTURE_ASPECT_NONE) {
+			if (vic >= 93 && vic <= 95)
+				hdmi->edid_data.mode_buf[i].picture_aspect_ratio =
+					HDMI_PICTURE_ASPECT_16_9;
+			else if (vic == 98)
+				hdmi->edid_data.mode_buf[i].picture_aspect_ratio =
+					HDMI_PICTURE_ASPECT_256_135;
+		}
+	}
 
 	drm_mode_sort(&hdmi->edid_data);
 	drm_rk_selete_output(&hdmi->edid_data, conn_state, &bus_format,
@@ -2463,7 +2586,6 @@
 	*mode = *hdmi->edid_data.preferred_mode;
 	hdmi->vic = drm_match_cea_mode(mode);
 
-	printf("mode:%dx%d\n", mode->hdisplay, mode->vdisplay);
 	if (state->force_output)
 		bus_format = state->force_bus_format;
 	conn_state->bus_format = bus_format;

--
Gitblit v1.6.2