From 9d77db3c730780c8ef5ccd4b66403ff5675cfe4e Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Mon, 13 May 2024 10:30:14 +0000
Subject: [PATCH] modify sin led gpio

---
 kernel/drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2346 ++++++++++++++++++++++++++--------------------------------
 1 files changed, 1,043 insertions(+), 1,303 deletions(-)

diff --git a/kernel/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/kernel/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index 294547b..9f64ad8 100644
--- a/kernel/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/kernel/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -1,102 +1,283 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
  * Author:Mark Yao <mark.yao@rock-chips.com>
  *
  * based on exynos_drm_drv.c
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
  */
 
-#include <drm/drmP.h>
-#include <drm/drm_atomic.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_fb_helper.h>
-#include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_of.h>
-#include <linux/devfreq.h>
-#include <linux/dma-buf.h>
+#include <linux/dma-buf-cache.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-iommu.h>
 #include <linux/genalloc.h>
 #include <linux/pm_runtime.h>
-#include <linux/memblock.h>
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/of_graph.h>
+#include <linux/of_platform.h>
 #include <linux/clk.h>
-#include <linux/clk-provider.h>
 #include <linux/component.h>
 #include <linux/console.h>
 #include <linux/iommu.h>
 #include <linux/of_reserved_mem.h>
 
+#include <drm/drm_debugfs.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_displayid.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
+
 #include "rockchip_drm_drv.h"
 #include "rockchip_drm_fb.h"
 #include "rockchip_drm_fbdev.h"
 #include "rockchip_drm_gem.h"
+#include "rockchip_drm_logo.h"
 
-#include "../drm_internal.h"
+#include "../drm_crtc_internal.h"
 
 #define DRIVER_NAME	"rockchip"
 #define DRIVER_DESC	"RockChip Soc DRM"
 #define DRIVER_DATE	"20140818"
-#define DRIVER_MAJOR	2
+#define DRIVER_MAJOR	3
 #define DRIVER_MINOR	0
-#define DRIVER_PATCH	0
-
-/***********************************************************************
- *  Rockchip DRM driver version
- *
- *  v2.0.0	: add basic version for linux 4.19 rockchip drm driver(hjc)
- *
- **********************************************************************/
 
 #if IS_ENABLED(CONFIG_DRM_ROCKCHIP_VVOP)
 static bool is_support_iommu = false;
 #else
 static bool is_support_iommu = true;
 #endif
+static bool iommu_reserve_map;
+
 static struct drm_driver rockchip_drm_driver;
 
-struct rockchip_drm_mode_set {
-	struct list_head head;
-	struct drm_framebuffer *fb;
-	struct drm_connector *connector;
-	struct drm_crtc *crtc;
-	struct drm_display_mode *mode;
-	int clock;
-	int hdisplay;
-	int vdisplay;
-	int vrefresh;
-	int flags;
-	int picture_aspect_ratio;
-	int crtc_hsync_end;
-	int crtc_vsync_end;
+static unsigned int drm_debug;
+module_param_named(debug, drm_debug, int, 0600);
 
-	int left_margin;
-	int right_margin;
-	int top_margin;
-	int bottom_margin;
+static inline bool rockchip_drm_debug_enabled(enum rockchip_drm_debug_category category)
+{
+	return unlikely(drm_debug & category);
+}
 
-	unsigned int brightness;
-	unsigned int contrast;
-	unsigned int saturation;
-	unsigned int hue;
+__printf(3, 4)
+void rockchip_drm_dbg(const struct device *dev, enum rockchip_drm_debug_category category,
+		      const char *format, ...)
+{
+	struct va_format vaf;
+	va_list args;
 
-	bool mode_changed;
-	bool force_output;
-	int ratio;
-};
+	if (!rockchip_drm_debug_enabled(category))
+		return;
+
+	va_start(args, format);
+	vaf.fmt = format;
+	vaf.va = &args;
+
+	if (dev)
+		dev_printk(KERN_DEBUG, dev, "%pV", &vaf);
+	else
+		printk(KERN_DEBUG "%pV", &vaf);
+
+	va_end(args);
+}
+
+/**
+ * rockchip_drm_wait_vact_end
+ * @crtc: CRTC to enable line flag
+ * @mstimeout: millisecond for timeout
+ *
+ * Wait for vact_end line flag irq or timeout.
+ *
+ * Returns:
+ * Zero on success, negative errno on failure.
+ */
+int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout)
+{
+	struct rockchip_drm_private *priv;
+	int pipe, ret = 0;
+
+	if (!crtc)
+		return -ENODEV;
+
+	if (mstimeout <= 0)
+		return -EINVAL;
+
+	priv = crtc->dev->dev_private;
+	pipe = drm_crtc_index(crtc);
+
+	if (priv->crtc_funcs[pipe] && priv->crtc_funcs[pipe]->wait_vact_end)
+		ret = priv->crtc_funcs[pipe]->wait_vact_end(crtc, mstimeout);
+
+	return ret;
+}
+EXPORT_SYMBOL(rockchip_drm_wait_vact_end);
+
+void drm_mode_convert_to_split_mode(struct drm_display_mode *mode)
+{
+	u16 hactive, hfp, hsync, hbp;
+
+	hactive = mode->hdisplay;
+	hfp = mode->hsync_start - mode->hdisplay;
+	hsync = mode->hsync_end - mode->hsync_start;
+	hbp = mode->htotal - mode->hsync_end;
+
+	mode->clock *= 2;
+	mode->crtc_clock *= 2;
+	mode->hdisplay = hactive * 2;
+	mode->hsync_start = mode->hdisplay + hfp * 2;
+	mode->hsync_end = mode->hsync_start + hsync * 2;
+	mode->htotal = mode->hsync_end + hbp * 2;
+	drm_mode_set_name(mode);
+}
+EXPORT_SYMBOL(drm_mode_convert_to_split_mode);
+
+void drm_mode_convert_to_origin_mode(struct drm_display_mode *mode)
+{
+	u16 hactive, hfp, hsync, hbp;
+
+	hactive = mode->hdisplay;
+	hfp = mode->hsync_start - mode->hdisplay;
+	hsync = mode->hsync_end - mode->hsync_start;
+	hbp = mode->htotal - mode->hsync_end;
+
+	mode->clock /= 2;
+	mode->crtc_clock /= 2;
+	mode->hdisplay = hactive / 2;
+	mode->hsync_start = mode->hdisplay + hfp / 2;
+	mode->hsync_end = mode->hsync_start + hsync / 2;
+	mode->htotal = mode->hsync_end + hbp / 2;
+}
+EXPORT_SYMBOL(drm_mode_convert_to_origin_mode);
+
+/**
+ * drm_connector_oob_hotplug_event - Report out-of-band hotplug event to connector
+ * @connector: connector to report the event on
+ *
+ * On some hardware a hotplug event notification may come from outside the display
+ * driver / device. An example of this is some USB Type-C setups where the hardware
+ * muxes the DisplayPort data and aux-lines but does not pass the altmode HPD
+ * status bit to the GPU's DP HPD pin.
+ *
+ * This function can be used to report these out-of-band events after obtaining
+ * a drm_connector reference through calling drm_connector_find_by_fwnode().
+ */
+void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode)
+{
+	struct rockchip_drm_sub_dev *sub_dev;
+
+	if (!connector_fwnode || !connector_fwnode->dev)
+		return;
+
+	sub_dev = rockchip_drm_get_sub_dev(dev_of_node(connector_fwnode->dev));
+
+	if (sub_dev && sub_dev->connector && sub_dev->oob_hotplug_event)
+		sub_dev->oob_hotplug_event(sub_dev->connector);
+}
+EXPORT_SYMBOL(drm_connector_oob_hotplug_event);
+
+uint32_t rockchip_drm_get_bpp(const struct drm_format_info *info)
+{
+	/* use whatever a driver has set */
+	if (info->cpp[0])
+		return info->cpp[0] * 8;
+
+	switch (info->format) {
+	case DRM_FORMAT_YUV420_8BIT:
+		return 12;
+	case DRM_FORMAT_YUV420_10BIT:
+		return 15;
+	case DRM_FORMAT_VUY101010:
+		return 30;
+	default:
+		break;
+	}
+
+	/* all attempts failed */
+	return 0;
+}
+EXPORT_SYMBOL(rockchip_drm_get_bpp);
+
+uint32_t rockchip_drm_get_cycles_per_pixel(uint32_t bus_format)
+{
+	switch (bus_format) {
+	case MEDIA_BUS_FMT_RGB565_1X16:
+	case MEDIA_BUS_FMT_RGB666_1X18:
+	case MEDIA_BUS_FMT_RGB888_1X24:
+	case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
+		return 1;
+	case MEDIA_BUS_FMT_RGB565_2X8_LE:
+	case MEDIA_BUS_FMT_BGR565_2X8_LE:
+		return 2;
+	case MEDIA_BUS_FMT_RGB666_3X6:
+	case MEDIA_BUS_FMT_RGB888_3X8:
+	case MEDIA_BUS_FMT_BGR888_3X8:
+		return 3;
+	case MEDIA_BUS_FMT_RGB888_DUMMY_4X8:
+	case MEDIA_BUS_FMT_BGR888_DUMMY_4X8:
+		return 4;
+	default:
+		return 1;
+	}
+}
+EXPORT_SYMBOL(rockchip_drm_get_cycles_per_pixel);
+
+/**
+ * rockchip_drm_of_find_possible_crtcs - find the possible CRTCs for an active
+ * encoder port
+ * @dev: DRM device
+ * @port: encoder port to scan for endpoints
+ *
+ * Scan all active endpoints attached to a port, locate their attached CRTCs,
+ * and generate the DRM mask of CRTCs which may be attached to this
+ * encoder.
+ *
+ * See Documentation/devicetree/bindings/graph.txt for the bindings.
+ */
+uint32_t rockchip_drm_of_find_possible_crtcs(struct drm_device *dev,
+					     struct device_node *port)
+{
+	struct device_node *remote_port, *ep;
+	uint32_t possible_crtcs = 0;
+
+	for_each_endpoint_of_node(port, ep) {
+		if (!of_device_is_available(ep))
+			continue;
+
+		remote_port = of_graph_get_remote_port(ep);
+		if (!remote_port) {
+			of_node_put(ep);
+			continue;
+		}
+
+		possible_crtcs |= drm_of_crtc_port_mask(dev, remote_port);
+
+		of_node_put(remote_port);
+	}
+
+	return possible_crtcs;
+}
+EXPORT_SYMBOL(rockchip_drm_of_find_possible_crtcs);
 
 static DEFINE_MUTEX(rockchip_drm_sub_dev_lock);
 static LIST_HEAD(rockchip_drm_sub_dev_list);
+
+void rockchip_connector_update_vfp_for_vrr(struct drm_crtc *crtc, struct drm_display_mode *mode,
+					   int vfp)
+{
+	struct rockchip_drm_sub_dev *sub_dev;
+
+	mutex_lock(&rockchip_drm_sub_dev_lock);
+	list_for_each_entry(sub_dev, &rockchip_drm_sub_dev_list, list) {
+		if (sub_dev->connector->state->crtc == crtc) {
+			if (sub_dev->update_vfp_for_vrr)
+				sub_dev->update_vfp_for_vrr(sub_dev->connector, mode, vfp);
+		}
+	}
+	mutex_unlock(&rockchip_drm_sub_dev_lock);
+}
+EXPORT_SYMBOL(rockchip_connector_update_vfp_for_vrr);
 
 void rockchip_drm_register_sub_dev(struct rockchip_drm_sub_dev *sub_dev)
 {
@@ -150,6 +331,26 @@
 }
 EXPORT_SYMBOL(rockchip_drm_get_sub_dev_type);
 
+u32 rockchip_drm_get_scan_line_time_ns(void)
+{
+	struct rockchip_drm_sub_dev *sub_dev = NULL;
+	struct drm_display_mode *mode;
+	int linedur_ns = 0;
+
+	mutex_lock(&rockchip_drm_sub_dev_lock);
+	list_for_each_entry(sub_dev, &rockchip_drm_sub_dev_list, list) {
+		if (sub_dev->connector->encoder && sub_dev->connector->state->crtc) {
+			mode = &sub_dev->connector->state->crtc->state->adjusted_mode;
+			linedur_ns  = div_u64((u64) mode->crtc_htotal * 1000000, mode->crtc_clock);
+			break;
+		}
+	}
+	mutex_unlock(&rockchip_drm_sub_dev_lock);
+
+	return linedur_ns;
+}
+EXPORT_SYMBOL(rockchip_drm_get_scan_line_time_ns);
+
 void rockchip_drm_te_handle(struct drm_crtc *crtc)
 {
 	struct rockchip_drm_private *priv = crtc->dev->dev_private;
@@ -165,22 +366,22 @@
 	{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390,
 		   1430, 1650, 0, 720, 725, 730, 750, 0,
 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
-	  .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
+	  .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
 	/* 16 - 1920x1080@60Hz 16:9 */
 	{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
 		   2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
-	  .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
+	  .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
 	/* 31 - 1920x1080@50Hz 16:9 */
 	{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
 		   2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
-	  .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
+	  .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
 	/* 19 - 1280x720@50Hz 16:9 */
 	{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720,
 		   1760, 1980, 0, 720, 725, 730, 750, 0,
 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
-	  .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
+	  .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
 	/* 0x10 - 1024x768@60Hz */
 	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
 		   1184, 1344, 0,  768, 771, 777, 806, 0,
@@ -189,12 +390,12 @@
 	{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732,
 		   796, 864, 0, 576, 581, 586, 625, 0,
 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-	  .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
+	  .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
 	/* 2 - 720x480@60Hz 4:3 */
 	{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736,
 		   798, 858, 0, 480, 489, 495, 525, 0,
 		   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-	  .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
+	  .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
 };
 
 int rockchip_drm_add_modes_noedid(struct drm_connector *connector)
@@ -223,1013 +424,638 @@
 }
 EXPORT_SYMBOL(rockchip_drm_add_modes_noedid);
 
-#ifdef CONFIG_ARCH_ROCKCHIP
-struct drm_prime_callback_data {
-	struct drm_gem_object *obj;
-	struct sg_table *sgt;
+static const struct rockchip_drm_width_dclk {
+	int width;
+	u32 dclk_khz;
+} rockchip_drm_dclk[] = {
+	{1920, 148500},
+	{2048, 200000},
+	{2560, 280000},
+	{3840, 594000},
+	{4096, 594000},
+	{7680, 2376000},
 };
-#endif
 
-#ifndef MODULE
-static struct drm_crtc *find_crtc_by_node(struct drm_device *drm_dev, struct device_node *node)
+u32 rockchip_drm_get_dclk_by_width(int width)
 {
-	struct device_node *np_crtc;
-	struct drm_crtc *crtc;
+	int i = 0;
+	u32 dclk_khz;
 
-	np_crtc = of_get_parent(node);
-	if (!np_crtc || !of_device_is_available(np_crtc))
+	for (i = 0; i < ARRAY_SIZE(rockchip_drm_dclk); i++) {
+		if (width == rockchip_drm_dclk[i].width) {
+			dclk_khz = rockchip_drm_dclk[i].dclk_khz;
+			break;
+		}
+	}
+
+	if (i == ARRAY_SIZE(rockchip_drm_dclk)) {
+		DRM_ERROR("Can't not find %d width solution and use 148500 khz as max dclk\n", width);
+
+		dclk_khz = 148500;
+	}
+
+	return dclk_khz;
+}
+EXPORT_SYMBOL(rockchip_drm_get_dclk_by_width);
+
+static int
+cea_db_tag(const u8 *db)
+{
+	return db[0] >> 5;
+}
+
+static int
+cea_db_payload_len(const u8 *db)
+{
+	return db[0] & 0x1f;
+}
+
+#define for_each_cea_db(cea, i, start, end) \
+	for ((i) = (start); \
+	     (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); \
+	     (i) += cea_db_payload_len(&(cea)[(i)]) + 1)
+
+#define HDMI_NEXT_HDR_VSDB_OUI 0xd04601
+
+static bool cea_db_is_hdmi_next_hdr_block(const u8 *db)
+{
+	unsigned int oui;
+
+	if (cea_db_tag(db) != 0x07)
+		return false;
+
+	if (cea_db_payload_len(db) < 11)
+		return false;
+
+	oui = db[3] << 16 | db[2] << 8 | db[1];
+
+	return oui == HDMI_NEXT_HDR_VSDB_OUI;
+}
+
+static bool cea_db_is_hdmi_forum_vsdb(const u8 *db)
+{
+	unsigned int oui;
+
+	if (cea_db_tag(db) != 0x03)
+		return false;
+
+	if (cea_db_payload_len(db) < 7)
+		return false;
+
+	oui = db[3] << 16 | db[2] << 8 | db[1];
+
+	return oui == HDMI_FORUM_IEEE_OUI;
+}
+
+static int
+cea_db_offsets(const u8 *cea, int *start, int *end)
+{
+	/* DisplayID CTA extension blocks and top-level CEA EDID
+	 * block header definitions differ in the following bytes:
+	 *   1) Byte 2 of the header specifies length differently,
+	 *   2) Byte 3 is only present in the CEA top level block.
+	 *
+	 * The different definitions for byte 2 follow.
+	 *
+	 * DisplayID CTA extension block defines byte 2 as:
+	 *   Number of payload bytes
+	 *
+	 * CEA EDID block defines byte 2 as:
+	 *   Byte number (decimal) within this block where the 18-byte
+	 *   DTDs begin. If no non-DTD data is present in this extension
+	 *   block, the value should be set to 04h (the byte after next).
+	 *   If set to 00h, there are no DTDs present in this block and
+	 *   no non-DTD data.
+	 */
+	if (cea[0] == 0x81) {
+		/*
+		 * for_each_displayid_db() has already verified
+		 * that these stay within expected bounds.
+		 */
+		*start = 3;
+		*end = *start + cea[2];
+	} else if (cea[0] == 0x02) {
+		/* Data block offset in CEA extension block */
+		*start = 4;
+		*end = cea[2];
+		if (*end == 0)
+			*end = 127;
+		if (*end < 4 || *end > 127)
+			return -ERANGE;
+	} else {
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static u8 *find_edid_extension(const struct edid *edid,
+			       int ext_id, int *ext_index)
+{
+	u8 *edid_ext = NULL;
+	int i;
+
+	/* No EDID or EDID extensions */
+	if (edid == NULL || edid->extensions == 0)
 		return NULL;
 
-	drm_for_each_crtc(crtc, drm_dev) {
-		if (crtc->port == np_crtc)
-			return crtc;
+	/* Find CEA extension */
+	for (i = *ext_index; i < edid->extensions; i++) {
+		edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1);
+		if (edid_ext[0] == ext_id)
+			break;
+	}
+
+	if (i >= edid->extensions)
+		return NULL;
+
+	*ext_index = i + 1;
+
+	return edid_ext;
+}
+
+static int validate_displayid(u8 *displayid, int length, int idx)
+{
+	int i, dispid_length;
+	u8 csum = 0;
+	struct displayid_hdr *base;
+
+	base = (struct displayid_hdr *)&displayid[idx];
+
+	DRM_DEBUG_KMS("base revision 0x%x, length %d, %d %d\n",
+		      base->rev, base->bytes, base->prod_id, base->ext_count);
+
+	/* +1 for DispID checksum */
+	dispid_length = sizeof(*base) + base->bytes + 1;
+	if (dispid_length > length - idx)
+		return -EINVAL;
+
+	for (i = 0; i < dispid_length; i++)
+		csum += displayid[idx + i];
+	if (csum) {
+		DRM_NOTE("DisplayID checksum invalid, remainder is %d\n", csum);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static u8 *find_displayid_extension(const struct edid *edid,
+				    int *length, int *idx,
+				    int *ext_index)
+{
+	u8 *displayid = find_edid_extension(edid, 0x70, ext_index);
+	struct displayid_hdr *base;
+	int ret;
+
+	if (!displayid)
+		return NULL;
+
+	/* EDID extensions block checksum isn't for us */
+	*length = EDID_LENGTH - 1;
+	*idx = 1;
+
+	ret = validate_displayid(displayid, *length, *idx);
+	if (ret)
+		return NULL;
+
+	base = (struct displayid_hdr *)&displayid[*idx];
+	*length = *idx + sizeof(*base) + base->bytes;
+
+	return displayid;
+}
+
+static u8 *find_cea_extension(const struct edid *edid)
+{
+	int length, idx;
+	struct displayid_block *block;
+	u8 *cea;
+	u8 *displayid;
+	int ext_index;
+
+	/* Look for a top level CEA extension block */
+	/* FIXME: make callers iterate through multiple CEA ext blocks? */
+	ext_index = 0;
+	cea = find_edid_extension(edid, 0x02, &ext_index);
+	if (cea)
+		return cea;
+
+	/* CEA blocks can also be found embedded in a DisplayID block */
+	ext_index = 0;
+	for (;;) {
+		displayid = find_displayid_extension(edid, &length, &idx,
+						     &ext_index);
+		if (!displayid)
+			return NULL;
+
+		idx += sizeof(struct displayid_hdr);
+		for_each_displayid_db(displayid, block, idx, length) {
+			if (block->tag == 0x81)
+				return (u8 *)block;
+		}
 	}
 
 	return NULL;
 }
 
-static struct drm_connector *find_connector_by_node(struct drm_device *drm_dev,
-						    struct device_node *node)
+#define EDID_CEA_YCRCB422	(1 << 4)
+
+int rockchip_drm_get_yuv422_format(struct drm_connector *connector,
+				   struct edid *edid)
 {
-	struct device_node *np_connector;
-	struct rockchip_drm_sub_dev *sub_dev;
+	struct drm_display_info *info;
+	const u8 *edid_ext;
 
-	np_connector = of_graph_get_remote_port_parent(node);
-	if (!np_connector || !of_device_is_available(np_connector))
-		return NULL;
+	if (!connector || !edid)
+		return -EINVAL;
 
-	sub_dev = rockchip_drm_get_sub_dev(np_connector);
-	if (!sub_dev)
-		return NULL;
+	info = &connector->display_info;
 
-	return sub_dev->connector;
-}
+	edid_ext = find_cea_extension(edid);
+	if (!edid_ext)
+		return -EINVAL;
 
-static struct drm_connector *find_connector_by_bridge(struct drm_device *drm_dev,
-						      struct device_node *node)
-{
-	struct device_node *np_encoder, *np_connector = NULL;
-	struct drm_connector *connector = NULL;
-	struct device_node *port, *endpoint;
-	struct rockchip_drm_sub_dev *sub_dev;
-
-	np_encoder = of_graph_get_remote_port_parent(node);
-	if (!np_encoder || !of_device_is_available(np_encoder))
-		goto err_put_encoder;
-
-	port = of_graph_get_port_by_id(np_encoder, 1);
-	if (!port) {
-		dev_err(drm_dev->dev, "can't found port point!\n");
-		goto err_put_encoder;
-	}
-
-	for_each_child_of_node(port, endpoint) {
-		np_connector = of_graph_get_remote_port_parent(endpoint);
-		if (!np_connector) {
-			dev_err(drm_dev->dev,
-				"can't found connector node, please init!\n");
-			goto err_put_port;
-		}
-		if (!of_device_is_available(np_connector)) {
-			of_node_put(np_connector);
-			np_connector = NULL;
-			continue;
-		} else {
-			break;
-		}
-	}
-	if (!np_connector) {
-		dev_err(drm_dev->dev, "can't found available connector node!\n");
-		goto err_put_port;
-	}
-
-	sub_dev = rockchip_drm_get_sub_dev(np_connector);
-	if (!sub_dev)
-		goto err_put_port;
-	connector = sub_dev->connector;
-
-	of_node_put(np_connector);
-err_put_port:
-	of_node_put(port);
-err_put_encoder:
-	of_node_put(np_encoder);
-
-	return connector;
-}
-
-void rockchip_free_loader_memory(struct drm_device *drm)
-{
-	struct rockchip_drm_private *private = drm->dev_private;
-	struct rockchip_logo *logo;
-	void *start, *end;
-
-	if (!private || !private->logo || --private->logo->count)
-		return;
-
-	logo = private->logo;
-	start = phys_to_virt(logo->dma_addr);
-	end = phys_to_virt(logo->dma_addr + logo->size);
-
-	if (private->domain) {
-		u32 pg_size = 1UL << __ffs(private->domain->pgsize_bitmap);
-
-		iommu_unmap(private->domain, logo->dma_addr, ALIGN(logo->size, pg_size));
-	}
-
-	memblock_free(logo->start, logo->size);
-	free_reserved_area(start, end, -1, "drm_logo");
-	kfree(logo);
-	private->logo = NULL;
-	private->loader_protect = false;
-}
-
-static int init_loader_memory(struct drm_device *drm_dev)
-{
-	struct rockchip_drm_private *private = drm_dev->dev_private;
-	struct rockchip_logo *logo;
-	struct device_node *np = drm_dev->dev->of_node;
-	struct device_node *node;
-	phys_addr_t start, size;
-	u32 pg_size = PAGE_SIZE;
-	struct resource res;
-	int ret, idx;
-
-	idx = of_property_match_string(np, "memory-region-names", "drm-logo");
-	if (idx >= 0)
-		node = of_parse_phandle(np, "memory-region", idx);
-	else
-		node = of_parse_phandle(np, "logo-memory-region", 0);
-	if (!node)
-		return -ENOMEM;
-
-	ret = of_address_to_resource(node, 0, &res);
-	if (ret)
-		return ret;
-	if (private->domain)
-		pg_size = 1UL << __ffs(private->domain->pgsize_bitmap);
-	start = ALIGN_DOWN(res.start, pg_size);
-	size = resource_size(&res);
-	if (!size)
-		return -ENOMEM;
-
-	logo = kmalloc(sizeof(*logo), GFP_KERNEL);
-	if (!logo)
-		return -ENOMEM;
-
-	logo->kvaddr = phys_to_virt(start);
-
-	if (private->domain) {
-		ret = iommu_map(private->domain, start, start, ALIGN(size, pg_size),
-				IOMMU_WRITE | IOMMU_READ);
-		if (ret) {
-			dev_err(drm_dev->dev, "failed to create 1v1 mapping\n");
-			goto err_free_logo;
-		}
-	}
-
-	logo->dma_addr = start;
-	logo->size = size;
-	logo->count = 1;
-	private->logo = logo;
-
-	idx = of_property_match_string(np, "memory-region-names", "drm-cubic-lut");
-	if (idx < 0)
-		return 0;
-
-	node = of_parse_phandle(np, "memory-region", idx);
-	if (!node)
-		return -ENOMEM;
-
-	ret = of_address_to_resource(node, 0, &res);
-	if (ret)
-		return ret;
-	start = ALIGN_DOWN(res.start, pg_size);
-	size = resource_size(&res);
-	if (!size)
-		return 0;
-
-	private->cubic_lut_kvaddr = phys_to_virt(start);
-	if (private->domain) {
-		ret = iommu_map(private->domain, start, start, ALIGN(size, pg_size),
-				IOMMU_WRITE | IOMMU_READ);
-		if (ret) {
-			dev_err(drm_dev->dev, "failed to create 1v1 mapping for cubic lut\n");
-			goto err_free_logo;
-		}
-	}
-	private->cubic_lut_dma_addr = start;
+	if (edid_ext[3] & EDID_CEA_YCRCB422)
+		info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
 
 	return 0;
-
-err_free_logo:
-	kfree(logo);
-
-	return ret;
 }
+EXPORT_SYMBOL(rockchip_drm_get_yuv422_format);
 
-static struct drm_framebuffer *
-get_framebuffer_by_node(struct drm_device *drm_dev, struct device_node *node)
+static
+void get_max_frl_rate(int max_frl_rate, u8 *max_lanes, u8 *max_rate_per_lane)
 {
-	struct rockchip_drm_private *private = drm_dev->dev_private;
-	struct drm_mode_fb_cmd2 mode_cmd = { 0 };
-	u32 val;
-	int bpp;
-
-	if (WARN_ON(!private->logo))
-		return NULL;
-
-	if (of_property_read_u32(node, "logo,offset", &val)) {
-		pr_err("%s: failed to get logo,offset\n", __func__);
-		return NULL;
-	}
-	mode_cmd.offsets[0] = val;
-
-	if (of_property_read_u32(node, "logo,width", &val)) {
-		pr_err("%s: failed to get logo,width\n", __func__);
-		return NULL;
-	}
-	mode_cmd.width = val;
-
-	if (of_property_read_u32(node, "logo,height", &val)) {
-		pr_err("%s: failed to get logo,height\n", __func__);
-		return NULL;
-	}
-	mode_cmd.height = val;
-
-	if (of_property_read_u32(node, "logo,bpp", &val)) {
-		pr_err("%s: failed to get logo,bpp\n", __func__);
-		return NULL;
-	}
-	bpp = val;
-
-	mode_cmd.pitches[0] = ALIGN(mode_cmd.width * bpp, 32) / 8;
-
-	switch (bpp) {
-	case 16:
-		mode_cmd.pixel_format = DRM_FORMAT_RGB565;
+	switch (max_frl_rate) {
+	case 1:
+		*max_lanes = 3;
+		*max_rate_per_lane = 3;
 		break;
-	case 24:
-		mode_cmd.pixel_format = DRM_FORMAT_RGB888;
+	case 2:
+		*max_lanes = 3;
+		*max_rate_per_lane = 6;
 		break;
-	case 32:
-		mode_cmd.pixel_format = DRM_FORMAT_XRGB8888;
+	case 3:
+		*max_lanes = 4;
+		*max_rate_per_lane = 6;
 		break;
+	case 4:
+		*max_lanes = 4;
+		*max_rate_per_lane = 8;
+		break;
+	case 5:
+		*max_lanes = 4;
+		*max_rate_per_lane = 10;
+		break;
+	case 6:
+		*max_lanes = 4;
+		*max_rate_per_lane = 12;
+		break;
+	case 0:
 	default:
-		pr_err("%s: unsupported to logo bpp %d\n", __func__, bpp);
-		return NULL;
+		*max_lanes = 0;
+		*max_rate_per_lane = 0;
 	}
-
-	return rockchip_fb_alloc(drm_dev, &mode_cmd, NULL, private->logo, 1);
 }
 
-static struct rockchip_drm_mode_set *
-of_parse_display_resource(struct drm_device *drm_dev, struct device_node *route)
+#define EDID_DSC_10BPC			(1 << 0)
+#define EDID_DSC_12BPC			(1 << 1)
+#define EDID_DSC_16BPC			(1 << 2)
+#define EDID_DSC_ALL_BPP		(1 << 3)
+#define EDID_DSC_NATIVE_420		(1 << 6)
+#define EDID_DSC_1P2			(1 << 7)
+#define EDID_DSC_MAX_FRL_RATE_MASK	0xf0
+#define EDID_DSC_MAX_SLICES		0xf
+#define EDID_DSC_TOTAL_CHUNK_KBYTES	0x3f
+#define EDID_MAX_FRL_RATE_MASK		0xf0
+
+static
+void parse_edid_forum_vsdb(struct rockchip_drm_dsc_cap *dsc_cap,
+			   u8 *max_frl_rate_per_lane, u8 *max_lanes, u8 *add_func,
+			   const u8 *hf_vsdb)
 {
-	struct rockchip_drm_private *private = drm_dev->dev_private;
-	struct rockchip_drm_mode_set *set;
-	struct device_node *connect;
-	struct drm_framebuffer *fb;
-	struct drm_connector *connector;
-	struct drm_crtc *crtc;
-	const char *string;
-	u32 val;
+	u8 max_frl_rate;
+	u8 dsc_max_frl_rate;
+	u8 dsc_max_slices;
 
-	connect = of_parse_phandle(route, "connect", 0);
-	if (!connect)
-		return NULL;
-
-	fb = get_framebuffer_by_node(drm_dev, route);
-	if (IS_ERR_OR_NULL(fb))
-		return NULL;
-
-	crtc = find_crtc_by_node(drm_dev, connect);
-	connector = find_connector_by_node(drm_dev, connect);
-	if (!connector)
-		connector = find_connector_by_bridge(drm_dev, connect);
-	if (!crtc || !connector) {
-		dev_warn(drm_dev->dev,
-			 "No available crtc or connector for display");
-		drm_framebuffer_put(fb);
-		return NULL;
-	}
-
-	set = kzalloc(sizeof(*set), GFP_KERNEL);
-	if (!set)
-		return NULL;
-
-	if (!of_property_read_u32(route, "video,clock", &val))
-		set->clock = val;
-
-	if (!of_property_read_u32(route, "video,hdisplay", &val))
-		set->hdisplay = val;
-
-	if (!of_property_read_u32(route, "video,vdisplay", &val))
-		set->vdisplay = val;
-
-	if (!of_property_read_u32(route, "video,crtc_hsync_end", &val))
-		set->crtc_hsync_end = val;
-
-	if (!of_property_read_u32(route, "video,crtc_vsync_end", &val))
-		set->crtc_vsync_end = val;
-
-	if (!of_property_read_u32(route, "video,vrefresh", &val))
-		set->vrefresh = val;
-
-	if (!of_property_read_u32(route, "video,flags", &val))
-		set->flags = val;
-
-	if (!of_property_read_u32(route, "video,aspect_ratio", &val))
-		set->picture_aspect_ratio = val;
-
-	if (!of_property_read_u32(route, "overscan,left_margin", &val))
-		set->left_margin = val;
-
-	if (!of_property_read_u32(route, "overscan,right_margin", &val))
-		set->right_margin = val;
-
-	if (!of_property_read_u32(route, "overscan,top_margin", &val))
-		set->top_margin = val;
-
-	if (!of_property_read_u32(route, "overscan,bottom_margin", &val))
-		set->bottom_margin = val;
-
-	if (!of_property_read_u32(route, "bcsh,brightness", &val))
-		set->brightness = val;
-	else
-		set->brightness = 50;
-
-	if (!of_property_read_u32(route, "bcsh,contrast", &val))
-		set->contrast = val;
-	else
-		set->contrast = 50;
-
-	if (!of_property_read_u32(route, "bcsh,saturation", &val))
-		set->saturation = val;
-	else
-		set->saturation = 50;
-
-	if (!of_property_read_u32(route, "bcsh,hue", &val))
-		set->hue = val;
-	else
-		set->hue = 50;
-
-	set->force_output = of_property_read_bool(route, "force-output");
-
-	if (!of_property_read_u32(route, "cubic_lut,offset", &val)) {
-		private->cubic_lut[crtc->index].enable = true;
-		private->cubic_lut[crtc->index].offset = val;
-	}
-
-	set->ratio = 1;
-	if (!of_property_read_string(route, "logo,mode", &string) &&
-	    !strcmp(string, "fullscreen"))
-		set->ratio = 0;
-
-	set->fb = fb;
-	set->crtc = crtc;
-	set->connector = connector;
-
-	return set;
-}
-
-static int rockchip_drm_fill_connector_modes(struct drm_connector *connector,
-					     uint32_t maxX, uint32_t maxY,
-					     bool force_output)
-{
-	struct drm_device *dev = connector->dev;
-	struct drm_display_mode *mode;
-	const struct drm_connector_helper_funcs *connector_funcs =
-		connector->helper_private;
-	int count = 0;
-	bool verbose_prune = true;
-	enum drm_connector_status old_status;
-
-	WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
-
-	DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id,
-		      connector->name);
-	/* set all modes to the unverified state */
-	list_for_each_entry(mode, &connector->modes, head)
-		mode->status = MODE_STALE;
-
-	if (force_output)
-		connector->force = DRM_FORCE_ON;
-	if (connector->force) {
-		if (connector->force == DRM_FORCE_ON ||
-		    connector->force == DRM_FORCE_ON_DIGITAL)
-			connector->status = connector_status_connected;
-		else
-			connector->status = connector_status_disconnected;
-		if (connector->funcs->force)
-			connector->funcs->force(connector);
-	} else {
-		old_status = connector->status;
-
-		if (connector->funcs->detect)
-			connector->status = connector->funcs->detect(connector, true);
-		else
-			connector->status  = connector_status_connected;
-		/*
-		 * Normally either the driver's hpd code or the poll loop should
-		 * pick up any changes and fire the hotplug event. But if
-		 * userspace sneaks in a probe, we might miss a change. Hence
-		 * check here, and if anything changed start the hotplug code.
-		 */
-		if (old_status != connector->status) {
-			DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
-				      connector->base.id,
-				      connector->name,
-				      old_status, connector->status);
-
-			/*
-			 * The hotplug event code might call into the fb
-			 * helpers, and so expects that we do not hold any
-			 * locks. Fire up the poll struct instead, it will
-			 * disable itself again.
-			 */
-			dev->mode_config.delayed_event = true;
-			if (dev->mode_config.poll_enabled)
-				schedule_delayed_work(&dev->mode_config.output_poll_work,
-						      0);
-		}
-	}
-
-	/* Re-enable polling in case the global poll config changed. */
-	if (!dev->mode_config.poll_running)
-		drm_kms_helper_poll_enable(dev);
-
-	dev->mode_config.poll_running = true;
-
-	if (connector->status == connector_status_disconnected) {
-		DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n",
-			      connector->base.id, connector->name);
-		drm_connector_update_edid_property(connector, NULL);
-		verbose_prune = false;
-		goto prune;
-	}
-
-	count = (*connector_funcs->get_modes)(connector);
-
-	if (count == 0 && connector->status == connector_status_connected)
-		count = drm_add_modes_noedid(connector, 1024, 768);
-	if (force_output)
-		count += rockchip_drm_add_modes_noedid(connector);
-	if (count == 0)
-		goto prune;
-
-	drm_connector_list_update(connector);
-
-	list_for_each_entry(mode, &connector->modes, head) {
-		if (mode->status == MODE_OK)
-			mode->status = drm_mode_validate_driver(dev, mode);
-
-		if (mode->status == MODE_OK)
-			mode->status = drm_mode_validate_size(mode, maxX, maxY);
-
-		/**
-		 * if (mode->status == MODE_OK)
-		 *	mode->status = drm_mode_validate_flag(mode, mode_flags);
-		 */
-		if (mode->status == MODE_OK && connector_funcs->mode_valid)
-			mode->status = connector_funcs->mode_valid(connector,
-								   mode);
-		if (mode->status == MODE_OK)
-			mode->status = drm_mode_validate_ycbcr420(mode,
-								  connector);
-	}
-
-prune:
-	drm_mode_prune_invalid(dev, &connector->modes, verbose_prune);
-
-	if (list_empty(&connector->modes))
-		return 0;
-
-	list_for_each_entry(mode, &connector->modes, head)
-		mode->vrefresh = drm_mode_vrefresh(mode);
-
-	drm_mode_sort(&connector->modes);
-
-	DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id,
-		      connector->name);
-	list_for_each_entry(mode, &connector->modes, head) {
-		drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
-		drm_mode_debug_printmodeline(mode);
-	}
-
-	return count;
-}
-
-static int setup_initial_state(struct drm_device *drm_dev,
-			       struct drm_atomic_state *state,
-			       struct rockchip_drm_mode_set *set)
-{
-	struct rockchip_drm_private *priv = drm_dev->dev_private;
-	struct drm_connector *connector = set->connector;
-	struct drm_crtc *crtc = set->crtc;
-	struct drm_crtc_state *crtc_state;
-	struct drm_connector_state *conn_state;
-	struct drm_plane_state *primary_state;
-	struct drm_display_mode *mode = NULL;
-	const struct drm_connector_helper_funcs *funcs;
-	const struct drm_encoder_helper_funcs *encoder_funcs;
-	int pipe = drm_crtc_index(crtc);
-	bool is_crtc_enabled = true;
-	int hdisplay, vdisplay;
-	int fb_width, fb_height;
-	int found = 0, match = 0;
-	int num_modes;
-	int ret = 0;
-	struct rockchip_crtc_state *s = NULL;
-
-	if (!set->hdisplay || !set->vdisplay || !set->vrefresh)
-		is_crtc_enabled = false;
-
-	conn_state = drm_atomic_get_connector_state(state, connector);
-	if (IS_ERR(conn_state))
-		return PTR_ERR(conn_state);
-
-	funcs = connector->helper_private;
-
-	if (funcs->best_encoder)
-		conn_state->best_encoder = funcs->best_encoder(connector);
-	else
-		conn_state->best_encoder = drm_atomic_helper_best_encoder(connector);
-
-	if (funcs->loader_protect)
-		funcs->loader_protect(connector, true);
-	connector->loader_protect = true;
-	encoder_funcs = conn_state->best_encoder->helper_private;
-	if (encoder_funcs->loader_protect)
-		encoder_funcs->loader_protect(conn_state->best_encoder, true);
-	conn_state->best_encoder->loader_protect = true;
-	num_modes = rockchip_drm_fill_connector_modes(connector, 4096, 4096, set->force_output);
-	if (!num_modes) {
-		dev_err(drm_dev->dev, "connector[%s] can't found any modes\n",
-			connector->name);
-		ret = -EINVAL;
-		goto error_conn;
-	}
-
-	list_for_each_entry(mode, &connector->modes, head) {
-		if (mode->clock == set->clock &&
-		    mode->hdisplay == set->hdisplay &&
-		    mode->vdisplay == set->vdisplay &&
-		    mode->crtc_hsync_end == set->crtc_hsync_end &&
-		    mode->crtc_vsync_end == set->crtc_vsync_end &&
-		    drm_mode_vrefresh(mode) == set->vrefresh &&
-		    /* we just need to focus on DRM_MODE_FLAG_ALL flag, so here
-		     * we compare mode->flags with set->flags & DRM_MODE_FLAG_ALL.
-		     */
-		    mode->flags == (set->flags & DRM_MODE_FLAG_ALL) &&
-		    mode->picture_aspect_ratio == set->picture_aspect_ratio) {
-			found = 1;
-			match = 1;
-			break;
-		}
-	}
-
-	if (!found) {
-		ret = -EINVAL;
-		connector->status = connector_status_disconnected;
-		goto error_conn;
-	}
-
-	conn_state->tv.brightness = set->brightness;
-	conn_state->tv.contrast = set->contrast;
-	conn_state->tv.saturation = set->saturation;
-	conn_state->tv.hue = set->hue;
-	set->mode = mode;
-	crtc_state = drm_atomic_get_crtc_state(state, crtc);
-	if (IS_ERR(crtc_state)) {
-		ret = PTR_ERR(crtc_state);
-		goto error_conn;
-	}
-
-	drm_mode_copy(&crtc_state->adjusted_mode, mode);
-	if (!match || !is_crtc_enabled) {
-		set->mode_changed = true;
-	} else {
-		ret = drm_atomic_set_crtc_for_connector(conn_state, crtc);
-		if (ret)
-			goto error_conn;
-
-		mode->picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE;
-		ret = drm_atomic_set_mode_for_crtc(crtc_state, mode);
-		if (ret)
-			goto error_conn;
-
-		crtc_state->active = true;
-
-		if (priv->crtc_funcs[pipe] &&
-		    priv->crtc_funcs[pipe]->loader_protect)
-			priv->crtc_funcs[pipe]->loader_protect(crtc, true);
-	}
-
-	if (!set->fb) {
-		ret = 0;
-		goto error_crtc;
-	}
-	primary_state = drm_atomic_get_plane_state(state, crtc->primary);
-	if (IS_ERR(primary_state)) {
-		ret = PTR_ERR(primary_state);
-		goto error_crtc;
-	}
-
-	hdisplay = mode->hdisplay;
-	vdisplay = mode->vdisplay;
-	fb_width = set->fb->width;
-	fb_height = set->fb->height;
-
-	primary_state->crtc = crtc;
-	primary_state->src_x = 0;
-	primary_state->src_y = 0;
-	primary_state->src_w = fb_width << 16;
-	primary_state->src_h = fb_height << 16;
-	if (set->ratio) {
-		if (set->fb->width >= hdisplay) {
-			primary_state->crtc_x = 0;
-			primary_state->crtc_w = hdisplay;
-		} else {
-			primary_state->crtc_x = (hdisplay - fb_width) / 2;
-			primary_state->crtc_w = set->fb->width;
-		}
-
-		if (set->fb->height >= vdisplay) {
-			primary_state->crtc_y = 0;
-			primary_state->crtc_h = vdisplay;
-		} else {
-			primary_state->crtc_y = (vdisplay - fb_height) / 2;
-			primary_state->crtc_h = fb_height;
-		}
-	} else {
-		primary_state->crtc_x = 0;
-		primary_state->crtc_y = 0;
-		primary_state->crtc_w = hdisplay;
-		primary_state->crtc_h = vdisplay;
-	}
-	s = to_rockchip_crtc_state(crtc->state);
-	s->output_type = connector->connector_type;
-
-	return 0;
-
-error_crtc:
-	if (priv->crtc_funcs[pipe] && priv->crtc_funcs[pipe]->loader_protect)
-		priv->crtc_funcs[pipe]->loader_protect(crtc, false);
-error_conn:
-	if (funcs->loader_protect)
-		funcs->loader_protect(connector, false);
-	connector->loader_protect = false;
-	if (encoder_funcs->loader_protect)
-		encoder_funcs->loader_protect(conn_state->best_encoder, false);
-	conn_state->best_encoder->loader_protect = false;
-
-	return ret;
-}
-
-static int update_state(struct drm_device *drm_dev,
-			struct drm_atomic_state *state,
-			struct rockchip_drm_mode_set *set,
-			unsigned int *plane_mask)
-{
-	struct drm_crtc *crtc = set->crtc;
-	struct drm_connector *connector = set->connector;
-	struct drm_display_mode *mode = set->mode;
-	struct drm_plane_state *primary_state;
-	struct drm_crtc_state *crtc_state;
-	struct drm_connector_state *conn_state;
-	int ret;
-	struct rockchip_crtc_state *s;
-
-	crtc_state = drm_atomic_get_crtc_state(state, crtc);
-	if (IS_ERR(crtc_state))
-		return PTR_ERR(crtc_state);
-	conn_state = drm_atomic_get_connector_state(state, connector);
-	if (IS_ERR(conn_state))
-		return PTR_ERR(conn_state);
-	s = to_rockchip_crtc_state(crtc_state);
-	s->left_margin = set->left_margin;
-	s->right_margin = set->right_margin;
-	s->top_margin = set->top_margin;
-	s->bottom_margin = set->bottom_margin;
-
-	if (set->mode_changed) {
-		ret = drm_atomic_set_crtc_for_connector(conn_state, crtc);
-		if (ret)
-			return ret;
-
-		ret = drm_atomic_set_mode_for_crtc(crtc_state, mode);
-		if (ret)
-			return ret;
-
-		crtc_state->active = true;
-	} else {
-		const struct drm_encoder_helper_funcs *encoder_helper_funcs;
-		const struct drm_connector_helper_funcs *connector_helper_funcs;
-		struct drm_encoder *encoder;
-
-		connector_helper_funcs = connector->helper_private;
-		if (!connector_helper_funcs)
-			return -ENXIO;
-		if (connector_helper_funcs->best_encoder)
-			encoder = connector_helper_funcs->best_encoder(connector);
-		else
-			encoder = drm_atomic_helper_best_encoder(connector);
-		if (!encoder)
-			return -ENXIO;
-		encoder_helper_funcs = encoder->helper_private;
-		if (!encoder_helper_funcs->atomic_check)
-			return -ENXIO;
-		ret = encoder_helper_funcs->atomic_check(encoder, crtc->state,
-							 conn_state);
-		if (ret)
-			return ret;
-
-		if (encoder_helper_funcs->atomic_mode_set)
-			encoder_helper_funcs->atomic_mode_set(encoder,
-							      crtc_state,
-							      conn_state);
-		else if (encoder_helper_funcs->mode_set)
-			encoder_helper_funcs->mode_set(encoder, mode, mode);
-	}
-
-	primary_state = drm_atomic_get_plane_state(state, crtc->primary);
-	if (IS_ERR(primary_state))
-		return PTR_ERR(primary_state);
-
-	crtc_state->plane_mask = 1 << drm_plane_index(crtc->primary);
-	*plane_mask |= crtc_state->plane_mask;
-
-	drm_atomic_set_fb_for_plane(primary_state, set->fb);
-	drm_framebuffer_put(set->fb);
-	ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
-
-	return ret;
-}
-
-static void show_loader_logo(struct drm_device *drm_dev)
-{
-	struct drm_atomic_state *state, *old_state;
-	struct device_node *np = drm_dev->dev->of_node;
-	struct drm_mode_config *mode_config = &drm_dev->mode_config;
-	struct rockchip_drm_private *private = drm_dev->dev_private;
-	struct device_node *root, *route;
-	struct rockchip_drm_mode_set *set, *tmp, *unset;
-	struct list_head mode_set_list;
-	struct list_head mode_unset_list;
-	unsigned int plane_mask = 0;
-	int ret, i;
-
-	root = of_get_child_by_name(np, "route");
-	if (!root) {
-		dev_warn(drm_dev->dev, "failed to parse display resources\n");
+	if (!hf_vsdb[7])
 		return;
-	}
 
-	if (init_loader_memory(drm_dev)) {
-		dev_warn(drm_dev->dev, "failed to parse loader memory\n");
+	DRM_DEBUG_KMS("hdmi_21 sink detected. parsing edid\n");
+	max_frl_rate = (hf_vsdb[7] & EDID_MAX_FRL_RATE_MASK) >> 4;
+	get_max_frl_rate(max_frl_rate, max_lanes,
+			 max_frl_rate_per_lane);
+
+	*add_func = hf_vsdb[8];
+
+	if (cea_db_payload_len(hf_vsdb) < 13)
 		return;
+
+	dsc_cap->v_1p2 = hf_vsdb[11] & EDID_DSC_1P2;
+
+	if (!dsc_cap->v_1p2)
+		return;
+
+	dsc_cap->native_420 = hf_vsdb[11] & EDID_DSC_NATIVE_420;
+	dsc_cap->all_bpp = hf_vsdb[11] & EDID_DSC_ALL_BPP;
+
+	if (hf_vsdb[11] & EDID_DSC_16BPC)
+		dsc_cap->bpc_supported = 16;
+	else if (hf_vsdb[11] & EDID_DSC_12BPC)
+		dsc_cap->bpc_supported = 12;
+	else if (hf_vsdb[11] & EDID_DSC_10BPC)
+		dsc_cap->bpc_supported = 10;
+	else
+		dsc_cap->bpc_supported = 0;
+
+	dsc_max_frl_rate = (hf_vsdb[12] & EDID_DSC_MAX_FRL_RATE_MASK) >> 4;
+	get_max_frl_rate(dsc_max_frl_rate, &dsc_cap->max_lanes,
+			 &dsc_cap->max_frl_rate_per_lane);
+	dsc_cap->total_chunk_kbytes = hf_vsdb[13] & EDID_DSC_TOTAL_CHUNK_KBYTES;
+
+	dsc_max_slices = hf_vsdb[12] & EDID_DSC_MAX_SLICES;
+	switch (dsc_max_slices) {
+	case 1:
+		dsc_cap->max_slices = 1;
+		dsc_cap->clk_per_slice = 340;
+		break;
+	case 2:
+		dsc_cap->max_slices = 2;
+		dsc_cap->clk_per_slice = 340;
+		break;
+	case 3:
+		dsc_cap->max_slices = 4;
+		dsc_cap->clk_per_slice = 340;
+		break;
+	case 4:
+		dsc_cap->max_slices = 8;
+		dsc_cap->clk_per_slice = 340;
+		break;
+	case 5:
+		dsc_cap->max_slices = 8;
+		dsc_cap->clk_per_slice = 400;
+		break;
+	case 6:
+		dsc_cap->max_slices = 12;
+		dsc_cap->clk_per_slice = 400;
+		break;
+	case 7:
+		dsc_cap->max_slices = 16;
+		dsc_cap->clk_per_slice = 400;
+		break;
+	case 0:
+	default:
+		dsc_cap->max_slices = 0;
+		dsc_cap->clk_per_slice = 0;
 	}
-
-	INIT_LIST_HEAD(&mode_set_list);
-	INIT_LIST_HEAD(&mode_unset_list);
-	drm_modeset_lock_all(drm_dev);
-	state = drm_atomic_state_alloc(drm_dev);
-	if (!state) {
-		dev_err(drm_dev->dev, "failed to alloc atomic state\n");
-		ret = -ENOMEM;
-		goto err_unlock;
-	}
-
-	state->acquire_ctx = mode_config->acquire_ctx;
-
-	for_each_child_of_node(root, route) {
-		if (!of_device_is_available(route))
-			continue;
-
-		set = of_parse_display_resource(drm_dev, route);
-		if (!set)
-			continue;
-
-		if (setup_initial_state(drm_dev, state, set)) {
-			drm_framebuffer_put(set->fb);
-			INIT_LIST_HEAD(&set->head);
-			list_add_tail(&set->head, &mode_unset_list);
-			continue;
-		}
-		INIT_LIST_HEAD(&set->head);
-		list_add_tail(&set->head, &mode_set_list);
-	}
-
-	/*
-	 * the mode_unset_list store the unconnected route, if route's crtc
-	 * isn't used, we should close it.
-	 */
-	list_for_each_entry_safe(unset, tmp, &mode_unset_list, head) {
-		struct rockchip_drm_mode_set *tmp_set;
-		int find_used_crtc = 0;
-
-		list_for_each_entry_safe(set, tmp_set, &mode_set_list, head) {
-			if (set->crtc == unset->crtc) {
-				find_used_crtc = 1;
-				continue;
-			}
-		}
-
-		if (!find_used_crtc) {
-			struct drm_crtc *crtc = unset->crtc;
-			int pipe = drm_crtc_index(crtc);
-			struct rockchip_drm_private *priv =
-							drm_dev->dev_private;
-
-			if (unset->hdisplay && unset->vdisplay) {
-				if (priv->crtc_funcs[pipe] &&
-				    priv->crtc_funcs[pipe]->loader_protect)
-					priv->crtc_funcs[pipe]->loader_protect(crtc, true);
-				priv->crtc_funcs[pipe]->crtc_close(crtc);
-				if (priv->crtc_funcs[pipe] &&
-				    priv->crtc_funcs[pipe]->loader_protect)
-					priv->crtc_funcs[pipe]->loader_protect(crtc, false);
-			}
-		}
-
-		list_del(&unset->head);
-		kfree(unset);
-	}
-
-	if (list_empty(&mode_set_list)) {
-		dev_warn(drm_dev->dev, "can't not find any loader display\n");
-		ret = -ENXIO;
-		goto err_free_state;
-	}
-
-	/*
-	 * The state save initial devices status, swap the state into
-	 * drm devices as old state, so if new state come, can compare
-	 * with this state to judge which status need to update.
-	 */
-	WARN_ON(drm_atomic_helper_swap_state(state, false));
-	drm_atomic_state_put(state);
-	old_state = drm_atomic_helper_duplicate_state(drm_dev,
-						      mode_config->acquire_ctx);
-	if (IS_ERR(old_state)) {
-		dev_err(drm_dev->dev, "failed to duplicate atomic state\n");
-		ret = PTR_ERR_OR_ZERO(old_state);
-		goto err_free_state;
-	}
-
-	state = drm_atomic_helper_duplicate_state(drm_dev,
-						  mode_config->acquire_ctx);
-	if (IS_ERR(state)) {
-		dev_err(drm_dev->dev, "failed to duplicate atomic state\n");
-		ret = PTR_ERR_OR_ZERO(state);
-		goto err_free_old_state;
-	}
-	state->acquire_ctx = mode_config->acquire_ctx;
-	list_for_each_entry(set, &mode_set_list, head)
-		/*
-		 * We don't want to see any fail on update_state.
-		 */
-		WARN_ON(update_state(drm_dev, state, set, &plane_mask));
-
-	for (i = 0; i < state->num_connector; i++) {
-		if (state->connectors[i].new_state->connector->status !=
-		    connector_status_connected)
-			state->connectors[i].new_state->best_encoder = NULL;
-	}
-
-	ret = drm_atomic_commit(state);
-	/**
-	 * todo
-	 * drm_atomic_clean_old_fb(drm_dev, plane_mask, ret);
-	 */
-
-	list_for_each_entry_safe(set, tmp, &mode_set_list, head) {
-		if (set->force_output)
-			set->connector->force = DRM_FORCE_UNSPECIFIED;
-		list_del(&set->head);
-		kfree(set);
-	}
-
-	/*
-	 * Is possible get deadlock here?
-	 */
-	WARN_ON(ret == -EDEADLK);
-
-	if (ret) {
-		/*
-		 * restore display status if atomic commit failed.
-		 */
-		WARN_ON(drm_atomic_helper_swap_state(old_state, false));
-		goto err_free_state;
-	}
-
-	rockchip_free_loader_memory(drm_dev);
-	drm_atomic_state_put(old_state);
-	drm_atomic_state_put(state);
-
-	private->loader_protect = true;
-	drm_modeset_unlock_all(drm_dev);
-	return;
-err_free_old_state:
-	drm_atomic_state_put(old_state);
-err_free_state:
-	drm_atomic_state_put(state);
-err_unlock:
-	drm_modeset_unlock_all(drm_dev);
-	if (ret)
-		dev_err(drm_dev->dev, "failed to show loader logo\n");
 }
 
-static const char *const loader_protect_clocks[] __initconst = {
-	"hclk_vio",
-	"hclk_vop",
-	"hclk_vopb",
-	"hclk_vopl",
-	"aclk_vio",
-	"aclk_vio0",
-	"aclk_vio1",
-	"aclk_vop",
-	"aclk_vopb",
-	"aclk_vopl",
-	"aclk_vo_pre",
-	"aclk_vio_pre",
-	"dclk_vop",
-	"dclk_vop0",
-	"dclk_vop1",
-	"dclk_vopb",
-	"dclk_vopl",
+enum {
+	VER_26_BYTE_V0,
+	VER_15_BYTE_V1,
+	VER_12_BYTE_V1,
+	VER_12_BYTE_V2,
 };
 
-static struct clk **loader_clocks __initdata;
-static int __init rockchip_clocks_loader_protect(void)
+static int check_next_hdr_version(const u8 *next_hdr_db)
 {
-	int nclocks = ARRAY_SIZE(loader_protect_clocks);
-	struct clk *clk;
-	int i;
+	u16 ver;
 
-	loader_clocks = kcalloc(nclocks, sizeof(void *), GFP_KERNEL);
-	if (!loader_clocks)
-		return -ENOMEM;
+	ver = (next_hdr_db[5] & 0xf0) << 8 | next_hdr_db[0];
 
-	for (i = 0; i < nclocks; i++) {
-		clk = __clk_lookup(loader_protect_clocks[i]);
-
-		if (clk) {
-			loader_clocks[i] = clk;
-			clk_prepare_enable(clk);
-		}
+	switch (ver) {
+	case 0x00f9:
+		return VER_26_BYTE_V0;
+	case 0x20ee:
+		return VER_15_BYTE_V1;
+	case 0x20eb:
+		return VER_12_BYTE_V1;
+	case 0x40eb:
+		return VER_12_BYTE_V2;
+	default:
+		return -ENOENT;
 	}
-
-	return 0;
 }
-arch_initcall_sync(rockchip_clocks_loader_protect);
 
-static int __init rockchip_clocks_loader_unprotect(void)
+static void parse_ver_26_v0_data(struct ver_26_v0 *hdr, const u8 *data)
 {
-	int i;
+	hdr->yuv422_12bit = data[5] & BIT(0);
+	hdr->support_2160p_60 = (data[5] & BIT(1)) >> 1;
+	hdr->global_dimming = (data[5] & BIT(2)) >> 2;
 
-	if (!loader_clocks)
-		return -ENODEV;
+	hdr->dm_major_ver = (data[21] & 0xf0) >> 4;
+	hdr->dm_minor_ver = data[21] & 0xf;
 
-	for (i = 0; i < ARRAY_SIZE(loader_protect_clocks); i++) {
-		struct clk *clk = loader_clocks[i];
+	hdr->t_min_pq = (data[19] << 4) | ((data[18] & 0xf0) >> 4);
+	hdr->t_max_pq = (data[20] << 4) | (data[18] & 0xf);
 
-		if (clk)
-			clk_disable_unprepare(clk);
+	hdr->rx = (data[7] << 4) | ((data[6] & 0xf0) >> 4);
+	hdr->ry = (data[8] << 4) | (data[6] & 0xf);
+	hdr->gx = (data[10] << 4) | ((data[9] & 0xf0) >> 4);
+	hdr->gy = (data[11] << 4) | (data[9] & 0xf);
+	hdr->bx = (data[13] << 4) | ((data[12] & 0xf0) >> 4);
+	hdr->by = (data[14] << 4) | (data[12] & 0xf);
+	hdr->wx = (data[16] << 4) | ((data[15] & 0xf0) >> 4);
+	hdr->wy = (data[17] << 4) | (data[15] & 0xf);
+}
+
+static void parse_ver_15_v1_data(struct ver_15_v1 *hdr, const u8 *data)
+{
+	hdr->yuv422_12bit = data[5] & BIT(0);
+	hdr->support_2160p_60 = (data[5] & BIT(1)) >> 1;
+	hdr->global_dimming = data[6] & BIT(0);
+
+	hdr->dm_version = (data[5] & 0x1c) >> 2;
+
+	hdr->colorimetry = data[7] & BIT(0);
+
+	hdr->t_max_lum = (data[6] & 0xfe) >> 1;
+	hdr->t_min_lum = (data[7] & 0xfe) >> 1;
+
+	hdr->rx = data[9];
+	hdr->ry = data[10];
+	hdr->gx = data[11];
+	hdr->gy = data[12];
+	hdr->bx = data[13];
+	hdr->by = data[14];
+}
+
+static void parse_ver_12_v1_data(struct ver_12_v1 *hdr, const u8 *data)
+{
+	hdr->yuv422_12bit = data[5] & BIT(0);
+	hdr->support_2160p_60 = (data[5] & BIT(1)) >> 1;
+	hdr->global_dimming = data[6] & BIT(0);
+
+	hdr->dm_version = (data[5] & 0x1c) >> 2;
+
+	hdr->colorimetry = data[7] & BIT(0);
+
+	hdr->t_max_lum = (data[6] & 0xfe) >> 1;
+	hdr->t_min_lum = (data[7] & 0xfe) >> 1;
+
+	hdr->low_latency = data[8] & 0x3;
+
+	hdr->unique_rx = (data[11] & 0xf8) >> 3;
+	hdr->unique_ry = (data[11] & 0x7) << 2 | (data[10] & BIT(0)) << 1 |
+		(data[9] & BIT(0));
+	hdr->unique_gx = (data[9] & 0xfe) >> 1;
+	hdr->unique_gy = (data[10] & 0xfe) >> 1;
+	hdr->unique_bx = (data[8] & 0xe0) >> 5;
+	hdr->unique_by = (data[8] & 0x1c) >> 2;
+}
+
+static void parse_ver_12_v2_data(struct ver_12_v2 *hdr, const u8 *data)
+{
+	hdr->yuv422_12bit = data[5] & BIT(0);
+	hdr->backlt_ctrl = (data[5] & BIT(1)) >> 1;
+	hdr->global_dimming = (data[6] & BIT(2)) >> 2;
+
+	hdr->dm_version = (data[5] & 0x1c) >> 2;
+	hdr->backlt_min_luma = data[6] & 0x3;
+	hdr->interface = data[7] & 0x3;
+	hdr->yuv444_10b_12b = (data[8] & BIT(0)) << 1 | (data[9] & BIT(0));
+
+	hdr->t_min_pq_v2 = (data[6] & 0xf8) >> 3;
+	hdr->t_max_pq_v2 = (data[7] & 0xf8) >> 3;
+
+	hdr->unique_rx = (data[10] & 0xf8) >> 3;
+	hdr->unique_ry = (data[11] & 0xf8) >> 3;
+	hdr->unique_gx = (data[8] & 0xfe) >> 1;
+	hdr->unique_gy = (data[9] & 0xfe) >> 1;
+	hdr->unique_bx = data[10] & 0x7;
+	hdr->unique_by = data[11] & 0x7;
+}
+
+static
+void parse_next_hdr_block(struct next_hdr_sink_data *sink_data,
+			  const u8 *next_hdr_db)
+{
+	int version;
+
+	version = check_next_hdr_version(next_hdr_db);
+	if (version < 0)
+		return;
+
+	sink_data->version = version;
+
+	switch (version) {
+	case VER_26_BYTE_V0:
+		parse_ver_26_v0_data(&sink_data->ver_26_v0, next_hdr_db);
+		break;
+	case VER_15_BYTE_V1:
+		parse_ver_15_v1_data(&sink_data->ver_15_v1, next_hdr_db);
+		break;
+	case VER_12_BYTE_V1:
+		parse_ver_12_v1_data(&sink_data->ver_12_v1, next_hdr_db);
+		break;
+	case VER_12_BYTE_V2:
+		parse_ver_12_v2_data(&sink_data->ver_12_v2, next_hdr_db);
+		break;
+	default:
+		break;
 	}
-	kfree(loader_clocks);
-
-	return 0;
 }
-late_initcall_sync(rockchip_clocks_loader_unprotect);
-#endif
 
-int rockchip_drm_crtc_send_mcu_cmd(struct drm_device *drm_dev,
-				   struct device_node *np_crtc,
-				   u32 type, u32 value)
+int rockchip_drm_parse_cea_ext(struct rockchip_drm_dsc_cap *dsc_cap,
+			       u8 *max_frl_rate_per_lane, u8 *max_lanes, u8 *add_func,
+			       const struct edid *edid)
 {
-	struct drm_crtc *crtc;
-	int pipe = 0;
-	struct rockchip_drm_private *priv;
+	const u8 *edid_ext;
+	int i, start, end;
 
-	if (!np_crtc || !of_device_is_available(np_crtc))
+	if (!dsc_cap || !max_frl_rate_per_lane || !max_lanes || !edid || !add_func)
 		return -EINVAL;
 
-	drm_for_each_crtc(crtc, drm_dev) {
-		if (of_get_parent(crtc->port) == np_crtc)
-			break;
-	}
-
-	pipe = drm_crtc_index(crtc);
-	if (pipe >= ROCKCHIP_MAX_CRTC)
+	edid_ext = find_cea_extension(edid);
+	if (!edid_ext)
 		return -EINVAL;
-	priv = crtc->dev->dev_private;
-	if (priv->crtc_funcs[pipe]->crtc_send_mcu_cmd)
-		priv->crtc_funcs[pipe]->crtc_send_mcu_cmd(crtc, type, value);
+
+	if (cea_db_offsets(edid_ext, &start, &end))
+		return -EINVAL;
+
+	for_each_cea_db(edid_ext, i, start, end) {
+		const u8 *db = &edid_ext[i];
+
+		if (cea_db_is_hdmi_forum_vsdb(db))
+			parse_edid_forum_vsdb(dsc_cap, max_frl_rate_per_lane,
+					      max_lanes, add_func, db);
+	}
 
 	return 0;
 }
-EXPORT_SYMBOL(rockchip_drm_crtc_send_mcu_cmd);
+EXPORT_SYMBOL(rockchip_drm_parse_cea_ext);
+
+int rockchip_drm_parse_next_hdr(struct next_hdr_sink_data *sink_data,
+				const struct edid *edid)
+{
+	const u8 *edid_ext;
+	int i, start, end;
+
+	if (!sink_data || !edid)
+		return -EINVAL;
+
+	memset(sink_data, 0, sizeof(struct next_hdr_sink_data));
+
+	edid_ext = find_cea_extension(edid);
+	if (!edid_ext)
+		return -EINVAL;
+
+	if (cea_db_offsets(edid_ext, &start, &end))
+		return -EINVAL;
+
+	for_each_cea_db(edid_ext, i, start, end) {
+		const u8 *db = &edid_ext[i];
+
+		if (cea_db_is_hdmi_next_hdr_block(db))
+			parse_next_hdr_block(sink_data, db);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(rockchip_drm_parse_next_hdr);
+
+#define COLORIMETRY_DATA_BLOCK		0x5
+#define USE_EXTENDED_TAG		0x07
+
+static bool cea_db_is_hdmi_colorimetry_data_block(const u8 *db)
+{
+	if (cea_db_tag(db) != USE_EXTENDED_TAG)
+		return false;
+
+	if (db[1] != COLORIMETRY_DATA_BLOCK)
+		return false;
+
+	return true;
+}
+
+int
+rockchip_drm_parse_colorimetry_data_block(u8 *colorimetry, const struct edid *edid)
+{
+	const u8 *edid_ext;
+	int i, start, end;
+
+	if (!colorimetry || !edid)
+		return -EINVAL;
+
+	*colorimetry = 0;
+
+	edid_ext = find_cea_extension(edid);
+	if (!edid_ext)
+		return -EINVAL;
+
+	if (cea_db_offsets(edid_ext, &start, &end))
+		return -EINVAL;
+
+	for_each_cea_db(edid_ext, i, start, end) {
+		const u8 *db = &edid_ext[i];
+
+		if (cea_db_is_hdmi_colorimetry_data_block(db))
+			/* As per CEA 861-G spec */
+			*colorimetry = ((db[3] & (0x1 << 7)) << 1) | db[2];
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(rockchip_drm_parse_colorimetry_data_block);
 
 /*
  * Attach a (component) device to the shared drm dma mapping from master drm
@@ -1264,6 +1090,17 @@
 		return;
 
 	iommu_detach_device(domain, dev);
+}
+
+void rockchip_drm_crtc_standby(struct drm_crtc *crtc, bool standby)
+{
+	struct rockchip_drm_private *priv = crtc->dev->dev_private;
+	int pipe = drm_crtc_index(crtc);
+
+	if (pipe < ROCKCHIP_MAX_CRTC &&
+	    priv->crtc_funcs[pipe] &&
+	    priv->crtc_funcs[pipe]->crtc_standby)
+		priv->crtc_funcs[pipe]->crtc_standby(crtc, standby);
 }
 
 int rockchip_register_crtc_funcs(struct drm_crtc *crtc,
@@ -1320,6 +1157,7 @@
 	struct rockchip_drm_private *private = drm_dev->dev_private;
 	struct iommu_domain_geometry *geometry;
 	u64 start, end;
+	int ret = 0;
 
 	if (!is_support_iommu)
 		return 0;
@@ -1340,7 +1178,23 @@
 	iommu_set_fault_handler(private->domain, rockchip_drm_fault_handler,
 				drm_dev);
 
-	return 0;
+	if (iommu_reserve_map) {
+		/*
+		 * At 32 bit platform size_t maximum value is 0xffffffff, SZ_4G(0x100000000) will be
+		 * cliped to 0, so we split into two mapping
+		 */
+		ret = iommu_map(private->domain, 0, 0, (size_t)SZ_2G,
+				IOMMU_WRITE | IOMMU_READ | IOMMU_PRIV);
+		if (ret)
+			dev_err(drm_dev->dev, "failed to create 0-2G pre mapping\n");
+
+		ret = iommu_map(private->domain, SZ_2G, SZ_2G, (size_t)SZ_2G,
+				IOMMU_WRITE | IOMMU_READ | IOMMU_PRIV);
+		if (ret)
+			dev_err(drm_dev->dev, "failed to create 2G-4G pre mapping\n");
+	}
+
+	return ret;
 }
 
 static void rockchip_iommu_cleanup(struct drm_device *drm_dev)
@@ -1350,6 +1204,10 @@
 	if (!is_support_iommu)
 		return;
 
+	if (iommu_reserve_map) {
+		iommu_unmap(private->domain, 0, (size_t)SZ_2G);
+		iommu_unmap(private->domain, SZ_2G, (size_t)SZ_2G);
+	}
 	drm_mm_takedown(&private->mm);
 	iommu_domain_free(private->domain);
 }
@@ -1361,16 +1219,12 @@
 	struct drm_minor *minor = node->minor;
 	struct drm_device *drm_dev = minor->dev;
 	struct rockchip_drm_private *priv = drm_dev->dev_private;
-
 	struct drm_printer p = drm_seq_file_printer(s);
 
 	if (!priv->domain)
 		return 0;
-
 	mutex_lock(&priv->mm_lock);
-
 	drm_mm_print(&priv->mm, &p);
-
 	mutex_unlock(&priv->mm_lock);
 
 	return 0;
@@ -1440,21 +1294,15 @@
 	{ "mm_dump", rockchip_drm_mm_dump, 0, NULL },
 };
 
-static int rockchip_drm_debugfs_init(struct drm_minor *minor)
+static void rockchip_drm_debugfs_init(struct drm_minor *minor)
 {
 	struct drm_device *dev = minor->dev;
 	struct rockchip_drm_private *priv = dev->dev_private;
 	struct drm_crtc *crtc;
-	int ret;
 
-	ret = drm_debugfs_create_files(rockchip_debugfs_files,
-				       ARRAY_SIZE(rockchip_debugfs_files),
-				       minor->debugfs_root,
-				       minor);
-	if (ret) {
-		dev_err(dev->dev, "could not install rockchip_debugfs_list\n");
-		return ret;
-	}
+	drm_debugfs_create_files(rockchip_debugfs_files,
+				 ARRAY_SIZE(rockchip_debugfs_files),
+				 minor->debugfs_root, minor);
 
 	drm_for_each_crtc(crtc, dev) {
 		int pipe = drm_crtc_index(crtc);
@@ -1463,10 +1311,14 @@
 		    priv->crtc_funcs[pipe]->debugfs_init)
 			priv->crtc_funcs[pipe]->debugfs_init(minor, crtc);
 	}
-
-	return 0;
 }
 #endif
+
+static const struct drm_prop_enum_list split_area[] = {
+	{ ROCKCHIP_DRM_SPLIT_UNSET, "UNSET" },
+	{ ROCKCHIP_DRM_SPLIT_LEFT_SIDE, "LEFT" },
+	{ ROCKCHIP_DRM_SPLIT_RIGHT_SIDE, "RIGHT" },
+};
 
 static int rockchip_drm_create_properties(struct drm_device *dev)
 {
@@ -1486,24 +1338,6 @@
 	private->color_space_prop = prop;
 
 	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
-					 "GLOBAL_ALPHA", 0, 255);
-	if (!prop)
-		return -ENOMEM;
-	private->global_alpha_prop = prop;
-
-	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
-					 "BLEND_MODE", 0, 1);
-	if (!prop)
-		return -ENOMEM;
-	private->blend_mode_prop = prop;
-
-	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
-					 "ALPHA_SCALE", 0, 1);
-	if (!prop)
-		return -ENOMEM;
-	private->alpha_scale_prop = prop;
-
-	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
 					 "ASYNC_COMMIT", 0, 1);
 	if (!prop)
 		return -ENOMEM;
@@ -1515,53 +1349,35 @@
 		return -ENOMEM;
 	private->share_id_prop = prop;
 
-	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_IMMUTABLE,
 					 "CONNECTOR_ID", 0, 0xf);
 	if (!prop)
 		return -ENOMEM;
 	private->connector_id_prop = prop;
 
+	prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "SPLIT_AREA",
+					split_area,
+					ARRAY_SIZE(split_area));
+	private->split_area_prop = prop;
+
+	prop = drm_property_create_object(dev,
+					  DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_IMMUTABLE,
+					  "SOC_ID", DRM_MODE_OBJECT_CRTC);
+	private->soc_id_prop = prop;
+
+	prop = drm_property_create_object(dev,
+					  DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_IMMUTABLE,
+					  "PORT_ID", DRM_MODE_OBJECT_CRTC);
+	private->port_id_prop = prop;
+
+	private->aclk_prop = drm_property_create_range(dev, 0, "ACLK", 0, UINT_MAX);
+	private->bg_prop = drm_property_create_range(dev, 0, "BACKGROUND", 0, UINT_MAX);
+	private->line_flag_prop = drm_property_create_range(dev, 0, "LINE_FLAG1", 0, UINT_MAX);
+	private->cubic_lut_prop = drm_property_create(dev, DRM_MODE_PROP_BLOB, "CUBIC_LUT", 0);
+	private->cubic_lut_size_prop = drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE,
+								 "CUBIC_LUT_SIZE", 0, UINT_MAX);
+
 	return drm_mode_create_tv_properties(dev, 0, NULL);
-}
-
-static int rockchip_gem_pool_init(struct drm_device *drm)
-{
-	struct rockchip_drm_private *private = drm->dev_private;
-	struct device_node *np = drm->dev->of_node;
-	struct device_node *node;
-	phys_addr_t start, size;
-	struct resource res;
-	int ret;
-
-	node = of_parse_phandle(np, "secure-memory-region", 0);
-	if (!node)
-		return -ENXIO;
-
-	ret = of_address_to_resource(node, 0, &res);
-	if (ret)
-		return ret;
-	start = res.start;
-	size = resource_size(&res);
-	if (!size)
-		return -ENOMEM;
-
-	private->secure_buffer_pool = gen_pool_create(PAGE_SHIFT, -1);
-	if (!private->secure_buffer_pool)
-		return -ENOMEM;
-
-	gen_pool_add(private->secure_buffer_pool, start, size, -1);
-
-	return 0;
-}
-
-static void rockchip_gem_pool_destroy(struct drm_device *drm)
-{
-	struct rockchip_drm_private *private = drm->dev_private;
-
-	if (!private->secure_buffer_pool)
-		return;
-
-	gen_pool_destroy(private->secure_buffer_pool);
 }
 
 static void rockchip_attach_connector_property(struct drm_device *drm)
@@ -1633,20 +1449,44 @@
 	drm_modeset_unlock_all(drm);
 }
 
-static bool is_support_hotplug(uint32_t output_type)
+static int rockchip_gem_pool_init(struct drm_device *drm)
 {
-	switch (output_type) {
-	case DRM_MODE_CONNECTOR_DVII:
-	case DRM_MODE_CONNECTOR_DVID:
-	case DRM_MODE_CONNECTOR_DVIA:
-	case DRM_MODE_CONNECTOR_DisplayPort:
-	case DRM_MODE_CONNECTOR_HDMIA:
-	case DRM_MODE_CONNECTOR_HDMIB:
-	case DRM_MODE_CONNECTOR_TV:
-		return true;
-	default:
-		return false;
-	}
+	struct rockchip_drm_private *private = drm->dev_private;
+	struct device_node *np = drm->dev->of_node;
+	struct device_node *node;
+	phys_addr_t start, size;
+	struct resource res;
+	int ret;
+
+	node = of_parse_phandle(np, "secure-memory-region", 0);
+	if (!node)
+		return -ENXIO;
+
+	ret = of_address_to_resource(node, 0, &res);
+	if (ret)
+		return ret;
+	start = res.start;
+	size = resource_size(&res);
+	if (!size)
+		return -ENOMEM;
+
+	private->secure_buffer_pool = gen_pool_create(PAGE_SHIFT, -1);
+	if (!private->secure_buffer_pool)
+		return -ENOMEM;
+
+	gen_pool_add(private->secure_buffer_pool, start, size, -1);
+
+	return 0;
+}
+
+static void rockchip_gem_pool_destroy(struct drm_device *drm)
+{
+	struct rockchip_drm_private *private = drm->dev_private;
+
+	if (!private->secure_buffer_pool)
+		return;
+
+	gen_pool_destroy(private->secure_buffer_pool);
 }
 
 static int rockchip_drm_bind(struct device *dev)
@@ -1654,9 +1494,6 @@
 	struct drm_device *drm_dev;
 	struct rockchip_drm_private *private;
 	int ret;
-	struct device_node *np = dev->of_node;
-	struct device_node *parent_np;
-	struct drm_crtc *crtc;
 
 	drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev);
 	if (IS_ERR(drm_dev))
@@ -1670,35 +1507,16 @@
 		goto err_free;
 	}
 
-	mutex_init(&private->commit_lock);
 	mutex_init(&private->ovl_lock);
-	INIT_WORK(&private->commit_work, rockchip_drm_atomic_work);
+
 	drm_dev->dev_private = private;
 
-	private->dmc_support = false;
-	private->devfreq = devfreq_get_devfreq_by_phandle(dev, 0);
-	if (IS_ERR(private->devfreq)) {
-		if (PTR_ERR(private->devfreq) == -EPROBE_DEFER) {
-			parent_np = of_parse_phandle(np, "devfreq", 0);
-			if (parent_np &&
-			    of_device_is_available(parent_np)) {
-				private->dmc_support = true;
-				dev_warn(dev, "defer getting devfreq\n");
-			} else {
-				dev_info(dev, "dmc is disabled\n");
-			}
-		} else {
-			dev_info(dev, "devfreq is not set\n");
-		}
-		private->devfreq = NULL;
-	} else {
-		private->dmc_support = true;
-		dev_info(dev, "devfreq is ready\n");
-	}
-	private->hdmi_pll.pll = devm_clk_get(dev, "hdmi-tmds-pll");
-	if (PTR_ERR(private->hdmi_pll.pll) == -ENOENT) {
-		private->hdmi_pll.pll = NULL;
-	} else if (PTR_ERR(private->hdmi_pll.pll) == -EPROBE_DEFER) {
+	INIT_LIST_HEAD(&private->psr_list);
+	mutex_init(&private->psr_list_lock);
+	mutex_init(&private->commit_lock);
+
+	private->hdmi_pll.pll = devm_clk_get_optional(dev, "hdmi-tmds-pll");
+	if (PTR_ERR(private->hdmi_pll.pll) == -EPROBE_DEFER) {
 		ret = -EPROBE_DEFER;
 		goto err_free;
 	} else if (IS_ERR(private->hdmi_pll.pll)) {
@@ -1706,10 +1524,8 @@
 		ret = PTR_ERR(private->hdmi_pll.pll);
 		goto err_free;
 	}
-	private->default_pll.pll = devm_clk_get(dev, "default-vop-pll");
-	if (PTR_ERR(private->default_pll.pll) == -ENOENT) {
-		private->default_pll.pll = NULL;
-	} else if (PTR_ERR(private->default_pll.pll) == -EPROBE_DEFER) {
+	private->default_pll.pll = devm_clk_get_optional(dev, "default-vop-pll");
+	if (PTR_ERR(private->default_pll.pll) == -EPROBE_DEFER) {
 		ret = -EPROBE_DEFER;
 		goto err_free;
 	} else if (IS_ERR(private->default_pll.pll)) {
@@ -1718,14 +1534,9 @@
 		goto err_free;
 	}
 
-	INIT_LIST_HEAD(&private->psr_list);
-	mutex_init(&private->psr_list_lock);
-
-	ret = rockchip_drm_init_iommu(drm_dev);
+	ret = drmm_mode_config_init(drm_dev);
 	if (ret)
 		goto err_free;
-
-	drm_mode_config_init(drm_dev);
 
 	rockchip_drm_mode_config_init(drm_dev);
 	rockchip_drm_create_properties(drm_dev);
@@ -1751,50 +1562,38 @@
 	/* init kms poll for handling hpd */
 	drm_kms_helper_poll_init(drm_dev);
 
-	private->page_pools = dmabuf_page_pool_create(GFP_HIGHUSER | __GFP_ZERO | __GFP_COMP, 0);
+	ret = rockchip_drm_init_iommu(drm_dev);
+	if (ret)
+		goto err_unbind_all;
 
 	rockchip_gem_pool_init(drm_dev);
-#ifndef MODULE
-	show_loader_logo(drm_dev);
-#endif
 	ret = of_reserved_mem_device_init(drm_dev->dev);
 	if (ret)
 		DRM_DEBUG_KMS("No reserved memory region assign to drm\n");
 
+	rockchip_drm_show_logo(drm_dev);
+
 	ret = rockchip_drm_fbdev_init(drm_dev);
 	if (ret)
-		goto err_kms_helper_poll_fini;
-
-	drm_for_each_crtc(crtc, drm_dev) {
-		struct drm_fb_helper *helper = private->fbdev_helper;
-		struct rockchip_crtc_state *s = NULL;
-
-		if (!helper)
-			break;
-
-		s = to_rockchip_crtc_state(crtc->state);
-		if (is_support_hotplug(s->output_type))
-			drm_framebuffer_get(helper->fb);
-	}
+		goto err_iommu_cleanup;
 
 	drm_dev->mode_config.allow_fb_modifiers = true;
 
 	ret = drm_dev_register(drm_dev, 0);
 	if (ret)
-		goto err_fbdev_fini;
+		goto err_kms_helper_poll_fini;
 
 	return 0;
-err_fbdev_fini:
-	rockchip_drm_fbdev_fini(drm_dev);
 err_kms_helper_poll_fini:
 	rockchip_gem_pool_destroy(drm_dev);
 	drm_kms_helper_poll_fini(drm_dev);
+	rockchip_drm_fbdev_fini(drm_dev);
+err_iommu_cleanup:
+	rockchip_iommu_cleanup(drm_dev);
 err_unbind_all:
-	dmabuf_page_pool_destroy(private->page_pools);
 	component_unbind_all(dev, drm_dev);
 err_mode_config_cleanup:
 	drm_mode_config_cleanup(drm_dev);
-	rockchip_iommu_cleanup(drm_dev);
 err_free:
 	drm_dev->dev_private = NULL;
 	dev_set_drvdata(dev, NULL);
@@ -1951,61 +1750,20 @@
 	return rockchip_gem_prime_end_cpu_access(obj, dir);
 }
 
-static int rockchip_drm_gem_begin_cpu_access_partial(
-	struct dma_buf *dma_buf,
-	enum dma_data_direction dir,
-	unsigned int offset, unsigned int len)
-{
-	struct drm_gem_object *obj = dma_buf->priv;
-
-	return rockchip_gem_prime_begin_cpu_access_partial(obj, dir, offset, len);
-}
-
-static int rockchip_drm_gem_end_cpu_access_partial(
-	struct dma_buf *dma_buf,
-	enum dma_data_direction dir,
-	unsigned int offset, unsigned int len)
-{
-	struct drm_gem_object *obj = dma_buf->priv;
-
-	return rockchip_gem_prime_end_cpu_access_partial(obj, dir, offset, len);
-}
-
 static const struct dma_buf_ops rockchip_drm_gem_prime_dmabuf_ops = {
+	.cache_sgt_mapping = true,
 	.attach = drm_gem_map_attach,
 	.detach = drm_gem_map_detach,
 	.map_dma_buf = drm_gem_map_dma_buf,
 	.unmap_dma_buf = drm_gem_unmap_dma_buf,
 	.release = drm_gem_dmabuf_release,
-	.map = drm_gem_dmabuf_kmap,
-	.unmap = drm_gem_dmabuf_kunmap,
 	.mmap = drm_gem_dmabuf_mmap,
 	.vmap = drm_gem_dmabuf_vmap,
 	.vunmap = drm_gem_dmabuf_vunmap,
+	.get_uuid = drm_gem_dmabuf_get_uuid,
 	.begin_cpu_access = rockchip_drm_gem_dmabuf_begin_cpu_access,
 	.end_cpu_access = rockchip_drm_gem_dmabuf_end_cpu_access,
-	.begin_cpu_access_partial = rockchip_drm_gem_begin_cpu_access_partial,
-	.end_cpu_access_partial = rockchip_drm_gem_end_cpu_access_partial,
 };
-
-#ifdef CONFIG_ARCH_ROCKCHIP
-static void drm_gem_prime_dmabuf_release_callback(void *data)
-{
-	struct drm_prime_callback_data *cb_data = data;
-
-	if (cb_data && cb_data->obj && cb_data->obj->import_attach) {
-		struct dma_buf_attachment *attach = cb_data->obj->import_attach;
-		struct sg_table *sgt = cb_data->sgt;
-
-		if (sgt)
-			dma_buf_unmap_attachment(attach, sgt,
-						 DMA_BIDIRECTIONAL);
-		dma_buf_detach(attach->dmabuf, attach);
-		drm_gem_object_put_unlocked(cb_data->obj);
-		kfree(cb_data);
-	}
-}
-#endif
 
 static struct drm_gem_object *rockchip_drm_gem_prime_import_dev(struct drm_device *dev,
 								struct dma_buf *dma_buf,
@@ -2014,9 +1772,6 @@
 	struct dma_buf_attachment *attach;
 	struct sg_table *sgt;
 	struct drm_gem_object *obj;
-#ifdef CONFIG_ARCH_ROCKCHIP
-	struct drm_prime_callback_data *cb_data = NULL;
-#endif
 	int ret;
 
 	if (dma_buf->ops == &rockchip_drm_gem_prime_dmabuf_ops) {
@@ -2031,15 +1786,6 @@
 		}
 	}
 
-#ifdef CONFIG_ARCH_ROCKCHIP
-	cb_data = dma_buf_get_release_callback_data(dma_buf,
-					drm_gem_prime_dmabuf_release_callback);
-	if (cb_data && cb_data->obj && cb_data->obj->dev == dev) {
-		drm_gem_object_get(cb_data->obj);
-		return cb_data->obj;
-	}
-#endif
-
 	if (!dev->driver->gem_prime_import_sg_table)
 		return ERR_PTR(-EINVAL);
 
@@ -2048,14 +1794,6 @@
 		return ERR_CAST(attach);
 
 	get_dma_buf(dma_buf);
-
-#ifdef CONFIG_ARCH_ROCKCHIP
-	cb_data = kmalloc(sizeof(*cb_data), GFP_KERNEL);
-	if (!cb_data) {
-		ret = -ENOMEM;
-		goto fail_detach;
-	}
-#endif
 
 	sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
 	if (IS_ERR(sgt)) {
@@ -2070,24 +1808,13 @@
 	}
 
 	obj->import_attach = attach;
-
-#ifdef CONFIG_ARCH_ROCKCHIP
-	cb_data->obj = obj;
-	cb_data->sgt = sgt;
-	dma_buf_set_release_callback(dma_buf,
-			drm_gem_prime_dmabuf_release_callback, cb_data);
-	dma_buf_put(dma_buf);
-	drm_gem_object_get(obj);
-#endif
+	obj->resv = dma_buf->resv;
 
 	return obj;
 
 fail_unmap:
 	dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
 fail_detach:
-#ifdef CONFIG_ARCH_ROCKCHIP
-	kfree(cb_data);
-#endif
 	dma_buf_detach(dma_buf, attach);
 	dma_buf_put(dma_buf);
 
@@ -2100,10 +1827,10 @@
 	return rockchip_drm_gem_prime_import_dev(dev, dma_buf, dev->dev);
 }
 
-static struct dma_buf *rockchip_drm_gem_prime_export(struct drm_device *dev,
-						     struct drm_gem_object *obj,
+static struct dma_buf *rockchip_drm_gem_prime_export(struct drm_gem_object *obj,
 						     int flags)
 {
+	struct drm_device *dev = obj->dev;
 	struct dma_buf_export_info exp_info = {
 		.exp_name = KBUILD_MODNAME, /* white lie for debug */
 		.owner = dev->driver->fops->owner,
@@ -2111,26 +1838,20 @@
 		.size = obj->size,
 		.flags = flags,
 		.priv = obj,
+		.resv = obj->resv,
 	};
-
-	if (dev->driver->gem_prime_res_obj)
-		exp_info.resv = dev->driver->gem_prime_res_obj(obj);
 
 	return drm_gem_dmabuf_export(dev, &exp_info);
 }
 
 static struct drm_driver rockchip_drm_driver = {
-	.driver_features	= DRIVER_MODESET | DRIVER_GEM |
-				  DRIVER_PRIME | DRIVER_ATOMIC |
-				  DRIVER_RENDER,
+	.driver_features	= DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC | DRIVER_RENDER,
 	.postclose		= rockchip_drm_postclose,
 	.lastclose		= rockchip_drm_lastclose,
 	.open			= rockchip_drm_open,
 	.gem_vm_ops		= &drm_gem_cma_vm_ops,
 	.gem_free_object_unlocked = rockchip_gem_free_object,
 	.dumb_create		= rockchip_gem_dumb_create,
-	.dumb_map_offset	= rockchip_gem_dumb_map_offset,
-	.dumb_destroy		= drm_gem_dumb_destroy,
 	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
 	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
 	.gem_prime_import	= rockchip_drm_gem_prime_import,
@@ -2151,64 +1872,21 @@
 	.date	= DRIVER_DATE,
 	.major	= DRIVER_MAJOR,
 	.minor	= DRIVER_MINOR,
-	.patchlevel	= DRIVER_PATCH,
 };
 
 #ifdef CONFIG_PM_SLEEP
-static void rockchip_drm_fb_suspend(struct drm_device *drm)
-{
-	struct rockchip_drm_private *priv = drm->dev_private;
-
-	console_lock();
-	drm_fb_helper_set_suspend(priv->fbdev_helper, 1);
-	console_unlock();
-}
-
-static void rockchip_drm_fb_resume(struct drm_device *drm)
-{
-	struct rockchip_drm_private *priv = drm->dev_private;
-
-	console_lock();
-	drm_fb_helper_set_suspend(priv->fbdev_helper, 0);
-	console_unlock();
-}
-
 static int rockchip_drm_sys_suspend(struct device *dev)
 {
 	struct drm_device *drm = dev_get_drvdata(dev);
-	struct rockchip_drm_private *priv;
 
-	if (!drm)
-		return 0;
-
-	drm_kms_helper_poll_disable(drm);
-	rockchip_drm_fb_suspend(drm);
-
-	priv = drm->dev_private;
-	priv->state = drm_atomic_helper_suspend(drm);
-	if (IS_ERR(priv->state)) {
-		rockchip_drm_fb_resume(drm);
-		drm_kms_helper_poll_enable(drm);
-		return PTR_ERR(priv->state);
-	}
-
-	return 0;
+	return drm_mode_config_helper_suspend(drm);
 }
 
 static int rockchip_drm_sys_resume(struct device *dev)
 {
 	struct drm_device *drm = dev_get_drvdata(dev);
-	struct rockchip_drm_private *priv;
 
-	if (!drm)
-		return 0;
-
-	priv = drm->dev_private;
-	drm_atomic_helper_resume(drm, priv->state);
-	rockchip_drm_fb_resume(drm);
-	drm_kms_helper_poll_enable(drm);
-
-	return 0;
+	return drm_mode_config_helper_resume(drm);
 }
 #endif
 
@@ -2220,6 +1898,53 @@
 #define MAX_ROCKCHIP_SUB_DRIVERS 16
 static struct platform_driver *rockchip_sub_drivers[MAX_ROCKCHIP_SUB_DRIVERS];
 static int num_rockchip_sub_drivers;
+
+/*
+ * Check if a vop endpoint is leading to a rockchip subdriver or bridge.
+ * Should be called from the component bind stage of the drivers
+ * to ensure that all subdrivers are probed.
+ *
+ * @ep: endpoint of a rockchip vop
+ *
+ * returns true if subdriver, false if external bridge and -ENODEV
+ * if remote port does not contain a device.
+ */
+int rockchip_drm_endpoint_is_subdriver(struct device_node *ep)
+{
+	struct device_node *node = of_graph_get_remote_port_parent(ep);
+	struct platform_device *pdev;
+	struct device_driver *drv;
+	int i;
+
+	if (!node)
+		return -ENODEV;
+
+	/* status disabled will prevent creation of platform-devices */
+	pdev = of_find_device_by_node(node);
+	of_node_put(node);
+	if (!pdev)
+		return -ENODEV;
+
+	/*
+	 * All rockchip subdrivers have probed at this point, so
+	 * any device not having a driver now is an external bridge.
+	 */
+	drv = pdev->dev.driver;
+	if (!drv) {
+		platform_device_put(pdev);
+		return false;
+	}
+
+	for (i = 0; i < num_rockchip_sub_drivers; i++) {
+		if (rockchip_sub_drivers[i] == to_platform_driver(drv)) {
+			platform_device_put(pdev);
+			return true;
+		}
+	}
+
+	platform_device_put(pdev);
+	return false;
+}
 
 static int compare_dev(struct device *dev, void *data)
 {
@@ -2244,8 +1969,7 @@
 		struct device *p = NULL, *d;
 
 		do {
-			d = bus_find_device(&platform_bus_type, p, &drv->driver,
-					    (void *)platform_bus_type.match);
+			d = platform_find_device_by_driver(p, &drv->driver);
 			put_device(p);
 			p = d;
 
@@ -2291,7 +2015,7 @@
 		}
 
 		iommu = of_parse_phandle(port->parent, "iommus", 0);
-		if (!iommu || !of_device_is_available(iommu->parent)) {
+		if (!iommu || !of_device_is_available(iommu)) {
 			DRM_DEV_DEBUG(dev,
 				      "no iommu attached for %pOF, using non-iommu buffers\n",
 				      port->parent);
@@ -2304,6 +2028,7 @@
 
 		found = true;
 
+		iommu_reserve_map |= of_property_read_bool(iommu, "rockchip,reserve-map");
 		of_node_put(iommu);
 		of_node_put(port);
 	}
@@ -2338,14 +2063,19 @@
 	if (IS_ERR(match))
 		return PTR_ERR(match);
 
+	ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64));
+	if (ret)
+		goto err;
+
 	ret = component_master_add_with_match(dev, &rockchip_drm_ops, match);
-	if (ret < 0) {
-		rockchip_drm_match_remove(dev);
-		return ret;
-	}
-	dev->coherent_dma_mask = DMA_BIT_MASK(64);
+	if (ret < 0)
+		goto err;
 
 	return 0;
+err:
+	rockchip_drm_match_remove(dev);
+
+	return ret;
 }
 
 static int rockchip_drm_platform_remove(struct platform_device *pdev)
@@ -2361,10 +2091,8 @@
 {
 	struct drm_device *drm = platform_get_drvdata(pdev);
 
-	if (drm) {
-		drm_kms_helper_poll_fini(drm);
+	if (drm)
 		drm_atomic_helper_shutdown(drm);
-	}
 }
 
 static const struct of_device_id rockchip_drm_dt_ids[] = {
@@ -2400,6 +2128,7 @@
 #else
 	ADD_ROCKCHIP_SUB_DRIVER(vop_platform_driver, CONFIG_ROCKCHIP_VOP);
 	ADD_ROCKCHIP_SUB_DRIVER(vop2_platform_driver, CONFIG_ROCKCHIP_VOP2);
+	ADD_ROCKCHIP_SUB_DRIVER(vconn_platform_driver, CONFIG_ROCKCHIP_VCONN);
 	ADD_ROCKCHIP_SUB_DRIVER(rockchip_lvds_driver,
 				CONFIG_ROCKCHIP_LVDS);
 	ADD_ROCKCHIP_SUB_DRIVER(rockchip_dp_driver,
@@ -2407,12 +2136,17 @@
 	ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP);
 	ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_rockchip_pltfm_driver,
 				CONFIG_ROCKCHIP_DW_HDMI);
-	ADD_ROCKCHIP_SUB_DRIVER(dw_mipi_dsi_driver,
+	ADD_ROCKCHIP_SUB_DRIVER(dw_mipi_dsi_rockchip_driver,
+				CONFIG_ROCKCHIP_DW_MIPI_DSI);
+	ADD_ROCKCHIP_SUB_DRIVER(dw_mipi_dsi2_rockchip_driver,
 				CONFIG_ROCKCHIP_DW_MIPI_DSI);
 	ADD_ROCKCHIP_SUB_DRIVER(inno_hdmi_driver, CONFIG_ROCKCHIP_INNO_HDMI);
-	ADD_ROCKCHIP_SUB_DRIVER(rockchip_tve_driver,
-				CONFIG_ROCKCHIP_DRM_TVE);
+	ADD_ROCKCHIP_SUB_DRIVER(rk3066_hdmi_driver,
+				CONFIG_ROCKCHIP_RK3066_HDMI);
 	ADD_ROCKCHIP_SUB_DRIVER(rockchip_rgb_driver, CONFIG_ROCKCHIP_RGB);
+	ADD_ROCKCHIP_SUB_DRIVER(rockchip_tve_driver, CONFIG_ROCKCHIP_DRM_TVE);
+	ADD_ROCKCHIP_SUB_DRIVER(dw_dp_driver, CONFIG_ROCKCHIP_DW_DP);
+
 #endif
 	ret = platform_register_drivers(rockchip_sub_drivers,
 					num_rockchip_sub_drivers);
@@ -2422,6 +2156,8 @@
 	ret = platform_driver_register(&rockchip_drm_platform_driver);
 	if (ret)
 		goto err_unreg_drivers;
+
+	rockchip_gem_get_ddr_info();
 
 	return 0;
 
@@ -2439,7 +2175,11 @@
 				    num_rockchip_sub_drivers);
 }
 
+#ifdef CONFIG_VIDEO_REVERSE_IMAGE
+fs_initcall(rockchip_drm_init);
+#else
 module_init(rockchip_drm_init);
+#endif
 module_exit(rockchip_drm_fini);
 
 MODULE_AUTHOR("Mark Yao <mark.yao@rock-chips.com>");

--
Gitblit v1.6.2