From 9df731a176aab8e03b984b681b1bea01ccff6644 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Mon, 06 Nov 2023 07:23:06 +0000
Subject: [PATCH] rk3568 rt uboot init

---
 u-boot/drivers/video/drm/rockchip_display.c |  661 +++++++++++++++++++++++++-----------------------------
 1 files changed, 304 insertions(+), 357 deletions(-)

diff --git a/u-boot/drivers/video/drm/rockchip_display.c b/u-boot/drivers/video/drm/rockchip_display.c
index b6e8774..96ef65e 100644
--- a/u-boot/drivers/video/drm/rockchip_display.c
+++ b/u-boot/drivers/video/drm/rockchip_display.c
@@ -57,7 +57,7 @@
 static unsigned long cubic_lut_memory_start;
 static unsigned long memory_end;
 static struct base2_info base_parameter;
-static uint32_t crc32_table[256];
+static u32 align_size = PAGE_SIZE;
 
 /*
  * the phy types are used by different connectors in public.
@@ -75,41 +75,6 @@
 	int public_phy_type;
 	bool phy_init;
 };
-
-void rockchip_display_make_crc32_table(void)
-{
-	uint32_t c;
-	int n, k;
-	unsigned long poly;		/* polynomial exclusive-or pattern */
-	/* terms of polynomial defining this crc (except x^32): */
-	static const char p[] = {0, 1, 2, 4, 5, 7, 8, 10, 11, 12, 16, 22, 23, 26};
-
-	/* make exclusive-or pattern from polynomial (0xedb88320L) */
-	poly = 0L;
-	for (n = 0; n < sizeof(p) / sizeof(char); n++)
-		poly |= 1L << (31 - p[n]);
-
-	for (n = 0; n < 256; n++) {
-		c = (unsigned long)n;
-		for (k = 0; k < 8; k++)
-		c = c & 1 ? poly ^ (c >> 1) : c >> 1;
-		crc32_table[n] = cpu_to_le32(c);
-	}
-}
-
-uint32_t rockchip_display_crc32c_cal(unsigned char *data, int length)
-{
-	int i;
-	uint32_t crc;
-	crc = 0xFFFFFFFF;
-
-	for (i = 0; i < length; i++) {
-		crc = crc32_table[(crc ^ *data) & 0xff] ^ (crc >> 8);
-		data++;
-	}
-
-	return crc ^ 0xffffffff;
-}
 
 int rockchip_get_baseparameter(void)
 {
@@ -152,6 +117,7 @@
 	struct base2_disp_header *disp_header;
 	int i = 0, offset = -1;
 	u32 crc_val;
+	u32 base2_length;
 	void *base_parameter_addr = (void *)&base_parameter;
 
 	for (i = 0; i < 8; i++) {
@@ -178,11 +144,23 @@
 	if (strncasecmp(disp_info->disp_head_flag, "DISP", 4))
 		return NULL;
 
-	crc_val = rockchip_display_crc32c_cal((unsigned char *)disp_info, sizeof(struct base2_disp_info) - 4);
-
-	if (crc_val != disp_info->crc) {
-		printf("error: connector type[%d], id[%d] disp info crc check error\n", type, id);
-		return NULL;
+	if (base_parameter.major_version == 3 && base_parameter.minor_version == 0) {
+		crc_val = rockchip_display_crc32c_cal((unsigned char *)disp_info,
+						      sizeof(struct base2_disp_info) - 4);
+		if (crc_val != disp_info->crc2) {
+			printf("error: connector type[%d], id[%d] disp info crc2 check error\n",
+			       type, id);
+			return NULL;
+		}
+	} else {
+		base2_length = sizeof(struct base2_disp_info) - sizeof(struct csc_info) -
+			       sizeof(struct acm_data) - 10 * 1024 - 4;
+		crc_val = rockchip_display_crc32c_cal((unsigned char *)disp_info, base2_length - 4);
+		if (crc_val != disp_info->crc) {
+			printf("error: connector type[%d], id[%d] disp info crc check error\n",
+			       type, id);
+			return NULL;
+		}
 	}
 
 	return disp_info;
@@ -253,9 +231,9 @@
 
 static void init_display_buffer(ulong base)
 {
-	memory_start = base + DRM_ROCKCHIP_FB_SIZE;
+	memory_start = ALIGN(base + DRM_ROCKCHIP_FB_SIZE, align_size);
 	memory_end = memory_start;
-	cubic_lut_memory_start = memory_start + MEMORY_POOL_SIZE;
+	cubic_lut_memory_start = ALIGN(memory_start + MEMORY_POOL_SIZE, align_size);
 }
 
 void *get_display_buffer(int size)
@@ -340,38 +318,15 @@
 	return 0;
 }
 
-int drm_mode_vrefresh(const struct drm_display_mode *mode)
-{
-	int refresh = 0;
-	unsigned int calc_val;
-
-	if (mode->vrefresh > 0) {
-		refresh = mode->vrefresh;
-	} else if (mode->htotal > 0 && mode->vtotal > 0) {
-		int vtotal;
-
-		vtotal = mode->vtotal;
-		/* work out vrefresh the value will be x1000 */
-		calc_val = (mode->clock * 1000);
-		calc_val /= mode->htotal;
-		refresh = (calc_val + vtotal / 2) / vtotal;
-
-		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
-			refresh *= 2;
-		if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
-			refresh /= 2;
-		if (mode->vscan > 1)
-			refresh /= mode->vscan;
-	}
-	return refresh;
-}
-
-int rockchip_ofnode_get_display_mode(ofnode node, struct drm_display_mode *mode)
+int rockchip_ofnode_get_display_mode(ofnode node, struct drm_display_mode *mode, u32 *bus_flags)
 {
 	int hactive, vactive, pixelclock;
 	int hfront_porch, hback_porch, hsync_len;
 	int vfront_porch, vback_porch, vsync_len;
 	int val, flags = 0;
+
+#define FDT_GET_BOOL(val, name) \
+	val = ofnode_read_bool(node, name);
 
 #define FDT_GET_INT(val, name) \
 	val = ofnode_read_s32_default(node, name, -1); \
@@ -396,8 +351,18 @@
 	flags |= val ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC;
 	FDT_GET_INT(val, "vsync-active");
 	flags |= val ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC;
+
+	FDT_GET_BOOL(val, "interlaced");
+	flags |= val ? DRM_MODE_FLAG_INTERLACE : 0;
+	FDT_GET_BOOL(val, "doublescan");
+	flags |= val ? DRM_MODE_FLAG_DBLSCAN : 0;
+	FDT_GET_BOOL(val, "doubleclk");
+	flags |= val ? DISPLAY_FLAGS_DOUBLECLK : 0;
+
+	FDT_GET_INT(val, "de-active");
+	*bus_flags |= val ? DRM_BUS_FLAG_DE_HIGH : DRM_BUS_FLAG_DE_LOW;
 	FDT_GET_INT(val, "pixelclk-active");
-	flags |= val ? DRM_MODE_FLAG_PPIXDATA : 0;
+	*bus_flags |= val ? DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE : DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
 
 	FDT_GET_INT_DEFAULT(val, "screen-rotate", 0);
 	if (val == DRM_MODE_FLAG_XMIRROR) {
@@ -425,11 +390,13 @@
 	return 0;
 }
 
-static int display_get_force_timing_from_dts(ofnode node, struct drm_display_mode *mode)
+static int display_get_force_timing_from_dts(ofnode node,
+					     struct drm_display_mode *mode,
+					     u32 *bus_flags)
 {
 	int ret = 0;
 
-	ret = rockchip_ofnode_get_display_mode(node, mode);
+	ret = rockchip_ofnode_get_display_mode(node, mode, bus_flags);
 
 	if (ret) {
 		mode->clock = 74250;
@@ -456,14 +423,24 @@
 }
 
 static int display_get_timing_from_dts(struct rockchip_panel *panel,
-				       struct drm_display_mode *mode)
+				       struct drm_display_mode *mode,
+				       u32 *bus_flags)
 {
 	struct ofnode_phandle_args args;
-	ofnode dt, timing;
+	ofnode dt, timing, mcu_panel;
 	int ret;
 
+	mcu_panel = dev_read_subnode(panel->dev, "mcu-panel");
 	dt = dev_read_subnode(panel->dev, "display-timings");
 	if (ofnode_valid(dt)) {
+		ret = ofnode_parse_phandle_with_args(dt, "native-mode", NULL,
+						     0, 0, &args);
+		if (ret)
+			return ret;
+
+		timing = args.node;
+	} else if (ofnode_valid(mcu_panel)) {
+		dt = ofnode_find_subnode(mcu_panel, "display-timings");
 		ret = ofnode_parse_phandle_with_args(dt, "native-mode", NULL,
 						     0, 0, &args);
 		if (ret)
@@ -479,163 +456,26 @@
 		return -ENXIO;
 	}
 
-	rockchip_ofnode_get_display_mode(timing, mode);
+	rockchip_ofnode_get_display_mode(timing, mode, bus_flags);
+
+	if (IS_ENABLED(CONFIG_ROCKCHIP_RK3568) || IS_ENABLED(CONFIG_ROCKCHIP_RK3588)) {
+		if (mode->hdisplay % 4) {
+			int old_hdisplay = mode->hdisplay;
+			int align = 4 - (mode->hdisplay % 4);
+
+			mode->hdisplay += align;
+			mode->hsync_start += align;
+			mode->hsync_end += align;
+			mode->htotal += align;
+
+			ofnode_write_u32_array(timing, "hactive", (u32 *)&mode->hdisplay, 1);
+
+			printf("WARN: hactive need to be aligned with 4-pixel, %d -> %d\n",
+				old_hdisplay, mode->hdisplay);
+		}
+	}
 
 	return 0;
-}
-
-/**
- * drm_mode_max_resolution_filter - mark modes out of vop max resolution
- * @edid_data: structure store mode list
- * @max_output: vop max output resolution
- */
-void drm_mode_max_resolution_filter(struct hdmi_edid_data *edid_data,
-				    struct vop_rect *max_output)
-{
-	int i;
-
-	for (i = 0; i < edid_data->modes; i++) {
-		if (edid_data->mode_buf[i].hdisplay > max_output->width ||
-		    edid_data->mode_buf[i].vdisplay > max_output->height)
-			edid_data->mode_buf[i].invalid = true;
-	}
-}
-
-/**
- * drm_mode_set_crtcinfo - set CRTC modesetting timing parameters
- * @p: mode
- * @adjust_flags: a combination of adjustment flags
- *
- * Setup the CRTC modesetting timing parameters for @p, adjusting if necessary.
- *
- * - The CRTC_INTERLACE_HALVE_V flag can be used to halve vertical timings of
- *   interlaced modes.
- * - The CRTC_STEREO_DOUBLE flag can be used to compute the timings for
- *   buffers containing two eyes (only adjust the timings when needed, eg. for
- *   "frame packing" or "side by side full").
- * - The CRTC_NO_DBLSCAN and CRTC_NO_VSCAN flags request that adjustment *not*
- *   be performed for doublescan and vscan > 1 modes respectively.
- */
-void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
-{
-	if ((p == NULL) || ((p->type & DRM_MODE_TYPE_CRTC_C) == DRM_MODE_TYPE_BUILTIN))
-		return;
-
-	if (p->flags & DRM_MODE_FLAG_DBLCLK)
-		p->crtc_clock = 2 * p->clock;
-	else
-		p->crtc_clock = p->clock;
-	p->crtc_hdisplay = p->hdisplay;
-	p->crtc_hsync_start = p->hsync_start;
-	p->crtc_hsync_end = p->hsync_end;
-	p->crtc_htotal = p->htotal;
-	p->crtc_hskew = p->hskew;
-	p->crtc_vdisplay = p->vdisplay;
-	p->crtc_vsync_start = p->vsync_start;
-	p->crtc_vsync_end = p->vsync_end;
-	p->crtc_vtotal = p->vtotal;
-
-	if (p->flags & DRM_MODE_FLAG_INTERLACE) {
-		if (adjust_flags & CRTC_INTERLACE_HALVE_V) {
-			p->crtc_vdisplay /= 2;
-			p->crtc_vsync_start /= 2;
-			p->crtc_vsync_end /= 2;
-			p->crtc_vtotal /= 2;
-		}
-	}
-
-	if (!(adjust_flags & CRTC_NO_DBLSCAN)) {
-		if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
-			p->crtc_vdisplay *= 2;
-			p->crtc_vsync_start *= 2;
-			p->crtc_vsync_end *= 2;
-			p->crtc_vtotal *= 2;
-		}
-	}
-
-	if (!(adjust_flags & CRTC_NO_VSCAN)) {
-		if (p->vscan > 1) {
-			p->crtc_vdisplay *= p->vscan;
-			p->crtc_vsync_start *= p->vscan;
-			p->crtc_vsync_end *= p->vscan;
-			p->crtc_vtotal *= p->vscan;
-		}
-	}
-
-	if (adjust_flags & CRTC_STEREO_DOUBLE) {
-		unsigned int layout = p->flags & DRM_MODE_FLAG_3D_MASK;
-
-		switch (layout) {
-		case DRM_MODE_FLAG_3D_FRAME_PACKING:
-			p->crtc_clock *= 2;
-			p->crtc_vdisplay += p->crtc_vtotal;
-			p->crtc_vsync_start += p->crtc_vtotal;
-			p->crtc_vsync_end += p->crtc_vtotal;
-			p->crtc_vtotal += p->crtc_vtotal;
-			break;
-		}
-	}
-
-	p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay);
-	p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal);
-	p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay);
-	p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal);
-}
-
-/**
- * drm_mode_is_420_only - if a given videomode can be only supported in YCBCR420
- * output format
- *
- * @connector: drm connector under action.
- * @mode: video mode to be tested.
- *
- * Returns:
- * true if the mode can be supported in YCBCR420 format
- * false if not.
- */
-bool drm_mode_is_420_only(const struct drm_display_info *display,
-			  struct drm_display_mode *mode)
-{
-	u8 vic = drm_match_cea_mode(mode);
-
-	return test_bit(vic, display->hdmi.y420_vdb_modes);
-}
-
-/**
- * drm_mode_is_420_also - if a given videomode can be supported in YCBCR420
- * output format also (along with RGB/YCBCR444/422)
- *
- * @display: display under action.
- * @mode: video mode to be tested.
- *
- * Returns:
- * true if the mode can be support YCBCR420 format
- * false if not.
- */
-bool drm_mode_is_420_also(const struct drm_display_info *display,
-			  struct drm_display_mode *mode)
-{
-	u8 vic = drm_match_cea_mode(mode);
-
-	return test_bit(vic, display->hdmi.y420_cmdb_modes);
-}
-
-/**
- * drm_mode_is_420 - if a given videomode can be supported in YCBCR420
- * output format
- *
- * @display: display under action.
- * @mode: video mode to be tested.
- *
- * Returns:
- * true if the mode can be supported in YCBCR420 format
- * false if not.
- */
-bool drm_mode_is_420(const struct drm_display_info *display,
-		     struct drm_display_mode *mode)
-{
-	return drm_mode_is_420_only(display, mode) ||
-		drm_mode_is_420_also(display, mode);
 }
 
 static int display_get_timing(struct display_state *state)
@@ -649,7 +489,7 @@
 		return panel->funcs->get_mode(panel, mode);
 
 	if (dev_of_valid(panel->dev) &&
-	    !display_get_timing_from_dts(panel, mode)) {
+	    !display_get_timing_from_dts(panel, mode, &conn_state->bus_flags)) {
 		printf("Using display timing dts\n");
 		return 0;
 	}
@@ -730,6 +570,47 @@
 	return ret;
 }
 
+static int display_mode_valid(struct display_state *state)
+{
+	struct connector_state *conn_state = &state->conn_state;
+	struct rockchip_connector *conn = conn_state->connector;
+	const struct rockchip_connector_funcs *conn_funcs = conn->funcs;
+	struct crtc_state *crtc_state = &state->crtc_state;
+	const struct rockchip_crtc *crtc = crtc_state->crtc;
+	const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs;
+	int ret;
+
+	if (conn_funcs->mode_valid && state->enabled_at_spl == false) {
+		ret = conn_funcs->mode_valid(conn, state);
+		if (ret)
+			return ret;
+	}
+
+	if (crtc_funcs->mode_valid) {
+		ret = crtc_funcs->mode_valid(state);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int display_mode_fixup(struct display_state *state)
+{
+	struct crtc_state *crtc_state = &state->crtc_state;
+	const struct rockchip_crtc *crtc = crtc_state->crtc;
+	const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs;
+	int ret;
+
+	if (crtc_funcs->mode_fixup) {
+		ret = crtc_funcs->mode_fixup(state);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
 static int display_init(struct display_state *state)
 {
 	struct connector_state *conn_state = &state->conn_state;
@@ -741,7 +622,9 @@
 	const char *compatible;
 	int ret = 0;
 	static bool __print_once = false;
-
+#ifdef CONFIG_SPL_BUILD
+	struct spl_display_info *spl_disp_info = (struct spl_display_info *)CONFIG_SPL_VIDEO_BUF;
+#endif
 	if (!__print_once) {
 		__print_once = true;
 		printf("Rockchip UBOOT DRM driver version: %s\n", DRIVER_VERSION);
@@ -755,6 +638,12 @@
 		return -ENXIO;
 	}
 
+#ifdef CONFIG_SPL_BUILD
+	if (state->conn_state.type == DRM_MODE_CONNECTOR_HDMIA)
+		state->enabled_at_spl = spl_disp_info->enabled == 1 ? true : false;
+	if (state->enabled_at_spl)
+		printf("HDMI enabled at SPL\n");
+#endif
 	if (crtc_state->crtc->active && !crtc_state->ports_node &&
 	    memcmp(&crtc_state->crtc->active_mode, &conn_state->mode,
 		   sizeof(struct drm_display_mode))) {
@@ -773,14 +662,16 @@
 			return ret;
 	}
 
-	ret = rockchip_connector_init(state);
-	if (ret)
-		goto deinit;
+	if (state->enabled_at_spl == false) {
+		ret = rockchip_connector_init(state);
+		if (ret)
+			goto deinit;
+	}
 
 	/*
 	 * support hotplug, but not connect;
 	 */
-#ifdef CONFIG_ROCKCHIP_DRM_TVE
+#ifdef CONFIG_DRM_ROCKCHIP_TVE
 	if (crtc->hdmi_hpd && conn_state->type == DRM_MODE_CONNECTOR_TV) {
 		printf("hdmi plugin ,skip tve\n");
 		goto deinit;
@@ -793,14 +684,27 @@
 #endif
 
 	ret = rockchip_connector_detect(state);
-#if defined(CONFIG_ROCKCHIP_DRM_TVE) || defined(CONFIG_DRM_ROCKCHIP_RK1000)
+#if defined(CONFIG_DRM_ROCKCHIP_TVE) || defined(CONFIG_DRM_ROCKCHIP_RK1000)
 	if (conn_state->type == DRM_MODE_CONNECTOR_HDMIA)
 		crtc->hdmi_hpd = ret;
+	if (state->enabled_at_spl)
+		crtc->hdmi_hpd = true;
 #endif
 	if (!ret && !state->force_output)
 		goto deinit;
 
-	if (conn->panel) {
+	ret = 0;
+	if (state->enabled_at_spl == true) {
+#ifdef CONFIG_SPL_BUILD
+		struct drm_display_mode *mode = &conn_state->mode;
+
+		memcpy(mode, &spl_disp_info->mode,  sizeof(*mode));
+		conn_state->bus_format = spl_disp_info->bus_format;
+
+		printf("%s get display mode from spl:%dx%d, bus format:0x%x\n",
+			conn->dev->name, mode->hdisplay, mode->vdisplay, conn_state->bus_format);
+#endif
+	} else if (conn->panel) {
 		ret = display_get_timing(state);
 		if (!ret)
 			conn_state->bpc = conn->panel->bpc;
@@ -853,10 +757,15 @@
 	if (state->force_output)
 		display_use_force_mode(state);
 
+	if (display_mode_valid(state))
+		goto deinit;
+
 	/* rk356x series drive mipi pixdata on posedge */
 	compatible = dev_read_string(conn->dev, "compatible");
-	if (!strcmp(compatible, "rockchip,rk3568-mipi-dsi"))
-		conn_state->mode.flags |= DRM_MODE_FLAG_PPIXDATA;
+	if (!strcmp(compatible, "rockchip,rk3568-mipi-dsi")) {
+		conn_state->bus_flags &= ~DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
+		conn_state->bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
+	}
 
 	printf("%s: %s detailed mode clock %u kHz, flags[%x]\n"
 	       "    H: %04d %04d %04d %04d\n"
@@ -871,20 +780,13 @@
 	       mode->vsync_end, mode->vtotal,
 	       conn_state->bus_format);
 
-	drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
-
-	if (conn_state->secondary) {
-		mode->crtc_clock *= 2;
-		mode->crtc_hdisplay *= 2;
-		mode->crtc_hsync_start *= 2;
-		mode->crtc_hsync_end *= 2;
-		mode->crtc_htotal *= 2;
-	}
+	if (display_mode_fixup(state))
+		goto deinit;
 
 	if (conn->bridge)
 		rockchip_bridge_mode_set(conn->bridge, &conn_state->mode);
 
-	if (crtc_funcs->init) {
+	if (crtc_funcs->init && state->enabled_at_spl == false) {
 		ret = crtc_funcs->init(state);
 		if (ret)
 			goto deinit;
@@ -955,12 +857,17 @@
 	if (crtc_funcs->prepare)
 		crtc_funcs->prepare(state);
 
-	rockchip_connector_pre_enable(state);
+	if (state->enabled_at_spl == false)
+		rockchip_connector_pre_enable(state);
 
 	if (crtc_funcs->enable)
 		crtc_funcs->enable(state);
 
-	rockchip_connector_enable(state);
+	if (state->enabled_at_spl == false)
+		rockchip_connector_enable(state);
+
+	if (crtc_state->soft_te)
+		crtc_funcs->apply_soft_te(state);
 
 	state->is_enable = true;
 
@@ -990,54 +897,6 @@
 	state->is_init = 0;
 
 	return 0;
-}
-
-static int display_rect_calc_scale(int src, int dst)
-{
-	int scale = 0;
-
-	if (WARN_ON(src < 0 || dst < 0))
-		return -EINVAL;
-
-	if (dst == 0)
-		return 0;
-
-	src <<= 16;
-
-	if (src > (dst << 16))
-		return DIV_ROUND_UP(src, dst);
-	else
-		scale = src / dst;
-
-	return scale;
-}
-
-int display_rect_calc_hscale(struct display_rect *src, struct display_rect *dst,
-			     int min_hscale, int max_hscale)
-{
-	int hscale = display_rect_calc_scale(src->w, dst->w);
-
-	if (hscale < 0 || dst->w == 0)
-		return hscale;
-
-	if (hscale < min_hscale || hscale > max_hscale)
-		return -ERANGE;
-
-	return hscale;
-}
-
-int display_rect_calc_vscale(struct display_rect *src, struct display_rect *dst,
-			     int min_vscale, int max_vscale)
-{
-	int vscale = display_rect_calc_scale(src->h, dst->h);
-
-	if (vscale < 0 || dst->h == 0)
-		return vscale;
-
-	if (vscale < min_vscale || vscale > max_vscale)
-		return -ERANGE;
-
-	return vscale;
 }
 
 static int display_check(struct display_state *state)
@@ -1074,38 +933,6 @@
 	return 0;
 
 check_fail:
-	state->is_init = false;
-	return ret;
-}
-
-static int display_mode_valid(struct display_state *state)
-{
-	struct connector_state *conn_state = &state->conn_state;
-	struct rockchip_connector *conn = conn_state->connector;
-	const struct rockchip_connector_funcs *conn_funcs = conn->funcs;
-	struct crtc_state *crtc_state = &state->crtc_state;
-	const struct rockchip_crtc *crtc = crtc_state->crtc;
-	const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs;
-	int ret;
-
-	if (!state->is_init)
-		return 0;
-
-	if (conn_funcs->mode_valid) {
-		ret = conn_funcs->mode_valid(conn, state);
-		if (ret)
-			goto invalid_mode;
-	}
-
-	if (crtc_funcs->mode_valid) {
-		ret = crtc_funcs->mode_valid(state);
-		if (ret)
-			goto invalid_mode;
-	}
-
-	return 0;
-
-invalid_mode:
 	state->is_init = false;
 	return ret;
 }
@@ -1170,7 +997,6 @@
 		}
 	}
 
-	display_mode_valid(state);
 	display_check(state);
 	display_set_plane(state);
 	display_enable(state);
@@ -1213,14 +1039,22 @@
 	return 0;
 }
 
-static int get_crtc_mcu_mode(struct crtc_state *crtc_state)
+static int get_crtc_mcu_mode(struct crtc_state *crtc_state, struct device_node *port_node,
+			     bool is_ports_node)
 {
-	ofnode mcu_node;
+	ofnode mcu_node, vp_node;
 	int total_pixel, cs_pst, cs_pend, rw_pst, rw_pend;
 
-	mcu_node = dev_read_subnode(crtc_state->dev, "mcu-timing");
-	if (!ofnode_valid(mcu_node))
-		return -ENODEV;
+	if (is_ports_node) {
+		vp_node = np_to_ofnode(port_node);
+		mcu_node = ofnode_find_subnode(vp_node, "mcu-timing");
+		if (!ofnode_valid(mcu_node))
+			return -ENODEV;
+	} else {
+		mcu_node = dev_read_subnode(crtc_state->dev, "mcu-timing");
+		if (!ofnode_valid(mcu_node))
+			return -ENODEV;
+	}
 
 #define FDT_GET_MCU_INT(val, name) \
 	do { \
@@ -1464,6 +1298,35 @@
 	return ret;
 }
 
+int rockchip_vop_dump(const char *cmd)
+{
+	struct display_state *state;
+	struct crtc_state *crtc_state;
+	struct rockchip_crtc *crtc;
+	const struct rockchip_crtc_funcs *crtc_funcs;
+	int ret = -EINVAL;
+
+	list_for_each_entry(state, &rockchip_display_list, head) {
+		if (!state->is_init)
+			continue;
+		crtc_state = &state->crtc_state;
+		crtc = crtc_state->crtc;
+		crtc_funcs = crtc->funcs;
+
+		if (!cmd)
+			ret = crtc_funcs->active_regs_dump(state);
+		else if (!strcmp(cmd, "a") || !strcmp(cmd, "all"))
+			ret = crtc_funcs->regs_dump(state);
+		if (!ret)
+			break;
+	}
+
+	if (ret)
+		ret = CMD_RET_USAGE;
+
+	return ret;
+}
+
 enum {
 	PORT_DIR_IN,
 	PORT_DIR_OUT,
@@ -1505,13 +1368,12 @@
 	return ofnode_to_np(parent);
 }
 
-static const struct device_node *rockchip_of_graph_get_remote_node(ofnode node, int port,
-								   int endpoint)
+const struct device_node *
+rockchip_of_graph_get_endpoint_by_regs(ofnode node, int port, int endpoint)
 {
 	const struct device_node *port_node;
 	ofnode ep;
 	u32 reg;
-	uint phandle;
 
 	port_node = rockchip_of_graph_get_port_by_id(node, port);
 	if (!port_node)
@@ -1527,7 +1389,21 @@
 	if (!ofnode_valid(ep))
 		return NULL;
 
-	if (ofnode_read_u32(ep, "remote-endpoint", &phandle))
+	return ofnode_to_np(ep);
+}
+
+static const struct device_node *
+rockchip_of_graph_get_remote_node(ofnode node, int port, int endpoint)
+{
+	const struct device_node *ep_node;
+	ofnode ep;
+	uint phandle;
+
+	ep_node = rockchip_of_graph_get_endpoint_by_regs(node, port, endpoint);
+	if (!ep_node)
+		return NULL;
+
+	if (ofnode_read_u32(np_to_ofnode(ep_node), "remote-endpoint", &phandle))
 		return NULL;
 
 	ep = ofnode_get_by_phandle(phandle);
@@ -1611,6 +1487,10 @@
 					    struct rockchip_bridge **bridge)
 {
 	int ret = 0;
+
+	if (*panel)
+		return 0;
+
 	*panel = NULL;
 	*bridge = NULL;
 
@@ -1952,7 +1832,9 @@
 
 		if (s->force_output) {
 			timing_node = ofnode_find_subnode(node, "force_timing");
-			ret = display_get_force_timing_from_dts(timing_node, &s->force_mode);
+			ret = display_get_force_timing_from_dts(timing_node,
+								&s->force_mode,
+								&s->conn_state.bus_flags);
 			if (ofnode_read_u32(node, "force-bus-format", &s->force_bus_format))
 				s->force_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
 		}
@@ -2002,10 +1884,11 @@
 						s->crtc_state.crtc->vps[vp_id].plane_mask = ret;
 						s->crtc_state.crtc->assign_plane |= true;
 						s->crtc_state.crtc->vps[vp_id].primary_plane_id =
-							ofnode_read_u32_default(vp_node, "rockchip,primary-plane", -1);
+							ofnode_read_u32_default(vp_node, "rockchip,primary-plane", U8_MAX);
 						printf("get vp%d plane mask:0x%x, primary id:%d, cursor_plane:%d, from dts\n",
 						       vp_id,
 						       s->crtc_state.crtc->vps[vp_id].plane_mask,
+						       s->crtc_state.crtc->vps[vp_id].primary_plane_id == U8_MAX ? -1 :
 						       s->crtc_state.crtc->vps[vp_id].primary_plane_id,
 						       cursor_plane);
 					}
@@ -2020,7 +1903,7 @@
 			}
 		}
 
-		get_crtc_mcu_mode(&s->crtc_state);
+		get_crtc_mcu_mode(&s->crtc_state, port_node, is_ports_node);
 
 		ret = ofnode_read_u32_default(s->crtc_state.node,
 					      "rockchip,dual-channel-swap", 0);
@@ -2061,27 +1944,41 @@
 	const struct rockchip_crtc *crtc;
 	struct display_state *s;
 	int offset;
+	int ret;
 	const struct device_node *np;
 	const char *path;
+	const char *cacm_header;
+	u64 aligned_memory_size;
 
 	if (fdt_node_offset_by_compatible(blob, 0, "rockchip,drm-logo") >= 0) {
-		list_for_each_entry(s, &rockchip_display_list, head)
-			load_bmp_logo(&s->logo, s->klogo_name);
+		list_for_each_entry(s, &rockchip_display_list, head) {
+			ret = load_bmp_logo(&s->logo, s->klogo_name);
+			if (ret < 0) {
+				s->is_klogo_valid = false;
+				printf("VP%d fail to load kernel logo\n", s->crtc_state.crtc_id);
+			} else {
+				s->is_klogo_valid = true;
+			}
+		}
 
 		if (!get_display_size())
 			return;
 
+		aligned_memory_size = (u64)ALIGN(get_display_size(), align_size);
 		offset = fdt_update_reserved_memory(blob, "rockchip,drm-logo",
 						    (u64)memory_start,
-						    (u64)get_display_size());
+						    aligned_memory_size);
 		if (offset < 0)
 			printf("failed to reserve drm-loader-logo memory\n");
 
-		offset = fdt_update_reserved_memory(blob, "rockchip,drm-cubic-lut",
-						    (u64)cubic_lut_memory_start,
-						    (u64)get_cubic_memory_size());
-		if (offset < 0)
-			printf("failed to reserve drm-cubic-lut memory\n");
+		if (get_cubic_memory_size()) {
+			aligned_memory_size = (u64)ALIGN(get_cubic_memory_size(), align_size);
+			offset = fdt_update_reserved_memory(blob, "rockchip,drm-cubic-lut",
+							    (u64)cubic_lut_memory_start,
+							    aligned_memory_size);
+			if (offset < 0)
+				printf("failed to reserve drm-cubic-lut memory\n");
+		}
 	} else {
 		printf("can't found rockchip,drm-logo, use rockchip,fb-logo\n");
 		/* Compatible with rkfb display, only need reserve memory */
@@ -2097,7 +1994,14 @@
 	}
 
 	list_for_each_entry(s, &rockchip_display_list, head) {
-		if (!s->is_init)
+		/*
+		 * If plane mask is not set in dts, fixup dts to assign it
+		 * whether crtc is initialized or not.
+		 */
+		if (s->crtc_state.crtc->funcs->fixup_dts && !s->crtc_state.crtc->assign_plane)
+			s->crtc_state.crtc->funcs->fixup_dts(s, blob);
+
+		if (!s->is_init || !s->is_klogo_valid)
 			continue;
 
 		conn = s->conn_state.connector;
@@ -2123,9 +2027,6 @@
 			printf("failed to get exist crtc\n");
 			continue;
 		}
-
-		if (crtc_funcs->fixup_dts)
-			crtc_funcs->fixup_dts(s, blob);
 
 		np = ofnode_to_np(s->node);
 		path = np->full_name;
@@ -2155,10 +2056,37 @@
 		FDT_SET_U32("overscan,bottom_margin", s->conn_state.overscan.bottom_margin);
 
 		if (s->conn_state.disp_info) {
+			cacm_header = (const char*)&s->conn_state.disp_info->cacm_header;
+
 			FDT_SET_U32("bcsh,brightness", s->conn_state.disp_info->bcsh_info.brightness);
 			FDT_SET_U32("bcsh,contrast", s->conn_state.disp_info->bcsh_info.contrast);
 			FDT_SET_U32("bcsh,saturation", s->conn_state.disp_info->bcsh_info.saturation);
 			FDT_SET_U32("bcsh,hue", s->conn_state.disp_info->bcsh_info.hue);
+
+			if (!strncasecmp(cacm_header, "CACM", 4)) {
+				FDT_SET_U32("post_csc,hue",
+					    s->conn_state.disp_info->csc_info.hue);
+				FDT_SET_U32("post_csc,saturation",
+					    s->conn_state.disp_info->csc_info.saturation);
+				FDT_SET_U32("post_csc,contrast",
+					    s->conn_state.disp_info->csc_info.contrast);
+				FDT_SET_U32("post_csc,brightness",
+					    s->conn_state.disp_info->csc_info.brightness);
+				FDT_SET_U32("post_csc,r_gain",
+					    s->conn_state.disp_info->csc_info.r_gain);
+				FDT_SET_U32("post_csc,g_gain",
+					    s->conn_state.disp_info->csc_info.g_gain);
+				FDT_SET_U32("post_csc,b_gain",
+					    s->conn_state.disp_info->csc_info.b_gain);
+				FDT_SET_U32("post_csc,r_offset",
+					    s->conn_state.disp_info->csc_info.r_offset);
+				FDT_SET_U32("post_csc,g_offset",
+					    s->conn_state.disp_info->csc_info.g_offset);
+				FDT_SET_U32("post_csc,b_offset",
+					    s->conn_state.disp_info->csc_info.b_offset);
+				FDT_SET_U32("post_csc,csc_enable",
+					    s->conn_state.disp_info->csc_info.csc_enable);
+			}
 		}
 
 		if (s->conn_state.disp_info->cubic_lut_data.size &&
@@ -2213,6 +2141,19 @@
 	return 0;
 }
 
+static int do_rockchip_vop_dump(cmd_tbl_t *cmdtp, int flag, int argc,
+				char *const argv[])
+{
+	int ret;
+
+	if (argc < 1 || argc > 2)
+		return CMD_RET_USAGE;
+
+	ret = rockchip_vop_dump(argv[1]);
+
+	return ret;
+}
+
 U_BOOT_CMD(
 	rockchip_show_logo, 1, 1, do_rockchip_logo_show,
 	"load and display log from resource partition",
@@ -2224,3 +2165,9 @@
 	"load and display bmp from resource partition",
 	"    <bmp_name>"
 );
+
+U_BOOT_CMD(
+	vop_dump, 2, 1, do_rockchip_vop_dump,
+	"dump vop regs",
+	" [a/all]"
+);

--
Gitblit v1.6.2